Objective: Move the red rectangle within the group of black rectangles. Black rectangles form a figure which is restricted to move the red rectangle.
window.onload=function(){
var inter = false;
//Make an SVG Container
var svgContainer = d3.select("body").append("svg")
.attr("width", 800)
.attr("height", 600);
//draw some rects
var r1 = svgContainer.append("rect")
.attr("class", "interactive")
.attr("x", 10)
.attr("y", 223)
.attr("width", 50)
.attr("height", 150);
var r2 = svgContainer.append("rect")
.attr("class", "interactive")
.attr("x", 223)
.attr("y", 10)
.attr("width", 50)
.attr("height", 300)
.attr("transform", "rotate(45 220,10)");
//group of elements for limit red rect drag
var interactive = d3.selectAll(".interactive")
.on("mouseover", function(d){
inter = true;
})
.on("mouseleave", function(d){
inter = false;
});
// dragging function
var drag = d3.behavior.drag()
.on("drag", function(d,i) {
if(inter){
d.x += d3.event.dx;
d.y += d3.event.dy;
d3.select(this).attr("transform", function(d,i){
return "translate(" + [ d.x,d.y ] + ")"
});
}
})
.on("dragstart", function() {
d3.select(this).style("pointer-events", "none")
})
.on("dragend", function() {
d3.select(this).style("pointer-events", "auto")
});
// red rectangle for draging
var r = svgContainer.append("rect")
.attr("x", 150)
.attr("y", 100)
.attr("width", 20)
.attr("height", 20)
.attr("fill", "red")
.data([ {"x":0, "y":0} ])
.call(drag);
}
http://codepen.io/anon/pen/pjorBb
Here's my example of a subject. But it is not working properly. Maybe someone has a similar example of a correct or give clue how to do it correctly.
This is not a perfect solution. But you may get the idea of how to implement the functionality from this demo.
//Make an SVG Container
var svgContainer = d3.select("body").append("svg")
.attr("width", 800)
.attr("height", 600);
//draw some rects
var r1 = svgContainer.append("rect")
.attr("class", "interactive")
.attr("x", 10)
.attr("y", 223)
.attr("width", 50)
.attr("height", 150);
var r2 = svgContainer.append("rect")
.attr("class", "interactive")
.attr("x",223)
.attr("y", 10)
.attr("width", 50)
.attr("height", 300)
.attr("transform", "rotate(45 220,10)");
function pointRectangleIntersection(p, r) {
return p.x >= r.x1 && p.x <= r.x2 && p.y >= r.y1 && p.y <= r.y2;
}
// dragging function
var drag = d3.behavior.drag()
.on("drag", function(d,i) {
var pt1 = d3.mouse(r1.node());
var point1 = {x: pt1[0], y: pt1[1]};
var bbox1 = r1.node().getBBox();
var rect1 = { x1: bbox1.x, x2: bbox1.x+bbox1.width, y1: bbox1.y, y2: bbox1.y+bbox1.height };
var pt2 = d3.mouse(r2.node());
var point2 = {x: pt2[0], y: pt2[1]};
var bbox2 = r2.node().getBBox();
var rect2 = { x1: bbox2.x, x2: bbox2.x+bbox2.width, y1: bbox2.y, y2: bbox2.y+bbox2.height };
if(pointRectangleIntersection(point1, rect1) || pointRectangleIntersection(point2, rect2)){
if(pointRectangleIntersection(point1, rect1)){
d.x = Math.max(0, Math.min(rect1.x2 - 20, d3.event.x));
d.y = Math.max(0, Math.min(rect1.y2 - 20, d3.event.y));
} else{
d.x = Math.max(0, Math.min(rect2.x2 - 20, d3.event.x));
d.y = Math.max(0, Math.min(rect2.y2 - 20, d3.event.y));
}
d3.select(this).attr("x", d.x);
d3.select(this).attr("y", d.y);
d3.event.sourceEvent.stopPropagation();
}
});
// red rectangle for draging
var r = svgContainer.append("rect")
.attr("x", 150)
.attr("y", 100)
.attr("width", 20)
.attr("height", 20)
.attr("fill", "red")
.datum({"x":0, "y":0})
.call(drag);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I have came up with a similar situation in the past, This is how I overcame the issue.
When I drag the small element I use a getXY()
function to determine the x, y of the element being dragged.
getXY()
will take the mouse coordinates ( d3.mouse(this)
) and x, y , width, height
of the inner & outer objects. Then it will figure out whether to return the mouse coordinates or not (in this case border coordinates of the outer object).
I hope you will get the idea. I think you can use it to solve your problem.
This is my original post. d3js transforming nested group images
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With