如何使用Canvas平移d3 v4 / v5中的滚动

时间:2018-06-09 19:25:07

标签: javascript d3.js canvas

背景

我正在渲染很多元素,所以我使用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元素。那么也许浏览器会为我照顾它? (尝试这种天真的方式对我来说没有用,所以如果这是最好的选择,那就一定会有所帮助。)

1 个答案:

答案 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;
&#13;
&#13;