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

## Installing

If you use NPM, `npm install d3-xyzoom`

. If you use Bower `bower install d3-xyzoom`

. Otherwise, download the latest release.

## 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 _{x}* = 1,

*k*= 1,

_{y}*t*=

_{x}*t*= 0.

_{y}For example, to reset the zoom transform to the identity transform instantaneously:

`selection;`

# *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;`

The returned transform represents a two-dimensional transformation matrix of the form:

*k _{x}* 0

*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 = d3zoomIdentity;`

To apply the transformation to a Canvas 2D context, use *context*.translate followed by *context*.scale:

`context;context;`

Similarly, to apply the transformation to HTML elements via CSS:

`divstyle"transform" "translate(" + transformx + "px," + transformy + "px) scale(" + transformkx + "," + transformky + ")";`

To apply the transformation to SVG:

`g;`

Or more simply, taking advantage of *transform*.toString:

`g;`

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}