3

I am not sure what's going on, but I have 2 very simple examples set up to show what I am asking.

Both examples have a 'g' that contains a 'rect' and 'text'.

In the 1st example, I am setting up drag on the 'g' itself, i.e., if you mousedown anywhere in that group and drag, it will drag the entire thing (both 'rect' and 'text') around the viewpoint. http://jsfiddle.net/wup4d0nx/

var chart = d3.select("body").append("svg")
   .attr("height", 500)
   .attr("width", 500)
   .style("background", "lightgrey");

var group = chart.selectAll("g")
    .data(["Hello"])
    .enter()
    .append("g")
    .attr("id", function (d) { return d;});

var rect = group.append("rect")
    .attr("stroke", "red")
    .attr("fill", "blue")
    .attr("width", 200)
    .attr("height", 200)
    .attr("x", 10)
    .attr("y", 10);

var label = group.append("text")
    .attr("x", 40)
    .attr("y", 40)
    .attr("font-size", "22px")
    .attr("text-anchor", "start")
    .text(function (d) { return d;});

// Set up dragging for the entire group
var dragMove = function (d) {
    var x = d3.event.x;
    var y = d3.event.y;
    d3.select(this).attr("transform", "translate(" + x + "," + y + ")");
};


var drag = d3.behavior.drag()
    .origin(function (data) {
        var element = d3.select("#" + data);
        return {
            x: d3.transform(element.attr("transform")).translate[0],
            y: d3.transform(element.attr("transform")).translate[1]
        };
    })
    .on("drag", dragMove);

group.call(drag);

In the 2nd example, which doesn't work and is what I am interested in, I want ONLY THE TEXT to be something the user can grab to drag the entire group around.

I tried many attempts. Some don't work at all, some work but flicker like the example I provide here: http://jsfiddle.net/9xeo7ehf/

var chart = d3.select("body").append("svg")
    .attr("height", 500)
    .attr("width", 500)
    .style("background", "lightgrey");

var group = chart.selectAll("g")
    .data(["Hello"])
    .enter()
    .append("g")
    .attr("id", function (d) { return d;});

var rect = group.append("rect")
    .attr("stroke", "red")
    .attr("fill", "blue")
    .attr("width", 200)
    .attr("height", 200)
    .attr("x", 10)
    .attr("y", 10);

var label = group.append("text")
    .attr("x", 40)
    .attr("y", 40)
    .attr("font-size", "22px")
    .attr("text-anchor", "start")
    .text(function (d) { return d;});

// Set up dragging for the entire group USING THE LABEL ONLY TO DRAG
var dragMove = function (d) {
    var x = d3.event.x;
    var y = d3.event.y;
    d3.select(this.parentNode).attr("transform", "translate(" + x + "," + y + ")");
};


var drag = d3.behavior.drag()
    .origin(function (data) {
        var element = d3.select("#" + data);
        return {
            x: d3.transform(element.attr("transform")).translate[0],
            y: d3.transform(element.attr("transform")).translate[1]
        };
    })
    .on("drag", dragMove);

label.call(drag);

What's going on with this that it flickers and what am I doing wrong?

Any help would be greatly appreciated!

Thanks!

user1902183
  • 3,203
  • 9
  • 31
  • 48
  • I have answered exaclty the same question [here](https://stackoverflow.com/a/45817005/3620572). Hope it helps. – roland Aug 22 '17 at 12:09

2 Answers2

0

I'm not sure exactly why it is flickering (as I am not too familiar with D3), but one way to get it to stop is to use the source event for D3:

// 50 is the offset x/y position you set for your text
var x = d3.event.sourceEvent.pageX - 50;
var y = d3.event.sourceEvent.pageY - 50;

Edit: While the above code works, it causes the box to initially "jump" to the coordinates of the text, A better fix would be to take your first example and just filter our events that aren't executed on the text element. Try putting the following at the top of the dragMove method:

if(d3.event.sourceEvent.target.nodeName !== 'text') {
    return;
}
wjohnsto
  • 4,323
  • 2
  • 14
  • 20
0

Try d3.event.sourceEvent.stopPropagation(); inside on-drag function

kittu
  • 6,662
  • 21
  • 91
  • 185