提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
本篇blog在于把已经编写好的D3代码从一般HTML文件迁移到Vue框架中,关于D3的技术不予讨论
准备:D3代码
条形图
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<head>
<title>
直方图
</title>
</head>
<body>
<h2 style="text-align: center;" >中国2022年各类商品进口金额占比</h2>
<h3 style="text-align: center;">数据来源:国家统计局2020年对外贸易数据</h3>
<script src="d3.min.js"></script>
<script>
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.98;
var svg=d3.select("body")
.append("svg")
.attr("width",w)
.attr("height",h);
/*svg.append("rect")
.attr("x",0)
.attr("y",0)
.attr("width",100)
.attr("height",400)
*/
w=w*0.8;
h=h*0.8;
var size = 6;
var dataset = new Array(size);
var colors = new Array(size);
for(var i=0;i<=size;i++){
dataset[i] = Math.random()*h;
colors[i] = "FF"+i%10+"00";
}
var population=[949052.98,682100.83,178452.85,203726,73186,239257];
var rate = new Array(size);
var sum = 0;
for(var i = 0;i < size;i++){
sum = sum + population[i];
}
for(var i=0; i < size;i++){
rate[i] = (population[i]/sum)*100;
console.log(rate[i]);
}
svg.append("line")
.attr("x1",w*0.1-10)
.attr("y1",h)
.attr("x2",w*0.1-10)
.attr("y2",0)
.attr("stroke","black");
svg.append("line")
.attr("x1",w*0.1-10)
.attr("y1",h)
.attr("x2",w*1.17)
.attr("y2",h)
.attr("stroke","black");
svg.append("text")
.attr("x",w*0.1-10)
.attr("y",h*0.02)
.text("金额占比")
svg.append("text")
.attr("x",w*1.17)
.attr("y",h)
.text("种类")
svg.selectAll("rect")
.data(rate)
.enter()
.append("rect")
.attr("x",function(d,i){
return w*0.1 + w/size*i;
})
.attr("y",function(d){
return h-d*10;
})
.attr("width",0.8*w/size)
.attr("height",function(d){
return d*10;
})
.attr("fill",function(d,i){
return "#FF"+(i%10)+"000";
});
svg.selectAll(".dashline")
.data(rate)
.enter()
.append("line")
.attr("class","dashline")
.attr("x1",w*0.1-10)
.attr("x2",w*1.17)
.attr("y1",function(d){
return h-d*10;
})
.attr("y2",function(d){
return h-d*10;
})
.attr("stroke","black")
.attr("stroke-dasharray","5,5");
svg.selectAll(".data")
.data(rate)
.enter()
.append("text")
.text(function(d){
console.log(Math.trunc(d*1000)/1000);
return Math.trunc(d*1000)/1000 + "%";
})
.attr("class","data")
.attr("x",function(d,i){
return w*0.1 + w/size*i;
})
.attr("y",function(d){
return h-d*10;
})
.attr("fill","black");
var regions=["机电产品","高新技术产品","原油","铁铜矿砂,精矿,铜材","汽车及其零件","其他"];
svg.selectAll(".Mytext")
.data(rate)
.enter()
.append("text")
.attr("class","Mytext")
.text(function(d,i){
return regions[i];
})
.attr("x",function(d,i){
return w*0.1 + w/size*i;
})
.attr("y",h+14)
.attr("fill","black");
</script>
</body>
</html>
力导向图
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<head>
<title>
力导向图
</title>
</head>
<body bgcolor="#00a7d0">
<a href="https://www.bilibili.com/video/BV1Xq4y1T7ne?spm_id_from=333.337.search-card.all.click" style="text-align: center;">https://www.bilibili.com/video/BV1Xq4y1T7ne?spm_id_from=333.337.search-card.all.click</a>
<h1 style="text-align: center;">古典音乐体裁力导向图</h1>
<script src="d3.min.js"></script>
<script>
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.98;
var svg=d3.select("body")
.append("svg")
.attr("width",w)
.attr("height",h);
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-600)
.linkDistance(200)
.size([w,h]);
d3.json("node.json",function(error,graph){
console.log(graph)
force.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll()
.data(graph.links)
.enter()
.append("line")
.attr("class","link")
.style("stroke-width",4)
.style("stroke","pink");
var node = svg.selectAll()
.data(graph.nodes)
.enter()
.append("circle")
.attr("class","node")
.attr("r",function(d){
return 15;
})
.attr("cx",200)
.attr("cy",100)
.attr("fill",function(d,i){
return color(i);
})
.on("dblclick",function(d){
window.location.href = "https://baike.baidu.com/item/"+d.name;
})
.call(force.drag);
var text = svg.selectAll(".forcetext")
.data(graph.nodes)
.enter()
.append("text")
.attr("class","forcetext")
.attr("x","100")
.attr("y","200")
.text(function(d){
return d.name
})
force.on("tick",function(){
node.attr("cx",function(d){
return d.x;
})
.attr("cy",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;
})
text.attr("x",function(d){
return d.x;
})
.attr("y",function(d){
return d.y
});
})
})
</script>
</body>
</html>
力导向图所需要的json文件node.json
{"nodes":
[
{"name":"音乐体裁","group":0},
{"name":"人声","group":1},
{"name":"器乐","group":2},
{"name":"歌剧","group":3},
{"name":"艺术歌曲","group":4},
{"name":"费加罗的婚礼","group":5},
{"name":"尼伯龙根的指环","group":6},
{"name":"魔王","group":7},
{"name":"交响乐","group":8},
{"name":"室内乐","group":9},
{"name":"交响曲","group":10},
{"name":"协奏曲","group":11},
{"name":"乐队组曲","group":12},
{"name":"序曲","group":13},
{"name":"交响诗","group":14},
{"name":"四乐章","group":15},
{"name":"三乐章","group":16},
{"name":"单乐章","group":17},
{"name":"华彩","group":18},
{"name":"独奏","group":19},
{"name":"重奏","group":20},
{"name":"三重奏","group":21},
{"name":"四重奏","group":22},
{"name":"钢琴","group":23},
{"name":"小提琴","group":24},
{"name":"大提琴","group":25}
],
"links":
[
{"source":0,"target":1,"value":1},
{"source":0,"target":2,"value":1},
{"source":1,"target":3,"value":1},
{"source":1,"target":4,"value":1},
{"source":3,"target":5,"value":1},
{"source":3,"target":6,"value":1},
{"source":4,"target":7,"value":1},
{"source":2,"target":8,"value":1},
{"source":2,"target":9,"value":1},
{"source":8,"target":10,"value":1},
{"source":8,"target":11,"value":1},
{"source":8,"target":12,"value":1},
{"source":8,"target":13,"value":1},
{"source":8,"target":14,"value":1},
{"source":10,"target":15,"value":1},
{"source":11,"target":16,"value":1},
{"source":13,"target":17,"value":1},
{"source":14,"target":17,"value":1},
{"source":11,"target":18,"value":1},
{"source":11,"target":18,"value":1},
{"source":9,"target":19,"value":1},
{"source":9,"target":20,"value":1},
{"source":20,"target":21,"value":1},
{"source":20,"target":22,"value":1},
{"source":21,"target":23,"value":1},
{"source":21,"target":24,"value":1},
{"source":21,"target":25,"value":1},
{"source":22,"target":24,"value":1},
{"source":22,"target":25,"value":1}
]
}
在已经创建的vue项目框架中
注意:
1-运行安装依赖包:npm install
2-如果是从标准的空工程文件开始,需要安装d3和axios
npm install d3
npm install axios
3-运行程序:npm run dev
在main.js中`
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
createApp(App).mount('#app')
定义CSS文件index.css
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
1.条形图
在APP.vue中定义模板和组件名称及其文件路劲
<template>
<BarChart />
</template>
<script>
import BarChart from './components/BarChart.vue';
export default {
name: 'App',
components: {
BarChart
}
}
</script>
定义组件BarChart.vue
<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){
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.98;
var svg=d3.select("body")
.append("svg")
.attr("width",w)
.attr("height",h);
/*svg.append("rect")
.attr("x",0)
.attr("y",0)
.attr("width",100)
.attr("height",400)
*/
w=w*0.8;
h=h*0.8;
var size = 6;
var dataset = new Array(size);
var colors = new Array(size);
for(var i=0;i<=size;i++){
dataset[i] = Math.random()*h;
colors[i] = "FF"+i%10+"00";
}
var population=[949052.98,682100.83,178452.85,203726,73186,239257];
var rate = new Array(size);
var sum = 0;
for(var i = 0;i < size;i++){
sum = sum + population[i];
}
for(var i=0; i < size;i++){
rate[i] = (population[i]/sum)*100;
console.log(rate[i]);
}
svg.append("line")
.attr("x1",w*0.1-10)
.attr("y1",h)
.attr("x2",w*0.1-10)
.attr("y2",0)
.attr("stroke","black");
svg.append("line")
.attr("x1",w*0.1-10)
.attr("y1",h)
.attr("x2",w*1.17)
.attr("y2",h)
.attr("stroke","black");
svg.append("text")
.attr("x",w*0.1-10)
.attr("y",h*0.02)
.text("金额占比")
svg.append("text")
.attr("x",w*1.17)
.attr("y",h)
.text("种类")
svg.selectAll("rect")
.data(rate)
.enter()
.append("rect")
.attr("x",function(d,i){
return w*0.1 + w/size*i;
})
.attr("y",function(d){
return h-d*10;
})
.attr("width",0.8*w/size)
.attr("height",function(d){
return d*10;
})
.attr("fill",function(d,i){
return "#FF"+(i%10)+"000";
});
svg.selectAll(".dashline")
.data(rate)
.enter()
.append("line")
.attr("class","dashline")
.attr("x1",w*0.1-10)
.attr("x2",w*1.17)
.attr("y1",function(d){
return h-d*10;
})
.attr("y2",function(d){
return h-d*10;
})
.attr("stroke","black")
.attr("stroke-dasharray","5,5");
svg.selectAll(".data")
.data(rate)
.enter()
.append("text")
.text(function(d){
console.log(Math.trunc(d*1000)/1000);
return Math.trunc(d*1000)/1000 + "%";
})
.attr("class","data")
.attr("x",function(d,i){
return w*0.1 + w/size*i;
})
.attr("y",function(d){
return h-d*10;
})
.attr("fill","black");
var regions=["机电产品","高新技术产品","原油","铁铜矿砂,精矿,铜材","汽车及其零件","其他"];
svg.selectAll(".Mytext")
.data(rate)
.enter()
.append("text")
.attr("class","Mytext")
.text(function(d,i){
return regions[i];
})
.attr("x",function(d,i){
return w*0.1 + w/size*i;
})
.attr("y",h+14)
.attr("fill","black");
}
}
})
</script>
在此注意在mouted定义drawBarChart方法,在method中定义这个方法,此时只用将对应的HTML文件的js部分代码复制到所定义的方法中(在这里的data负责传参,也可以不传参,在方法中直接定义数据,使用视情况而定)
2.力导向图
将上述项目文件夹进行复制,得到一个项目模板,同时注意将上文提到的node.json文件移到项目的根目录下
此时APP.vue为
<template>
<HelloD3 msg="D3.JS@Vue3"/>
</template>
<script>
import HelloD3 from './components/D3Hist.vue';
export default {
name: 'App',
components: {
HelloD3
}
}
</script>
定义组件D3Hist.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
<head>
<title>
力导向图
</title>
</head>
<a href="https://www.bilibili.com/video/BV1Xq4y1T7ne?spm_id_from=333.337.search-card.all.click" style="text-align: center;">https://www.bilibili.com/video/BV1Xq4y1T7ne?spm_id_from=333.337.search-card.all.click</a>
<h1 style="text-align: center;">古典音乐体裁力导向图</h1>
</template>
<script>
import axios from "axios";
import { defineComponent } from 'vue';
//import axios from "axios";
import * as d3 from "d3";
var data;
export default defineComponent({
//挂载后执行
mounted(){
axios.get("./node.json").then(res => {
console.log(res.data);
this.drawBarChart(res.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.98;
var svg=d3.select("body")
.append("svg")
.attr("width",w)
.attr("height",h);
var color = d3.schemeCategory10;
var forceSimulation = d3.forceSimulation()
.force("link",d3.forceLink())
.force("charge",d3.forceManyBody().strength(-100))
.force("center",d3.forceCenter(w/2,h/2));
forceSimulation.nodes(data.nodes)
.on("tick");
forceSimulation.force("link")
.links(data.links)
.distance(100);
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 link = svg.selectAll()
.data(data.links)
.enter()
.append("line")
.attr("class","link")
.style("stroke-width",4)
.style("stroke","pink");
var node = svg.selectAll()
.data(data.nodes)
.enter()
.append("circle")
.attr("class","node")
.attr("r",function(d){
return 15;
})
.attr("cx",200)
.attr("cy",100)
.attr("fill",function(d,i){
return color[i%10];
})
.on("dblclick",function(d){
window.location.href = "https://baike.baidu.com/item/"+d.name;
})
.call(drag());
var text = svg.selectAll(".forcetext")
.data(data.nodes)
.enter()
.append("text")
.attr("class","forcetext")
.attr("x","100")
.attr("y","200")
.text(function(d){
return d.name
})
forceSimulation.on("tick",function(){
node.attr("cx",function(d){
return d.x;
})
.attr("cy",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;
});
text.attr("x",function(d){
return d.x;
})
.attr("y",function(d){
return d.y
});
})
}
}
})
</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>
这里需要注意这里通过axios发出获取json文件的请求,将json数据作为数据传入到所定义的方法,同时将d3的代码移入其中(注意源代码是d3的v3版本vue中使用的是v7版本,已经经过了改造,所以如果直接从之前的代码复制会报错,而我所展示的vue的代码可以直接使用),这样就完成对d3代码的复制迁移