D3 仅在 Vue 3 组件的第一个实例中正常工作

D3 working properly only in first instance of Vue 3 component

我正在开发 Vue 3 应用程序,我想在其中使用一个组件的多个实例。每个组件都应该有它的 D3 实例来显示各种 SVG 图像。在我的例子中,D3 仅在 Vue 组件的第一个实例上按预期工作。

点是由 D3 随机生成的。在检查元素时,我可以看到在组件的第二个实例中附加了 none 个点。问题截图可能见here.

我的 D3 组件如下所示:

<template>
  <div class="fill-100">
    <svg ref="svgRef" width="400" height=667>
      <g></g>
    </svg>
  </div>
</template>

<script>

import {ref, onMounted} from "@vue/runtime-core";
import {select, zoom} from "d3";

export default {
  name: "SldSvgD3",
  props: ["id"],
  setup() {
    const svgRef = ref(null);

    onMounted(() =>{
      const svg = select(svgRef.value);
      svg.append("svg")


      let data = [], width = 400, height = 667, numPoints = 100;

      let zoom3 = zoom()
        .on('zoom', handleZoom);

      function handleZoom(e) {
          select('svg g')
          .attr('transform', e.transform);
      }

      function initZoom() {
        select('svg')
          .call(zoom3);
      }

      function updateData() {
        data = [];
        for(let i=0; i<numPoints; i++) {
          data.push({
            id: i,
            x: Math.random() * width,
            y: Math.random() * height
          });
        }
      }

      function update() {
        select('svg g')
          .selectAll('circle')
          .data(data)
          .join('circle')
          .attr('cx', function(d) { return d.x; })
          .attr('cy', function(d) { return d.y; })
          .attr('r', 3);
      }

      initZoom();
      updateData();
      update();

    });

    return {svgRef}
  }
}

</script>


<style lang="scss">
  .fill-100{
    width: 100%;
    height: 100%;
  }
</style>

D3 缩放和平移的实现取自 this site

我不知道 d3.select() 调用的范围是整个应用程序的全局范围。在我的案例中,解决方案只是为根 div 创建唯一的 id 并选择此 div 在任何操作之前。

对我很有帮助。

完整代码:

<template>
  <div class="fill-100" :id="'sld_div'+this.id">
  </div>
</template>

<script>

import {ref, onMounted} from "@vue/runtime-core";
import * as d3 from "d3";

export default {
  name: "SldSvgD3",
  props: ["id"],
  setup(props) {
    const svgRef = ref(null);
    const svg_width = 400;
    const svg_height = 667;

    onMounted(() =>{

        const svg = d3
          .select("#sld_div"+props.id)
        svg.append("svg")
          .attr("id","sld_root"+props.id)
          .attr("width", svg_width)
          .attr("height", svg_height)
        .append("g")
          .attr("id","sld_root_g"+props.id)

      let data = [], width = 600, height = 400, numPoints = 100;

      let zoom = d3.zoom()
        .on('zoom', handleZoom);

      function handleZoom(e) {
        d3.select("#sld_div"+props.id)
          .select('svg g')
          .attr('transform', e.transform);
      }

      function initZoom() {
        d3.select("#sld_div"+props.id)
          .select('svg')
          .call(zoom);
      }

      function updateData() {
        data = [];
        for(let i=0; i<numPoints; i++) {
          data.push({
            id: i,
            x: Math.random() * width,
            y: Math.random() * height
          });
        }
      }

      function update() {
        d3.select("#sld_div"+props.id)
          .select('svg g')
          .selectAll('circle')
          .data(data)
          .join('circle')
          .attr('cx', function(d) { return d.x; })
          .attr('cy', function(d) { return d.y; })
          .attr('r', 3);
      }

      initZoom();
      updateData();
      update();

    });

    return {svgRef}
  }
}

</script>


<style lang="scss">
  .fill-100{
    width: 100%;
    height: 100%;
  }
</style>