我正在尝试连接来自不同组的两个矩形,但这些组可以拖动。如果组是静态的,我可以完成工作。但是当我拖动大组时,线条行为变得混乱。我想点击一个圆圈并开始绘制线条,当鼠标移动时移动线条,然后我想点击另一个圆圈并结束线条。这是我工作的fiddle,有人可以帮我一把吗?
<g id="a" transform="translate(0,0)">
<g>
<rect x="10" y="10" width="200" height="200" fill="red"></rect>
<circle r="5" cx="10" cy="105" fill="blue"></circle>
<circle r="5" cx="210" cy="105" fill="blue"></circle>
<line id="lineOne" x1="210" y1="105" x2="200" y2="200" style="stroke: green; stroke-width: 3px"></line>
</g>
<g id="b" class="e">
<rect x="20" y="20" width="50" height="50" fill="black"></rect>
<circle r="5" cx="20" cy="45" fill="blue"></circle>
<circle r="5" cx="70" cy="45" fill="blue"></circle>
</g>
<g id="c" class="e">
<rect x="90" y="20" width="50" height="50" fill="black"></rect>
<circle r="5" cx="90" cy="45" fill="blue"></circle>
<circle r="5" cx="140" cy="45" fill="blue"></circle>
</g>
</g>
<script>
d3.select('svg').on('mousemove', function () {
d3.select('#lineOne').attr('x2', d3.mouse(this)[0]).attr('y2', d3.mouse(this)[1]);
})
;
d3.select('#a').call(d3.behavior.drag()
.origin(function () {
var t = d3.select(this);
return {
x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
};
})
.on('drag', function () {
d3.select(this).attr('transform', 'translate(' + d3.event.x + ',' + d3.event.y + ')');
}));
d3.selectAll('.e')
.call(d3.behavior.drag()
.origin(function () {
var t = d3.select(this);
return {
x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
};
}
)
.on('dragstart', function () {
d3.event.sourceEvent.stopPropagation();
})
.on('drag', function () {
var parent = d3.select('#a').select('rect');
var current = d3.select(this).select('rect');
var dx = d3.event.x;
var dy = d3.event.y;
var x, y;
if (((Number(current.attr('x')) + dx) > Number(parent.attr('width')))) {
console.log('x case');
x = Number(parent.attr('width')) - Number(current.attr('width')) - Number(current.attr('x'));
}
else if (dx < 0 && (Number(current.attr('x')) - Number(parent.attr('x')) + dx ) < 0) {
x = -1 * Number(current.attr('x')) + 20;
}
else {
x = dx;
}
if (((Number(current.attr('y')) + dy) > Number(parent.attr('height')))) {
y = Number(parent.attr('height')) - Number(current.attr('height')) - Number(current.attr('y'));
}
else if (dy < 0 && (Number(current.attr('y')) - Number(parent.attr('y')) + dy ) < 0) {
y = -1 * Number(current.attr('y')) + 20;
}
else {
y = dy;
}
d3.select(this).attr('transform', 'translate(' + x + ',' + y + ')');
}))
.on('dragend', function () {
d3.select(this).call(d3.behavior.drag().origin(function () {
var t = d3.select(this);
return {x: t.attr("x"), y: t.attr("y")};
}))
})
;
</script>
答案 0 :(得分:4)
拖动矩形时,您还必须更新链接。使用变换矩阵计算x1,x2,y1和y2位置。我创建了一个有效的代码片段。有关详细信息,请参阅代码。如果有的话,请随时提出疑问。
d3.selectAll(".line")[0]
.forEach(function(el) {
var d = d3.select(el).data()[0],
line = d3.select(el);
if (d.src == g.attr("id")) {
var pt = svg.createSVGPoint();
pt.x = parseInt(g.select("circle." + d.sPos).attr("cx"));
pt.y = parseInt(g.select("circle." + d.sPos).attr("cy"));
pt = pt.matrixTransform(g.node().getCTM());
pt = pt.matrixTransform(d3.select("#a").node().getCTM().inverse());
line.attr('x1', pt.x).attr('y1', pt.y);
} else if (d.tgt == g.attr("id")) {
var pt = svg.createSVGPoint();
pt.x = parseInt(g.select("circle." + d.ePos).attr("cx"));
pt.y = parseInt(g.select("circle." + d.ePos).attr("cy"));
pt = pt.matrixTransform(g.node().getCTM());
pt = pt.matrixTransform(d3.select("#a").node().getCTM().inverse());
line.attr('x2', pt.x)
.attr('y2', pt.y);
}
});
var svg = d3.select('svg').node();
d3.select('svg').on('mousemove', function() {
if (dragging) {
var rad = 5;
var x = d3.mouse(d3.select('#a').node())[0],
y = d3.mouse(d3.select('#a').node())[1];
d3.select('#dummyPath').attr('x2', x - rad).attr('y2', y - rad);
d3.select('#dummyPath').style("display", "block")
}
});
d3.select('#a').call(d3.behavior.drag()
.origin(function() {
var t = d3.select(this);
return {
x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
};
})
.on('drag', function() {
d3.select(this).attr('transform', 'translate(' + d3.event.x + ',' + d3.event.y + ')');
}));
d3.selectAll('.e')
.call(d3.behavior.drag()
.origin(function() {
var t = d3.select(this);
return {
x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
};
})
.on('dragstart', function() {
d3.event.sourceEvent.stopPropagation();
})
.on('drag', function() {
var g = d3.select(this);
var parent = d3.select('#a').select('rect');
var current = d3.select(this).select('rect');
var dx = d3.event.x;
var dy = d3.event.y;
var x, y;
if (((Number(current.attr('x')) + dx) > Number(parent.attr('width')))) {
console.log('x case');
x = Number(parent.attr('width')) - Number(current.attr('width')) - Number(current.attr('x'));
} else if (dx < 0 && (Number(current.attr('x')) - Number(parent.attr('x')) + dx) < 0) {
x = -1 * Number(current.attr('x')) + 20;
} else {
x = dx;
}
if (((Number(current.attr('y')) + dy) > Number(parent.attr('height')))) {
y = Number(parent.attr('height')) - Number(current.attr('height')) - Number(current.attr('y'));
} else if (dy < 0 && (Number(current.attr('y')) - Number(parent.attr('y')) + dy) < 0) {
y = -1 * Number(current.attr('y')) + 20;
} else {
y = dy;
}
d3.select(this).attr('transform', 'translate(' + x + ',' + y + ')');
d3.selectAll(".line")[0]
.forEach(function(el) {
var d = d3.select(el).data()[0],
line = d3.select(el);
if (d.src == g.attr("id")) {
var pt = svg.createSVGPoint();
pt.x = parseInt(g.select("circle." + d.sPos).attr("cx"));
pt.y = parseInt(g.select("circle." + d.sPos).attr("cy"));
pt = pt.matrixTransform(g.node().getCTM());
pt = pt.matrixTransform(d3.select("#a").node().getCTM().inverse());
line.attr('x1', pt.x).attr('y1', pt.y);
} else if (d.tgt == g.attr("id")) {
var pt = svg.createSVGPoint();
pt.x = parseInt(g.select("circle." + d.ePos).attr("cx"));
pt.y = parseInt(g.select("circle." + d.ePos).attr("cy"));
pt = pt.matrixTransform(g.node().getCTM());
pt = pt.matrixTransform(d3.select("#a").node().getCTM().inverse());
line.attr('x2', pt.x)
.attr('y2', pt.y);
}
});
}))
.on('dragend', function() {
d3.select(this).call(d3.behavior.drag().origin(function() {
var t = d3.select(this);
return {
x: t.attr("x"),
y: t.attr("y")
};
}))
})
;
var dragging = false;
var drag = d3.behavior.drag()
.on("dragstart", function() {
dragging = true;
d3.event.sourceEvent.stopPropagation();
var x = d3.mouse(d3.select('#a').node())[0],
y = d3.mouse(d3.select('#a').node())[1];
d3.select('#dummyPath').attr('x1', x).attr('y1', y);
})
.on("dragend", function() {
var sCircle = d3.select(this);
var eCircle = d3.select(d3.event.sourceEvent.target);
dragging = false;
if (d3.event.sourceEvent.target.tagName == "circle" && this != d3.event.sourceEvent.target) {
var rad = 5;
var source = d3.select(this.parentNode).attr("id");
var target = d3.select(d3.event.sourceEvent.target.parentNode).attr("id");
var x1 = d3.select('#dummyPath').attr('x1'),
y1 = d3.select('#dummyPath').attr('y1'),
x2 = d3.mouse(d3.select('#a').node())[0],
y2 = d3.mouse(d3.select('#a').node())[1];
d3.select("#a")
.append("line")
.datum({
src: source,
tgt: target,
sPos: sCircle.attr("class"),
ePos: eCircle.attr("class")
})
.attr("class", "line")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr('y2', y2);
}
d3.select('#dummyPath').style("display", "none");
});
d3.selectAll("circle").call(drag);
&#13;
#dummyPath {
stroke: green;
stroke-width: 3px;
display:none;
stroke-dasharray: 5 7;
}
.line {
stroke: blue;
stroke-width: 3px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="500" height="500">
<g id="a" transform="translate(0,0)">
<g id="d">
<rect x="10" y="10" width="200" height="200" fill="red"></rect>
<circle r="5" class="left" cx="10" cy="105" fill="blue"></circle>
<circle r="5" class="right" cx="210" cy="105" fill="blue"></circle>
</g>
<g id="b" class="e">
<rect x="20" y="20" width="50" height="50" fill="black"></rect>
<circle class="left" r="5" cx="20" cy="45" fill="blue"></circle>
<circle class="right" r="5" cx="70" cy="45" fill="blue"></circle>
</g>
<g id="c" class="e">
<rect x="90" y="20" width="50" height="50" fill="black"></rect>
<circle r="5" class="left" cx="90" cy="45" fill="blue"></circle>
<circle r="5" class="right" cx="140" cy="45" fill="blue"></circle>
</g>
<line id="dummyPath" x1="0" y1="0" x2="0" y2="0" class="dummy"></line>
</g>
</svg>
&#13;
<强>更新强>