Giter VIP home page Giter VIP logo

d3-drag's Introduction

D3: Data-Driven Documents

D3 (or D3.js) is a free, open-source JavaScript library for visualizing data. Its low-level approach built on web standards offers unparalleled flexibility in authoring dynamic, data-driven graphics. For more than a decade D3 has powered groundbreaking and award-winning visualizations, become a foundational building block of higher-level chart libraries, and fostered a vibrant community of data practitioners around the world.

Resources

d3-drag's People

Contributors

dependabot[bot] avatar fil avatar herst avatar letavocado avatar mbostock avatar nicolas-van avatar stof avatar yaph avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

d3-drag's Issues

"this" do NOT refer to dragged element in event-listener of d3.drag.on()

abstract

"this" do NOT refer to dragged element in event-listener of d3.drag.on(*, event-listener) when I use "arrow function" for event-listener.
If I use normal function (e.g. function(){...}), it seems normal.
I think this problem is related to this-binding in arrow function.
I don't good at "this" binding, so I hope someone fix this bug(bug?) or write it in document.

problem

"this" do NOT refer to dragged element in event-listener of d3.drag.on(*, event-listener) when I use "arrow function" for event-listener.
I wrote and upload sample on bl.ocks.org => sample

In event-listener of d3.drag().on(*, event-listener), "this" should refer to current DOM element.

from_API_reference ... listener will be invoked ... with the this context as the current DOM element.

But, when I use "arrow function" for event-listener, "this" do NOT refer to the current DOM element, instead, refer to "Window object".

// code for explanation. I do NOT check this code work or not. Sample in bl.ocks.org is checked to work.
<div id=div1>div1</div>
<div id=div2>div2</div>
d3.select("#div1").call(d3.drag().on("start", function(){console.log(this);})); // -> "<div>" ◎  
d3.select("#div2").call(d3.drag().on("start", ()=>{console.log(this);})); // -> "Window" !?

condition

  • PC: Microsoft sarface Pro (1)
  • OS: Windows 10
  • browser: google Chrome 55.0.2883.87 m (64-bit)

cause

I am not good at javascript grammar, so I have no confident to my opinion.
I think this problem is related this-binding of arrow function.
I am glad if this opinion is useful for bag-sweepers.

hope

If can, please someone fix this bug (bug?).
Even if that is difficult, please write this phenomenon in document.
I hope this issue will helpful for d3.js users (this is my first issue to github lol).

Expose d3.dragDisable(window).

Anything that wants to use the common gesture mousedown, mousemove+, mouseup will need to use the same trick employed by the drag behavior (not prevent default on mousedown, then suppress dragstart and selectstart or set user-select: none). That includes d3-zoom and d3-brush. So rather than duplicate that hack three times, we should expose it in this module.

Pass d3 scroll/drag event to parent element if some conditions not met

If opening the d3 example https://bl.ocks.org/mbostock/9669633 with an touch device its not possible to scroll down the page while the touch point, to move the page around, is above the SVG (not on one of the circles).

If the touch point is outside the SVG area the page scrolls normally.

How could I achive normal scrolling in the SVG area too?

I want to achive scrolling up/down on touch device only if at least two fingers are used otherwise the event should be ignored and the browser should handle event.

On none touch devices its relatively easy to prevent, for instance, the zooming, by adding an filter function to the zoom handler and handling the "wheel" event. But for touch devices i am not getting it to function to allow the page scroll until my condition (2 fingers) are met.

I would like to simulate the same functionality like google maps offers.

https://stackoverflow.com/questions/47442911/pass-d3-scroll-drag-event-to-parent-element-if-some-conditions-not-met

Drag drop is not working using d3.js

I am trying to drag SVG element using d3.js. but it gives and stated "Cannot read property 'drag' of undefined"
my code is given below.

<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
<script src="https://d3js.org/d3-drag.v1.min.js"></script>
<script>
    var drag = d3.behavior.drag().on("drag", dragMovement);
    function dragMovement(d) {
        var dX = d3.event.x - 50;
        var dY = d3.event.y - 50;
        d3.select(this).attr("transform", "translate(" + dX + ", " + dY + ")");
    }
    d3.select(".dragCircle").call(drag);

</script>
<svg width="500" height="500" style="background-color: lightgrey; border: 1px solid black;">
    <circle class="dragCircle" cx="50" cy="50" fill="blue" r="30" cursor="pointer" />
</svg>

Possible typo in README

Hello,

this is from the README

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);  <--- should the event name contain dot? 

although I'm no expert on d3, this looks like a typo.

Use distance threshold when suppressing click.

Currently, the drag handler suppresses all click events by checking for the mousemoving variable that always validates to true because as soon as the mousedown event fires, D3 starts listening to the mousemove.drag event, which immediately starts firing without any actual cursor move.

See lines 44, 53, and 59

By default it might be okay to suppress all click events but sometimes it's desirable to actually trigger a click event when the cursor did not move or moved within a tolerable distance only (e.g., 1 or 2 pixel).

Currently I am doing something like the following to work around the click suppression:

let dX, dY;

drag.on('start', () => {
  dX = d3.event.x;
  dY = d3.event.y;
});

drag.on('end', () => {
  dX = Math.abs(dX - d3.event.x);
  dY = Math.abs(dY - d3.event.y);
  if (Math.max(dX, dY) <= (clickTolerance || 0)) {
    d3.select(window).on('click.drag', null);
  }
});

or

let dX, dY;

drag.on('start', () => {
  dX = 0;
  dY = 0;
});

drag.on('drag', () => {
  if (!mouseMoved) {
    dX += Math.abs(d3.event.dx);
    dY += Math.abs(d3.event.dy);
    if (Math.max(dX, dY) > (clickTolerance || 0)) {
      mouseMoved = true;
    }
  }
});

drag.on('end', () => {
  if (!mouseMoved) {
    d3.select(window).on('click.drag', null);
  }
  mouseMoved = false;
});

It works but it feels kind of hacky. Or is there another, more elegant way to achieve the same thing?

I am not sure if my approach adds lots of overhead but I would advocate to let the user decide whether he/she wants all click events to be suppressed.

How to remove drag listener that has been called while dragging?

I am unable to remove the drag listener while I am dragging the element that call d3.drag(). While removing the drag listener, if I mouseup, the listener will be gone but if I hold the mouse down, drag is still listening and drag event will be fired.

I did an experiment. I have an event listener that listen for a keyboard press that will call on(".drag", null). I drag my element around and press the key. I can continue to drag.

Is this expected? If so, how should I stop the drag listener while dragging?

https://jsfiddle.net/38wtj4y0/33/

This jsfiddle is quite similar. It deletes the element when a key is pressed. However, you will notice that console is still printing "dragging" if you delete while mousedown and never release.

Make the drag behavior independent of the target element’s data?

What if you wanted to use d3-drag on Canvas to drag circles? In that case, you wouldn’t be able to listen for mousedown on a specific element, since it would always be dragging on the Canvas element. But maybe there’s still a way to do it: the drag behavior could track the coordinates relative to the first click (and maybe there’s an equivalent to drag.origin in D3 3.x that lets you offset the coordinates to something more natural). You’d also presumably need something like drag.filter that lets you test whether you clicked on something before initiating the drag. And, when a drag event is dispatched, to know that’s being dragged (since there could be multiple things in motion).

Expose dx and dy on the DragEvent.

In v3 the drag event exposed the properties dx and dy "representing the element’s coordinates relative to its position at the beginning of the gesture", which on many occasions came in handy. As far as I can tell, these are no longer available in v4, and they are missed already. Is there a chance, we could have them back?

Examples.

Rename drag.subject to drag.data?

The word subject implies it’s the thing doing the dragging, not the thing being dragged. We could use the word object, but I think data would be better.

Or not. Subject is defined as “a person or thing that is being discussed, described, or dealt with.” Which could be appropriate.

drag.filter is awkward.

In the case of using d3-drag to drag nodes with Canvas, you might want to use drag.filter to check whether a node was clicked on before allowing the drag behavior. However, there’s no way to access whatever is computed during filter on dragstart (aside from having the caller use a global). For example, you might hit-test your circles:

function filter() {
  var node, i, x, y, n = nodes.length;
  for (i = 0; i < n; ++i) {
    node = nodes[i];
    x = d3.event.x - node.x;
    y = d3.event.y - node.y;
    if (x * x + y * y < 25) return node;
  }
}

Unfortunately, you’d have to perform this same hit-test again to determine the current node on dragstart.

Maybe drag.filter should be replaced by drag.target, which sets the target property on the event to whatever you like? But the default filter is still useful:

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

Would it be weird to do this?

function target() {
  return d3.event.sourceEvent.button ? null : this;
}

Maybe context is a better name, since there’s already a concept of the event’s target, which is the DOM element.

Signal reaching clickDistance threshold?

In my application I want to do certain things only after I am certain that the user intents to do a drag, e.g.:

  • Adding the styles for dragged elements. If I would do it on the drag start event then it the style would be added on every mousedown which is not what I want.

  • .raise() the element being dragged. If I would do it right away it might cause the click event to not be triggered (at least in some browsers) if the element got removed from the DOM.

The way I solved it is to simply use the delta x and y inside the drag event handler to calculate whether the click stance threshold has been breached or not.

Now d3 already does the same calculation already, I wondered whether it couldn't just simply tell me about whether the distance has been overstepped in the drag event, e.g. using d3.event.isOutsideClickDistance.


On a side note, an alternative idea would be a .dragDistance() which would cause the start events to only appear after a certain distance. This would cause the elements to appear a bit sticky though and it depends on the specific use case whether that's what you want or not.

Dispatching mousedown event with drag behaviour throws error

I wrote small jsFiddle to demonstrate issue.
Dispatching 'mousedown' event on selection with drag behaviour results in TypeError: Cannot read property 'document' of undefined.

I need to add element on mousedown, and drag it along untill I release it, but since it does not exist on actual mousedown I'm trying to dispatch event after its added.

Force examples shouldn’t set target alpha to zero on end.

If there are multiple active touches, we want to leave the target alpha at 0.3 (or bad things happen). I wonder if this means we should have an afterlastend event (related #7)? Or an easy way to query whether there are other active pointers during a drag event (other than looking at the source event)?

Support pointer events?

Carrying this over from d3/d3#2556. The new d3-drag is (at least in my mind) very similar conceptually to what Pointer Events do: unify touch/mouse into a single API that generically tracks "engaged movement".

The readme here already mentions this:

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.

So I'm filing this as an official ticket to track pointer events support in d3-drag, so I can reference it as necessary :-)

[Would love to personally contribute support based on some of my earlier work, but unfortunately don't have an active client project that needs it at the moment, and I've been horrible at keeping "evenings and weekends" promises lately, sorry…]

How to test d3-drag ?

Hi,

I want to unit test my library made with d3 and d3-drag but I'm not able to test the drag.

I tried something like d3.selectAll(document.querySelectorAll('*')).dispatch('drag') or .dispatch('mousedown') but I'm not able to trigger anything and the dispatch doesn't seem to work with the drag (it does with the other events like click).

Thank you for your clarification on the issue

d3.event.x and d3.event.y coordinates are different on different browsers

In the callbacks for drag related events, the d3.event.x and d3.event.y values are reported differently on different browsers.

This is observed on elements that are children of a translated group of elements.

Here is a fiddle:

http://jsfiddle.net/6fz23evr/16/

on firefox 61.0b13 (64-bit) Linux:

the top-left corner of black square reports (200,200)
the bottom-right corner of black square reports (300,300)

on chromium 69.0.3458.0 (Developer Build) (64-bit) Linux:

the top-left corner of black square reports (0,0)
the bottom-right corner of black square reports (100,100)

Drag event issue

Hi,

Drag event is attached to the vertical dashed line. Can't make it work, it seems that the drag event is NOT firing when trying to drag for the first time. Instead, the digits of the scale are being selected. And only when those digits remain selected, the drag fires when trying to move the dashed bar for the second time. This is in Chrome. In Firefox, it doesn't work at all.
Block:
https://bl.ocks.org/user1313/a0999345634bd7c7b6ddc955f37609a4

Is this me or a bug? Thanks.

Extending d3 drag behaviour to enable dragover detection

It seems that D3.drag supports drag but not "drop" i.e. it does not enable the generation of dragenter, dragleave and dragover events. I can get object created by D3 to listen to these events but cannot make a D3 object 'draggable' not access the drag event property. Is this because you disable the default dag behaviour?

Here's the code that demonstrate the above.
https://stackoverflow.com/questions/47318662/d3-support-for-dragenter-and-dragleave-events

I'd like to extend the d3 darg to enable elements created with d3 to generate the dragover, etc events but not sure how or if this would interfere with the current behaviour.

Thanks

Browser pinch-zoom in IE/Edge breaks things

I have a page where I am using d3.drag and since the pinch gesture apparently does not trigger a zooming through d3 in IE/Edge the browser will some sort-of page zoom instead (I am saying sort-of because it seems to be different from the one through e.g. Ctrl++/-). If zoomed this way certain d3.drag related things on my stop working.

To reproduce the problem:

  1. Using Internet Explorer or Microsoft Edge go to https://bl.ocks.org/Herst/raw/093ff9962405dd564ef58ad8af9544d0/
  2. Drag around the handles in the corners to resize the rectangle.
  3. Pinch-zoom the page.
  4. Again try to resize. You will see that it fails (no matter whether using touch or the mouse).

Works in Google Chrome and Mozilla Firefox.

BTW, by adding touch-action to your d3.drag demos you could improve the experience on IE/Edge in general because currently a long touch brings up the selection frame which prevents dragging.

Ignore “ghost” mousedown after touchend.

Similar to how we suppress a click after the drag gesture ends, we should briefly ignore mousedown events using a zero-delay timeout after a touchend. (This only seems to happen with single-touch gestures, but it shouldn’t matter since we’re just talking about ignoring the event inside the drag behavior, and not preventing default behaviors or stopping propagation.)

Reaching drag event scope with ES6

For instance I put some circles onto a SVG canvas and want them to trigger a function on a drag event.

Setup:

  • TypeScript/ES6
  • Importing specific D3 components
  • Angular 6

Reduced code snippet: Please have a look on drawPoints()

import { ElementRef, HostListener, Output, EventEmitter, OnInit, Input, OnChanges, SimpleChanges, Directive } from '@angular/core';
import * as Selection from 'd3-selection';
import * as Shape from 'd3-shape';
import * as Random from 'd3-random';
import * as Drag from 'd3-drag';

import { Config } from './../models/config.model';
import { Point } from './../models/point.model';
import { Param } from './../models/param.model';

@Directive({
  selector: '[appCanvas]'
})
export class CanvasDirective implements OnInit, OnChanges {
  private canvas: any;
  private defs: any;
  private gradient: any;
  private svg: any;
  private expandedPoints: Point[];
  private drag: Point;
  public config: Config;

  @Input()
  private param: Param;

  @Output()
  private emitConfig: EventEmitter<Config>;

  @HostListener('window:resize', ['$event'])
  private onResize(event) {
    this.init();
  }

  constructor(
    private el: ElementRef
  ) {
    this.canvas = el.nativeElement;
    this.emitConfig = new EventEmitter();
  }

  ngOnInit() {
    intSvg();
    // ..
  }

  private initSvg() {
    if (!this.svg) {
      this.svg = Selection.select(this.canvas).append('svg');
    }
    this.svg
      .attr('width', this.config.width)
      .attr('height', this.config.height);
  }

  private drawPoints(points: Point[]) {
    points.forEach(point => {
      this.svg.append('circle')
        .attr('r', point.color ? 20 : 10)
        .attr('cx', point.x)
        .attr('cy', point.y)
        .attr('fill', point.color ? point.color : 'lightgray')
        .attr('stroke-width', !point.color ? 2 : 0)
        .attr('stroke', !point.color ? 'gray' : '')
        .call(Drag.drag()
          .on('drag', () => {
            // What to call here?
            // Selection.select(this) will not work
            // So how to target the correct „this“?
          }));
    });
  }
  // ...
}

The problem that occures is not beeing able to reach the correct this inside the drag function of the appended circles.

Multiple examples are out there, but they won't work inside the class, because the this argument is protected.

Credits to Mike Bostock's example https://bl.ocks.org/mbostock/22994cc97fefaeede0d861e6815a847e

preventDefault on mousedown and touchstart by default?

There’s a long history here (d3/d3#1322, particularly @jfirebaugh’s comment) but I think it may be best to mousedown.preventDefault and touchstart.preventDefault by default, rather than allow the defaults and then subsequently try to prevent them selectively later.

Here’s my rationale:

  • It’s a Chrome bug that calling mousemove.preventDefault prevents text selection, drag-and-drop, and scrolling (see issue 485892). The mousemove event is defined as having no default action. Thus, the only standards-compliant way of preventing these default behaviors is to do it on mousedown.

    Yes, this prevents capturing mouse events outside an iframe in Chrome due to another bug (issue 269917), but when Pointer Events are implemented (issue 471824) we’ll have element.setPointerCapture as the standard way of capturing events without needing the window hack for mousemove and mouseup.

  • If multiple touches start on the same element, you must call touchstart.preventDefault to disable pinch-and-zoom. We’ve ignored this in the past because the old drag behavior assumed the touches were always on different elements (e.g., distinct SVG circles). The new d3-drag is agnostic about the DOM structure, and it should be usable even if the circles are rendered with Canvas. It would be brittle and inconsistent to allow the default behavior on touchstart if there’s only one touch (on a given element) and not allow it if there are multiple touches.

    Calling touchstart.preventDefault prevents a subsequent click. That’s somewhat unfortunate because this is not true of mousedown.preventDefault, and in the future, pointerdown.preventDefault:

    In user agents that support firing click and/or contextmenu, calling preventDefault during a pointer event typically does not have an effect on whether click and/or contextmenu are fired or not.

    However, you could still implement clickable and draggable things by calling element.click on drag end (if there’s no movement), and this is probably more obvious than checking click.defaultPrevented. I’ll have to test whether it’s possible to call element.click to explicitly click during a mouse-based drag, while still suppressing the default click…

  • The selectstart event is a working draft specification and not yet available in Firefox (Standard). Yes, Firefox supports -moz-user-select, but that’s vendor-prefixed (and buggy; see issue 648624). Given the inconsistency of default behaviors across browsers and input modes, trying to prevent them selectively has been an ongoing headache.

  • Whatever we choose as the default behavior of d3-drag (no pun intended!), that behavior is just the default and can be overridden or disabled. So if we decide that d3-drag should mousedown.preventDefault and touchstart.preventDefault by default, users can disable this behavior by calling drag.on and removing the .nodefault listener, and then do whatever they want. In contrast to D3 3.x, it is not necessary to fork the implementation.

The Chrome bug is unfortunate. But it feels like we should assume that this will eventually be fixed when Pointer Events are implemented, and that the most future-proof way to implement d3-drag will be to mousedown.preventDefault and touchstart.preventDefault (and eventually, pointerdown.preventDefault). Changing d3-drag’s default behavior in regards to preventing browser default behaviors in the future should probably be considered a breaking change, so it’d be great to commit to doing it now as part of the D3 4.0 major release.

/cc @jfirebaugh @jasondavies

afterdrag event?

As nice as it is to process the drag gestures independently, we might also need a hook for running code after all the active pointers have moved. Hopefully this will allow us to build a zoom gesture on top of the drag gesture…

click.stopPropagation?

Rather than allowing the click to propagate and ask people to check click.defaultPrevented, we should call click.stopPropagation. If people want to allow clicks, they can now do it by removing the noclick listener.

Listeners may not see the latest data.

If data changes during a drag gesture, listeners do not receive the latest data because it was captured in the arguments when the gesture started. Maybe this is okay, if we document it? Alternatively, the drag gesture would need to capture the index and the group, but retrieve the data from node.__data__.

Is React compatible with d3-drag?

My situation is that I have multiple polylines/polygons with circles at each point, and when I click a circle I'd like the polyline to move appropriately. I don't have any id's/className's on any polyline, and the circles are being caught via d3.event.

I have a version of this working (somewhat) at the moment but there are few issues:

  1. My cursor, if moving too fast, will stop dragging the previously-dragged circle
  2. The circle, if it gets too close to another point with a circle on it, will stop moving the point that I was originally moving and instead move the point that I'm close to.
  3. Sometimes, circles are completely dragged off the line and unable to rejoin the line.

screen shot 2017-09-25 at 7 47 00 pm

I'm confused about how to get drag and drop to work with d3/react and if this is even a potentially fruitful pursuit. Would appreciate some help.

Drag events force you to use inverted y-coordinate system

In a d3 application I have functions that manually convert to and from the rendering coordinate system to my preferred (cartesian) coordinate system:

let width = 800;
let height = 600;
let svg = d3.select("body").append("svg")
                           .attr("width", width)
                           .attr("height", height);

let originX = width / 2;
let originY = height / 2;
function fromCartesianX(x) { return originX + x; }
function fromCartesianY(y) { return originY - y; }
function toCartesianX(x) { return x - originX; }
function toCartesianY(y) { return -y + originY; }

This was working fine for rendering points and lines:

let circles = svg.selectAll("circle").data(data).enter().append("circle");
circles.attr("cx", function (d) { return fromCartesianX(d.x); })  // d has cartesian coordinates
       .attr("cy", function (d) { return fromCartesianY(d.y); })
       .attr("r", 20);

However, when I introduce a drag event handler, the drag event coordinates are computed relative to the input point, and assumes that data point uses the "y-inverted" coordinate system!

function dragged(d) {
  d.x = d3.event.x;
  d.y = d3.event.y;
  ...
  d3.select(this).attr("cx", fromCartesianX(d.x))
                   .attr("cy", fromCartesianY(d.y));

When dragging, this causes the y value to move inverted to how it should.

How can I tell d3 to compute the event x,y absolutely, in the containing svg coordinate system? Then I could replace the above with the following, which makes much more sense.

function dragged(d) {
  d.x = toCartesian(d3.event.x);
  d.y = toCartesian(d3.event.y);
  ...
  d3.select(this).attr("cx", fromCartesianX(d.x))
                          .attr("cx", fromCartesianY(d.y));

Reduce the scope of default behavior prevention.

Currently, we register selectstart, dragstart and click preventers on all drag gestures. However, it’s only necessary to prevent these events on mouse-based drag gestures. A click event is only emulated on touch if the (single) finger doesn’t move between touchstart and touchend, so there’s no reason to suppress the click event after a touch gesture. Furthermore, it doesn’t look like selectstart or dragstart is necessary to prevent, either.

Cache getScreenCTM on start?

I wonder if it’s worth caching getScreenCTM (and getBoundingClientRect) on start, since they shouldn’t change during a drag gesture?

function pointSvg(node, point) {
  var matrix = node.getScreenCTM().inverse();
  return function(event) {
    point.x = event.clientX, point.y = event.clientY;
    point = point.matrixTransform(matrix);
    return [point.x, point.y];
  };
}

function pointHtml(node) {
  var rect = node.getBoundingClientRect(),
      left = rect.left + node.clientLeft,
      top = rect.top + node.clientTop;
  return function(event) {
    return [event.clientX - left, event.clientY - top];
  };
}

export default function(node) {
  var svg = node.ownerSVGElement || node;
  return svg.createSVGPoint ? pointSvg(node, svg.createSVGPoint()) : pointHtml(node);
}

Related d3/d3#1797.

Inertial dragging?

is there any method for adding acceleration to d3's drag, which in my opinion can make many interactive pieces seem more natural. For instance, Google Maps [0] allows you to "throw" the map.

Excellent work all around on drag so far.

[0] https://v.usetapes.com/IdX0dPuvD9

Remove drag.x and drag.y.

It seems unnecessary given that you can specify a custom drag subject. Even the old behavior just had drag.origin.

How to expose state to callbacks?

I think the new design is better, but it presents an interesting conundrum: I want callbacks that conform to the D3 convention (this is the selected element, d is its datum, i is its index, and nodes is its group) but that can also receive additional information from the drag behavior (namely the coordinates x and y and the touch identifier id).

I could pass additional arguments to the callback, but that’s annoying because you have to specify (and then ignore) the standard arguments you may not care about, most often i and nodes.

I could omit the conventional arguments, and just provide this, but then you have to use this.data if you want the datum, which is ugly. And there’s no (easy) way to recover i or nodes.

I could temporarily expose the state on the drag behavior, or temporarily set them as globals, but isn’t that just a different way of accomplishing what d3.event is for?

This seems to imply that the additional state should be exposed on a custom d3.event.

I’ve so far avoided custom events because callbacks have either not been associated with a selection (d3-request and d3-force) or there wasn’t a need to pass any additional information (d3-transition; related d3/d3-transition#41). Though if we do want to pass additional information to transition callbacks, such as the transition’s name and id, it seems reasonable to expose that on d3.event, too.

So, if we are going to allow callers to temporarily override d3.event (and set event.sourceEvent automatically; related d3/d3-selection#70), then we’ll need a new method in d3-selection.

d3-drag doesn't work in Chrome's mobile test mode

I'm using Chrome 60.

To reproduce open the developers tools (Menu -> More Tools -> Developper Tools) then "Toggle device toolbar", then choose a device (as example: Ipad). Then open any examples for d3 drag (like this one).

It simply doesn't work anymore. As far as I can read d3 should support touch events, which Chrome is using to emulate its mobile test mode.

Click events following drag are not suppressed in Firefox?

Whenever the drag behavior is applied, the click event will not be triggered on the same element in Chrome but is triggered in Mozilla Firefox.

To work around this, I dispatch a click event whenever there is no dragging. This will work in Chrome. The click event will be triggered twice in Mozilla Firefox.

It seems the click event is not prevented in Firefox like it is supposed to be.

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

Example :

return d3.drag()
                .on("start", function (d) {
                    dragged = false;

                    if (!d3.event.active) simulation.alphaTarget(0.2).restart();
                    instance.get.getNodeSvg(c.id).raise();
                    d.fx = d.x;
                    d.fy = d.y;
                })
                .on("drag", function (d) {
                    dragged = true;

                    d.fx += d3.event.dx;
                    d.fy += d3.event.dy;
                })
                .on("end", function (d) {
                    if (!d3.event.active) simulation.alphaTarget(0);
                    d.fx = null;
                    d.fy = null;

                    if (!dragged) {
                        this.dispatchEvent(new MouseEvent("click", d3.event.sourceEvent));
                    }

                    dragged = false;
                });

Implement dragstart, selectstart, click suppression as listeners.

Pretty sure they could be implemented like this:

drag.on("start.nodrag", function() {
  var name = ".nodrag" + (d3.event.identifier == null ? "" : "-" + d3.event.identifier),
      view = d3.select(d3.event.sourceEvent.view).on("dragstart" + name, nodefault, true);
  d3.event.on("end" + name, function() { view.on(type, null); });
});

drag.on("start.noselect", function() {
  var name = ".noselect" + (d3.event.identifier == null ? "" : "-" + d3.event.identifier),
      view = d3.select(d3.event.sourceEvent.view).on("selectstart" + name, nodefault, true);
  d3.event.on("end" + name, function() { view.on("selectstart" + name, null); });
});

drag.on("start.noclick", function() {
  var name = ".noclick" + (d3.event.identifier == null ? "" : "-" + d3.event.identifier),
      view = d3.select(d3.event.sourceEvent.view),
      start = d3.event;
  start.on("drag" + name, function() { start.on("drag" + name, null).on("end" + name, end); });
  function end() { view.on("click" + name, nodefault, true); setTimeout(afterend, 0); }
  function afterend() { view.on("click" + name, null); }
});

gestures.mouse is not a function

I hate it when you get an error that noone on google has ever had before. In my case it is this:

Uncaught TypeError: gestures.mouse is not a function
at mousemoved (drag.js:69)

Relevant part og my parckage.json:

"d3": "4.13.0",
"d3-axis": "1.0.8",
"d3-scale": "1.0.7",
"d3-selection": "1.3.0",

And my handler:

nodes.call(d3.drag()
.on('start', (d) => {
	this.onDragStart(d);
})
.on('drag', (d) => {
	this.onDrag(d);
})
.on('end', () => {
	this.onDragEnd();
}));

The Error from above starts being logged to the console on any mousemoved event after the first drag end. this.onDragEnd is always being called, but after that i get the Error and all further handling of this event stops propagating, so it breaks all mouse handling after the first drag end.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.