Skip to content

Instantly share code, notes, and snippets.

@mrcslws mrcslws/.block
Last active Mar 17, 2017

Embed
What would you like to do?
d3-zoom: You must position your rect with "transform"
license: gpl-3.0

This demonstrates that d3-zoom doesn't compute the zoom point as expected if you position a zoom-catching rect with "x" and "y" attributes. If you position the rect with "transform", it works as expected.

Point your mouse at a certain point, e.g. (100, 100). Try to zoom in on it. See how the point (100, 100) starts to scroll out of sight?

Now click "Fix it" and try it again. It works.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.axis path {
display: none;
}
.axis line {
stroke-opacity: 0.3;
shape-rendering: crispEdges;
}
.view {
fill: url(#gradient);
stroke: #000;
}
button {
position: absolute;
top: 20px;
left: 20px;
}
</style>
<button>Fix it</button>
<svg width="960" height="500">
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0.0%" stop-color="#2c7bb6"></stop>
<stop offset="12.5%" stop-color="#00a6ca"></stop>
<stop offset="25.0%" stop-color="#00ccbc"></stop>
<stop offset="37.5%" stop-color="#90eb9d"></stop>
<stop offset="50.0%" stop-color="#ffff8c"></stop>
<stop offset="62.5%" stop-color="#f9d057"></stop>
<stop offset="75.0%" stop-color="#f29e2e"></stop>
<stop offset="87.5%" stop-color="#e76818"></stop>
<stop offset="100.0%" stop-color="#d7191c"></stop>
</linearGradient>
</defs>
</svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var padding = {top: 100, right: 100, bottom: 100, left: 100};
var svg = d3.select("svg"),
width = +svg.attr("width") - padding.top - padding.bottom,
height = +svg.attr("height") - padding.left - padding.right;
svg.append("defs")
.append('clipPath')
.attr('id', "myClipPath")
.append('rect')
.attr('width', width)
.attr('height', height);
var zoom = d3.zoom()
.extent([[0, 0], [width, height]])
.scaleExtent([1, 40])
.translateExtent([[0, 0], [width, height]])
.on("zoom", zoomed);
var x = d3.scaleLinear()
.domain([0, width])
.range([0, width]);
var y = d3.scaleLinear()
.domain([0, height])
.range([0, height]);
var xAxis = d3.axisBottom(x)
.tickSize(height)
.tickPadding(8 - height);
var yAxis = d3.axisRight(y)
.ticks(4)
.tickSize(width)
.tickPadding(8 - width);
var view = svg
.append("g")
.attr("transform", "translate(" + padding.left + "," + padding.top + ")")
.style("clip-path", "url(#myClipPath)")
.append("rect")
.attr("class", "view")
.attr("width", width)
.attr("height", height);
var gX = svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(" + padding.left + "," + padding.top + ")")
.call(xAxis);
var gY = svg.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(" + padding.left + "," + padding.top + ")")
.call(yAxis);
d3.select("button")
.on("click", fixIt);
var zoomCatcher = svg
.append("rect")
.attr("class", "zoomCatcher")
.attr("x", padding.left)
.attr("y", padding.top)
.attr("width", width)
.attr("height", height)
.attr("fill", "transparent")
.attr("stroke", "none")
.call(zoom);
function zoomed() {
view.attr("transform", d3.event.transform);
gX.call(xAxis.scale(d3.event.transform.rescaleX(x)));
gY.call(yAxis.scale(d3.event.transform.rescaleY(y)));
}
function fixIt() {
zoomCatcher
.call(zoom.transform, d3.zoomIdentity);
zoomCatcher
.attr("transform", "translate(" + padding.left + "," + padding.top + ")")
.attr("x", 0)
.attr("y", 0);
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.