一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
开始绘制
引入D3模块,创建目标节点
<!-- 选择器模块 -->
<script src="https://cdn.jsdelivr.net/npm/d3-selection@3"></script>
<!-- 比例尺模块 和 依赖 -->
<script src="https://cdn.jsdelivr.net/npm/d3-array@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-color@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-format@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-interpolate@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-time@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-time-format@4"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-scale@4"></script>
<!-- 坐标轴 -->
<script src="https://cdn.jsdelivr.net/npm/d3-axis@3"></script>
<body>
<div class="d3Chart"></div>
</body>
创建数据
var bColor = ['#4385F4', '#34A853', '#FBBC05', '#E94335', '#01ACC2', '#AAACC2']
var dataArr = [
{
label: '1月',
value: 10.5
},
{
label: '2月',
value: 70.5
},
{
label: '3月',
value: 60.5
},
{
label: '4月',
value: 10.5
},
{
label: '5月',
value: 20.5
},
{
label: '6月',
value: 30.5
}
]
创建画布
var svg = d3
.select('.d3Chart')
.append('svg')
.attr('width', 450)
.attr('height', 440)
.style('background-color', '#1a3055')
.select()选中与指定选择器字符串匹配的第一个元素,返回当前选中的元素结果。注意它返回的不只是这个元素节点对象,是D3封装后的选择集对象(selection)。
selection.append()是selection对象中的方法。用于创建html节点,返回包含追加元素的新选择对象。
selection.attr(name[,value])获取或则设置元素的属性。selection.attr(name[,value])获取或则设置元素的样式属性。
绘制坐标轴
// 创建 一个组 移动位置
var chart = svg.append('g').attr('transform', 'translate(20, 10)')
// 创建 序数分段比例尺
// 设置输出值0~400,输入为X轴的分段标题
var xScale = d3
.scaleBand()
.range([0, 400])
.domain(dataArr.map((s) => s.label))
.padding(0.4)
// 绘制X轴
chart.append('g').attr('transform', 'translate(15, 400)').call(d3.axisBottom(xScale))
// 创建 定量的线性比例尺
var yScale = d3.scaleLinear().range([400, 0]).domain([0, 100])
var makeYlines = () =>
d3
.axisLeft()
.scale(yScale)
.tickSize(-400)
.tickFormat((d) => {
return d + '%'
})
// 绘制Y轴
chart.append('g').attr('transform', 'translate(15, 0)').call(makeYlines())
// 修改颜色
d3.selectAll('text').style('fill', '#fff')
d3.selectAll('.d3Chart text').style('fill', '#fff')
d3.selectAll('.d3Chart line').style('stroke', '#fff')
d3.selectAll('.d3Chart path').style('stroke', '#fff')
- 使用比例尺模块,对数据进行转换。然后使用坐标轴模块绘制坐标轴。最后修改坐标轴样式。
d3.scaleBand()分段比例尺。简单理解就是通过.range([0, 400])方法设置输出值域范围,通过.domain([])设置输入的分段数组。在使用时根据值域范围中的值,计算出输入为那个分段。selection.call()调用指定的函数一次。被调用函数的this上下文也是当前的选择。简单理解就是把选择对象的this传入调用指定的函数。d3.axisBottom()根据比例尺创建一个刻度在下的坐标轴。d3.scaleLinear()线性比例尺。和分段比例尺不同的是,.domain([])设置的是输入值域范围。d3.axisLeft()根据比例尺创建一个刻度在左的坐标轴。axis.tickSize()设置刻度的长度。axis.tickFormat()自定义标签的刻度。
绘制柱状
// 选中当前组子节点 绑定数据 创建元素占位符 对占位符创建元素
var barG = chart.selectAll().data(dataArr).enter().append('g')
barG
.append('rect')
.style('fill', (d, i) => bColor[i])
.attr('x', (g, i) => xScale(g.label) + xScale.bandwidth() / 2)
.attr('y', (g) => yScale(g.value))
.attr('width', xScale.bandwidth())
.attr('height', (g) => 400 - yScale(g.value))
- 创建元素和数据绑定。
barG为一组选择对象,使用的方法会对每一个元素对象使用。- 当绑定了数据后,
attr()的第二个参数可以传入一个函数,接受绑定数据。然后使用比例尺计算出柱状的位置和高度。
.data()设置一组元素的数据。.enter()当数据和元素比匹配时,生成站位符。使用.append('g')为占位符创建元素。.bandwidth()每一个分段的宽度。
绘制标题
barG
.append('text')
.style('font-size', '14px')
.style('fill', '#fff')
.attr('x', (g, i) => xScale(g.label) + xScale.bandwidth() / 2 + 2)
.attr('y', (g) => yScale(g.value) - 10)
.text((g) => `${g.value}%`)
- 在每一个绑定了数据的元素中创建文本。使用比例尺计算文本位置。
selection.text()取得或设置文本内容
创建提示框
var tooltips = d3
.select('body')
.append('div')
.style('width', '100px')
.style('height', '40px')
.style('background-color', '#fff')
.style('dispaly', 'flex')
.style('justify-content', 'center')
.style('padding', '10px')
.style('border-radius', '5px')
.style('opacity', 0)
// 对每个柱状添加交互
barG
.append('rect')
...
.on('mouseenter', (e, g) => {
tooltips
.html(`月份:${g.label}<br /> 数据:${g.value}%`)
.style('position', 'absolute')
.style('left', `${e.clientX}px`)
.style('top', `${e.clientY}px`)
.style('opacity', 1)
})
.on('mouseleave', (e, g) => {
tooltips.style('opacity', 0).style('left', `0px`).style('top', `0px`)
})
- 在每个柱状上添加鼠标监听事件,修改提示框的位置和内容,形成交货。
.html()设置一个html文档片段。
- 一个基础的柱状图就完成绘制了。
- 代码地址