如何为Mapbox donutSegment聚合SVG添加指定宽度的白色描边
问题原因
你出现偏移的核心原因是 donutSegment 函数内所有路径坐标都是以 (r, r) 为圆心计算的,但你为了加描边扩容SVG画布后,新的画布圆心变成了 (r + STROKE_WIDTH, r + STROKE_WIDTH),二者坐标基准不匹配,导致环形图整体往左上偏移了等于STROKE_WIDTH的距离。
最简修复方案
不需要修改donutSegment的原有逻辑,只要把所有环形片段用<g>标签包裹,添加对应偏移即可,改动量最小:
export function createDonutChart(props: Record<string, number>) { // code for creating an SVG donut chart from feature properties const offsets: number[] = []; const counts = Object.entries(props); let total = 0; for (const [, count] of counts) { offsets.push(total); if (count) { total += count; } } const fontSize = 16; const r = 18; const stroke_r = r + STROKE_WIDTH; const r0 = Math.round(r * 0.6); const w = stroke_r * 2; return ( <div> <svg width={w} height={w} viewBox={`0 0 ${w} ${w} `} textAnchor="middle" style={{ font: `${fontSize}px sans-serif`, display: 'block' }} > <circle cx={stroke_r} cy={stroke_r} r={stroke_r} fill="white" /> {/* 新增g标签,把环形整体偏移STROKE_WIDTH距离,对齐新画布圆心 */} <g transform={`translate(${STROKE_WIDTH}, ${STROKE_WIDTH})`}> {counts.map(([color, count], i) => donutSegment(offsets[i] / total, (offsets[i] + (count ?? 0)) / total, r, r0, color), )} </g> <text dominantBaseline="central" transform={`translate(${stroke_r}, ${stroke_r})`}> {total.toLocaleString()} </text> </svg> </div> ); }
可选更精简的描边方案
如果你不想额外加底层白色圆形,也可以直接通过描边属性实现效果,不需要调整环形偏移:
把底层的白色圆形替换为:
<circle cx={r} cy={r} r={r} fill="none" stroke="white" stroke-width={STROKE_WIDTH * 2} />
同时把SVG画布宽高、viewBox改回r*2即可。原理是SVG的描边会往路径两侧延伸,设置2倍STROKE_WIDTH的描边后,内侧的描边会被上层的环形图案覆盖,只会露出外侧等于STROKE_WIDTH的白色描边。
内容的提问来源于stack exchange,提问作者Sasa
相关产品推荐
相关产品推荐

