如何使用 d3js 拖动完整的 svg?
How to drag complete svg with d3js?
我试图在单击 svg 上的任意位置时产生拖动行为。
这是我尝试过的 JSFiddle:https://jsfiddle.net/d2fx196n/2/
我尝试的直觉是这样的:
svg = d3.select("body")
.append("svg:svg")
.attr("width", 200)
.attr("height", 200)
.style("border", "solid")
.call(drag);
有没有一种简单的方法可以将拖动行为应用于整个 svg,使每个对象都以相同的方式移动?
编辑:我更确切地说是通过单击 svg 中的任意位置(甚至是 "background")来拖动 svg 中的所有内容。当我拖动时,svg 中的所有内容都应该一起移动。
EDIT2:基本上,我希望有与此处相同的行为:http://jsfiddle.net/superboggly/2hfx3/,但也有线条
策略
您可以将 svg 的内容包装在 g 中并对其进行变换,然后在拖动时更新变换转换。
战术
d3.event
公开了 dx
和 dy
,因此您可以在拖动时将它们添加到变换中。
- 在 d3 数学模块中有一个方便的 API 变换,您可以使用它来省去解析 g 元素的变换属性的麻烦。
代码
var drag = d3.behavior.drag()
//.origin(function (d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended),
data = {
"nodes": [
{ "id": "0", "x": 50, "y": 50 },
{ "id": "1", "x": 100, "y": 50 },
{ "id": "2", "x": 50, "y": 100 },
{ "id": "3", "x": 100, "y": 100 }
],
"edges": [
{ "id": "0", "source": "0", "target": "1" },
{ "id": "1", "source": "2", "target": "3" }
]
},
log = d3.select("body").append("div")
.style({ "background-color": "1px solid #ccc" })
.text("waiting..."),
svg = d3.select("body")
.append("svg:svg")
.attr("width", 200)
.attr("height", 200)
.style("border", "solid")
.call(drag)
.append("g"),
nodes = data.nodes,
links = data.edges;
for (var i in data.edges) {
for (var j in nodes) {
if (nodes[j].id == data.edges[i].source) {
data.edges[i].source = nodes[j];
} else if (nodes[j].id == data.edges[i].target) {
data.edges[i].target = nodes[j];
}
}
}
var lines = svg.selectAll(".line")
.data(links)
.enter()
.append("line")
.attr("x1", function (d) { return d.source.x })
.attr("y1", function (d) { return d.source.y })
.attr("x2", function (d) { return d.target.x })
.attr("y2", function (d) { return d.target.y })
.attr("stroke-width", "4")
.style("stroke", "#000000");
var circles = svg.selectAll("circle.nodes")
.data(nodes)
.enter()
.append("svg:circle")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("r", "8px")
.attr("fill", "#FF0000");
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault;
console.log("start")
log.text("start")
}
function dragged(e) {
var t = d3.transform(svg.attr("transform")).translate;
svg.attr("transform", "translate(" + [t[0] + d3.event.dx, t[1] + d3.event.dy] + ")")
console.log("drag: " + d3.transform(svg.attr("transform")).translate);
log.text("drag: " + d3.transform(svg.attr("transform")).translate)
}
function dragended(d) {
console.log("end")
log.text("end")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
我试图在单击 svg 上的任意位置时产生拖动行为。
这是我尝试过的 JSFiddle:https://jsfiddle.net/d2fx196n/2/
我尝试的直觉是这样的:
svg = d3.select("body")
.append("svg:svg")
.attr("width", 200)
.attr("height", 200)
.style("border", "solid")
.call(drag);
有没有一种简单的方法可以将拖动行为应用于整个 svg,使每个对象都以相同的方式移动?
编辑:我更确切地说是通过单击 svg 中的任意位置(甚至是 "background")来拖动 svg 中的所有内容。当我拖动时,svg 中的所有内容都应该一起移动。
EDIT2:基本上,我希望有与此处相同的行为:http://jsfiddle.net/superboggly/2hfx3/,但也有线条
策略
您可以将 svg 的内容包装在 g 中并对其进行变换,然后在拖动时更新变换转换。
战术
d3.event
公开了dx
和dy
,因此您可以在拖动时将它们添加到变换中。- 在 d3 数学模块中有一个方便的 API 变换,您可以使用它来省去解析 g 元素的变换属性的麻烦。
代码
var drag = d3.behavior.drag()
//.origin(function (d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended),
data = {
"nodes": [
{ "id": "0", "x": 50, "y": 50 },
{ "id": "1", "x": 100, "y": 50 },
{ "id": "2", "x": 50, "y": 100 },
{ "id": "3", "x": 100, "y": 100 }
],
"edges": [
{ "id": "0", "source": "0", "target": "1" },
{ "id": "1", "source": "2", "target": "3" }
]
},
log = d3.select("body").append("div")
.style({ "background-color": "1px solid #ccc" })
.text("waiting..."),
svg = d3.select("body")
.append("svg:svg")
.attr("width", 200)
.attr("height", 200)
.style("border", "solid")
.call(drag)
.append("g"),
nodes = data.nodes,
links = data.edges;
for (var i in data.edges) {
for (var j in nodes) {
if (nodes[j].id == data.edges[i].source) {
data.edges[i].source = nodes[j];
} else if (nodes[j].id == data.edges[i].target) {
data.edges[i].target = nodes[j];
}
}
}
var lines = svg.selectAll(".line")
.data(links)
.enter()
.append("line")
.attr("x1", function (d) { return d.source.x })
.attr("y1", function (d) { return d.source.y })
.attr("x2", function (d) { return d.target.x })
.attr("y2", function (d) { return d.target.y })
.attr("stroke-width", "4")
.style("stroke", "#000000");
var circles = svg.selectAll("circle.nodes")
.data(nodes)
.enter()
.append("svg:circle")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("r", "8px")
.attr("fill", "#FF0000");
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault;
console.log("start")
log.text("start")
}
function dragged(e) {
var t = d3.transform(svg.attr("transform")).translate;
svg.attr("transform", "translate(" + [t[0] + d3.event.dx, t[1] + d3.event.dy] + ")")
console.log("drag: " + d3.transform(svg.attr("transform")).translate);
log.text("drag: " + d3.transform(svg.attr("transform")).translate)
}
function dragended(d) {
console.log("end")
log.text("end")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>