• Stars
    star
    328
  • Rank 123,408 (Top 3 %)
  • Language
    JavaScript
  • License
    ISC License
  • Created almost 8 years ago
  • Updated 7 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Drag and drop SVG, HTML or Canvas using mouse or touch input.

d3-drag

Drag-and-drop is a popular and easy-to-learn pointing gesture: move the pointer to an object, press and hold to grab it, “drag” the object to a new location, and release to “drop”. D3’s drag behavior provides a convenient but flexible abstraction for enabling drag-and-drop interaction on selections. For example, you can use d3-drag to facilitate interaction with a force-directed graph, or a simulation of colliding circles:

Force-Directed GraphForce Dragging II

You can also use d3-drag to implement custom user interface elements, such as a slider. But the drag behavior isn’t just for moving elements around; there are a variety of ways to respond to a drag gesture. For example, you can use it to lasso elements in a scatterplot, or to paint lines on a canvas:

Line Drawing

The drag behavior can be combined with other behaviors, such as d3-zoom for zooming.

Drag & Zoom II

The drag behavior is agnostic about the DOM, so you can use it with SVG, HTML or even Canvas! And you can extend it with advanced selection techniques, such as a Voronoi overlay or a closest-target search:

Circle Dragging IVCircle Dragging II

Best of all, the drag behavior automatically unifies mouse and touch input, and avoids browser idiosyncrasies. When Pointer Events are more widely available, the drag behavior will support those, too.

Installing

If you use npm, npm install d3-drag. You can also download the latest release on GitHub. For vanilla HTML in modern browsers, import d3-drag from Skypack:

<script type="module">

import {drag} from "https://cdn.skypack.dev/d3-drag@3";

const handler = drag();

</script>

For legacy environments, you can load d3-drag’s UMD bundle from an npm-based CDN such as jsDelivr; a d3 global is exported:

<script src="https://cdn.jsdelivr.net/npm/d3-dispatch@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-selection@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-drag@3"></script>
<script>

const handler = d3.drag();

</script>

Try d3-drag in your browser.

API Reference

This table describes how the drag behavior interprets native events:

Event Listening Element Drag Event Default Prevented?
mousedown⁵ selection start no¹
mousemove² window¹ drag yes
mouseup² window¹ end yes
dragstart² window - yes
selectstart² window - yes
click³ window - yes
touchstart selection start no⁴
touchmove selection drag yes
touchend selection end no⁴
touchcancel selection end no⁴

The propagation of all consumed events is immediately stopped. If you want to prevent some events from initiating a drag gesture, use drag.filter.

¹ Necessary to capture events outside an iframe; see #9.
² Only applies during an active, mouse-based gesture; see #9.
³ Only applies immediately after some mouse-based gestures; see drag.clickDistance.
⁴ Necessary to allow click emulation on touch input; see #9.
⁵ Ignored if within 500ms of a touch gesture ending; assumes click emulation.

# d3.drag() · Source, Examples

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

# drag(selection) · Source, Examples

Applies this drag behavior to the specified selection. This function is typically not invoked directly, and is instead invoked via selection.call. For example, to instantiate a drag behavior and apply it to a selection:

d3.selectAll(".node").call(d3.drag().on("start", started));

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

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

Applying the drag 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.

# drag.container([container]) · Source, Examples

If container is specified, sets the container accessor to the specified object or function and returns the drag behavior. If container is not specified, returns the current container accessor, which defaults to:

function container() {
  return this.parentNode;
}

The container of a drag gesture determines the coordinate system of subsequent drag events, affecting event.x and event.y. The element returned by the container accessor is subsequently passed to d3.pointer to determine the local coordinates of the pointer.

The default container accessor returns the parent node of the element in the originating selection (see drag) that received the initiating input event. This is often appropriate when dragging SVG or HTML elements, since those elements are typically positioned relative to a parent. For dragging graphical elements with a Canvas, however, you may want to redefine the container as the initiating element itself:

function container() {
  return this;
}

Alternatively, the container may be specified as the element directly, such as drag.container(canvas).

# drag.filter([filter]) · Source, Examples

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

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

If the filter returns falsey, the initiating event is ignored and no drag 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.

# drag.touchable([touchable]) · Source, Examples

If touchable is specified, sets the touch support detector to the specified function and returns the drag behavior. If touchable is not specified, returns the current touch support detector, which defaults to:

function touchable() {
  return navigator.maxTouchPoints || ("ontouchstart" in this);
}

Touch event listeners are only registered if the detector returns truthy for the corresponding element when the drag behavior is applied. The default detector works well for most browsers that are capable of touch input, but not all; Chrome’s mobile device emulator, for example, fails detection.

# drag.subject([subject]) · Source, Examples

If subject is specified, sets the subject accessor to the specified object or function and returns the drag behavior. If subject is not specified, returns the current subject accessor, which defaults to:

function subject(event, d) {
  return d == null ? {x: event.x, y: event.y} : d;
}

The subject of a drag gesture represents the thing being dragged. It is computed when an initiating input event is received, such as a mousedown or touchstart, immediately before the drag gesture starts. The subject is then exposed as event.subject on subsequent drag events for this gesture.

The default subject is the datum of the element in the originating selection (see drag) that received the initiating input event; if this datum is undefined, an object representing the coordinates of the pointer is created. When dragging circle elements in SVG, the default subject is thus the datum of the circle being dragged. With Canvas, the default subject is the canvas element’s datum (regardless of where on the canvas you click). In this case, a custom subject accessor would be more appropriate, such as one that picks the closest circle to the mouse within a given search radius:

function subject(event) {
  let n = circles.length,
      i,
      dx,
      dy,
      d2,
      s2 = radius * radius,
      circle,
      subject;

  for (i = 0; i < n; ++i) {
    circle = circles[i];
    dx = event.x - circle.x;
    dy = event.y - circle.y;
    d2 = dx * dx + dy * dy;
    if (d2 < s2) subject = circle, s2 = d2;
  }

  return subject;
}

(If necessary, the above can be accelerated using quadtree.find, simulation.find or delaunay.find.)

The returned subject should be an object that exposes x and y properties, so that the relative position of the subject and the pointer can be preserved during the drag gesture. If the subject is null or undefined, no drag gesture is started for this pointer; however, other starting touches may yet start drag gestures. See also drag.filter.

The subject of a drag gesture may not be changed after the gesture starts. The subject accessor is invoked with the same context and arguments as selection.on listeners: the current event (event) and datum d, with the this context as the current DOM element. During the evaluation of the subject accessor, event is a beforestart drag event. Use event.sourceEvent to access the initiating input event and event.identifier to access the touch identifier. The event.x and event.y are relative to the container, and are computed using d3.pointer.

# drag.clickDistance([distance]) · Source

If distance is specified, sets the maximum distance that the mouse can move between mousedown and mouseup that will trigger a subsequent click event. If at any point between mousedown and mouseup the mouse is greater than or equal to distance from its position on mousedown, the click event following mouseup will be suppressed. If distance is not specified, returns the current distance threshold, which defaults to zero. The distance threshold is measured in client coordinates (event.clientX and event.clientY).

# drag.on(typenames, [listener]) · Source

If listener is specified, sets the event listener for the specified typenames and returns the drag 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 event (event) and datum d, 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 drag.foo and drag.bar; the name allows multiple listeners to be registered for the same type. The type must be one of the following:

  • start - after a new pointer becomes active (on mousedown or touchstart).
  • drag - after an active pointer moves (on mousemove or touchmove).
  • end - after an active pointer becomes inactive (on mouseup, touchend or touchcancel).

See dispatch.on for more.

Changes to registered listeners via drag.on during a drag gesture do not affect the current drag gesture. Instead, you must use event.on, which also allows you to register temporary event listeners for the current drag gesture. Separate events are dispatched for each active pointer during a drag gesture. For example, if simultaneously dragging multiple subjects with multiple fingers, a start event is dispatched for each finger, even if both fingers start touching simultaneously. See Drag Events for more.

# d3.dragDisable(window) · Source

Prevents native drag-and-drop and text selection on the specified window. As an alternative to preventing the default action of mousedown events (see #9), this method prevents undesirable default actions following mousedown. In supported browsers, this means capturing dragstart and selectstart events, preventing the associated default actions, and immediately stopping their propagation. In browsers that do not support selection events, the user-select CSS property is set to none on the document element. This method is intended to be called on mousedown, followed by d3.dragEnable on mouseup.

# d3.dragEnable(window[, noclick]) · Source

Allows native drag-and-drop and text selection on the specified window; undoes the effect of d3.dragDisable. This method is intended to be called on mouseup, preceded by d3.dragDisable on mousedown. If noclick is true, this method also temporarily suppresses click events. The suppression of click events expires after a zero-millisecond timeout, such that it only suppress the click event that would immediately follow the current mouseup event, if any.

Drag Events

When a drag event listener is invoked, it receives the current drag event as its first argument. The event object exposes several fields:

  • target - the associated drag behavior.
  • type - the string “start”, “drag” or “end”; see drag.on.
  • subject - the drag subject, defined by drag.subject.
  • x - the new x-coordinate of the subject; see drag.container.
  • y - the new y-coordinate of the subject; see drag.container.
  • dx - the change in x-coordinate since the previous drag event.
  • dy - the change in y-coordinate since the previous drag event.
  • identifier - the string “mouse”, or a numeric touch identifier.
  • active - the number of currently active drag gestures (on start and end, not including this one).
  • sourceEvent - the underlying input event, such as mousemove or touchmove.

The event.active field is useful for detecting the first start event and the last end event in a sequence of concurrent drag gestures: it is zero when the first drag gesture starts, and zero when the last drag gesture ends.

The event object also exposes the event.on method.

# event.on(typenames, [listener]) · Source

Equivalent to drag.on, but only applies to the current drag gesture. Before the drag gesture starts, a copy of the current drag event listeners is made. This copy is bound to the current drag gesture and modified by event.on. This is useful for temporary listeners that only receive events for the current drag gesture. For example, this start event listener registers temporary drag and end event listeners as closures:

function started(event) {
  const circle = d3.select(this).classed("dragging", true);

  event.on("drag", dragged).on("end", ended);

  function dragged(event, d) {
    circle.raise().attr("cx", d.x = event.x).attr("cy", d.y = event.y);
  }

  function ended() {
    circle.classed("dragging", false);
  }
}

More Repositories

1

d3

Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript
106,311
star
2

d3-shape

Graphical primitives for visualization, such as lines and areas.
JavaScript
2,458
star
3

d3-plugins

[DEPRECATED] A repository for sharing D3.js V3 plugins.
JavaScript
1,808
star
4

d3-force

Force-directed graph layout using velocity Verlet integration.
JavaScript
1,702
star
5

d3-scale

Encodings that map abstract data to visual representation.
JavaScript
1,567
star
6

d3-queue

Evaluate asynchronous tasks with configurable concurrency.
JavaScript
1,411
star
7

d3-hierarchy

2D layout algorithms for visualizing hierarchical data.
JavaScript
1,064
star
8

d3-geo-projection

Extended geographic projections for d3-geo.
JavaScript
1,058
star
9

d3-geo

Geographic projections, spherical shapes and spherical trigonometry.
JavaScript
988
star
10

d3-scale-chromatic

Sequential, diverging and categorical color scales.
JavaScript
787
star
11

d3-sankey

Visualize flow between nodes in a directed acyclic network.
JavaScript
763
star
12

d3-format

Format numbers for human consumption.
JavaScript
611
star
13

d3-ease

Easing functions for smooth animation.
JavaScript
604
star
14

d3-delaunay

Compute the Voronoi diagram of a set of two-dimensional points.
JavaScript
588
star
15

d3-selection

Transform the DOM by selecting elements and joining to data.
JavaScript
547
star
16

d3-zoom

Pan and zoom SVG, HTML or Canvas using mouse or touch input.
JavaScript
495
star
17

d3-contour

Compute contour polygons using marching squares.
JavaScript
487
star
18

d3-interpolate

Interpolate numbers, colors, strings, arrays, objects, whatever!
JavaScript
482
star
19

d3-array

Array manipulation, ordering, searching, summarizing, etc.
JavaScript
452
star
20

d3-dsv

A parser and formatter for delimiter-separated values, such as CSV and TSV.
JavaScript
416
star
21

d3-color

Color spaces! RGB, HSL, Cubehelix, CIELAB, and more.
JavaScript
389
star
22

d3-time-format

Parse and format times, inspired by strptime and strftime.
JavaScript
324
star
23

d3-voronoi

Compute the Voronoi diagram of a set of two-dimensional points.
JavaScript
250
star
24

d3-hexbin

Group two-dimensional points into hexagonal bins.
JavaScript
231
star
25

d3-time

A calculator for humanity’s peculiar conventions of time.
JavaScript
227
star
26

d3-quadtree

Two-dimensional recursive spatial subdivision.
JavaScript
225
star
27

d3-transition

Animated transitions for D3 selections.
JavaScript
219
star
28

d3-fetch

Convenient parsing for Fetch.
JavaScript
215
star
29

d3-axis

Human-readable reference marks for scales.
JavaScript
204
star
30

d3.github.com

The D3 website.
JavaScript
195
star
31

d3-path

Serialize Canvas path commands to SVG.
JavaScript
192
star
32

d3-timer

An efficient queue for managing thousands of concurrent animations.
JavaScript
159
star
33

d3-brush

Select a one- or two-dimensional region using the mouse or touch.
JavaScript
154
star
34

d3-3.x-api-reference

An archive of the D3 3.x API Reference.
153
star
35

d3-random

Generate random numbers from various distributions.
JavaScript
136
star
36

d3-chord

Visualizations relationships or network flow with a circular layout.
JavaScript
122
star
37

d3-tile

Compute the quadtree tiles to display in a rectangular viewport.
JavaScript
120
star
38

d3-collection

Handy data structures for elements keyed by string.
JavaScript
111
star
39

d3-request

A convenient alternative to XMLHttpRequest.
JavaScript
109
star
40

d3-geo-polygon

Clipping and geometric operations for spherical polygons.
JavaScript
102
star
41

d3-polygon

Geometric operations for two-dimensional polygons.
JavaScript
97
star
42

d3-require

A minimal, promise-based implementation to require asynchronous module definitions.
JavaScript
78
star
43

d3-selection-multi

Multi-value syntax for d3-selection and d3-transition.
JavaScript
75
star
44

d3-dispatch

Register named callbacks and call them with arguments.
JavaScript
75
star
45

versor

a home for Mike Bostock's versor.js
JavaScript
34
star
46

d3-bundler

DEPRECATED; use rollup/rollup.
JavaScript
34
star
47

d3-hsv

The HSV (Hue, Saturation, Value) color space.
JavaScript
26
star
48

d3-logo

D3 brand assets.
23
star
49

d3-cam16

A d3 implementation of the CIECAM16 color appearance model.
JavaScript
22
star
50

d3-hcg

The HCG (Hue, Chroma, Grayness) color space derived from the Munsell color system.
JavaScript
20
star
51

d3-scripts

Common scripts for D3 modules.
JavaScript
15
star
52

d3-hull

DEPRECATED; see d3-polygon’s hull function.
JavaScript
14
star
53

blur-benchmark

temporary benchmark for d3.blur implementations
JavaScript
2
star