Skip to content

Instantly share code, notes, and snippets.

@1Cr18Ni9
Created May 27, 2019 07:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 1Cr18Ni9/b1bdb9fe29c99618ddd153153cf66c6f to your computer and use it in GitHub Desktop.
Save 1Cr18Ni9/b1bdb9fe29c99618ddd153153cf66c6f to your computer and use it in GitHub Desktop.
Understanding of Zoom behavior
license: mit

I'm trying to make a map that have zoom-in and zoom-out functionality.

The problem is when wheeling on the map:

  1. some shape will scale accordingly,
  2. all borders will increase or decrease,
  3. texts will change it's size either.

Firstly, we need understanding what is Zoom Behavior, as the document suggests:

The zoom behavior stores the zoom state on the element to which the zoom behavior was applied

We have two ways to access this object that applied on some node. One way to access it on the fly is when user trigger the zoom event:

var transform = d3.event.transform

Another way is to utilise d3.zoomTransform(node), node is DomNode which bind this behavior.

transform is some kind of 2d matrix object:

k b tx

d k ty

0 0 1

  • transform.x - the translation amount tx along the x-axis.
  • transform.y - the translation amount ty along the y-axis.
  • transform.k - the scale factor k.
  • transform.toString() - return "translate(tx, ty) scale(k)"
  • d3.zoomIdentity - identity matrix normally used for reinstates

When scaling I can use d3.event.transform.k to get scale factor, and descale the stroke-width make it always seems identical width( normalWidth / scale ).

Symbol path area linear scale with k^2, I was trying to utilise with the same trick but failed because all symbole seems more luminous. So I just redraw the d attribute.

<!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; }
svg {outline: 1px solid gray; margin: 1em; }
</style>
</head>
<body>
<svg width="600" height="500">
<g></g>
</svg>
<script>
var shapes = ["symbolCircle", "symbolCross", "symbolTriangle"]
var data = (function () {
var res = [];
for (var i = 0; i < 500; i++) {
res.push({
cx: Math.random() * 1000 - 200,
cy: Math.random() * 700 - 100,
shape: shapes[Math.round(Math.random() * 3 - 0.5)]
});
}
return res;
})();
var svg = d3.select("svg"),
g = d3.select("g"),
sb = d3.symbol();
g.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("transform", d => "translate(" + [d.cx, d.cy] + ")")
.attr("d", d => sb.type(d3[d.shape])())
.attr("fill", "transparent")
.attr("stroke", "#333");
function zoomed () {
var t = d3.event.transform;
g.attr("transform", t);
g.selectAll("path")
.attr("stroke-width", 1 / t.k)
.attr("d", d => sb.type(d3[d.shape]).size(64 / (t.k * t.k))());
//.attr("transform", d => "translate(" + [d.cx, d.cy] + ")" + " scale(" + 1 / t.k + ")")
}
var zoom = d3.zoom().on("zoom", zoomed);
svg.call(zoom);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment