Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
const svg = d3.select("body").append("svg")
.attr("width", 600)
.attr("height", 500)
const BAR_HEIGHT = 18
const BAR_GAP = 60
const COLORS = ['#21CD69', '#f8bc29', '#fb4848']
const data = [
{ name: '下单', stack: [50], rate: '82%' },
{ name: '推单', stack: [40], rate: '82%' },
{ name: '接单', stack: [20, 5, 5], rate: '82%' },
{ name: '配送', stack: [10, 5, 5], rate: '82%'},
{ name: '完成', stack: [8], rate: '82%' }
]
data.forEach((item, index) => {
// bar
let lastX = 0
const container = svg.append('g')
.attr('transform', `translate(40, ${index * BAR_GAP + (BAR_GAP - BAR_HEIGHT) / 2})`)
container
.selectAll('rect')
.data(item.stack)
.enter().append('rect')
.attr('x', d => {
const preX = lastX
lastX = preX + d * 10
return preX
})
.attr('y', 0)
.attr('width', d => d * 10)
.attr('height', BAR_HEIGHT)
.attr('fill', (d, i) => COLORS[i])
// area
if (index < data.length - 1) {
container.append('path')
.attr('d', `M0 ${BAR_HEIGHT}L ${item.stack[0] * 10} ${BAR_HEIGHT}L${data[index + 1].stack[0] * 10} ${BAR_GAP}L0 ${BAR_GAP}}z`)
.attr('fill', '#CDF4E0')
container.append('text')
.attr('x', (item.stack[0] * 10 + data[index + 1].stack[0] * 10) / 2)
.attr('y', BAR_GAP / 2 + BAR_HEIGHT)
.attr('text-anchor', 'middle')
.attr('fill', '#21CD69')
.text(`转化率:${item.rate}`)
}
})
// text
svg.append('g')
.selectAll('text')
.data(data)
.enter().append('text')
.attr('x', 0)
.attr('y', (data, i) => i * BAR_GAP + BAR_GAP / 2)
.attr('dy', '.3em')
.attr('fill', '#475669')
.text(d => d.name)
</script>
</body>
https://d3js.org/d3.v4.min.js