rega measured the WAGF Regions tab on Simple Research: the polygon highlight lands 51-85 ms after the click, then 433-667 ms later it is gone — fill-opacity back to 0.7, line-width back to 0.6, no row marked, every region at full colour. That reads exactly like the Driver's "the legend isn't connecting with the map", and it is worse than not connecting: it connected and then undid itself. Those two values are the fingerprint. 0.7 and 0.6 are written only by this profile's CLEAR paths, every one of which is reached from a deselect — so something sent select(null) half a second after the click, and nobody clicked twice. SemanticTreeLegend watches the IDENTITY of its nodes array, and every tree feeding it is a computed that returns a NEW array each evaluation. Any late async that touches a dependency — pins still arriving, a lazily loaded layer, a refresh — rebuilds the array with IDENTICAL CONTENT, and the reset in that watcher then cancelled the reader's selection: expandedIds cleared, selectedNode nulled, select(null) emitted. The reset is right for genuinely new data; what was wrong is that it could not tell the two cases apart. It asks one question now: does the selected row still EXIST in the new nodes? If it does, re-point at the new object and leave the tab and the expansion alone, because nothing about the reader's state has become invalid. If it is gone, the reset runs exactly as before and the deselect is honest. Re-pointed rather than kept, because the old object belongs to the discarded array and holding it would compare the highlight against a node the tree no longer contains. This is shared, so it is every tree legend on every map, not only mine: any profile whose data arrives or refreshes after a click was silently losing that click. NOT changed, and deliberately: the WAGF Regions TAB click also compiles shaders for regions-fill and regions-border (rega: 2.9-4.1 s on SwiftShader), because those layers are added on that click. Warming them at boot would mean paying for two more layers on every reader of every tab to save a one-time cost on one tab, and the 6.4 MB regions GeoJSON is lazily loaded there on purpose. SwiftShader inflates a compile by roughly an order of magnitude — the pins variant measured 3.2-3.5 s there and +0.5 s of real boot delta — so the honest expectation on a GPU is a few hundred milliseconds, once, on a tab that is already loading megabytes. That is a trade I am declining to make rather than one I missed. Verified: gates:pre 12/12. Needs eyes: rega, the same WAGF Regions row click — the highlight should now still be there at 5 s, and the variant compile may appear on that click once the selection sticks. |
||
|---|---|---|
| .. | ||
| charts | ||
| dashboards | ||
| hints | ||
| legends | ||
| map-controls | ||
| poster | ||
| qa | ||
| regions | ||
| search | ||
| tables | ||
| PeopleGroupDetail.vue | ||
| README.md | ||
| ResearchMapFilterPanel.vue | ||
| ResearchMapSideMenu.vue | ||
| SideMenuDrawer.vue | ||
| ViewSelect.vue | ||
| WARNING.md | ||
library/components/ — shared Vue components
The map UI, built from parameterized pieces every app-profile reuses. Fix one here and every map benefits — never edit a shared component to customize one map.
library/components/
┌───────────────────────────────────────────┐
│ legends/ map-controls/ poster/ │
│ charts/ tables/ │
│ PeopleGroupDetail.vue SideMenuDrawer.vue │
│ ResearchMapFilterPanel.vue …SideMenu.vue │
└───────────────────────────────────────────┘
reused by every app-profile via @map/components/…
legends/,map-controls/,poster/each have their own README.- Every component uses
<script setup>, callsuseShadowStyles(), and reaches stores viainject('mapStore' | 'uiStore' | 'dataStore')— never a direct store import.
Full catalog + conventions:
../../documentation/architecture/components.md ·
per-file roles: ../../documentation/reference.md.