我在 D3 中有以下代码(来自基本示例),用于平移和缩放 Canvas - 以及用于拖动单个元素的第二个代码块。我想要的是既能够在整个 Canvas 上平移/缩放,又能够在用户在特定对象上开始拖动时移动单个对象。
我的平移/缩放代码是:
var svgCanvas = d3.select('body')
.append("svg:svg")
.attr("width", 800)
.attr("height", 800)
var g = svgCanvas.append("g")
$('body').append(
$("<div>", {id: "canvas-wrapper" })
.append("<div/>", { id: "canvas" })
);
var svg = d3.select("svg");
var canvas = d3.select("#canvas");
var canvasWrapper = d3.select("#canvas-wrapper");
var root = svg.append("g");
root.append("rect")
.attr("x", 50).attr("y", 50)
.attr("width", 50).attr("height", 50)
.style("fill", "blue")
.style("stroke", "green").style("stroke-width", "3px");
root.append("rect")
.attr("x", 150).attr("y", 150)
.attr("width", 50).attr("height", 50)
.style("fill", "blue")
.style("stroke", "green").style("stroke-width", "3px");
var zoom = d3.zoom()
.scaleExtent([1, 8])
.on("zoom", function () {
var t = d3.event.transform;
root.attr("transform", t);
canvas.style("transform", "translateX(" + t.x + "px) translateY(" + t.y + "px) scale(" + t.k + ")")
});
canvasWrapper.call(zoom);
我的拖动代码是:
var svg = d3.select('body')
.append("svg:svg")
.attr("width", 800)
.attr("height", 800)
var nodes = svg
.selectAll('.node')
.data([
{ x: 10, y: 10 },
{ x: 100, y: 100 }
])
.enter()
.append('g')
.attr('class', 'node')
.attr("transform", function (data) {
return "translate(" + [data.x, data.y] + ")";
})
.call(function () {
return d3.drag()
.on('drag', function (d, i) {
d.x += d3.event.dx;
d.y += d3.event.dy;
d3.select(this).attr("transform", function () {
return "translate(" + [d.x, d.y] + ")";
});
})
.on('start', function (d, i) {})
.on('end', function (d, i) {});
}());
nodes.append("svg:rect")
.attr("width", 100)
.attr("height", 100)
.style("fill", "red")
除了当用户在开放区域上拖动时在整个 Canvas 上拖动之外,我还需要做什么才能允许单独拖动每个对象?
显然,两个代码部分之间的区别在于,一个在整个 Canvas 上工作,一个在单个元素上工作(第一个有额外的外部容器) - 我如何将两者结合起来?
我尝试通过向外部容器添加节点并向每个节点添加拖动处理来简单地组合两个代码示例,但 Canvas 似乎捕获所有事件,从而忽略节点上的拖动。
组合的非工作代码:
d3.select('body')
.append("svg:svg")
.attr("width", 800)
.attr("height", 800);
$('body').append(
$("<div>", {
id: "canvas-wrapper"
}).append("<div/>", {
id: "canvas"
})
);
var svg = d3.select("svg");
var canvas = d3.select("#canvas");
var canvasWrapper = d3.select("#canvas-wrapper");
var root = svg.append("g");
var nodes = root
.selectAll('.node')
.data(dataArray)
.enter()
.append('g')
.attr('class', 'node')
.attr("transform", function (data) {
return "translate(" + [data.x, data.y] + ")";
})
.call(function () {
return d3.drag().on('drag', function (d, i) {
d.x += d3.event.dx;
d.y += d3.event.dy;
d3.select(this).attr("transform", function () {
return "translate(" + [d.x, d.y] + ")";
});
})
}());
nodes.append("svg:rect")
.attr("width", 50)
.attr("height", 50)
.style("fill", "#ffb5b5")
.style("fill", "#ffb5b5")
.style("stroke", "green").style("stroke-width", "3px");
var zoom = d3.zoom()
.scaleExtent([1, 8])
.on("zoom", function () {
var t = d3.event.transform;
root.attr("transform", t);
canvas.style("transform", "translateX(" + t.x + "px) translateY(" + t.y + "px) scale(" + t.k + ")")
});
canvasWrapper.call(zoom);
已解决:
通过检测 Canvas 中的鼠标事件位置,可以隐藏/显示覆盖 SVG Canvas 的 Canvas 。因此,当鼠标事件在节点上启动时, Canvas 应隐藏,允许拖动功能,而其他事件应由 Canvas 捕获,允许平移/缩放
最佳答案
首先向 svg
添加一个 rect
并在此 rect
上调用缩放。任何未被元素捕获的鼠标事件都将用于缩放,删除 Canvas 包装。
对于 Chrome,您可以在 svg
上调用缩放,无需额外的 rect
。
var dataArray = [{x:100, y:100}, {x:200, y:200}];
var svgWidth = 800, svgHeight = 800;
var svg = d3.select('body')
.append("svg:svg")
.attr("width", svgWidth)
.attr("height", svgHeight);
var zoomRect = svg.append('rect')
.attr("width", svgWidth)
.attr("height", svgHeight)
.attr("fill", "white");
var root = svg.append("g");
var nodes = root
.selectAll('.node')
.data(dataArray)
.enter()
.append('g')
.attr('class', 'node')
.attr("transform", function (data) {
return "translate(" + [data.x, data.y] + ")";
})
.call(function () {
return d3.drag().on('drag', function (d, i) {
d.x += d3.event.dx;
d.y += d3.event.dy;
d3.select(this).attr("transform", function () {
return "translate(" + [d.x, d.y] + ")";
});
})
}());
nodes.append("svg:rect")
.attr("width", 50)
.attr("height", 50)
.style("fill", "#ffb5b5")
.style("stroke", "green").style("stroke-width", "3px");
var zoom = d3.zoom()
.scaleExtent([1, 8])
.on("zoom", function () {
var t = d3.event.transform;
root.attr("transform", t);
//canvas.style("transform", "translateX(" + t.x + "px) translateY(" + t.y + "px) scale(" + t.k + ")");
});
zoomRect.call(zoom);
<script src="http://d3js.org/d3.v5.min.js"></script>
关于d3.js - 在 D3 中平移、缩放 Canvas 以及拖动节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53420396/