本章实现的是分区图
预告一下下一章会研究堆栈图,下下章最终章是地图探究,第一阶段的内容会在地图探究后结束,结束后就将进入第二阶段的优化,以echarts为标准,实现echarts的图形动画效果,实现echarts的交互。有兴趣的童鞋可以关注下后续内容~
分区图代码如下
<template>
<div id='svgContainer' style="">
<div class="every">
<h3>分区图</h3>
<div class="svg" id="partition"></div>
</div>
<div class="every">
<h3>分区图扩展--圆形</h3>
<div class="svg" id="partitionR"></div>
</div>
</template>
<script>
import * as d3 from 'd3'
export default {
methods: {
partition () {
let width = 400
let height = 400
let data = {
'name': '中国',
'value': '950',
'children': [
{
'name': '浙江',
'value': '450',
'children':
[
{'name': '杭州', 'value': '150'},
{'name': '宁波', 'value': '120'},
{'name': '温州', 'value': '130'},
{'name': '绍兴', 'value': '150'}
]
},
{
'name': '广西',
'value': '200',
'children': [
{'name': '桂林', 'value': '80'},
{'name': '南宁', 'value': '50'},
{'name': '柳州', 'value': '30'},
{'name': '防城港', 'value': '40'}
]
},
{
'name': '黑龙江',
'value': '200',
'children': [
{'name': '哈尔滨', 'value': '50'},
{'name': '齐齐哈尔', 'value': '40'},
{'name': '牡丹江', 'value': '60'},
{'name': '大庆', 'value': '50'}
]
},
{
'name': '新疆',
'value': '100',
'children':
[
{'name': '乌鲁木齐', 'value': '30'},
{'name': '克拉玛依', 'value': '20'},
{'name': '吐鲁番', 'value': '25'},
{'name': '哈密', 'value': '25'}
]
}
]
}
// 公式
let partition = d3.partition()
.size([width, height])
let color = d3.scaleOrdinal(d3.schemeCategory10)
let hierarchyData = d3.hierarchy(data)
// 数据转化,取所有节点的数组
let partitionData = partition(hierarchyData).descendants()
// 绘图
let svg = d3.select('#partition')
.append('svg')
.attr('width', width)
.attr('height', height)
let g = svg.selectAll('g')
.data(partitionData)
.enter()
.append('g')
g.append('rect')
.attr('x', function (d) { return d.x0 })
.attr('y', function (d) { return d.y0 })
.attr('width', function (d) { return d.x1 - d.x0 })
.attr('height', function (d) { return d.y1 - d.y0 })
.style('stroke', '#ccc')
.style('fill', function (d) { return color(d.data.name) })
g.append('text')
.attr('x', function (d) { return d.x0 })
.attr('y', function (d) { return d.y0 })
.attr('dx', function (d) { return (d.x1 - d.x0) / 2 }) // 文字水平居中
.attr('dy', function (d) { return (d.y1 - d.y0) / 2 - d.data.name.length / 2 * 12 }) // 文字垂直居中,有点瑕疵
.attr('font-size', function (d) { return 12 - d.depth + 'px' }) // 文字按深度缩小
.attr('writing-mode', 'tb') // 文字从上往下书写
.text(function (d) { return d.data.name })
},
partitionR () {
let width = 400
let height = 400
let data = {
'name': '中国',
'value': '950',
'children': [
{
'name': '浙江',
'value': '450',
'children':
[
{'name': '杭州', 'value': '150'},
{'name': '宁波', 'value': '120'},
{'name': '温州', 'value': '130'},
{'name': '绍兴', 'value': '150'}
]
},
{
'name': '广西',
'value': '200',
'children': [
{'name': '桂林', 'value': '80'},
{'name': '南宁', 'value': '50'},
{'name': '柳州', 'value': '30'},
{'name': '防城港', 'value': '40'}
]
},
{
'name': '黑龙江',
'value': '200',
'children': [
{'name': '哈尔滨', 'value': '50'},
{'name': '齐齐哈尔', 'value': '40'},
{'name': '牡丹江', 'value': '60'},
{'name': '大庆', 'value': '50'}
]
},
{
'name': '新疆',
'value': '100',
'children':
[
{'name': '乌鲁木齐', 'value': '30'},
{'name': '克拉玛依', 'value': '20'},
{'name': '吐鲁番', 'value': '25'},
{'name': '哈密', 'value': '25'}
]
}
]
}
// 公式,注意size的参数
let radius = 200
let partition = d3.partition()
.size([2 * Math.PI, radius * radius])
let color = d3.scaleOrdinal(d3.schemeCategory10)
let hierarchyData = d3.hierarchy(data)
// 数据转化,取所有节点的数组
let partitionData = partition(hierarchyData).descendants()
// 创建弧生成器
let arc = d3.arc()
.innerRadius(function (d) { return Math.sqrt(d.y0) })
.outerRadius(function (d) { return Math.sqrt(d.y1) })
.startAngle(function (d) { return d.x0 })
.endAngle(function (d) { return d.x1 })
// 绘图
let svg = d3.select('#partitionR')
.append('svg')
.attr('width', width)
.attr('height', height)
let g = svg.selectAll('g')
.data(partitionData)
.enter()
.append('g')
.attr('transform', 'translate(200,200)')
g.append('path')
.attr('display', function (d) {
return d.depth ? null : 'none'
})// 是否绘制中心,留白好看一些
.attr('d', arc)
.style('stroke', '#ccc')
.style('fill', function (d) { return color(d.data.name) })
g.append('text')
.attr('transform', function (d, i) {
if (i !== 0) {
let r = (d.x0 + d.x1) / 2
let angle = Math.PI / 2
r += r < Math.PI ? (angle - Math.PI) : angle
r *= 180 / Math.PI
return 'translate(' + arc.centroid(d) + ')' + 'rotate(' + r + ')'
}
})
.text(function (d) { return d.data.name })
.attr('font-size', function (d) { return 12 - d.depth + 'px' }) // 文字按深度缩小
.attr('dy', '.5em')
.attr('dx', function (d) { return -d.data.name.length / 2 + 'em' }) // 文字居中
},
},
mounted () {
this.partition()
this.partitionR()
}
}
</script>
<style lang="less">
#svgContainer{
width: 100%;
height: 100%;
.every{
width: 400px;
height: 425px;
margin:15px;
float: left;
h3{
margin:0;
.button{
float: right;
margin-right: 20px;
font-size: 14px;
cursor: pointer;
padding: 2px 8px;
border:1px solid #ccc;
background: yellowgreen;
border-radius: 4px;
&:hover{
background: violet;
}
}
}
.svg{
width: 400px;
height: 400px;
}
}
}
</style>