我正在渲染很多元素,所以我使用d3和canvas而不是SVG。
This lovely block from @mbostock describes how to zoom the canvas on mouse scroll in d3v4。但是,我想鼠标滚动 pan 而不是缩放(如常规网页和this block)。
有一个couple folks已经找到了如何使用带有SVG的d3平移滚动。不幸的是,这些答案不适用于画布。
canvas.call(d3.zoom()
.scaleExtent([1 / 2, 4])
.on("zoom", zoomed));
...稍后......
function zoomed() {
context.save();
context.clearRect(0, 0, w, h);
// this gives the default zooming and panning behavior in canvas:
context.translate(d3.event.transform.x, d3.event.transform.y);
context.scale(d3.event.transform.k, d3.event.transform.k);
// Instead, something like this might work?:
current_translate = d3....?
new_translate = {'x': current_translate.x + d3.event.sourceEvent.wheelDeltaX,
'y': current_translate.y + d3.event.sourceEvent.wheelDeltaY};
context.translate(new_translate.x, new_translate.y);
drawCanvas();
context.restore();
}
或者,我可能根本不应该使用d3.zoom
。应该是这样的:
canvas.call(d3.pan() // ??
.on("zoom", pan));
我能想到的最后一个选择是我不应该为滚动行为设置任何javascript处理程序,而是只有一个大于window.innerHeight
的canvas元素。那么也许浏览器会为我照顾它? (尝试这种天真的方式对我来说没有用,所以如果这是最好的选择,那就一定会有所帮助。)
答案 0 :(得分:1)
以下是一些结合了两个相关示例的代码:
<!DOCTYPE html>
<meta charset="utf-8">
<canvas width="960" height="500"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var canvas = d3.select("canvas"),
context = canvas.node().getContext("2d"),
width = canvas.property("width"),
height = canvas.property("height"),
radius = 2.5;
var points = d3.range(2000).map(phyllotaxis(10));
canvas.call(d3.zoom()
.scaleExtent([1 / 2, 4])
.on("zoom", zoomed))
.on("wheel.zoom", pan);
drawPoints();
var currentTransform = d3.zoomIdentity;
function zoomed() {
context.save();
context.clearRect(0, 0, width, height);
currentTransform = d3.event.transform;
context.translate(currentTransform.x, currentTransform.y);
context.scale(currentTransform.k, currentTransform.k);
drawPoints();
context.restore();
}
function pan() {
context.save();
context.clearRect(0, 0, width, height);
currentTransform.x += d3.event.wheelDeltaX;
currentTransform.y += d3.event.wheelDeltaY;
context.translate(currentTransform.x, currentTransform.y);
drawPoints();
context.restore();
}
function drawPoints() {
context.beginPath();
points.forEach(drawPoint);
context.fill();
}
function drawPoint(point) {
context.moveTo(point[0] + radius, point[1]);
context.arc(point[0], point[1], radius, 0, 2 * Math.PI);
}
function phyllotaxis(radius) {
var theta = Math.PI * (3 - Math.sqrt(5));
return function(i) {
var r = radius * Math.sqrt(i), a = theta * i;
return [
width / 2 + r * Math.cos(a),
height / 2 + r * Math.sin(a)
];
};
}
</script>
&#13;