携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情
引入D3模块
- 引入整个D3模块。
<!-- D3模块 -->
<script src="https://d3js.org/d3.v7.min.js"></script>
数据
// 坐标
const names = ['生命', '力量', '耐力', '速度', '魔力']
// 数据
const dataArr = [
{
name: '张三',
a1: '90',
a2: '80',
a3: '20',
a4: '20',
a5: '5'
},
{
name: '李四',
a1: '50',
a2: '5',
a3: '20',
a4: '10',
a5: '95'
},
{
name: '王五',
a1: '50',
a2: '60',
a3: '50',
a4: '60',
a5: '50'
}
]
- 格式不是唯一的,按自己习惯的格式设计。
添加画布
// 画布
const width = 500
const height = 500
const margin = 20
const svg = d3
.select('.d3Chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.style('background-color', '#1a3055')
// 图
const chart = svg.append('g').attr('transform', `translate(${margin}, ${margin})`)
比例尺和配置信息
// 创建颜色比例尺
const colorScale = d3.scaleOrdinal(d3.quantize(d3.interpolateRainbow, dataArr.length + 1))
- 颜色比例尺。
const scale = d3
.scaleLinear()
.domain([0, 100])
.range([height - margin * 3, 0])
- 线性比例尺,这里每个轴使用的时同一个。如需不同轴使用不同比例尺,循环保存,后面使用下标获取。
绘制坐标轴和折线
const axiss = chart.append('g').selectAll().data(names)
axiss
.enter()
.append('g')
.attr('class', (d, i) => 'axis axis-' + i)
.attr('transform', (d, i) => 'translate(' + ((i + 0.5) * (height - margin * 2)) / 5 + ',0)')
.call(d3.axisLeft(scale).ticks(10))
.append('text')
.attr('dx', '0.5em')
.attr('transform', (d, i) => 'translate(0,' + (height - margin * 2) + ')')
.text((d) => d)
d3.selectAll('.d3Chart text').style('fill', '#fff')
d3.selectAll('.d3Chart line').style('stroke', '#fff')
d3.selectAll('.d3Chart path').style('stroke', '#fff')
- 创建绘制组,绑定数据。对每个数据创建绘制组,绘制坐标轴和文本。
- 设置坐标轴和文本的颜色。
const lines = chart.append('g').selectAll().data(dataArr)
const line = lines.enter().append('g').attr('class', 'line')
- 创建线绘制组,绑定数据。对每个数据创建绘制组,并设置唯一标识。
line
.append('path')
.attr('class', (d, i) => 'line line-' + d.name)
.attr('stroke', (d, i) => colorScale(d.name))
.attr('stroke-width', 2)
.attr('fill', 'none')
.attr('d', (d) => d3.line()(generatePoints(d)))
/**
* 折线点计算
* */
function generatePoints(d) {
const arr = names.map((item, i) => {
return [((i + 0.5) * (height - margin * 2)) / 5, scale(d[`a${i + 1}`])]
})
return arr
}
- 创建折线点计算函数,绘制折线。
line
.append('text')
.attr('class', (d, i) => 'lineText lineText-' + i)
.attr('dx', '0.5em')
.attr('fill', (d, i) => colorScale(d.name))
.attr('style', 'cursor: pointer;')
.attr('transform', (d, i) => 'translate(' + ((4 + 0.5) * (height - margin * 2)) / 5 + ',' + scale(d['a5']) + ')')
.text((d) => d.name)
- 绘制文本并设置唯一标识。这里文本是绘制在结束位置,一共5条轴,所以是
((4 + 0.5) * (height - margin * 2)) / 5 + ',' + scale(d['a5'])
。
交互
const tooltips = d3
.select('body')
.append('div')
.style('width', 'auto')
.style('height', 'auto')
.style('background-color', '#fff')
.style('dispaly', 'flex')
.style('justify-content', 'center')
.style('padding', '20px')
.style('border-radius', '5px')
.style('opacity', 0)
d3.selectAll('.lineText')
.on('mouseenter', (e, d) => {
tooltips
.html(
`生命:${d.a1}
<br /> 力量:${d.a2}
<br /> 耐力:${d.a3}
<br /> 速度:${d.a4}
<br /> 魔力:${d.a5}`
)
.style('position', 'absolute')
.style('left', `${e.clientX - 120}px`)
.style('top', `${e.clientY}px`)
.style('opacity', 1)
d3.select(`.line-${d.name}`).attr('stroke-width', '5')
})
.on('mouseleave', (e, d) => {
tooltips.style('opacity', 0).style('left', `0px`).style('top', `0px`)
d3.select(`.line-${d.name}`).attr('stroke-width', '2')
})
- 创建提示框,监听鼠标移入移出事件。移入,修改DOM对象的文本和样式。移出,重置元素。