不使用第三方库基于SVG实现stacked barchart堆叠柱状图的方法咨询
原生SVG堆叠柱状图调整方案
核心调整点
- 取消同分类下不同堆叠块的横向偏移:同一分类的所有分段x坐标保持一致,仅不同分类的柱子做横向位置偏移
- 新增堆叠高度累加逻辑:计算每个分段的y坐标时,需要叠加当前分类下排在它前面的所有分段的总高度,实现纵向层叠效果
- 统一SVG容器:所有分类的柱子放在同一个SVG内渲染,避免每个分类单独生成SVG导致布局错乱
- 优化坐标计算逻辑:移除X轴翻转的写法,直接通过y轴坐标正向计算,降低维护成本
修正后可运行代码
const ReleaseScopeCharts = () => { const data = [ { name: 'Transit', passed: 2, skipped: 5, failed: 22, }, { name: 'Access', passed: 7, skipped: 2, failed: 11, }, ]; const svgWidth = 500; const svgHeight = 500; const barWidth = 50; const barGap = 80; // 不同柱子之间的间距 const colors = ['#30D158', '#005EA7', '#FF453A']; const categories = ['passed', 'skipped', 'failed']; // 计算所有分类的总量最大值,用于高度比例换算 const maxTotal = Math.max(...data.map(d => categories.reduce((sum, key) => sum + d[key], 0))); return ( <div className="new-card"> <svg viewBox={`0 0 ${svgWidth} ${svgHeight}`} height={svgHeight} width={svgWidth}> {data.map((entry, barIndex) => { // 当前柱子的横向位置 const barX = barIndex * barGap; // 累计前面堆叠段的高度 let prevHeight = 0; return ( <g key={barIndex}> {/* 分类名称展示 */} <text x={barX + barWidth/2} y={svgHeight - 10} textAnchor="middle" fontSize="14"> {entry.name} </text> {categories.map((key, segIndex) => { const value = entry[key]; if (value <= 0) return null; // 计算当前分段高度,预留40px放底部文字 const segHeight = (value / maxTotal) * (svgHeight - 40); // 计算当前分段纵向位置,从下往上堆叠 const segY = svgHeight - 40 - prevHeight - segHeight; prevHeight += segHeight; return ( <rect key={segIndex} x={barX} y={segY} width={barWidth} height={segHeight} fill={colors[segIndex]} /> ) })} </g> ) })} </svg> </div> ); };
如果需要实现百分比堆叠柱状图(每个柱子总高度统一为100%),把代码中高度计算的maxTotal替换为当前entry的总数值即可。
内容的提问来源于stack exchange,提问作者Aren Trot
相关产品推荐
相关产品推荐

