Skip to content

Instantly share code, notes, and snippets.

@baygeldin
Last active February 20, 2022 06:05
Show Gist options
  • Save baygeldin/16c9a7c23952ff2ade6c7708b88aa90f to your computer and use it in GitHub Desktop.
Save baygeldin/16c9a7c23952ff2ade6c7708b88aa90f to your computer and use it in GitHub Desktop.
Why "translateTo" would be useful in D3.
license: mit

An example showing why "translateTo" method that respects "translateExtent" would be useful in D3. The zoomable area contains a number of objects. When user clicks on an object, the area is translated to the object's center. However, since "transform" method does not respect "translateExtent" the viewport goes beyond borders.

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
.canvas { fill: lightgrey; }
.object { fill: white; stroke: black; stroke-width: 1.5; cursor: pointer; }
.object:hover { fill: aliceblue; }
</style>
</head>
<body>
<script>
let width = 960
let height = 500
let minObjectSize = 50
let maxObjectSize = 100
let svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
let group = svg.append('g')
let canvas = group.append('rect')
.attr('class', 'canvas')
.attr('width', width)
.attr('height', height)
let zoom = d3.zoom()
.scaleExtent([1, 8])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on('zoom', () => {
group.attr('transform', d3.event.transform)
})
group.call(zoom)
let objects = d3.range(0, 10, 1).map((i) => ({
x: d3.randomUniform(maxObjectSize, width - maxObjectSize)(),
y: d3.randomUniform(maxObjectSize, height - maxObjectSize)(),
width: d3.randomUniform(minObjectSize, maxObjectSize)(),
height: d3.randomUniform(minObjectSize, maxObjectSize)()
}))
group.selectAll()
.data(objects).enter().append('rect')
.attr('class', 'object')
.attr('x', (d) => d.x)
.attr('y', (d) => d.y)
.attr('width', (d) => d.width)
.attr('height', (d) => d.height)
.on('click', (d) => {
let t0 = d3.zoomTransform(group.node())
let x = Math.round(width / 2) / t0.k - (d.x + Math.round(d.width / 2))
let y = Math.round(height / 2) / t0.k - (d.y + Math.round(d.height / 2))
let t1 = d3.zoomIdentity.scale(t0.k).translate(x, y)
group.call(zoom.transform, t1)
})
</script>
</body>
@baygeldin
Copy link
Author

Related: d3/d3-zoom#94

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment