<!DOCTYPE html>
<html>
<head>
<title>Restricted zoom behavior in d3</title>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"></script>
<style>
</style>
</head>
<body>
<script>
// first, define your viewport dimensions
var width = 960,
height = 500;
// then, create your svg element and a <g> container
// for all of the transformed content
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.style("background-color", randomColor),
g = svg.append("g");
// then, create the zoom behvavior
var zoom = d3.behavior.zoom()
// only scale up, e.g. between 1x and 50x
.scaleExtent([1, 50])
.on("zoom", function() {
// the "zoom" event populates d3.event with an object that has
// a "translate" property (a 2-element Array in the form [x, y])
// and a numeric "scale" property
var e = d3.event,
// now, constrain the x and y components of the translation by the
// dimensions of the viewport
tx = Math.min(0, Math.max(e.translate[0], width - width * e.scale)),
ty = Math.min(0, Math.max(e.translate[1], height - height * e.scale));
// then, update the zoom behavior's internal translation, so that
// it knows how to properly manipulate it on the next movement
zoom.translate([tx, ty]);
// and finally, update the <g> element's transform attribute with the
// correct translation and scale (in reverse order)
g.attr("transform", [
"translate(" + [tx, ty] + ")",
"scale(" + e.scale + ")"
].join(" "));
});
// then, call the zoom behavior on the svg element, which will add
// all of the necessary mouse and touch event handlers.
// remember that if you call this on the <g> element, the even handlers
// will only trigger when the mouse or touch cursor intersects with the
// <g> elements' children!
svg.call(zoom);
// then, let's add some circles
var circle = g.selectAll("circle")
.data(d3.range(300).map(function(i) {
return {
x: Math.random() * width,
y: Math.random() * height,
r: .01 + Math.random() * 50,
color: randomColor()
};
}).sort(function(a, b) {
return d3.descending(a.r, b.r);
}))
.enter()
.append("circle")
.attr("fill", function(d) { return d.color; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.r; });
function randomColor() {
return "hsl(" + ~~(60 + Math.random() * 180) + ",80%,60%)";
}
</script>
</body>
</html>