使用来自 Mike Bostocks oberservablehq 示例的工具提示代码进行独立 d3v5 缩放后出现类型错误

Type error after making standalone d3v5 zoom with tooltip code from Mike Bostocks oberservablehq example

我正在尝试使用从 Mike 的 awesome https://observablehq.com/@d3/zoom-with-tooltip 下载的代码创建一个 html+js 文件 下面的代码显示数据和鼠标悬停有效,但尝试缩放失败:

index3.html:70 Uncaught TypeError: Cannot destructure property 'transform' of 'undefined' as it is undefined.
at SVGSVGElement.zoomed (index3.html:70)
at H.apply (d3.v5.min.js:2)
at kt (d3.v5.min.js:2)
at w.emit (d3.v5.min.js:2)
at w.zoom (d3.v5.min.js:2)
at d3.v5.min.js:2
at d3.v5.min.js:2

<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoom with Tooltip from https://observablehq.com/@d3/zoom-with-tooltip</title>

<body>
  <svg width="960" height="350"></svg>
</body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
  var radius = 6;
  var theta = Math.PI * (3 - Math.sqrt(5));
  var step = 12;
  var width = 800;
  var height = 350;

  function data() { //(radius,step,theta,width,height){
    return (
      Array.from({
        length: 2000
      }, (_, i) => {
        const radius = step * Math.sqrt(i += 0.5),
          a = theta * i;
        return [
          width / 2 + radius * Math.cos(a),
          height / 2 + radius * Math.sin(a)
        ];
      })
    )
  };

  // Replaced by select below
  // const svg = d3.create("svg")
  //        .attr("viewBox", [0, 0, width, height]);

  const svg = d3.select('svg');

  // all code below unchanged

  const g = svg.append("g")
    .attr("class", "circles");

  g.append("style").text(`
        .circles {
          stroke: transparent;
          stroke-width: 1.5px;
        }
        .circles circle:hover {
          stroke: black;
        }
    `);

  g.selectAll("circle")
    .data(data)
    .join("circle")
    .datum(([x, y], i) => [x, y, i])
    .attr("cx", ([x]) => x)
    .attr("cy", ([, y]) => y)
    .attr("r", radius)
    .attr("fill", ([, , i]) => d3.interpolateRainbow(i / 360))
    .on("mousedown", mousedowned)
    .append("title")
    .text((d, i) => `circle ${i}`);

  svg.call(d3.zoom()
    .extent([
      [0, 0],
      [width, height]
    ])
    .scaleExtent([1, 8])
    .on("zoom", zoomed));

  function mousedowned(event, [, , i]) {
    d3.select(this).transition()
      .attr("fill", "black")
      .attr("r", radius * 2)
      .transition()
      .attr("fill", d3.interpolateRainbow(i / 360))
      .attr("r", radius);
  }

  function zoomed({
    transform
  }) {
    g.attr("transform", transform);
  }
</script>

我只是看不出问题所在,感谢任何帮助。

我认为您对 d3.event 将是传递给事件处理程序的第一个参数感到困惑,而相反 - 至少对于 d3 v5 - 它是一个你可以访问的全局变量。更改 zoomedmousedowned 的签名为我修复了它。

<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoom with Tooltip from https://observablehq.com/@d3/zoom-with-tooltip</title>

<body>
  <svg width="960" height="350"></svg>
</body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
  var radius = 6;
  var theta = Math.PI * (3 - Math.sqrt(5));
  var step = 12;
  var width = 800;
  var height = 350;

  function data() { //(radius,step,theta,width,height){
    return (
      Array.from({
        length: 2000
      }, (_, i) => {
        const radius = step * Math.sqrt(i += 0.5),
          a = theta * i;
        return [
          width / 2 + radius * Math.cos(a),
          height / 2 + radius * Math.sin(a)
        ];
      })
    )
  };

  // Replaced by select below
  // const svg = d3.create("svg")
  //        .attr("viewBox", [0, 0, width, height]);

  const svg = d3.select('svg');

  // all code below unchanged

  const g = svg.append("g")
    .attr("class", "circles");

  g.append("style").text(`
        .circles {
          stroke: transparent;
          stroke-width: 1.5px;
        }
        .circles circle:hover {
          stroke: black;
        }
    `);

  g.selectAll("circle")
    .data(data)
    .join("circle")
    .datum(([x, y], i) => [x, y, i])
    .attr("cx", ([x]) => x)
    .attr("cy", ([, y]) => y)
    .attr("r", radius)
    .attr("fill", ([, , i]) => d3.interpolateRainbow(i / 360))
    .on("mousedown", mousedowned)
    .append("title")
    .text((d, i) => `circle ${i}`);

  svg.call(d3.zoom()
    .extent([
      [0, 0],
      [width, height]
    ])
    .scaleExtent([1, 8])
    .on("zoom", zoomed));

  function mousedowned([, , i]) {
    d3.select(this).transition()
      .attr("fill", "black")
      .attr("r", radius * 2)
      .transition()
      .attr("fill", d3.interpolateRainbow(i / 360))
      .attr("r", radius);
  }

  function zoomed() {
    g.attr("transform", d3.event.transform);
  }
</script>