一、基础知识
Node.js :是运行在服务端的 JavaScript,Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
Vue: The Progressive JavaScript Framework 目前最为流行的前端框架之一,不可否认的是它相比 React 的学习曲线要更为平缓。
VITE:Native-ESM powered web dev build tool. ⾯向未来的前端构建⼯具。
D3:D3.js是一个用于网页作图、生成互动图形的JavaScript函数库。它提供一个d3对象,所有方法都通过这个对象调用。
二、环境配置
1.node.js安装
下载链接:https://nodejs.org/en/download/
认准LTS版本,下载安装即可。
2.Vue安装
在nodejs根目录下执行以下命令:
npm install vue
npm:包管理⼯具,已随 Node.js 默认安装。
结果如下:
3.安装vite:
npm install vite 安装Vite 包
npm init vite-app hellovue 创建工程
npm run dev 运行
结果如下:
三、Vue+D3绘制直方图和力导向图
1.直方图
hist.vue: 数据为随机数
<template>
<h2><a href="https://d3js.org" target="_blank" >D3直方图@VUE3</a></h2>
<div id="hist-container"></div>
</template>
<script>
import { defineComponent } from 'vue';
//import axios from "axios";
import * as d3 from "d3";
var data=new Array(20);
for (var i=0;i<20;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){
var w=window.innerWidth|| document.documentElement.clientWidth|| document.body.clientWidth;
var h=window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
w=w*0.98;
h=h*0.5;
var svg=d3.select("#hist-container")
.append("svg")
.attr("width",w)
.attr("height",h);
svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("fill",(d,i)=>color[i%10])
.attr("x",function(d,i){
return w*i/20;
})
.attr("y",d=>(h-d))
.attr("height",d=>d)
.attr("width",w*0.9/20);
}
}
})
</script>
2.力导向图(可拖拽)
force.vue: 数据采用电视剧《爱情公寓》人物关系网络
<template>
<h2><a href="https://d3js.org" target="_blank" >D3力导向图@VUE3</a></h2>
<div id="force-container"></div>
</template>
<script>
import { defineComponent } from 'vue';
//import axios from "axios";
import * as d3 from "d3";
var color=d3.schemeCategory10;
var nodes = [
{"name":"爱情公寓"},
{"name":"曾小贤"},
{"name":"胡一菲"},
{"name":"吕子乔"},
{"name":"陈美嘉"},
{"name":"关谷神奇"},
{"name":"唐悠悠"},
{"name":"陆展博"},
{"name":"林宛瑜"},
{"name":"张伟"},
{"name":"诸葛大力"},
{"name":"秦羽墨"},
{"name":"诺澜"},
{"name":"Lisa榕"},
{"name":"杜俊"},
{"name":"赵海棠"},
{"name":"咖喱酱"}
];
var links = [
{"source":1,"target":0,"relation":"租户"},
{"source":2,"target":0,"relation":"租户"},
{"source":3,"target":0,"relation":"租户"},
{"source":4,"target":0,"relation":"租户"},
{"source":5,"target":0,"relation":"租户"},
{"source":6,"target":0,"relation":"租户"},
{"source":7,"target":0,"relation":"租户"},
{"source":8,"target":0,"relation":"租户"},
{"source":9,"target":0,"relation":"租户"},
{"source":10,"target":0,"relation":"租户"},
{"source":11,"target":0,"relation":"租户"},
{"source":15,"target":0,"relation":"租户"},
{"source":16,"target":0,"relation":"租户"},
{"source":1,"target":2,"relation":"夫妻"},
{"source":1,"target":13,"relation":"上下级"},
{"source":1,"target":12,"relation":"同事&喜欢"},
{"source":2,"target":7,"relation":"姐弟"},
{"source":2,"target":11,"relation":"同学"},
{"source":2,"target":12,"relation":"情敌"},
{"source":3,"target":4,"relation":"夫妻"},
{"source":3,"target":6,"relation":"小姨妈/大外甥"},
{"source":3,"target":13,"relation":"暗恋"},
{"source":4,"target":6,"relation":"闺蜜"},
{"source":5,"target":6,"relation":"夫妻"},
{"source":5,"target":14,"relation":"师兄弟"},
{"source":7,"target":8,"relation":"情侣"},
{"source":9,"target":10,"relation":"情侣"},
{"source":9,"target":15,"relation":"情敌"},
{"source":9,"target":16,"relation":"助理"},
{"source":10,"target":15,"relation":"同学"},
{"source":10,"target":2,"relation":"师生"},
{"source":15,"target":10,"relation":"追求"},
{"source":15,"target":2,"relation":"师生"},
{"source":13,"target":12,"relation":"同学"}
];
export default defineComponent({
mounted() {
this.drawBarChart(nodes,links);
},
methods:{
drawBarChart(nodes,links){
var w=window.innerWidth|| document.documentElement.clientWidth|| document.body.clientWidth;
var h=window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
w=w*0.98;
h=h*0.9;
var svg=d3.select("#force-container")
.append("svg")
.attr("width",w)
.attr("height",h*1.2);
var forceSimulation = d3.forceSimulation()
.force("link",d3.forceLink())
.force("charge",d3.forceManyBody().strength(-800))
.force("center",d3.forceCenter(w/2,h/2));
forceSimulation.nodes(nodes)
.on("tick");
forceSimulation.force("link")
.links(links)
.distance(180);
var link=svg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class","link")
.style("stroke-width",1)
.style("stroke",(d,i)=>color[i%10])
.style("opacity",0.6);
var node=svg.selectAll(".node")
.data(nodes)
.enter()
.append("circle")
.attr("r",16)
.style("fill",(d,i)=>color[i%10])
.call(drag());
forceSimulation.on("tick",()=>{
link.attr("x1",d=>d.source.x)
.attr("y1",d=>d.source.y)
.attr("x2",d=>d.target.x)
.attr("y2",d=>d.target.y);
node.attr("cx",d=>d.x)
.attr("cy",d=>d.y);
edges_text.attr("x",d=>(d.source.x + d.target.x) / 2 )
.attr("y",d=>(d.source.y + d.target.y) / 2 );
texts.attr("x",d=>d.x)
.attr("y",d=>d.y);
});
function drag()
{
function dragstarted(event,d){
if(!event.active) forceSimulation.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) forceSimulation.alphaTarget(0);
d.fx=null;
d.fy=null;
}
return d3.drag()
.on("start",dragstarted)
.on("drag",dragged)
.on("end",dragended);
};
var edges_text = svg.selectAll(".linetext")
.data(links)
.enter()
.append("text")
.attr("class","linetext")
.text(d=> d.relation)
.style("stroke",(d,i)=>color[i%10])
.style("font-size",10);
var texts=svg.selectAll(".forceText")
.data(nodes)
.enter()
.append("text")
.attr("class","forceText")
.style("stroke",(d,i)=>color[i%10])
.style("font-size","12px")
.attr("text-anchor","middle")
.attr("dy",30)
.text(d=>d.name);
}
}
})
</script>
3.结果展示
app.vue:
<template>
<BarChart />
<Hist />
</template>
<script>
import BarChart from './components/force.vue';
import Hist from './components/hist.vue';
export default {
name: 'App',
components: {
BarChart,
Hist
}
}
</script>