d3 v4 - 缩放按钮与缩放行为冲突
d3 v4 - zoom with buttons in conflicts with zoom behaviour
我已经为我的问题创建了 gist。
我从 this example 开始。
所以我的问题是除了鼠标控制之外,我还需要一些放大和缩小按钮。
鼠标控制(使用滚轮缩放和平移通过拖动)使用 zoom() behaviour 实现。效果很好。
然后我添加了两个用于放大和缩小的按钮:
var _zoom = d3.zoom()
.scaleExtent([1 / 2, 8])
.on("zoom", zoomed);
var gui = d3.select("#gui")
gui.append("span")
.classed("zoom in", true)
.text("+")
.on("click", function() { _zoom.scaleBy(container, 2); })
gui.append("span")
.classed("zoom out", true)
.text("-")
.on("click", function(){ _zoom.scaleBy(container, 0.5); })
它们与鼠标行为冲突。要重现该错误,您必须缩放并四处拖动(使用鼠标控件),然后单击 +
范围:当前转换被覆盖。
如何解决?
要记住的关键是缩放变换存储在 node
中,NOT 在 _zoom
对象中。
在您的例子中,您在 svg
节点上设置了鼠标侦听器,
svg.call(_zoom);
当在 svg
元素上触发缩放事件时,您将更新 svg
节点的缩放变换并将其应用于 g
节点,
g.attr("transform", d3.event.transform);
在单击按钮时更新 g 元素的缩放时,您需要做的就是获取正确的变换,在您的情况下是 svg
节点,
_zoom.scaleBy(svg, 0.5);
这将正确触发 svg
节点上的缩放事件,下面完整更新,
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
svg.style("border", "solid 1px black");
var points = d3.range(2000).map(phyllotaxis(10));
var g = svg.append("g");
var _zoom = d3.zoom()
.scaleExtent([1 / 2, 8])
.on("zoom", function() {
g.attr("transform", d3.event.transform);
});
svg.call(_zoom);
var container = g.selectAll("circle")
.data(points)
.enter().append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", 2.5)
function phyllotaxis(radius) {
var theta = Math.PI * (3 - Math.sqrt(5));
return function(i) {
var r = radius * Math.sqrt(i),
a = theta * i;
return {
x: width / 2 + r * Math.cos(a),
y: height / 2 + r * Math.sin(a)
};
};
}
var gui = d3.select("#gui");
gui.append("span")
.classed("zoom in", true)
.text("+")
.on("click", function() {
_zoom.scaleBy(svg, 2);
});
gui.append("span")
.classed("zoom out", true)
.text("-")
.on("click", function() {
_zoom.scaleBy(svg, 0.5);
})
<svg width="960" height="500"></svg>
<div id="gui"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
我已经为我的问题创建了 gist。
我从 this example 开始。
所以我的问题是除了鼠标控制之外,我还需要一些放大和缩小按钮。
鼠标控制(使用滚轮缩放和平移通过拖动)使用 zoom() behaviour 实现。效果很好。
然后我添加了两个用于放大和缩小的按钮:
var _zoom = d3.zoom()
.scaleExtent([1 / 2, 8])
.on("zoom", zoomed);
var gui = d3.select("#gui")
gui.append("span")
.classed("zoom in", true)
.text("+")
.on("click", function() { _zoom.scaleBy(container, 2); })
gui.append("span")
.classed("zoom out", true)
.text("-")
.on("click", function(){ _zoom.scaleBy(container, 0.5); })
它们与鼠标行为冲突。要重现该错误,您必须缩放并四处拖动(使用鼠标控件),然后单击 +
范围:当前转换被覆盖。
如何解决?
要记住的关键是缩放变换存储在 node
中,NOT 在 _zoom
对象中。
在您的例子中,您在 svg
节点上设置了鼠标侦听器,
svg.call(_zoom);
当在 svg
元素上触发缩放事件时,您将更新 svg
节点的缩放变换并将其应用于 g
节点,
g.attr("transform", d3.event.transform);
在单击按钮时更新 g 元素的缩放时,您需要做的就是获取正确的变换,在您的情况下是 svg
节点,
_zoom.scaleBy(svg, 0.5);
这将正确触发 svg
节点上的缩放事件,下面完整更新,
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
svg.style("border", "solid 1px black");
var points = d3.range(2000).map(phyllotaxis(10));
var g = svg.append("g");
var _zoom = d3.zoom()
.scaleExtent([1 / 2, 8])
.on("zoom", function() {
g.attr("transform", d3.event.transform);
});
svg.call(_zoom);
var container = g.selectAll("circle")
.data(points)
.enter().append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", 2.5)
function phyllotaxis(radius) {
var theta = Math.PI * (3 - Math.sqrt(5));
return function(i) {
var r = radius * Math.sqrt(i),
a = theta * i;
return {
x: width / 2 + r * Math.cos(a),
y: height / 2 + r * Math.sin(a)
};
};
}
var gui = d3.select("#gui");
gui.append("span")
.classed("zoom in", true)
.text("+")
.on("click", function() {
_zoom.scaleBy(svg, 2);
});
gui.append("span")
.classed("zoom out", true)
.text("-")
.on("click", function() {
_zoom.scaleBy(svg, 0.5);
})
<svg width="960" height="500"></svg>
<div id="gui"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>