Batch 8000 SVG circles into single path element in DottedMap

Instead of rendering 8000 individual <circle> elements (each a React
node to reconcile), batch all map dots into a single <path d="...">
string. Reduces DOM nodes from ~8000 to 1 for the base map layer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Usman Baig
2026-03-10 00:47:27 +01:00
parent 5f797112ec
commit 8c5b452f73

View File

@@ -77,6 +77,21 @@ export default function DottedMap({ data, className }: DottedMapProps) {
return { xStep: step || 1, yToRowIndex: rowMap }
}, [points])
// Batch all 8000 base dots into a single <path> instead of 8000 <circle> elements
const dotsPath = useMemo(() => {
const r = dotRadius
const d = r * 2
const parts: string[] = []
for (const point of points) {
const rowIndex = yToRowIndex.get(point.y) ?? 0
const offsetX = rowIndex % 2 === 1 ? xStep / 2 : 0
const cx = point.x + offsetX
const cy = point.y
parts.push(`M${cx - r},${cy}a${r},${r} 0 1,0 ${d},0a${r},${r} 0 1,0 ${-d},0`)
}
return parts.join('')
}, [points, dotRadius, xStep, yToRowIndex])
return (
<div className="relative w-full h-full flex items-center justify-center">
<svg
@@ -94,19 +109,10 @@ export default function DottedMap({ data, className }: DottedMapProps) {
</feMerge>
</filter>
</defs>
{points.map((point, index) => {
const rowIndex = yToRowIndex.get(point.y) ?? 0
const offsetX = rowIndex % 2 === 1 ? xStep / 2 : 0
return (
<circle
cx={point.x + offsetX}
cy={point.y}
r={dotRadius}
fill="currentColor"
key={`${point.x}-${point.y}-${index}`}
/>
)
})}
<path
d={dotsPath}
fill="currentColor"
/>
{processedMarkers.map((marker, index) => {
const rowIndex = yToRowIndex.get(marker.y) ?? 0
const offsetX = rowIndex % 2 === 1 ? xStep / 2 : 0