Skip to content

Instantly share code, notes, and snippets.

@emepyc
Last active December 5, 2023 13:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emepyc/7218bc9ea76951d6a78b0c7942e07a00 to your computer and use it in GitHub Desktop.
Save emepyc/7218bc9ea76951d6a78b0c7942e07a00 to your computer and use it in GitHub Desktop.
Limit panning/zooming in d3 v4

Example of how to use zoom.extent and zoom.translateExtent to limit panning/zooming in d3 v4. The initial state of the visualisation are centered on coordinates [500, 1500] using zoom.transform. The limits for panning/zooming are set to [0, 5000].

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.js"></script>
<style>
svg text {
font-family: sans-serif;
font-size: 13px;
}
circle {
fill: transparent;
stroke: black;
stroke-width: 1px;
pointer-events:none;
}
</style>
</head>
<body>
<div id="block"></div>
<script>
// dimensions
var dims = {
width: 800,
height: 300,
svg_dx: 100,
svg_dy: 100
};
// Data
var dataPoints = [1, 1010, 1020, 5000];
// Zoom
var zoom = d3.zoom()
.extent([[dims.svg_dx, dims.svg_dy], [dims.width-(dims.svg_dx*2), dims.height-dims.svg_dy]])
.scaleExtent([1, 10])
.translateExtent([[dims.svg_dx, dims.svg_dy], [dims.width-(dims.svg_dx*2), dims.height-dims.svg_dy]])
.on('zoom', zoomed);
// Scale
var xScale = d3.scaleLinear()
.domain([0, 5000])
.range([dims.svg_dx, dims.width-(dims.svg_dx*2)]);
// Axis
var xAxis = d3.axisTop(xScale)
// Main svg
var gMain = d3.select('#block')
.append("svg")
.attr("width", dims.width)
.attr("height", dims.height)
.append("g")
.attr("transform", "translate(100, 100)");
var rect = gMain
.append("rect")
.attr("x", 0)
.attr("y", -25)
.attr("width", dims.width)
.attr("height", 50)
.style("fill", "transparent")
.call(zoom);
// circles
var circles = gMain.selectAll('circle')
.data(dataPoints)
.enter()
.append('circle')
.attr('r', 7)
.attr('cx', function (d) {
return xScale(d);
});
// axis
var axis = gMain.append("g")
// Jump to position (500, 1500) at start
startTransition();
function zoomed() {
var transform = d3.event.transform;
// Zoom the circles
var xNewScale = transform.rescaleX(xScale);
circles
.attr("cx", function (d) {
return xNewScale(d);
});
// Zoom the axis
xAxis.scale(xNewScale);
axis.call(xAxis);
}
function startTransition() {
// Position to (500, 1500) at start
// to jump to [500,1500] we need to calculate a new scale factor (k)...
var k = (xScale(5000) - xScale(0)) / (xScale(1500) - xScale(500));
// ...and then a translate to [500, 0]
var tx = dims.svg_dx - (k * xScale(500));
var t = d3.zoomIdentity.translate(tx, 0).scale(k);
// Rescale the axis
xAxis.scale(t.rescaleX(xScale));
axis
.attr("transform", "translate(0,-20)")
.call(xAxis);
// Rescale the circles
rect.call(zoom.transform, t);
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment