This plugin is a fork of d3-zoom that adds several features by separating scaling on x and y:
- Scale independently along x-axis and y-axis
- Constrain scale extent on zoom out to respect translate extent constraints
- Apply "scale factor ratio" on user input. For instance, with a scale ratio of 0.5 on x-axis and 1 on y-axis, when user zoom with its mouse, the increase of scale factor on x-axis will only be half of the increase on y-axis.
If you use NPM, npm install d3-xyzoom
. If you use Bower bower install d3-xyzoom
. Otherwise, download the latest release.
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="d3-xyzoom.min.js"></script>
<script>
var xyzoom = d3.xyzoom();
</script>
Here are the API methods that are different from original d3-zoom.
# d3.xyzoom()
Creates a new zoom behavior. The returned behavior, xyzoom, is both an object and a function, and is typically applied to selected elements via selection.call.
# d3.xyzoomIdentity
The identity transform, where kx = 1, ky = 1, tx = ty = 0.
For example, to reset the zoom transform to the identity transform instantaneously:
selection.call(xyzoom.transform, d3.xyzoomIdentity);
# xyzoom.extent([extent])
The viewport extent is required to make this plugin works. It enforces translateExtent and scaleExtent.
# xyzoom.scaleExtent([extent])
If extent is specified, sets the scale extent to the specified array [[kx0, kx1], [ky0, ky1]] where kx0 (resp. ky0) is the minimum allowed scale factor on x (resp. y) and kx1 (resp. ky1) is the maximum allowed scale factor on x (resp. y), and returns this xyzoom behavior. If extent is not specified, returns the current scales extent, which defaults to [[0, ∞], [0, ∞]]. Note that it returns the scale extent defined with the same method, the minimum scale value can be greater than the one you defined in order to respect translate extent constrains. The scale extent restricts zooming in and out. It is enforced on interaction and when using xyzoom.scaleBy, xyzoom.scaleTo and xyzoom.translateBy ; however, it is not enforced when using xyzoom.transform to set the transform explicitly.
# xyzoom.translateExtent([extent])
The translate extent can be used the same way as in d3-zoom. However, it restricts zoom out instead of just causing translation. When you define a translate extent, a minimum scale factor is computed on x and y based on current extent and translate extent. This scale factor can override the one you have passed in scaleExtent it is a smaller value.
# xyzoom.scaleRatio([ratio])
If ratio is specified, sets the scale factor ratio on user input to the specified array [rx, ry] where rx / ry represents the relative increase of scale factor on x-axis compared to y-axis, and returns this xyzoom behavior. If ratio is not specified, returns the current scale factor ratio, which defaults to [1, 1].
On wheel event, the increase in kx will be rx% of the increase of the classic behaviour. To prevent zoom on x-axis, set rx to 0.
Currently, only wheel event is supported. If you can help for touch events, please contact me!
# xyzoom.interpolate([interpolate])
In d3-xyzoom, the default interpolation factory is a d3.interpolateNumber on transform parameters. It forces zoom behaviour to respect the extent constraints, on the contrary of d3.interpolateZoom I'm working on implementing a nonuniform scaling transition based on "A model for smooth viewing and navigation of large 2D information spaces.", van Wijk, J. J., & Nuij, W. A. (2004).
To retrieve the zoom state, use event.transform on the current zoom event within a zoom event listener or use d3.xyzoomTransform for a given node. The latter is particularly useful for modifying the zoom state programmatically, say to implement buttons for zooming in and out.
# d3.xyzoomTransform(node)
Returns the current transform for the specified node.
var transform = d3.xyzoomTransform(selection.node());
The returned transform represents a two-dimensional transformation matrix of the form:
kx 0 tx
0 ky ty
0 0 1
The position ⟨x,y⟩ is transformed to ⟨x × kx + tx,y × ky + ty⟩. The transform object exposes the following properties:
x
- the translation amount tx along the x-axis.y
- the translation amount ty along the y-axis.kx
- the scale factor kx along the x-axis.ky
- the scale factor ky along the y-axis.
These properties should be considered read-only; instead of mutating a transform, use transform.scale and transform.translate to derive a new transform. Also see xyzoom.scaleBy, xyzoom.scaleTo and xyzoom.translateBy for convenience methods on the zoom behavior. To create a transform with a given kx, ky, tx, and ty:
var t = d3.zoomIdentity.translate(x, y).scale(kx, ky);
To apply the transformation to a Canvas 2D context, use context.translate followed by context.scale:
context.translate(transform.x, transform.y);
context.scale(transform.kx, transform.ky);
Similarly, to apply the transformation to HTML elements via CSS:
div.style("transform", "translate(" + transform.x + "px," + transform.y + "px) scale(" + transform.kx + "," + transform.ky + ")");
To apply the transformation to SVG:
g.attr("transform", "translate(" + transform.x + "," + transform.y + ") scale(" + transform.kx + "," + transform.ky + ")");
Or more simply, taking advantage of transform.toString:
g.attr("transform", transform);
Note that the order of transformations matters! The translate must be applied before the scale.
# transform.scale(kx, ky)
Returns a transform whose scale kx1, ky1 are equals to kx0 × kx, ky0 × ky.
# transform.apply(point)
Returns the transformation of the specified point which is a two-element array of numbers [x, y]. The returned point is equal to [x × kx + tx, y × ky + ty].