d3-xyzoom

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.*

Try out the demo

Try out the demo

## Installing

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>
```

## API Reference

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

*k*= 1,

_{x}*k*= 1,

_{y}*t*=

_{x}*t*= 0.

_{y}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).

### Zoom Transforms

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:

*k*0

_{x}*t*

_{x}0

*k*

_{y}*t*

_{y}0 0 1

The position ⟨

*x*,

*y*⟩ is transformed to ⟨

*x*×

*k*+

_{x}*t*,

_{x}*y*×

*k*+

_{y}*t*⟩. The transform object exposes the following properties:

_{y}`x`

- the translation amount*t*along the_{x}*x*-axis.`y`

- the translation amount*t*along the_{y}*y*-axis.`kx`

- the scale factor*k*along the_{x}*x*-axis.`ky`

- the scale factor*k*along the_{y}*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

*k*,

_{x}*k*,

_{y}*t*, and

_{x}*t*:

_{y}`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

*k*,

_{x1}*k*are equals to

_{y1}*k*×

_{x0}*kx*,

*k*×

_{y0}*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*×

*k*+

_{x}*t*,

_{x}*y*×

*k*+

_{y}*t*.

_{y}