【Vue3+D3】基于Vue3+D3的数据可视化

目录

一、安装

(一)安装Node.JS

(二)安装Vue

(三)安装Vite

(四)安装VSCode

二、创建项目

三、数据可视化

(一)安装D3和axios

(二)绘制直方图

(三)绘制饼图


一、安装

(一)安装Node.JS

        Node.js 是一个基于 Chrome JavaScript 运行时建立的平台;是一个事件驱动 I/O 服务端的 JavaScript 环境,基于 Google 的 V8 引擎( V8 引擎执行 Javascript 的速度非常快,性能非常好)。总之,简单来说,Node.js 就是运行在服务端的 JavaScript 。它的目的是使前后端完全分离(前端 Node.js,后端 Python/Java )

        首先,我们到官网下载 Node.JS。因为我的电脑是64位的,所以我选择了64位Windows安装包(.msi),并下载到了"D:/node js/"路径下。下载 | Node.js 中文网http://nodejs.cn/download/

        下载好之后,打开命令提示符cmd转到Node.JS路径下(我这里是D:/node js/),查看是否下载成功以及下载的版本。可以看到我这里下载的是16.14.2版本。

         我们先来写一个简单的代码测试一下下载情况。在Node.JS路径下创建server.js文件,并写入以下内容:

var http = require('http');

http.createServer(function(request,response) {
	
	// 发送 HTTP 头部
	// HTTP  状态值:200:OK
	// 内容类型:text/plain
	response.writeHead(200,{'Content-Type':'text/plain'});
	
	// 发送响应数据 "Hello World"
	response.end('Hello World\n');
}).listen(8888);

// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');

        在cmd中键入 node server.js ,显示代码已经在网页中运行,我们打开它所指向的http://127.0.0.1:8888/,发现成功显示"Hello World",证明我们的Node.JS安装成功,且环境是正常可用的。(点击 Ctrl+C 可退出当前的 cmd 环境)

(二)安装Vue

        在 cmd 的 Node.JS 路径下(我这里为"D:/node js/")键入如下内容:

npm install vue
// 或者
npm install vue@next

        如果大家在现在及之后的安装过程中遇到报错提示“缺少相关文件”,可以点击Node.js安装包(.msi文件)中的Repair进行修复,亲测有效!

(三)安装Vite

        在 cmd 的 Node.JS 路径下(我这里为"D:/node js/")键入如下内容:

npm install vite

(四)安装VSCode

        VSCode安装过程可查看这篇博客,讲的超级详细!

VSCode安装使用教程(最新详细版)_Passerby_Wang的博客-CSDN博客_vscode安装教程最新版教程,1.63版本(超详细图文解说)1、下载2、安装3、初始化设置https://blog.csdn.net/Passerby_Wang/article/details/122179913        VSCode安装好之后,推荐大家安装两个扩展插件——Chinese Language Pack for Visual Studio CodeVolar,对后续的编程很有用。

二、创建项目

        在 cmd 或 VSCode 的终端中使用 Vite 创建项目:

npm create vite@latest

# 按照提示创建
# 1.输入项目名,例如:csdn_test
# 2.创建 vue 项目

cd <你的项目>   # 例如:cd csdn_test
npm install    # 下载依赖包
npm run dev    # 执行

        这时,它会自动显示出网页地址,如我这里的 http://localhost:3000/ ,我们在浏览器中打开该网页,会看到如下结果。

 

三、数据可视化

(一)安装D3和axios

        在项目目录下(我这里为"D:/node js/csdn_test/")安装D3和axios,键入以下代码:

npm install d3
npm install axios

        这样,我们就可以在项目目录下的node_modules中(我这里为"D:\node js\csdn_test\node_modules")看到我们需要用到的安装包。 接下来就可以在VSCode中编辑代码,进行数据可视化啦!

(二)绘制直方图

        首先我们尝试将之前学过的d3.js代码绘制的直方图修改为vue绘制的直方图。在 src/components/ 路径中删除HelloWorld.vue,新建Hist.vue文件,并写入如下代码:

<template>
    <h1>我国人口受教育程度-直方图</h1>
    <div id="bar-chart-container"></div>
</template>

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

var dataset = [["小学及以下",19.3],["初中",40.3],["高中/中专/技校",20.6],
			   ["大学专科",10.5],["大学本科及以上",9.3]];
var color=d3.schemeCategory10;

export default defineComponent({
    mounted() {      
        this.drawBarChart(dataset);      
    },
    methods:{
        drawBarChart(dataset){
            const w = 1200;
            const h = 500;
            var svg=d3.select("#bar-chart-container")
                        .append("svg")
                        .attr("width",w)
                        .attr("height",h);
			
			var rect = svg.selectAll("rect")
						  .data(dataset)
						  .enter()
						  .append("rect")
						  .attr("x",function(d,i){
								return i*((w-500)/dataset.length)+250;
						  })
						  .attr("y",function(d){
								return h-d[1]*8-20;
						  })
						  .attr("width",((w-500)/dataset.length-20))
						  .attr("height",function(d){
								return d[1]*8;
						  })
						  .attr("fill",function(d,i){
								return color[i];
						  });
			
			var number = svg.selectAll("text1")
						  .data(dataset)
						  .enter()
						  .append("text")
						  .attr("fill","black")
						  .attr("x",function(d,i){
								return i*((w-500)/dataset.length)+250;
						  })
						  .attr("y",function(d){
								return h-d[1]*8-40;
						  })
						  .attr("dx",45)
						  .attr("dy","1em")
						  .attr("font-size",14)
						  .text(function(d){
								return d[1]+"%";
						  });
			
			var index = svg.selectAll("text2")
						  .data(dataset)
						  .enter()
						  .append("text")
						  .attr("fill","black")
						  .attr("x",function(d,i){
								return i*((w-500)/dataset.length)+250;
						  })
						  .attr("y",h-15)
						  .attr("dx",20)
						  .attr("dy","1em")
						  .attr("font-size",14)
						  .text(function(d,i){
								return d[0];
						  });
        }
    }
})
</script>

        修改App.vue的内容如下:

<!-- App.vue -->
<template>
  <Hist />
</template>

<script>
  import Hist from "./components/Hist.vue";
  
  export default {
    name: "App",
    components: {
    Hist,
}, 
  };
</script>

        效果图如下所示:

 

        接下来,我们增加一点难度,绘制一个更加复杂一点的直方图。为了测试代码,我们这里提供一个 alphabet.json 作为之后可视化的数据。从网盘下载后放入新建好的项目的 public 文件夹中,我们可以通过访问 http://localhost:3000/alphabet.json 看到JSON文件。

链接:https://pan.baidu.com/s/1qcXwEwje5zjgnYkBM9UoOw?pwd=0cji 
提取码:0cji

        现在我们已经有了数据,可以正式开始写代码了。首先,在 src/components/ 路径中删除HelloWorld.vue,新建BarChart.vue文件,并写入如下代码:

<template>
    <h2>咱是直方图📊</h2>
    
    <!-- 定义一个bar-chart-container的容器,以供D3操作 -->
    <div id="bar-chart-container"></div>
</template>

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

        修改 APP.vue

<!-- App.vue -->
<template>
  <BarChart />
</template>

<script>
  import BarChart from "./components/BarChart.vue";
  
  export default {
    name: "App",
    components: {
        BarChart,    
    }, 
  };
</script>

        之后回到 BarChart.vue 中导入 d3 和 axios,搭起基本框架。将script中的代码修改如下:

<script>
    import axios from 'axios';
    import * as d3 from 'd3';
    
    export default {
        data() {
            return {
                color: "steelblue",
                margin: { top: 30, right: 0, bottom: 30, left: 40 },      
            };    
        },
        
        mounted() {
            axios.get("./alphabet.json").then((res) => {
                console.log(res.data);      
            });   
        },
    
        methods: {
            drawBarChart(data) {      
            },    
        },  
    };
</script>

        在 drawBarChart() 函数中初始化 SVG 元素,并放置于我们定义好的bar-chart-container容器中。

const margin = this.margin;
const width = 800;
const height = 500;
// 初始化SVG元素
const svg = d3.select("#bar-chart-container")
              .append("svg")        
              .attr("class", "bar-chart")      
              .attr("viewBox", `0 0 ${width}${height}`)      
              .attr("width", width)        
              .attr("height", height)        
              .append("g");  

        配置比例尺的缩放范围及间距。

// https://observablehq.com/@d3/d3-scaleband
// x轴的缩放比例尺
const x = d3.scaleBand()        
            .domain(d3.range(data.length))        
            .range([margin.left, width-margin.right])        
            .padding(0.1);
                
// y轴的缩放比例尺
const y = d3.scaleLinear()        
            .domain([0, d3.max(data, (d) =>d.value)])        
            .nice()        
            .range([height-margin.bottom, margin.top]);   

        定义绘制X/Y坐标轴的函数:

  • tickSizeOuter(0):移除 0 处初始的标记
  • tickFormat:记号格式
  • axisLeft:绘制左侧坐标轴
// x坐标轴
// tickSizeOuter(0):移除0处初始的标记
// tickFormat https://github.com/d3/d3-scale/blob/master/README.md#tickFormat
const xAxis= (g) =>
    g.attr("transform", `translate(0,${height-margin.bottom})`)
     .call(
         d3.axisBottom(x)            
           .tickFormat((i) => data[i].name)            
           .tickSizeOuter(0)        
     );

// y坐标轴
const yAxis = (g) =>
    g.attr("transform", `translate(${margin.left},0)`)
     .call(
         d3.axisLeft(y)
           .ticks(null, data.format)
     )
     // 移除区域间的竖线          
     .call((g) => g.select(".domain").remove())          
     .call((g) => 
         g.append("text")              
          .attr("x", -margin.left)              
          .attr("y", 10)              
          .attr("fill", "currentColor")              
          .attr("text-anchor", "start")              
          .text(data.y)          
     ); 

        根据数据绘制直方图、坐标轴,并添加到SVG中。

svg.append("g")        
   .attr("fill", this.color)        
   .selectAll("rect")        
   .data(data)        
   .join("rect")        
   .attr("x", (d, i) => x(i))        
   .attr("y", (d) => y(d.value))        
   .attr("height", (d) => y(0)-y(d.value)) 
   .attr("width", x.bandwidth());
                
// 绘制到SVG
svg.append("g")
   .call(xAxis);
svg.append("g")
   .call(yAxis);

        对此前的数据(这是一个英文字母使用频率的统计)进行简单的格式化:将 letter 与 frequency 分别映射到 name 与 value 字段,并降序排列。

<script>
    export default {
        ...,
        methods: {
            /**       
             * 格式化数据       
             */
            formatData(data) {
                return data.map(({ letter, frequency }) => {
                                return { name: letter, value: frequency };          
                           })
                           .sort((a, b) =>d3.descending(a.value, b.value));                      
                },
            
            drawBarChart(data) {...},    
        },  
    };
</script>

        现在,我们只需要在 mounted 中执行我们定义好的各个函数即可看到我们想要的直方图效果。

<script>
    export default {
        ...,
        
        mounted() {
            axios.get("./alphabet.json").then((res) => {
                const barChartData = Object.assign(this.formatData(res.data), {
                    format: "%",
                    y: "↑ Frequency",        
                });
                this.drawBarChart(barChartData);      
            }) 
        },
        
        methods: {...},
    };   
</script>

        直方图效果如下所示:

 

        

(三)绘制饼图

        下面,我们根据“我国人口受教育程度”的数据来绘制一个南丁格尔玫瑰图,该代码同样是由d3.js代码修改而成。在 src/components/ 路径中新建ArcPie.vue文件,并写入如下代码:

<template>
    <h1>我国人口受教育程度-饼图</h1>
    <div id="arcPie-container"></div>
</template>

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

var dataset = [["小学及以下",19.3],["初中",40.3],["高中/中专/技校",20.6],
			   ["大学专科",10.5],["大学本科及以上",9.3]];
console.log(dataset);
var color=d3.schemeCategory10;

export default defineComponent({
    mounted() {      
        this.drawArcPie(dataset);      
    },
    methods:{
        drawArcPie(dataset){
            const w = 1200;
            const h = 500;
            var svg=d3.select("#arcPie-container")
                      .append("svg")
                      .attr("width", w)
                      .attr("height",h);

			var pie = d3.pie()
						.value(function(d){
							return d[1];
						});
			var piedata = pie(dataset);
			
			var inner = 50;
			var arc = d3.arc()
						.innerRadius(inner)
						.outerRadius(function(d) {
							var value = d.value;
							return value*4 + inner;
						});		

			var arcs = svg.selectAll("g")
						  .data(piedata)
						  .enter()
						  .append("g")
						  .attr("transform","translate("+(w/2)+","+(h/2+50)+")");
						  
			arcs.append("path")
				.attr("d",function(d){
					return arc(d);
				})		  
				.attr("stroke","black")
				.attr("fill",(d,i)=>color[i]);
			
			svg.selectAll("text1")
			   .data(piedata)
			   .enter()
			   .append("text")
			   .attr("transform",function(d){
					//return "translate("+w/2+","+(h/2+50)+")" + "translate("+arc.centroid(d)+")";
					var x = arc.centroid(d)[0];
					var y = arc.centroid(d)[1];
					return "translate("+(w/2+x)+","+(h/2+50+y)+")";
				})
			   .attr("text-anchor","middle")
			   .attr("fill","black")
			   .attr("font-size","12px")
			   .text(function(d,i){
					//return Math.floor((d.endAngle - d.startAngle)*180/Math.PI) + "°";
					return d.value+"%";
			   });
			
			var hei = [240,265,290,315,340];
			svg.selectAll("c")
			   .data(hei)
			   .enter()
			   .append("circle")
			   .attr("cx",980)
			   .attr("cy",function(d,i){
					return d;
			   })
			   .attr("r",6)
			   .attr("fill",function(d,i){
					return color[i];
			   });
			  
			svg.selectAll("text2")
			   .data(hei)
			   .enter()
			   .append("text")
			   .attr("transform",function(d,i){
					var x = 1000;
					var y = d+6;
					return "translate("+x+","+y+")";
			   })
			   .attr("fill","black")
			   .attr("font-size","14px")
			   .text(function(d,i){return dataset[i][0];});
		}
	}
})
</script>

        修改App.vue如下:

<!-- App.vue -->
<template>
  <Hist />
  <ArcPie />
</template>

<script>
  import Hist from "./components/Hist.vue";
  import ArcPie from "./components/ArcPie.vue";
  
  export default {
    name: "App",
    components: {
    Hist,
    ArcPie,
    }, 
  };
</script>

        效果如下所示:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值