Skip to content
/ d3-zoom Public

Pan and zoom SVG, HTML or Canvas using mouse or touch input.

License

Notifications You must be signed in to change notification settings

d3/d3-zoom

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

d3-zoom

Installing

If you use NPM, npm install d3-zoom. Otherwise, download the latest release. You can also load directly from d3js.org, either as a standalone library or as part of D3 4.0. AMD, CommonJS, and vanilla environments are supported. In vanilla, a d3_zoom global is exported:

<script src="https://d3js.org/d3-color.v0.4.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v0.4.min.js"></script>
<script src="https://d3js.org/d3-ease.v0.7.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v0.8.min.js"></script>
<script src="https://d3js.org/d3-selection.v0.7.min.js"></script>
<script src="https://d3js.org/d3-timer.v0.4.min.js"></script>
<script src="https://d3js.org/d3-transition.v0.2.min.js"></script>
<script src="https://d3js.org/d3-drag.v0.2.min.js"></script>
<script src="https://d3js.org/d3-zoom.v0.1.min.js"></script>
<script>

var zoom = d3_zoom.zoom();

</script>

Try d3-zoom in your browser.

API Reference

This table describes how the zoom behavior interprets native events:

Event Listening Element Zoom Event Default Prevented?
mousedown⁵ selection start no¹
mousemove² window¹ zoom yes
mouseup² window¹ end yes
dragstart² window - yes
selectstart² window - yes
click³ window - yes
dblclick selection multiple yes
wheel selection zoom⁷ yes
touchstart selection multiple no⁴
touchmove selection zoom yes
touchend selection end no⁴
touchcancel selection end no⁴

The propagation of all consumed events is immediately stopped.

¹ Necessary to capture events outside an iframe; see d3-drag#9.
² Only applies during an active, mouse-based gesture; see d3-drag#9.
³ Only applies immediately after a non-empty, mouse-based gesture.
⁴ Necessary to allow click emulation on touch input; see d3-drag#9.
⁵ Ignored if within 500ms of a touch gesture ending; assumes click emulation.
⁶ Double-click and double-tap initiate a transition that emits start, zoom and end events.
⁷ The first wheel event emits a start event; an end event is emitted when no wheel events are received for 150ms.

# d3.zoom()

Creates a new zoom behavior. The returned behavior, zoom, is both an object and a function, and is typically applied to selected elements via selection.call.

# zoom(selection)

Applies this zoom behavior to the specified selection, binding the necessary event listeners to allow panning and zooming, and initializing the zoom transform on each selected element to the identity transform if not already defined. This function is typically not invoked directly, and is instead invoked via selection.call. For example, to instantiate a zoom behavior and apply it to a selection:

d3.selectAll(".node").call(d3.zoom().on("zoom", zoomed));

Internally, the zoom behavior uses selection.on to bind the necessary event listeners for zooming. The listeners use the name .zoom, so you can subsequently unbind the zoom behavior as follows:

selection.on(".zoom", null);

Applying the zoom behavior also sets the -webkit-tap-highlight-color style to transparent, disabling the tap highlight on iOS. If you want a different tap highlight color, remove or re-apply this style after applying the drag behavior.

# zoom.transform(selection, transform)

If selection is a selection, sets the current zoom transform of the selected elements to the specifed transform. If selection is a transition, defines a zoom transition to the specified transform using d3.interpolateZoom. The transform may be specified either as a zoom transform or as a function that returns a zoom transform. If a function, it is invoked for each selected element, being passed the current datum d and index i, with the this context as the current DOM element.

This function is typically not invoked directly, and is instead invoked via selection.call or transition.call. For example, to reset the zoom transform to the identity transform instantaneously:

d3.selectAll(".node").call(zoom.transform, d3.zoomIdentity);

To smoothly reset the zoom transform to the identity transform over 750 milliseconds:

d3.selectAll(".node").transition().duration(750).call(zoom.transform, d3.zoomIdentity);

This method requires that you specify the new zoom transform completely, and does not enforce the defined scale extent and translate extent, if any. To derive a new transform from the existing transform, and to enforce the scale and translate extents, see the convenience methods zoom.translateBy, zoom.scaleBy and zoom.scaleTo.

# zoom.translateBy(selection, x, y)

… A convenience alias for zoom.transform.

# zoom.scaleBy(selection, k)

… A convenience alias for zoom.transform.

# zoom.scaleTo(selection, k)

… A convenience alias for zoom.transform.

# zoom.filter([filter])

If filter is specified, sets the filter to the specified function and returns the zoom behavior. If filter is not specified, returns the current filter, which defaults to:

function filter() {
  return !event.button;
}

If the filter returns falsey, the initiating event is ignored and no zoom gestures are started. Thus, the filter determines which input events are ignored. The default filter ignores mousedown events on secondary buttons, since those buttons are typically intended for other purposes, such as the context menu.

# zoom.extent([extent])

function extent() {
  var node = this.ownerSVGElement || this;
  return [[0, 0], [node.clientWidth, node.clientHeight]];
}

# zoom.scaleExtent([extent])

… Defaults to [0, ∞]. Enforced on interaction and when using zoom.scaleBy, zoom.scaleTo and zoom.translateBy; not enforced when using zoom.transform to set the transform explicitly.

# zoom.translateExtent([extent])

… Defaults to [[-∞, -∞], [+∞, +∞]]. Enforced on interaction and when using zoom.scaleBy, zoom.scaleTo and zoom.translateBy; not enforced when using zoom.transform to set the transform explicitly.

# zoom.duration([duration])

If duration is specified, sets the duration for zoom transitions on double-click and double-tap to the specified number of milliseconds and returns the zoom behavior. If duration is not specified, returns the current duration, which defaults to 250 milliseconds. If the duration is not greater than zero, double-click and -tap trigger instantaneous changes to the zoom transform rather than initiating smooth transitions.

# zoom.on(typenames[, listener])

If listener is specified, sets the event listener for the specified typenames and returns the zoom behavior. If an event listener was already registered for the same type and name, the existing listener is removed before the new listener is added. If listener is null, removes the current event listeners for the specified typenames, if any. If listener is not specified, returns the first currently-assigned listener matching the specified typenames, if any. When a specified event is dispatched, each listener will be invoked with the same context and arguments as selection.on listeners: the current datum d and index i, with the this context as the current DOM element.

The typenames is a string containing one or more typename separated by whitespace. Each typename is a type, optionally followed by a period (.) and a name, such as zoom.foo and zoom.bar; the name allows multiple listeners to be registered for the same type. The type must be one of the following:

  • start - after zooming begins (such as on mousedown).
  • zoom - after a change to the zoom transform (such as on mousemove).
  • end - after zooming ends (such as on mouseup ).

See dispatch.on for more.

Zoom Events

When a zoom event listener is invoked, d3.event is set to the current zoom event. The event object exposes several fields:

  • target - the associated zoom behavior.
  • type - the string “start”, “zoom” or “end”; see zoom.on.
  • transform - the current zoom transform.
  • sourceEvent - the underlying input event, such as mousemove or touchmove.

Zoom Transforms

The zoom behavior stores the zoom state on the element to which the zoom behavior was applied, not on the zoom behavior itself. This is because the zoom behavior can be applied to many elements simultaneously, and each element can be zoomed independently. The zoom state can change either on user interaction or programmatically via zoom.transform.

To retrieve the zoom state, use event.transform on the current zoom event within a zoom event listener (see zoom.on), or use d3.zoomTransform 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.zoomTransform(node)

Returns the current transform for the specified node. Internally, an element’s transform is stored as element.__zoom; however, you should use this method rather than accessing it directly. If the given node has no defined transform, returns the identity transformation. The returned transform represents a two-dimensional transformation matrix of the form:

k 0 tx
0 k ty
0 0 1

(This matrix is capable of representing only scale and translation; a future release may also allow rotation, though this would probably not be a backwards-compatible change.) The position ⟨x,y⟩ is transformed to ⟨x × k + tx,y × k + 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.
  • k - the scale factor k.

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 zoom.scaleBy, zoom.scaleTo and zoom.translateBy for convenience methods on the zoom behavior. To create a transform with a given k, tx, and ty:

var t = d3.zoomIdentity.translate(x, y).scale(k);

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.k, transform.k);

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

div.style("transform", "translate(" + transform.x + "px," + transform.y + "px) scale(" + transform.k + ")");

To apply the transformation to SVG:

g.attr("transform", "translate(" + transform.x + "," + transform.y + ") scale(" + transform.k + ")");

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(k)

Returns a transform whose scale k₁ is equal to k₀ × k, where k₀ is this transform’s scale.

# transform.translate(x, y)

Returns a transform whose translation tx1 and ty1 is equal to tx0 + x and ty0 + y, where tx0 and ty0 is this transform’s translation.

# 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 + tx, y × k + ty].

# transform.applyX(x)

Returns the transformation of the specified x-coordinate, x × k + tx.

# transform.applyY(y)

Returns the transformation of the specified y-coordinate, y × k + ty.

# transform.invert(point)

Returns the inverse transformation of the specified point which is a two-element array of numbers [x, y]. The returned point is equal to [(x - tx) / k, (y - ty) / k].

# transform.invertX(x)

Returns the inverse transformation of the specified x-coordinate, (x - tx) / k.

# transform.invertY(y)

Returns the inverse transformation of the specified y-coordinate, (y - ty) / k.

# transform.rescaleX(x)

Returns a copy of the continuous scale x whose domain is transformed. This is implemented by first applying the inverse x-transform on the scale’s range, and then applying the inverse scale to compute the corresponding domain:

function rescaleX(x) {
  var range = x.range().map(transform.invertX, transform),
      domain = range.map(x.invert, x);
  return x.copy().domain(domain);
}

This method does not modify the input scale x; x thus represents the untransformed scale, while the returned scale represents its transformed view.

# transform.rescaleY(y)

Returns a copy of the continuous scale y whose domain is transformed. This is implemented by first applying the inverse y-transform on the scale’s range, and then applying the inverse scale to compute the corresponding domain:

function rescaleY(y) {
  var range = y.range().map(transform.invertY, transform),
      domain = range.map(y.invert, y);
  return y.copy().domain(domain);
}

This method does not modify the input scale y; y thus represents the untransformed scale, while the returned scale represents its transformed view.

# transform.toString()

Returns a string representing the SVG transform corresponding to this transform. Implemented as:

function toString() {
  return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
}

# d3.zoomIdentity

The identity transform, where k = 1, tx = ty = 0.