Facing a similar issue, my task was to generate a hexagonal map and populate the hexagons with various sprites like forests, water, and grasslands. When filling them with a solid color, rendering 10K elements only took two seconds.
However, when attempting to use fill: url('image.png');
, the process significantly slowed down, struggling to draw just 180 hexagons and eventually crashing the browser with 10K elements.
The underlying problem appears to be that Raphael JS generates individual texture definitions for each element before applying it as the fill. This results in having 10K texture definitions pointing to the same image, causing performance issues.
Update:
To address this challenge, I decided to shift away from SVG for this specific use case. Instead, opting to create HTML elements and set their backgrounds using CSS proved to be much faster. Additionally, combining these elements with SVG as an overlay provided flexibility. For projects dealing with a large number of elements, dynamically loading only necessary items can optimize performance, particularly when not all elements need to be simultaneously visible.
In scenarios where such optimizations are not feasible, leveraging Canvas to draw elements could be a viable alternative. While canvas may perform better than SVG for rendering numerous elements, implementing animations might require more effort compared to using the RaphaelJS library.