首页 > 解决方案 > 将大纲添加到 mapbox donutSegment cluster svg

问题描述

我基于 mapbox 中的代码创建了一个集群 svg,该集群 svg 被分段为https://docs.mapbox.com/mapbox-gl-js/example/cluster-html/

我希望集群有一个宽度为 STROKE_WIDTH 的白色轮廓。我试图通过在群集下方添加另一个稍大的白色圆圈来做到这一点。但是,要做到这一点,我必须调整该圆的 cx 和 cy ,使其在 svg 中正确居中。但是我不知道如何调整 donutSegments 的 cx 和 cy,因为我不完全理解 mapbox 的代码。如果您知道如何转换该 svg 或对如何添加白色轮廓有其他建议,我将不胜感激。

这是我现在得到的结果:off_center_cluster

这是我的简化代码:

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" />
        {counts.map(([color, count], i) =>
          donutSegment(offsets[i] / total, (offsets[i] + (count ?? 0)) / total, r, r0, color),
        )}
        <text dominantBaseline="central" transform={`translate(${stroke_r}, ${stroke_r})`}>
          {total.toLocaleString()}
        </text>
      </svg>
    </div>
  );
}

function donutSegment(start: number, end: number, r: number, r0: number, color: string) {
  if (end - start === 1) end -= 0.00001;
  const a0 = 2 * Math.PI * (start - 0.25);
  const a1 = 2 * Math.PI * (end - 0.25);
  const x0 = Math.cos(a0),
    y0 = Math.sin(a0);
  const x1 = Math.cos(a1),
    y1 = Math.sin(a1);
  const largeArc = end - start > 0.5 ? 1 : 0;

  return (
    <path
      d={`M ${r + r0 * x0} ${r + r0 * y0} L ${r + r * x0} ${r + r * y0} A ${r} ${r} 0 ${largeArc} 1 ${r + r * x1} ${
        r + r * y1
      } L ${r + r0 * x1} ${r + r0 * y1} A ${r0} ${r0} 0 ${largeArc} 0 ${r + r0 * x0} ${r + r0 * y0}`}
      fill={`${color}`}
    />
  );
}

标签: javascriptsvgmapboxmapbox-gl-js

解决方案


想通了!最好的方法是不要用 来重新定位较大圆圈的 cx 和 cy stroke_r,而是在“r”处保持中心相同,只使用宽度stroke_r并将 viewBox 位置移动到:

viewBox={`${-STROKE_WIDTH} ${-STROKE_WIDTH} ${w} ${w} `}

推荐阅读