new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

D3 · all subjects

d3-drag

25 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

d3-drag module overview

d3-drag enables drag and drop for SVG, HTML, or Canvas using mouse or touch input. It provides drag behavior creation, coordinate system configuration, subject definition, click distance threshold, and event listening with support for disabling/enabling native drag-and-drop.

d3.drag() creates a new drag behavior

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

drag behavior applied to selection via selection.call()

The drag behavior is applied to a selection by calling selection.call(d3.drag()...). Internally, the drag behavior uses selection.on() to bind event listeners with the name '.drag'. To unbind the drag behavior: selection.on('.drag', null).

drag.container() sets the coordinate system for drag events

drag.container(container) sets the container accessor, which determines the coordinate system for drag events and affects event.x and event.y. If container is not specified, returns the current container accessor, which defaults to: function container() { return this.parentNode; }. The container element is passed to pointer() to determine local coordinates. For Canvas, you may want to redefine it as: function container() { return this; }.

drag.filter() determines which input events initiate drag

drag.filter(filter) 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. The default filter ignores mousedown events on secondary buttons.

drag.touchable() sets touch support detector

drag.touchable(touchable) sets the touch support detector to the specified function and returns the drag behavior. If touchable is not specified, returns the current detector, which defaults to: function touchable() { return navigator.maxTouchPoints || ('ontouchstart' in this); }. Touch event listeners are only registered if the detector returns truthy when the drag behavior is applied.

drag.subject() defines what is being dragged

drag.subject(subject) sets the subject accessor to the specified object or function and returns the drag behavior. If subject is not specified, returns the current accessor, which defaults to: function subject(event, d) { return d == null ? {x: event.x, y: event.y} : d; }. The subject is computed when an initiating input event is received (mousedown or touchstart), immediately before the drag gesture starts. It represents the thing being dragged and is exposed as event.subject on subsequent drag events.

drag subject must expose x and y properties

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

drag.subject() accessor context and event timing

The subject accessor is invoked with the same context and arguments as selection.on listeners: the current event (event) and datum d, with this context as the current DOM element. During 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 computed using pointer().

drag.subject() cannot be changed after gesture starts

The subject of a drag gesture may not be changed after the gesture starts.

drag.on() registers drag event listeners

drag.on(typenames, listener) sets the event listener for the specified typenames and returns the drag behavior. If listener is null, removes the current event listeners. If listener is not specified, returns the first currently-assigned listener matching the typenames. 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 type must be one of: 'start' (after a new pointer becomes active on mousedown or touchstart), 'drag' (after an active pointer moves on mousemove or touchmove), or 'end' (after an active pointer becomes inactive on mouseup, touchend or touchcancel).

drag.on() listener invocation context

When a drag event listener is invoked, it receives the current drag event as its first argument. The listener 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.

Changes to drag.on() do not affect current gesture

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 allows you to register temporary event listeners for the current drag gesture. Separate events are dispatched for each active pointer during a drag gesture.

Drag event object structure

When a drag event listener is invoked, the event object exposes: target (the associated drag behavior), type (string 'start', 'drag' or 'end'), subject (the drag subject), x (new x-coordinate of subject), y (new y-coordinate of subject), dx (change in x-coordinate since previous drag event), dy (change in y-coordinate since previous drag event), identifier (string 'mouse' or numeric touch identifier), active (number of currently active drag gestures, on start and end not including this one), and sourceEvent (the underlying input event such as mousemove or touchmove).

event.active field detects first start and last end events

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.

dragDisable() prevents native drag-and-drop and text selection

dragDisable(window) prevents native drag-and-drop and text selection on the specified window. This captures dragstart and selectstart events, prevents their default actions, and immediately stops 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 dragEnable() on mouseup.

dragEnable() restores native drag-and-drop and text selection

dragEnable(window, noclick) allows native drag-and-drop and text selection on the specified window, undoing the effect of dragDisable(). This method is intended to be called on mouseup, preceded by dragDisable() on mousedown. If noclick is true, this method also temporarily suppresses click events. The suppression expires after a zero-millisecond timeout, suppressing only the click event that would immediately follow the current mouseup event.

Drag event native event handling table

The drag behavior interprets native events as follows: mousedown (on selection element, triggers start drag event, default not prevented), mousemove (on window, triggers drag event, default prevented), mouseup (on window, triggers end event, default prevented), dragstart (on window, no drag event, default prevented), selectstart (on window, no drag event, default prevented), click (on window, no drag event, default prevented), touchstart (on selection, triggers start event, default not prevented), touchmove (on selection, triggers drag event, default prevented), touchend (on selection, triggers end event, default not prevented), touchcancel (on selection, triggers end event, default not prevented). The propagation of all consumed events is immediately stopped.

event.on() registers temporary drag gesture listeners

event.on(typenames, listener) is 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 and bound to the current gesture, then modified by event.on(). This is useful for temporary listeners that only receive events for the current drag gesture.

event.on() example for temporary listeners

Example of using event.on() to register temporary drag and end event listeners within a start event listener: function started(event) { const circle = d3.select(this).classed('dragging', true); const dragged = (event, d) => circle.raise().attr('cx', d.x = event.x).attr('cy', d.y = event.y); const ended = () => circle.classed('dragging', false); event.on('drag', dragged).on('end', ended); }

Subject accessor example for Canvas with closest circle search

Example of a custom subject accessor for Canvas 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; }

Drag behavior application example

Example of instantiating a drag behavior and applying it to a selection: d3.selectAll('.node').call(d3.drag().on('start', started));

iOS tap highlight disabled by drag behavior

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

Mousedown ignored within 500ms of touch gesture ending

Mousedown events are ignored if they occur within 500ms of a touch gesture ending, to account for click emulation on touch input.

Quadtree, simulation, and delaunay can accelerate subject finding

For finding the closest circle to the mouse, the subject accessor can be accelerated using quadtree.find(), simulation.find() or delaunay.find() instead of a linear search.

Give your agent this brain