Bootstrap

NodeJS+Vue3+D3


一、任务目标

使用vue制作一个包含d3直方图的网页 再加上一个饼图、词云图或力导向图。

二、代码实现主要部分

1. App.vue文件中加入力导向图

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3.0 + D3" />
  <HelloD3 msg="D3.JS@Vue3"/>
  <BarChart />
  <Force />
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
import BarChart from './components/BarChart.vue';
import HelloD3 from './components/D3Hist.vue';
import Force from './components/1.vue';

export default {
  name: 'App',
  components: {
    HelloWorld,BarChart,HelloD3,Force
  }
}
</script>

2. 编写力导向图的js文件

代码如下:

data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

3. 编写力导向图的js文件

代码如下:

<template> 
<h2><a href="https://d3js.org" target="_blank" >D3力导向图@VUE3</a></h2>
<div>
  <svg id="svg2" width="1200" height="800" ></svg> 
</div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "ForceDirected",
  props: {
    id: String,
    width: String,
    height: String,
    nodes: Array,
    edges: Array,
  },
  data() {
    return {      
    };
  },
  mounted() {
    this.init();
  },
  watch: {
    load() {
      this.init();
    },
  },
  methods: {
    init() {
      let marge = { top: 100, bottom: 60, left: 60, right: 60 };
      let svg = d3.select("#svg2");
      let width = 900;
      let height = 600;
      let g = svg
        .append("g")
        .attr("transform", "translate(" + marge.top + "," + marge.left + ")");
      // 准备数据
      // 节点集
      let nodes = [//节点集
        {name:"中国传媒大学"},
        {name:"信息科学与技术学部"},
        {name:"新闻传播学部" },
        {name:"艺术学部" },
        {name:"人文社科学部" },
        {name:"广告与经管学部" },
        {name:"协同创新中心" },
        {name:"直属学院" },
        {name:"信息与通信工程学院"  },
        {name:"计算机与网络空间安全学院"  },
        {name:"数据科学与智能媒体学院"  },
        {name:"实验教学中心"  },
        {name:"新闻学院"  },
    {name:"电视学院"  },
        {name:"传播研究院"  },
        {name:"戏剧影视学院"  },
        {name:"播音主持艺术学院"  },
        {name:"动画与数字艺术学院"  },
    {name:"音乐与录音艺术学院"  },
        {name:"艺术研究院"  },
        {name:"艺术教育中心"  },
        {name:"人文学院"  },
        {name:"外国语言文化学院"  },
    {name:"政府与公共事务学院"  },
        {name:"汉语国际教育中心"  },
        {name:"体育部"  },
        {name:"经济与管理学院"  },
        {name:"广告学院"  },
    {name:"文化产业管理学院"  },
    {name:"文化发展研究院"  },
        {name:"雄安新区发展研究院"  },
        {name:"新媒体研究院"  },
        {name:"互联网信息研究院"  },
        {name:"脑科学与智能媒体研究院"  },
    {name:"马克思主义学院"  },
    ];
      // 边集
      let edges = [
        {source:0,target:1,value:3.5,relation: "隶属"},  //value控制线的长短
        {source:0,target:2,value:3.5,relation: "隶属"},
        {source:0,target:3,value:3.5,relation: "隶属"},
        {source:0,target:4,value:3.5,relation: "隶属"},
        {source:0,target:5,value:3.5,relation: "隶属"},
        {source:0,target:6,value:3.5,relation: "隶属"},
        {source:0,target:7,value:3.5,relation: "隶属"},
        {source:1,target:8,value:2,relation: "隶属"},
        {source:1,target:9,value:2,relation: "隶属"},
        {source:1,target:10,value:2,relation: "隶属"},
        {source:1,target:11,value:2,relation: "隶属"},
    {source:2,target:12,value:2,relation: "隶属"},
        {source:2,target:13,value:2,relation: "隶属"},
        {source:2,target:14,value:2,relation: "隶属"},
        {source:3,target:15,value:2,relation: "隶属"},
        {source:3,target:16,value:2,relation: "隶属"},
    {source:3,target:17,value:2,relation: "隶属"},
        {source:3,target:18,value:2,relation: "隶属"},
    {source:3,target:19,value:2,relation: "隶属"},
        {source:3,target:20,value:2,relation: "隶属"},
    {source:4,target:21,value:2,relation: "隶属"},
    {source:4,target:22,value:2,relation: "隶属"},
    {source:4,target:23,value:2,relation: "隶属"},
    {source:4,target:24,value:2,relation: "隶属"},
    {source:4,target:25,value:2,relation: "隶属"},
    {source:5,target:26,value:2,relation: "隶属"},
    {source:5,target:27,value:2,relation: "隶属"},
        {source:5,target:28,value:2,relation: "隶属"},
    {source:5,target:29,value:2,relation: "隶属"},
    {source:5,target:30,value:2,relation: "隶属"},
    {source:6,target:31,value:2,relation: "隶属"},
    {source:6,target:32,value:2,relation: "隶属"},
    {source:6,target:33,value:2,relation: "隶属"},
    {source:7,target:34,value:2,relation: "隶属"},
    ];
   
      let colorScale = d3
        .scaleOrdinal()
        .domain(d3.range(nodes.length))
        .range(d3.schemeTableau10);
 
      let forceSimulation = d3
        .forceSimulation()
        .force("link", d3.forceLink())
        .force("charge", d3.forceManyBody())
        .force("center", d3.forceCenter());
 
      forceSimulation.nodes(nodes).on("tick", ticked);
 
      forceSimulation
        .force("link")
        .links(edges)
        .distance(function (d) {

          return d.value * 90;
        });
 
      forceSimulation
        .force("center")
        .x(width / 2)
        .y(height / 2);
     
      let links = g
        .append("g")
        .selectAll("line")
        .data(edges)
        .enter()
        .append("line")
        .attr("stroke", function (d, i) {
          return colorScale(i);
        })
        .attr("stroke-width", 1);

      let linksText = g
        .append("g")
        .selectAll("text")
        .data(edges)
        .enter()
        .append("text")
        .text(function (d) {
          return d.relation;
        });
 
      let gs = g
        .selectAll(".circleText")
        .data(nodes)
        .enter()
        .append("g")
        .attr("transform", function (d) {
          let cirX = d.x;
          let cirY = d.y;
          return "translate(" + cirX + "," + cirY + ")";
        })
        .call(
          d3.drag().on("start", started).on("drag", dragged).on("end", ended)
        );

      gs.append("circle")
        .attr("r", 10)
        .attr("fill", function (d, i) {
          return colorScale(i);
        });

      gs.append("text")
        .attr("x", -10)
        .attr("y", -20)
        .attr("dy", 10)
        .text(function (d) {
          return d.name;
        });

      function ticked() {
        links
          .attr("x1", function (d) {
            return d.source.x;
          })
          .attr("y1", function (d) {
            return d.source.y;
          })
          .attr("x2", function (d) {
            return d.target.x;
          })
          .attr("y2", function (d) {
            return d.target.y;
          });
        linksText
          .attr("x", function (d) {
            return (d.source.x + d.target.x) / 2;
          })
          .attr("y", function (d) {
            return (d.source.y + d.target.y) / 2;
          });
        gs.attr("transform", function (d) {
          return "translate(" + d.x + "," + d.y + ")";
        });
      }

      function started(d) {
        if (!d3.event.active) {
          forceSimulation.alphaTarget(0.5).restart(); 
        }
        d.fx = d.x;
        d.fy = d.y;
      }
      function dragged(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
      }
      function ended(d) {
        if (!d3.event.active) {
          forceSimulation.alphaTarget(0);
        }
        d.fx = null;
        d.fy = null;
      }
    },
  },
};
</script>

4. 编写直方图的js文件

代码如下:

<template>
    <h2><a href="https://d3js.org" target="_blank" >D3直方图@VUE3</a></h2>
    <div id="bar-chart-container"></div>
</template>

<script>
import { defineComponent } from 'vue';
//import axios from "axios";
import * as d3 from "d3";

var data=new Array(10);
for (var i=0;i<10;i++)
{
    data[i]=Math.floor(Math.random()*255);           
    console.log(data[i]);
}
var color=d3.schemeCategory10;

export default defineComponent({
    mounted() {      
        this.drawBarChart(data);      
    },
    methods:{
        drawBarChart(data){
            const width=800;
            const height=400;
            var svg=d3.select("#bar-chart-container")
                        .append("svg")
                        .attr("width",width)
                        .attr("height",height);

            svg.selectAll("rect")
               .data(data)
               .enter()
               .append("rect")
               .attr("fill",(d,i)=>color[i])
               .attr("x",function(d,i){
                   return width*i/10;
               })
               .attr("y",d=>(height-d))
               .attr("height",d=>d)
               .attr("width",width*0.9/10);

            svg.selectAll("text")
               .data(data)
               .enter()
               .append("text")
               .attr("x",function(d,i){
                   return 25+width*i/10;
               })
               .attr("y",d=>(height-d-10))
               .text(function(d,i){
                    return d;
                })
        }
    }
})
</script>

三、注意事项

注意,在VUE中安装d3时,需要注意安装d3的版本,否则无法显示。

四、结果展示

在这里插入图片描述
在这里插入图片描述

总结

第一次学习VUE,项目的构建方法和以前接触过的方法完全不一样。这次尝试了将D3与VUE结构,实验效果较好,也比较顺利。能感觉到VUE的功能很强大,期待以后继续学习这方面的知识。

;