This question is closely related to the following question:
In that question, there was a single g element with a bunch of svg elements in the group. The solution was to use d3.event.sourceEvent.stopPropagation on dragstart.
In my case, I have a single g element with a bunch of svg elements including other g elements. Here is a simple example I created that illustrates my problem: http://jsfiddle.net/eforgy/x1cwur41/ (code copied below).
The fiddle creates three nested g elements and each g element contains just a single rect. If you open up a console and click the innermost red rect, despite having a stopPropagation on dragstart, you can see it appears to be propagating from the top red rect to the bottom blue rect and when you start dragging, it is using the drag from the blue rect, i.e. all three rects move. The behavior I am trying to produce is the following:
Any help would be appreciated.
PS: Here is the code:
var child = {index: 0};
var w = 800,
h = 600;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
var cinit = function() {
return svg;
};
cinit.x = 0;
cinit.y = 0;
cinit.width = w;
cinit.height = h;
var c0 = new Component(cinit); c0.fill = "blue";
var c1 = new Component(c0); c1.fill = "green";
var c2 = new Component(c1); c2.fill = "red";
function Component(parent) {
var id = child.index;
child.index += 1;
console.log("Created component "+id);
var x = 1.1*parent.x;
var y = 1.1*parent.y;
var width = .5*parent.width;
var height = .5*parent.height;
var fill = "blue";
var stroke = "black";
var drag = d3.behavior.drag()
.origin(function() {
var t = d3.transform(group.attr("transform")).translate;
return {
x: t[0],
y: t[1]
};
})
.on("drag", function() {
console.log("drag: "+id);
var p = component.position;
p[0] = d3.event.x;
p[1] = d3.event.y;
component.position = p;
})
.on("dragstart", function() {
console.log("dragstart: "+id);
d3.event.sourceEvent.stopPropagation;
});
var group = parent().append("g")
.attr("transform", "translate("+x+","+y+")")
.call(drag);
var rect = group.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", fill)
.attr("stroke", stroke)
.on("click", function() {console.log("Clicked "+id);});
function component() {
return group;
};
Object.defineProperty(component,"position",{
get: function() {return [x, y, width, height];},
set: function(_) {
x = _[0];
y = _[1];
width = _[2];
height = _[3];
rect.attr("width", width).attr("height", height);
group.attr("transform", "translate("+x+","+y+")");
return component;
}
});
Object.defineProperty(component,"x",{
get: function() {return x;},
set: function(_) {
x = _;
group.attr("transform", "translate("+x+","+y+")");
return component;
}
});
Object.defineProperty(component,"y",{
get: function() {return y;},
set: function(_) {
y = _;
group.attr("transform", "translate("+x+","+y+")");
return component;
}
});
Object.defineProperty(component,"width",{
get: function() {return width;},
set: function(_) {
width = _;
rect.attr("width", width).attr("height", height);
return component;
}
});
Object.defineProperty(component,"height",{
get: function() {return height;},
set: function(_) {
height = _;
rect.attr("width", width).attr("height", height);
return component;
}
});
Object.defineProperty(component,"fill",{
get: function() {return fill;},
set: function(_) {
fill = _;
rect.attr("fill", fill);
return component;
}
});
return component;
}
The problem is that you're not calling the function d3.event.sourceEvent.stopPropagation
. You are missing the parentheses ()
at the end.
When in doubt, don't forget to check the D3 documentation ;)