上一篇: 树图 https://blog.csdn.net/zjw_python/article/details/98492510
下一篇: 封闭图 https://blog.csdn.net/zjw_python/article/details/98591118
代码结构和初始化画布的Chart对象介绍,请先看 https://blog.csdn.net/zjw_python/article/details/98182540
本图完整的源码地址: https://github.com/zjw666/D3_demo/tree/master/src/funnelChart/basicFunnel
1 图表效果
2 数据
action,number
访问,60
咨询,40
订单,20
点击,80
展现,100
3 关键代码
导入数据
d3.csv('./data.csv', function(d){
return {
action: d.action,
number: +d.number
};
}).then(function(data){
....
一些样式配置参数,例如梯形间距等
const config = {
margins: {top: 80, left: 80, bottom: 50, right: 80},
textColor: 'black',
title: '基础漏斗图',
animateDuration: 1000,
trapezoidPadding: 3,
hoverColor: 'white',
}
尺度转换,这里根据数据数值大小来决定漏斗图梯形的宽度
/* ----------------------------尺度转换------------------------ */
chart.scale = d3.scaleLinear()
.domain([0, d3.max(data, (d) => d.number)])
.range([0, chart.getBodyWidth()*0.8]);
处理数据,转换数据结构,方便绘制
/* ----------------------------数据处理------------------------ */
const handleData = data.sort((a,b) => b.number - a.number).map(
(d,i,array) => {
if (i !== array.length-1){
d.nextNum = array[i+1].number;
}else{
d.nextNum = 0;
}
return d;
}
);
漏斗图可以看作由一个个梯形组成,也就是多边形,因此我们可以使用polygon
元素来绘制漏斗图
/* ----------------------------渲染梯形------------------------ */
chart.renderTrapezoid = function(){
let trapezoids = chart.body()
.append('g')
.attr('class', 'traps')
.attr('transform', 'translate(' + chart.getBodyWidth()/2 + ',0)')
.selectAll('.trap')
.data(handleData);
trapezoids.enter()
.append('polygon')
.attr('class', (d,i) => 'trap + trap-' + i)
.merge(trapezoids)
.attr('points', (d) => getPoints(chart.scale(d.number), chart.scale(d.nextNum), trapezoidsHeight))
.attr('transform', (d,i) => 'translate(0,' + i*(config.trapezoidPadding + trapezoidsHeight) + ')')
.attr('fill', (d,i) => chart._colors(i))
trapezoids.exit()
.remove();
//计算梯形的点坐标
function getPoints(topWidth, bottomWidth, height){
const points = [];
points.push(-topWidth/2 + ',' + 0);
points.push(topWidth/2 + ',' + 0);
if (bottomWidth === 0){
points.push(0 + ',' + height);
}else{
points.push(bottomWidth/2 + ',' + height);
points.push(-bottomWidth/2 + ',' + height);
}
return points.join(" ");
}
}
在梯形的中心点渲染文本标签
/* ----------------------------渲染文本标签------------------------ */
chart.renderText = function(){
let texts = d3.select('.traps')
.selectAll('.label')
.data(handleData);
texts.enter()
.append('text')
.attr('class','label')
.merge(texts)
.text((d) => d.action)
.attr('text-anchor', 'middle')
.attr('x', 0)
.attr('y', (d,i) => i * (config.trapezoidPadding + trapezoidsHeight) + trapezoidsHeight/2)
.attr('stroke', config.textColor);
texts.exit()
.remove();
}
最后绑定鼠标交互事件,鼠标悬停在梯形时,梯形颜色改变
/* ----------------------------绑定鼠标交互事件------------------------ */
chart.addMouseOn = function(){
d3.selectAll('.trap')
.on('mouseover', function(){
const e = d3.event;
d3.select(e.target)
.attr('fill', config.hoverColor);
})
.on('mouseleave', function(d,i){
const e = d3.event;
d3.select(e.target)
.attr('fill', chart._colors(i));
})
}