ERA-13076: Remove approach to loading icons via one enormous sprite#1529
ERA-13076: Remove approach to loading icons via one enormous sprite#1529jeslefcourt wants to merge 7 commits into
Conversation
Replace SVG sprite-based icon loading with direct img tags using static SVG file URLs, simplifying the icon rendering pipeline and removing the preloaded sprite dependency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
luixlive
left a comment
There was a problem hiding this comment.
A couple small suggestions and a couple questions. Nothing hard-blocking, but worth taking a minute to think them through.
…mage files. Had a bit of a snowball effect into things impacted by cascading styles.
- Remove !important flags on svgs - Fixed icon colors in clusters and cluster popups changing when editing events before saving - Sanitize SVGs to avoid injection attacks
d4bcd19 to
3d4d8ab
Compare
JoshuaVulcan
left a comment
There was a problem hiding this comment.
Looks and feels pretty good so far! Will keep manually testing. My feedback on this review pass is around finishing off the refactor by making sure files and names are cleaned up.
| import mapboxgl from 'mapbox-gl'; | ||
|
|
||
| import { CLUSTER_CLICK_ZOOM_THRESHOLD, LAYER_IDS, SUBJECT_FEATURE_CONTENT_TYPE } from '../constants'; | ||
| import { calcSvgImageIconId } from '../MapImageFromSvgSpriteRenderer'; |
There was a problem hiding this comment.
It seems like MapImageFromSvgSpriteRenderer should be removed entirely, and the utility function to calculate image URLS lifted/shifted elsewhere.
| const getFeatureIcon = (feature, mapImages) => | ||
| mapImages[`${feature.properties.icon_id}-${feature.properties.priority}`]?.image; | ||
| const getFeatureIcon = (feature, mapImages, locallyEditedEvent, eventStore) => { | ||
| const isLocally = locallyEditedEvent?.id === feature.properties.id; |
There was a problem hiding this comment.
variable naming nit: isLocally 😢
There was a problem hiding this comment.
Agreed. isLocally is ambiguous. The code that defines the variable isn't, but I'd rather have something like isLocallyEditedEventFeature.
| @@ -0,0 +1,64 @@ | |||
| import React from 'react'; | |||
There was a problem hiding this comment.
Love the changes here. Seems like we'd want to rename away from DasIcon as well?
luixlive
left a comment
There was a problem hiding this comment.
Just a couple more comments and questions. I see now we are also updating the clusters when we have a locally edited event, which is a nice addition, but it's increasing the size of this PR considerably.
Once these comments are solved / responded, I'll be ready to approve. Still think we will need a special treatment from QA to make sure all icons render correctly and that clusters work and update correctly when we have local changes in an event that haven't been saved yet 👍 @AlanCalvillo
|
|
||
| useMapEventBinding('sourcedata', onSourceData); | ||
|
|
||
| useEffect(() => { |
There was a problem hiding this comment.
I think these useEffects can have a performance impact. Their dependency arrays include the callback itself (updateClusterMarkersCallback), this means that everytime the callback gets redefined, they will be called. In other words, whenever any of the following variables changes, we will be running the markers update:
addClusterPolygon, eventStore, locallyEditedEvent, map, onShowClusterSelectPopup, removeClusterPolygon.
Probably we could stabilize this with a useRef or a more complex useEffect that only triggers the callback specifically when locallyEditedEvent and mapImages change.
| mapImages[`${feature.properties.icon_id}-${feature.properties.priority}`]?.image; | ||
| const getFeatureIcon = (feature, mapImages, locallyEditedEvent, eventStore) => { | ||
| const isLocally = locallyEditedEvent?.id === feature.properties.id; | ||
| if (isLocally) { |
There was a problem hiding this comment.
This code block gives me the impression that the agent thought locally edited events could update their icons, but they can't. All the user can changes that results in an update to the icon is priority. I feel this method can be simplified, something like:
const getFeatureIcon = (feature, mapImages) => {
const priority = locallyEditedEvent?.id === feature.properties.id
? locallyEditedEvent.priority
: feature.properties.priority
return mapImages[calcSvgImageIconId({ icon_id: feature.properties.icon_id, priority })]?.image;
}Unless of course I'm missing something 🤔
|
|
||
| const CONTAINER_SELECTOR = 'svg,g,defs,symbol,marker,clipPath,mask,pattern'; | ||
|
|
||
| const sanitizeSvg = (text) => { |
There was a problem hiding this comment.
Feels like a brute-force approach to clean the icons. I guess it's better to keep this file than the sprites file. Probably would try a last prompt to Claude like: "Refactor this file and apply clean code practices plus explanatory comments to improve its readability and maintainability". And I would say this requires some thorough manual testing in a couple envs just to make sure all icons render correctly 👍
Summary
<img>tags referencing static SVG file URLsReportTypeIconSpritefromApp.jsand thecalcIconUrlsprite-lookup logic fromDasIconsvgtoimg, replacingfillwithfilter: invert(1)Jira
ERA-13076
Test plan
🤖 Generated with Claude Code