持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
开始绘制
引入D3模块
- 引入整个D3模块。
<script src="https://d3js.org/d3.v7.min.js"></script>
数据
- 自定义树状结构数据,用户绘图使用。
const dataTree = {
name: '太刀',
children: [
{
name: '矿石',
children: [
{
name: '结晶框',
children: [
{ name: '蓝矿', num: 10 },
{ name: '黑铁矿', num: 3 },
{ name: '白灰矿', num: 4 }
]
}
]
},
{
name: '木材',
children: [
{
name: '稀木',
children: [
{ name: '钴木', num: 4 },
{ name: '黑木', num: 2 }
]
},
{
name: '水木',
children: [{ name: '蓝木', num: 4 }]
}
]
},
{
name: '宝石',
children: [
{
name: '太阳类',
children: [
{ name: '日金石', num: 6 },
{ name: '熔岩石', num: 1 }
]
},
{
name: '深海类',
children: [
{ name: '寒铁石', num: 2 },
{ name: '金晶石', num: 3 },
{ name: '玄冰结晶', num: 2 }
]
}
]
}
]
}
添加画布
- 初始化画布。
var width = 500
var height = 500
var margin = 30
var svg = d3
.select('.d3Chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.style('background-color', '#1a3055')
// 图
var chart = svg.append('g').attr('transform', `translate(${margin}, ${margin})`)
创建格式转换器
// 生成层次结构数据 - 并为各个节点指定 层次结构数据
const rootTree = d3
.hierarchy(dataTree)
.sum((d) => d.num) // 计算绘图属性value的值 -求和 其子节点所有.num属性的和值
.sort((a, b) => a.value - b.value) // 根据 上面计算出的 value属性 排序
console.log('🚀 ~ file: 学习D3.js(十二)矩形树状图.html ~ line 88 ~ rootTree', rootTree)
d3.hierarchy()
根据指定的层次结构数据构造一个根节点,并为每个节点创建层级属性。.sum()
给每个节点添加value
属性。当前节点的value
值和所有后代的value
的合计。.sort()
对每级节点排序排序。从大到小排序。
- 使用D3提供的
.hierarchy()
生成带有层级属性的数据。
const TreeMap = d3
.treemap()
.size([width - 2 * margin, height - 2 * margin])
.round(true)
.padding(1)(rootTree)
console.log('🚀 ~ file: 学习D3.js(十二)矩形树状图.html ~ line 99 ~ TreeMap', TreeMap)
d3.treemap()
根据每个节点的值递归的将区域划分为矩形。.size()
二元数值数组,设置矩形的宽高。.round()
启用或禁用四舍五入。.padding()
设置矩形布局之间的间隔。
- 使用D3提供的
.treemap()
计算出每个节点矩形数据x0、y0\x1、y1
。
var colorScale = d3.scaleOrdinal(d3.schemeSet3)
d3.scaleOrdinal()
用于创建和返回具有指定范围和域的序数标度。d3.schemeSet3
d3内部定义的颜色数组。
- 通过不同的传入值,依次获取颜色数组中的值。
绘制矩形
const rectChart = chart.append('g')
- 创建矩形绘制组
g
。
rectChart
.selectAll()
.data(rootTree.leaves())
.enter()
.append('rect')
.attr('class', 'cell')
.attr('x', (d) => d.x0)
.attr('y', (d) => d.y0)
.attr('width', (d) => d.x1 - d.x0)
.attr('height', (d) => d.y1 - d.y0)
.attr('fill', (d, i) => colorScale(i))
.leaves()
获取所有叶子节点的数据。
- 矩形树状图只展示叶子节点,所以使用
rootTree.leaves()
获取所有叶子节点的数据。 - 通过矩形数据绘制出每个叶子节点。
rectChart
.selectAll()
.data(rootTree.leaves())
.enter()
.append('text')
.attr('class', 'cellText')
.attr('transform', (d) => 'translate(' + (d.x0 + d.x1) / 2 + ',' + ((d.y0 + d.y1) / 2 + 6) + ')')
.attr('fill', '#555555')
.attr('text-anchor', 'middle')
.text((d) => d.data.name)
.text(function (d) {
if (textWidthIsOk(d, this)) {
return d.data.name
} else {
return '...'
}
})
// 检测文本长度是否合适
function textWidthIsOk(d, text) {
const textWidth = text.getBBox().width
if (d.x1 - d.x0 >= textWidth) return true
return false
}
.getBBox()
DOM对象中的方法。返回元素的边界框描述。
- 同样的绑定所有叶子节点数据。
- 文本位置信息特殊处理,移动到矩形中间。
- 对文本设置了,两次值。第一次是为了获取文本的宽度,判断是否超出矩形。超出修改为...。
添加交互
var tooltips = d3
.select('body')
.append('div')
.style('width', 'auto')
.style('height', '40px')
.style('background-color', '#fff')
.style('dispaly', 'flex')
.style('justify-content', 'center')
.style('padding', '10px')
.style('border-radius', '5px')
.style('opacity', 0)
d3.selectAll('.cell,.cellText')
.on('mouseover', function (e, d) {
tooltips
.html(`材料:${d.data.name}<br /> 数量:${d.value}`)
.style('position', 'absolute')
.style('left', `${e.clientX}px`)
.style('top', `${e.clientY}px`)
.style('opacity', 1)
})
.on('mouseleave', function (e, d) {
tooltips.style('opacity', 0).style('left', `0px`).style('top', `0px`)
})
- 创建提示框。
- 在鼠标事件监听函数中,控制提示框的内容和是否展示。
- 代码地址