NodeJS+Vue3+D3 简单的直方图、力导图、饼图实现

  • 结果展示

 

 

  • 主要代码

主要components有以下部分,arcpies是饼图,barchart是直方图,force是力导图。通过app.vue整合。

​​​​​​​

 

Arcpie.vue

该部分直接移植了可视化课上d3的代码,内容上与d3部分保持一致。通过mouseover和mouseout实现交互。​​​​​​​

<template>
    <h2><a href="https://d3js.org" target="_blank" >D3饼图@VUE3</a></h2>
    <div id="bar-chart-container"></div>
</template>
<script>
import * as d3 from 'd3'

    export default {
        mounted() {
            const width=300;
            const height=300;
            function getColor(i) {
		var palette = [
				'#688db9', '#515696', '#9bbcab', '#d6cea9', '#a74a90',
				'#864d93', '#f1a641', '#f38936', '#ed7975', '#f26862'] 
		return palette[i%palette.length];}
        var dataList = [30,20,10,20,30,40,15,20,40,10];
        var piedata = d3.pie()(dataList);

        var mapPadding = 20
        var svgMap = d3.select("div")
                       .append('svg')
                       .attr("width", width)
                       .attr("height", height)
                       .style("margin", "10px")
        //定义弧形生成器
        var innerRadius = 50;
        var outerRadius = width / 2 - mapPadding; 
        var arc_generator = d3.arc()
                              .innerRadius(innerRadius)
                              .outerRadius(outerRadius);

            
        var groups = svgMap.selectAll("g")
                           .data(piedata)
                           .enter()
                           .append("g")
                           .attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")")

        groups.append("path")
         	  .attr("fill",function(d,i){
			  		return getColor(i);})
              .attr("d", function (d) {
                    return arc_generator(d); //使用弧生成器获取路径
                  })
              .on("mouseover",function(d,i){
                      d3.select(this)
                        .transition()
                        .duration(300)
                        .attr("fill","yellow");
                  })
              .on("mouseout",function(d,i){
                      d3.select(this)
                        .transition()
                        .duration(300)
                        .attr("fill","grey");
                })

        //添加文字
        groups.append("text")
              .attr("transform", function (d) {//位置设在中心处
                    return "translate(" + arc_generator.centroid(d) + ")";
                })
              .attr("text-anchor", "middle")
              .text(function (d) {
                    return d.data;
                })
              .style("fill","black")
              .style("font-size","20px")
              .style('font-family', 'Arial')
        }, 
    }
</script>

Barchart.vue

该部分是直方图的代码,在老师给的vue3+d3基础上进行了部分修改。​​​​​​​

<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);
var data = [30,20,10,20,30,40,15,20,40,10];

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",function(d,i){
			  		return getColor(i);
			  	})

               .on("mouseover",function(d,i){
                      d3.select(this)
                        .transition()
                        .duration(300)
                        .attr("fill","yellow");
                })
                .on("mouseout",function(d,i){
                      d3.select(this)
                        .transition()
                        .duration(300)
                        .attr("fill","grey");
                })
               .attr("x",function(d,i){
                   return width*i/10;
               })
               .attr("y",d=>(height-8*d))
               .attr("height",function(d)
               {
                   return 100*d;
               })
               .attr("width",width*0.9/10);
            

			svg.selectAll("text")
               .data(data)
               .enter()
               .append("text")
			   .attr("dy", "-1em")
               .attr("x",function(d,i){
                   return width*i/10+width/20;
               })
               .attr("y",d=>(height-8*d))
			   .attr("text-anchor", "middle")
			   .attr("font-size", "20px")
			   .attr("fill", "Black")
			   .text(function(d) {
						return d;
					});

                  

        function getColor(i) {
		var palette = [
				'#688db9', '#515696', '#9bbcab', '#d6cea9', '#a74a90',
				'#864d93', '#f1a641', '#f38936', '#ed7975', '#f26862',
				] 
		return palette[i%palette.length];}
        }
    }
})
</script>

force.vue

该部分数据集来源于网络,版本是v4,参考了网络资料。

<template>
  <h2><a href="https://d3js.org" target="_blank" >D3力导图@VUE3</a></h2>
  <div>
    <svg width="960" height="300"></svg>
  </div>
</template>
<script>
import * as d3 from 'd3'
export default {
  data () {
    return {
    }
  },
  mounted () 
  {
		var svg = d3.select('svg')
		var width = svg.attr('width')
		var height = svg.attr('height')
	    var padding = {
        left: 30,
        right: 30,
        top: 20,
        bottom: 20
        }

		var nodesData = [
		{ 'name': 'Lillian', 'sex': 'F' ,index:'0'},
		{ 'name': 'Gordon', 'sex': 'M' ,index:'1'},
		{ 'name': 'Sylvester', 'sex': 'M' ,index:'2'},
		{ 'name': 'Mary', 'sex': 'F' ,index:'3'},
		{ 'name': 'Helen', 'sex': 'F' ,index:'4'},
		{ 'name': 'Jamie', 'sex': 'M' ,index:'5'},
		{ 'name': 'Jessie', 'sex': 'F' ,index:'6'},
		{ 'name': 'Ashton', 'sex': 'M' ,index:'7'},
		{ 'name': 'Duncan', 'sex': 'M' ,index:'8'},
		{ 'name': 'Evette', 'sex': 'F' ,index:'9'},
		{ 'name': 'Mauer', 'sex': 'M' ,index:'10'},
		{ 'name': 'Fray', 'sex': 'F' ,index:'11'},
		{ 'name': 'Duke', 'sex': 'M' ,index:'12'},
		{ 'name': 'Baron', 'sex': 'M' ,index:'13'},
		{ 'name': 'Infante', 'sex': 'M',index:'14' },
		{ 'name': 'Percy', 'sex': 'M' ,index:'15'},
		{ 'name': 'Cynthia', 'sex': 'F',index:'16' }
		]
	
		var linksData = [
		{ 'source': 'Sylvester', 'target': 'Gordon', 'type': 'A' },
		{ 'source': 'Sylvester', 'target': 'Lillian', 'type': 'A' },
		{ 'source': 'Sylvester', 'target': 'Mary', 'type': 'A' },
		{ 'source': 'Sylvester', 'target': 'Jamie', 'type': 'A' },
		{ 'source': 'Sylvester', 'target': 'Jessie', 'type': 'A' },
		{ 'source': 'Sylvester', 'target': 'Helen', 'type': 'A' },
		{ 'source': 'Helen', 'target': 'Gordon', 'type': 'A' },
		{ 'source': 'Mary', 'target': 'Lillian', 'type': 'A' },
		{ 'source': 'Ashton', 'target': 'Mary', 'type': 'A' },
		{ 'source': 'Duncan', 'target': 'Jamie', 'type': 'A' },
		{ 'source': 'Gordon', 'target': 'Jessie', 'type': 'A' },
		{ 'source': 'Sylvester', 'target': 'Fray', 'type': 'E' },
		{ 'source': 'Fray', 'target': 'Mauer', 'type': 'A' },
		{ 'source': 'Percy', 'target': 'Cynthia', 'type': 'A' },
		{ 'source': 'Infante', 'target': 'Duke', 'type': 'A' },
		{ 'source': 'Duke', 'target': 'Gordon', 'type': 'A' },
		{ 'source': 'Baron', 'target': 'Duke', 'type': 'A' },
		{ 'source': 'Baron', 'target': 'Sylvester', 'type': 'E' },
		{ 'source': 'Evette', 'target': 'Sylvester', 'type': 'E' },
		{ 'source': 'Cynthia', 'target': 'Sylvester', 'type': 'E' }
		]

		var force=d3.forceSimulation()
					.nodes(nodesData)
	             	.force('charge', d3.forceManyBody())
					.force('center', d3.forceCenter((width - padding.left - padding.right) / 2, (height - padding.top - padding.bottom) / 2))

	var linkForce = d3.forceLink(linksData)
		              .id((d) => { return d.name }).distance(150)
	force.force('links', linkForce)


	var link = svg.append('g')
			  	  .attr('class', 'links')
				  .selectAll('.line')
				  .data(linksData)
				  .enter()
				  .append('line')
				  .attr('stroke-width', 1)
				  .style('stroke', "#688db9")

	var node = svg.append('g')
				  .attr('class', 'nodes')
			      .selectAll('.node')
	    		  .data(nodesData)
				  .enter()
				  .append('circle')
				  .attr('r', 6)
				  .attr('fill', "#515696")
				  .style('opacity',0.8)	  

	var text = svg.append('g')
				  .attr('class', 'texts')
			      .selectAll('.node')
	    		  .data(nodesData)
				  .enter()
				  .append('text')
				  .attr('dx','-0.5em')
				  .attr('dy','1em')
				  .text(function(d){return d.name;})
				  

	force.on('tick', tickAction)

	function tickAction () {
		node
			.attr('cx', function(d){ return d.x })
			.attr('cy', function(d){ return d.y })
		text
			.attr('x', function(d){ return d.x })
			.attr('y', function(d){ return d.y })

		link
			.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 })
		}
  }
}
</script>
 

D3hist.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
    import axios from "axios";
    export default{
        //挂载后执行
        mounted(){
            axios.get("./alphabet.json").then(res => {
                console.log(res.data);
            });
        },
    };
</script>



<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

App.vue

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

<script>
import HelloWorld from './components/HelloWorld.vue'
import BarChart from './components/BarChart.vue';
import HelloD3 from './components/D3Hist.vue';
import pic from './components/force.vue';
import Arcpie from './components/arcpie.vue';

export default {
  name: 'App',
  components: {
    HelloWorld,
    BarChart,
    HelloD3,
    pic,
    Arcpie
}
}
</script>
  • 反思总结

首次接触vue和vscode,在调试和理解代码框架上花费了较多的时间。在实际操作过程中,依旧有很多报错问题没有得到彻底的解决,比如力导图的拖拽交互。最后在结果展示的时候回避掉了。希望在以后的学习中能够进步,解决这些问题。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值