How to set the Origin (drag.origin) for drag behavior in d3 JavaScript library
Asked Answered
B

2

10

I am trying to implement drag behavior for group consisting from HTML-text and background-rectangle using the d3 framework. I was able to get it working, although when not setting the drag.origin I can see noticeable jump due to the mouse-position/element-coordinates offset. Exactly how described on the d3 wiki-page Although the page described how to set the Origin for dragging, I do not properly understand how ti implement it in my example. I tried two different approaches : using the element for grouping the elements together and defining new element holding tose. In the first case I have to use the translate-function and I do not even know how to get the coordinates of the group.

var svg = d3.select("body").append("svg")
  .attr("width", 960)
  .attr("height", 500);

var group = svg.append("svg:g")
  .attr("transform", "translate(10, 10)")
  .attr("id", "group");

var rect1 = group.append("svg:rect")
  .attr("rx", 6)
  .attr("ry", 6)
  .attr("x", 5/2)
  .attr("y", 5/2)
  .attr("id", "rect")
  .attr("width", 250)
  .attr("height", 125)
  .style("fill", 'white')
  .style("stroke", d3.scale.category20c())
  .style('stroke-width', 5);


var html1 = group.append("foreignObject")
  .attr("x", 50)
  .attr("y", 25)
  .attr("width", 200)
  .attr("height", 100)
  .attr("id", "fobject")
  .style("border-color", d3.scale.category20c())
  .append("xhtml:div")
  .style("font", "14px 'Helvetica Neue'")
  .html("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam.");

var innerSvg = svg.append("svg")
  .attr("x", 500)
  .attr("y", 10)
  .attr("id", "innerSvg");

var rect2 = innerSvg.append("svg:rect")
  .attr("rx", 6)
  .attr("ry", 6)
  .attr("x", 5/2)
  .attr("y", 5/2)
  .attr("id", "rect")
  .attr("width", 250)
  .attr("height", 125)
  .style("fill", 'white')
  .style("stroke", d3.scale.category20c())
  .style('stroke-width', 5);

var html2 = innerSvg.append("foreignObject")
  .attr("x", 50)
  .attr("y", 25)
  .attr("width", 200)
  .attr("height", 100)
  .attr("id", "fobject")
  .style("border-color", d3.scale.category20c())
  .append("xhtml:div")
  .style("font", "14px 'Helvetica Neue'")
  .html("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam.");

var drag1 = d3.behavior.drag()
    .on("drag", function(d,i) {
        d3.select(this).attr("transform", function(d,i){
            return "translate(" + [ d3.event.x,d3.event.y ] + ")"
        })
    });

var drag2 = d3.behavior.drag()
    .on("drag", function(d,i) {
        d3.select(this)
        .attr("x", d3.event.x)
        .attr("y", d3.event.y);
    });

group.call(drag1);
innerSvg.call(drag2);

I would very appreciate any explanation, naturally I prepared a working example here : http://jsfiddle.net/Y8y7V/

Backstroke answered 12/4, 2013 at 8:12 Comment(0)
W
21

You simply need to set the origin() function accordingly. In the second case this is straightforward, in the first case somewhat more difficult because you are using coordinates as well as a transform. The basic pattern (for the second case) looks like this:

 .origin(function() { 
        var t = d3.select(this);
        return {x: t.attr("x"), y: t.attr("y")};
    })

Updated jsfiddle here.

Wakerly answered 12/4, 2013 at 8:26 Comment(3)
Thank you very much for your explanation. In the first case I can simply add the x/y coordinates as parameter of the <g> element. I wonder how can I set the translation parameter according to the defined x/y parameters, like : var group = svg.append("svg:g") .attr("x", 50) .attr("y", 25) .attr("transform", "translate(" + [ this.attr("x"),this.attr("y") ] + ")") This of ocourse wont work, because this references the window object.Backstroke
If you set the origin() appropriately, you don't need to set the transform based on the static coordinates.Wakerly
Which does not solve my problem - question for which I was not able to find answer yet - how to GET the position of the group, the <g>-element, when I can only use the "transformation" to set its position. Thanks anyhow, your previous explanation solved my problem and i was able to find a working solution for booth cases.Backstroke
T
0

group element has no x/y attributes - no problem! create ones:

var node = svg.append("g")
            .attr('x',x_1)
            .attr('y',y_1)
            .attr("class","node")
            .attr("name","Node_A")
            .attr("transform","translate(" + x_1 + ", " + y_1 +")")
            .call(drag);

when, the .origin function from Lars will work

and dont forget to update x,y attributes, while dragging:

function dragged() {

    d3.select(this).attr("transform","translate(" + d3.event.x + ", " + d3.event.y +")");
    d3.select(this).attr("x",d3.event.x);
    d3.select(this).attr("y",d3.event.y);
}
Taradiddle answered 30/3, 2015 at 18:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.