Skip to content

Commit 68e8b50

Browse files
committed
minor #3779 [Map] Render each UX icon once instead of once per marker (Kocal)
This PR was merged into the 3.x branch. Discussion ---------- [Map] Render each UX icon once instead of once per marker | Q | A | -------------- | --- | Bug fix? | no | New feature? | no | Deprecations? | no | Documentation? | no | Issues | - | License | MIT Markers on a map almost always share the same icon, but `AbstractRenderer::getMapAttributes()` called `UxIconRenderer::render()` for every single marker: a registry lookup, two attribute-validation passes and an HTML build, repeated identically thousands of times. Memoize inside `UxIconRenderer` on the arguments it receives, so the cache key can't drift from them and every map in the request shares it. The generated payload is unchanged. Rendering a Leaflet map: 1000 markers ~9.7 ms -> ~6.5 ms, 5000 markers ~53 ms -> ~37 ms. Benchmarked from the repository root with `blackfire run symfony php bench.php`: ```php <?php require __DIR__.'/src/Map/vendor/autoload.php'; require __DIR__.'/src/Map/src/Bridge/Leaflet/vendor/autoload.php'; use Symfony\UX\Icons\Icon as UxIconsIcon; use Symfony\UX\Icons\IconRegistryInterface; use Symfony\UX\Icons\IconRenderer; use Symfony\UX\Map\Bridge\Leaflet\Renderer\LeafletRenderer; use Symfony\UX\Map\Icon\Icon; use Symfony\UX\Map\Icon\UxIconRenderer; use Symfony\UX\Map\Map; use Symfony\UX\Map\Marker; use Symfony\UX\Map\Point; use Symfony\UX\StimulusBundle\Helper\StimulusHelper; $registry = new class implements IconRegistryInterface { public function get(string $name): UxIconsIcon { return new UxIconsIcon( '<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/>', ['viewBox' => '0 0 24 24', 'fill' => 'none', 'stroke' => 'currentColor', 'stroke-width' => '2'], ); } }; $renderer = new LeafletRenderer( new StimulusHelper(null), new UxIconRenderer(new IconRenderer($registry, ['fill' => 'currentColor'])), ); $map = new Map(center: new Point(48.86, 2.35), zoom: 12); for ($i = 0; $i < 2000; ++$i) { $map->addMarker(new Marker( position: new Point(48.86 + $i / 10000, 2.35 + $i / 10000), title: 'Marker '.$i, icon: Icon::ux('lucide:map-pin'), )); } $renderer->renderMap($map); ``` Blackfire: - before (177ms wall / 164ms CPU / 9MB): https://app.blackfire.io/envs/5f4f9a62-eaa0-45ee-b7b3-a1b879f550e9/profiles/e78d0d4c-5a78-4a30-a550-7ba075c36a90/graph - after (82ms wall / 81ms CPU / 8MB): https://app.blackfire.io/envs/5f4f9a62-eaa0-45ee-b7b3-a1b879f550e9/profiles/b299a751-fac7-4e67-96bb-4d0dcb0dda8c/graph - diff: https://app.blackfire.io/envs/5f4f9a62-eaa0-45ee-b7b3-a1b879f550e9/profiles/compare/e78d0d4c-5a78-4a30-a550-7ba075c36a90...b299a751-fac7-4e67-96bb-4d0dcb0dda8c/graph Analysis, implementation and benchmarks by Claude Opus 5. Commits ------- 3291457 [Map] Render each UX icon once instead of once per marker
2 parents 62f15ea + 3291457 commit 68e8b50

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

src/Map/src/Icon/UxIconRenderer.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
*/
2121
class UxIconRenderer
2222
{
23+
/**
24+
* @var array<string, string>
25+
*/
26+
private array $rendered = [];
27+
2328
public function __construct(
2429
private readonly ?IconRendererInterface $renderer,
2530
) {
@@ -34,7 +39,9 @@ public function render(string $name, array $attributes = []): string
3439
throw new \LogicException('You cannot use an UX Icon as the "UX Icons" package is not installed. Try running "composer require symfony/ux-icons" to install it.');
3540
}
3641

37-
return $this->renderer->renderIcon($name, [
42+
// Markers of a map overwhelmingly share the same icon, so the same SVG
43+
// was rebuilt once per marker.
44+
return $this->rendered[$name.'|'.serialize($attributes)] ??= $this->renderer->renderIcon($name, [
3845
'xmlns' => 'http://www.w3.org/2000/svg',
3946
...$attributes,
4047
]);

0 commit comments

Comments
 (0)