美文网首页
126.使用vue3+d3.js画一个知识图谱

126.使用vue3+d3.js画一个知识图谱

作者: wo不是黄蓉 | 来源:发表于2022-12-12 22:55 被阅读0次
    使用vue3+d3.js画一个知识图谱

    d3 demo
    看demo和echarts看起来差不多,有什么区别吗?
    d3的学习成本更高,echarts只需要查看api和配置项即可,多数情况下用来做数据的展示,而d3.js可以直接操作dom,很灵活但是学习成本高,英文的文档阅读起来也是很考验耐心
    npm init vue@latest根据指引创建一个Vue3项目
    npm install -D d3安装d3.js
    导入数据,我用的demo上的数据结构可以自行下载

    <script setup>
    import data from "../mock/data.json";
    import * as d3 from "d3";
    import { onMounted } from "vue";
    //挂载完成阶段进行初始化,否则找不到当前页面的容器
    onMounted(() => {
      init();
    });
    //增加拖拽功能
    const drag = (simulation) => {
      function dragstarted(event, d) {
        if (!event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
      }
    
      function dragged(event, d) {
        d.fx = event.x;
        d.fy = event.y;
      }
    
      function dragended(event, d) {
        if (!event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      }
    
      return d3
        .drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended);
    };
    function init() {
      const height = 800;
      const width = 1400;
      const root = d3.hierarchy(data);
      const links = root.links();
      const nodes = root.descendants();
    
      const simulation = d3
        .forceSimulation(nodes)
        .force(
          "link",
          d3
            .forceLink(links)
            .id((d) => d.id)
            //设置距离
            .distance(100)
            //设置聚合,越小越分散
            .strength(0.5)
        )
        //设置边距
        //设置超出拉扯距离,越小越不会超出画布
        .force("charge", d3.forceManyBody().strength(-100))
        .force("x", d3.forceX())
        .force("y", d3.forceY());
    
      //指定容器
      const svg = d3
        .select(".container")
        .append("svg")
        //设置展示到画板中间
        .attr("viewBox", [-width / 2, -height / 2, width, height]);
      const link = svg
        .append("g")
        .attr("stroke", "#999")
        .attr("stroke-opacity", 0.6)
        .selectAll("line")
        .data(links)
        .join("line");
    
      const node1 = svg
        .append("g")
        .attr("fill", "#fff")
        .attr("stroke", "#000")
        .attr("stroke-width", 1)
        .selectAll("circle")
        .data(nodes)
        .join("circle")
        //给圆设置背景色
        .attr("fill", (d) => (d.children ? null : "lightgreen"))
        .attr("stroke", (d) => (d.children ? null : "lightgreen"))
        //指定圆的半径
        .attr("r", 20)
        //应用拖拽
        .call(drag(simulation));
    
      const node = svg
        .append("g")
        //给元素设置class属性,目前给定了元素的样式但是不生效,和style一样的疑问??
        .attr("class", "my-class")
        .selectAll(".my-class")
        .data(nodes)
        .join("text")
        //可以直接设置style属性,试了很多属性不起作用,除了font-size和fill属性,暂时还没找到原因??
        .attr("style", "font-family: arial; ;")
        //设置两个text会被覆盖
        .text((d) => {
          console.log(d);
          return d.data.name;
        })
        //应用拖拽
        .call(drag(simulation));
    
      // node
      //   .append("g")
      //   .append("text")
      //   .style("font-weight", 500)
      //   .style("font-family", "Arial")
      //   .style("fill", "red")
      //   .text("矩形1");
    
      simulation.on("tick", () => {
        let x1 = 0;
        let x2 = 0;
        let y1 = 0;
        let y2 = 0;
        //线条需要用四个点来确定位置
        link
          .attr("x1", (d) => {
            console.log(d);
            x1 = d.source.x;
            return x1;
          })
          .attr("y1", (d) => {
            y1 = d.source.y;
            return y1;
          })
          .attr("x2", (d) => {
            x2 = d.target.x;
            return x2;
          })
          .attr("y2", (d) => {
            y2 = d.target.y;
            return y2;
          });
        //设置坐标进行定位
        node
          .attr("x", (d) => {
            return d.x;
          })
          .attr("y", (d) => {
            return d.y;
          });
          //画圆的时候需要用到的,指定cx和cy
        node1.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
      });
    
      // invalidation.then(() => simulation.stop());
    
      return svg.node();
    }
    </script>
    
    <template>
      <div class="container"></div>
    </template>
    
    <style>
    .classA {
      display: block;
      padding: 2px;
      background-color: aquamarine;
    }
    .style-text {
      display: block;
      padding: 2px;
      background-color: aquamarine;
    }
    </style>
    

    展示效果


    image.png

    后面学习一下如何给这些节点增加点击事件,动态维护数据,分散节点等

    相关文章

      网友评论

          本文标题:126.使用vue3+d3.js画一个知识图谱

          本文链接:https://www.haomeiwen.com/subject/lrlqqdtx.html