本文以柱状图为例。
数据分为三部分:update、enter、exit。
假设有3个 p 元素,和一个长度为 5 的数组 arr 进行 bind。
那还需要添加两个 p 元素才能实现1v1绑定,则添加的部分为 enter。
若arr的数组长度为 1,则p元素多余两个,需要删除后才能实现1v1绑定,则删除部分为exit。
本例子柱形图主要分为两部分:初始化、数据更新。
//第一部分:初始化函数
renderInit(id) {
const width = 600; // svg可视区域宽度
const height = 300; // svg可视区域高度
const svg = d3.select(id)
.append('svg')
.attr('class', 'chart')
.attr('width', width)
.attr('height', height);
}
//第二部分数据更新
renderUpdate(id, oldData, dataset) {
......
const svg = d3
.select(id)
.select('.chart')
.attr('width', width)
.attr('height', height);
......
//以上为部分配置参数部分(详见最后),数据处理部分单独抽出来细讲。
}
数据处理:
第一步,将数据分为三部分。
第二步,处理更新rect的填充数据。
第三步,更新坐标轴
const updateRect = svg.selectAll('rect').data(dataset);
const enterRect = updateRect.enter();
const exitRect = updateRect.exit();
const y = height - padding.bottom;
//无需添加---更新
updateRect.attr('fill', 'pink')
.transition()
.duration(2000)
.attr('width', xScale.bandwidth())
.attr('x', (d, i) => {
return xScale(i) + padding.left;
})
.attr('y', d => {
return height - padding.bottom - yScale(d);
})
.attr('height', (d) => {
return yScale(d);
});
// enter处理方法---添加
enterRect.append('rect').attr('fill', 'steelblue')
.attr('width', xScale.bandwidth())
.attr('y', y)
.attr('height', 0)
.attr('x', (d, i) => {
return xScale(i) + padding.left;
})
.transition()
.duration(2000)
.attr('y', d => {
return height - padding.bottom - yScale(d);
})
.attr('height', (d) => {
return yScale(d);
});
//多余部分---删除
exitRect.remove();
// 坐标轴
const xAxis = d3.axisBottom(xScale).ticks(dataset.length);
yScale.range([yAxisHeight, 0]); // 重新设置y轴比例尺的值域,与原来的相反
const yAxis = d3.axisLeft(yScale).ticks(10);
const xA = svg.selectAll('g.xAxis');
const yA = svg.selectAll('g.yAxis');
if (xA) {
xA.remove();
}
if (yA) {
yA.remove();
}
svg.append('g').attr('class', 'xAxis')
.attr('transform', 'translate(' + padding.left + ',' + (height - padding.bottom) + ')')
.call(xAxis);
svg.append('g').attr('class', 'yAxis')
.attr('transform', 'translate(' + padding.left + ',' + (height - padding.bottom - yAxisHeight) + ')')
.call(yAxis);