d3 缩放相对于视口大小

d3 zoom relative to viewport size

我目前正在尝试使用 d3 缩放库为我的 canvas 元素添加平滑的缩放和平移。它应该适用于不同的视口大小,所以我需要 canvas 元素相对于视口的大小。

当尽可能缩小(由 scaleExtent 控制)时,元素应该在所有设备上很好地填充屏幕宽度。

const canvas = document.querySelector('canvas')
const context = canvas.getContext('2d')

canvas.width = canvas.offsetWidth
canvas.height = canvas.offsetHeight

const zoom = d3.zoom()
  .scaleExtent([0.4, 2])
  .on('zoom', ({transform}) => zoomed(transform))

d3.select(canvas).call(zoom)
zoomed(d3.zoomIdentity)

function zoomed(transform)  {
  console.log(transform);

  context.save()
  context.clearRect(0,0, canvas.width, canvas.height)
  const scale = transform.k * canvas.width/2000

  context.translate(transform.x, transform.y)
  context.scale(scale, scale)
  
  drawPaths()

  context.restore()
}

我尝试将某种值(相对于 canvas 宽度)添加到比例值,但我只是猜测 2000,我担心稍后它可能会弄乱我的代码,当我不操作 d3 转换对象时。

这是一个代码笔: https://codepen.io/lkssmnt-the-lessful/pen/wvgjmbw

我在初始化时使用缩放到适合的方法解决了这个问题:

function initCanvas() {
  const midX = bbox.x + bbox.width / 2;
  const midY = bbox.y + bbox.height / 2;

  const scale = Math.min(viewportWidth / bbox.width, viewportHeight / bbox.height);
  const translateX = viewportWidth / 2 - midX * scale;
  const translateY = viewportHeight / 2 - midY * scale;

  d3.select(canvas).call(
    zoom_function.transform,
    d3.zoomIdentity.translate(translateX, translateY).scale(scale)
  );
}

这将使您的路径在初始化时居中,但不会使 zoomExtent 相对于视口大小。然而,这也可以通过给 scaleExtent 函数一个相对值来完成。

关于边界框的附加信息: 在我的例子中,由于路径没有改变,找出边界框不是我必须以编程方式做的事情,但有一些方法可以这样做: https://codepen.io/TomashKhamlai/pen/KNrjqE