目标: 在黑色矩形组中移动红色矩形。 黑色矩形形成一个限制移动红色矩形的图形。
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
这是我的一个主题的例子。 但它不能正常工作。 也许有人有一个类似的正确例子或提供如何正确地做到这一点的线索。
答案 0 :(得分:1)
我过去曾想出过类似的情况,这就是我克服这个问题的方法。
当我拖动小元素时,我使用getXY()
函数来确定被拖动元素的x,y。
getXY()
将采用内部和外部的鼠标坐标(d3.mouse(this)
)和x, y , width, height
。外部物体。然后它将确定是否返回鼠标坐标(在这种情况下是外部对象的边界坐标)。
我希望你能得到这个想法。我想你可以用它来解决你的问题。
这是我原来的帖子。 d3js transforming nested group images
答案 1 :(得分:1)
这不是一个完美的解决方案。但您可能会想到如何从此演示中实现该功能。
//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);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
答案 2 :(得分:0)
例如。 我根据自己的需要改变了任务。 并写了一个可能对某人有用的决定。 接下来是代码,其中矩形只能沿着线移动。 可以使用透明颜色(.attr(“填充”,“rgba(0,0,0,0)”);)隐藏线条,您可以为用户绘制任何其他内容。
http://codepen.io/anon/pen/pjoGOr
var deltaMax = 15; // max distance to line
var svgx = 0;
var svgy = 0;
var limiters = []; //array of lines for align
var svgContainer = d3.select("body").append("svg")
.attr("width", 700)
.attr("height", 700);
var line1 = svgContainer.append("line")
.style("stroke", "black")
.attr("x1", 100)
.attr("y1", 50)
.attr("x2", 100)
.attr("y2", 200);
var line2 = svgContainer.append("line")
.style("stroke", "blue")
.attr("x1", 100)
.attr("y1", 50)
.attr("x2", 300)
.attr("y2", 50);
var line3 = svgContainer.append("line")
.style("stroke", "green")
.attr("x1", 100)
.attr("y1", 50)
.attr("x2", 300)
.attr("y2", 200);
limiters.push(line1);
limiters.push(line2);
limiters.push(line3);
function distance2points(x1,y1,x2,y2){ //distance between 2 points
return Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
//find nearest intersection point
function stick(x1,y1,x2,y2,x3,y3) {
//intersection point
var ipoint = { x:0, y:0 };
var onSegment = false;
if((x2 - x1) == 0){
ipoint.x = x1;
ipoint.y = y3;
}else if((y2-y1) == 0){
ipoint.x = x3;
ipoint.y = y1;
}else{
var k = (y2-y1)/(x2-x1);
var b = y2-k*x2;
var kp = -1/k;
var bp = y3-kp*x3;
ipoint.x = (bp-b)/(k-kp);
ipoint.y = ipoint.x*k+b;
}
//xxx helper
point.attr("cx",ipoint.x);
point.attr("cy",ipoint.y);
if(distance2points(x3,y3,ipoint.x,ipoint.y) > deltaMax){
return false;
}
//intersectionn point on segment?
if( (( x1 >= ipoint.x ) && ( x2 <= ipoint.x ) || ( x1 <= ipoint.x ) && ( x2 >= ipoint.x )) &&
(( y1 >= ipoint.y ) && ( y2 <= ipoint.y ) || ( y1 <= ipoint.y ) && ( y2 >= ipoint.y )) ){
onSegment = true;
}else if(distance2points(x1,y1,ipoint.x,ipoint.y) < deltaMax){
ipoint.x = x1;
ipoint.y = y1;
onSegment = true;
}else if(distance2points(x2,y2,ipoint.x,ipoint.y) < deltaMax){
ipoint.x = x2;
ipoint.y = y2;
onSegment = true;
}else{
onSegment = false;
}
if(onSegment){
point.attr("fill","blue");
return ipoint;
}else{
point.attr("fill","red");
return false;
}
}
//mouse position
svgContainer.on('mousemove', function () {
svgx = d3.mouse(this)[0];
svgy = d3.mouse(this)[1];
});
// dragging function
var drag = d3.behavior.drag()
.on("drag", function(d,i) {
for (i = 0; i < limiters.length; i++) {
var obj = limiters[i];
var p = stick(
obj.attr("x1"),
obj.attr("y1"),
obj.attr("x2"),
obj.attr("y2"),
svgx,//mouse position
svgy
);
if(p !== false){
d3.select(this).attr("transform", function(d,i){
return "translate(" + [ p.x,p.y ] + ")"
});
break;
}
}
});
var r = svgContainer.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 20)
.attr("height", 20)
.attr("fill", "red")
.data([ {"x":0, "y":0} ])
.call(drag);
//xxx helper - nearest intersection point
var point = svgContainer.append("circle")
.attr("cx", 10)
.attr("cy", 30)
.attr("r", 5)
.attr("fill", "green");