You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With very large label sets (repro: ~10k node labels + ~10k edge labels), the schema view pins the main thread and never renders — even after the icon fan-out fix (#2103). A performance trace attributes 87.6% self-time to Cytoscape's style engine (getPropertiesDiff + getContextStyle); the layout is never reached (0.3 ms).
Root cause
createGraphStyles (useGraphStyles.ts) emits one selector per type — node[type="…"] and edge[type="…"] — so ~20k style contexts. Cytoscape resolves each element's style by scanning all contexts, making style application O(elements × contexts) ≈ 4×10⁸. Compounding it, useManageStyles's effect is keyed on a styles object with fresh identity every render, so the multi-second recompute can re-fire and never settle.
Evidence
Headless benchmark, per-type selectors vs. a single data() mapper rule, forcing per-element resolution:
n (each of node + edge types)
contexts
resolve
1,000
2,002
437 ms
3,000
6,002
3,622 ms
10,000
20,002
~100 min
10,000 (data-mapper)
2
324 ms
Fix
Two independently shippable phases:
Stabilize the effect — memoize the styles object identity so useManageStyles applies once instead of re-firing the recompute.
Data-mapper conversion — precompute each element's resolved style values onto ele.data() (ge_*) at the element-enrichment seam and emit one node rule + one edge rule using data(...), mirroring the existing node[__iconUrl] mapper. Contexts drop ~20k → ~2; cy.style() becomes O(elements). Extends Push node background-color to Cytoscape ele.data() with styled type atoms #1725 (which validates the architecture for background-color) to all per-type properties.
Per-element logic that must move out of the style loop into precompute: the isDark() label text-color pick, the line-dash-pattern/lineStyle remap, and shape coercion (ADR 20260710-coerce-retired-round-polygon-shapes).
Regression guard: assert style-context count stays O(1) regardless of type count.
Symptom
With very large label sets (repro: ~10k node labels + ~10k edge labels), the schema view pins the main thread and never renders — even after the icon fan-out fix (#2103). A performance trace attributes 87.6% self-time to Cytoscape's style engine (
getPropertiesDiff+getContextStyle); the layout is never reached (0.3 ms).Root cause
createGraphStyles(useGraphStyles.ts) emits one selector per type —node[type="…"]andedge[type="…"]— so ~20k style contexts. Cytoscape resolves each element's style by scanning all contexts, making style application O(elements × contexts) ≈ 4×10⁸. Compounding it,useManageStyles's effect is keyed on astylesobject with fresh identity every render, so the multi-second recompute can re-fire and never settle.Evidence
Headless benchmark, per-type selectors vs. a single
data()mapper rule, forcing per-element resolution:Fix
Two independently shippable phases:
stylesobject identity souseManageStylesapplies once instead of re-firing the recompute.ele.data()(ge_*) at the element-enrichment seam and emit onenoderule + oneedgerule usingdata(...), mirroring the existingnode[__iconUrl]mapper. Contexts drop ~20k → ~2;cy.style()becomes O(elements). Extends Push node background-color to Cytoscape ele.data() with styled type atoms #1725 (which validates the architecture forbackground-color) to all per-type properties.Per-element logic that must move out of the style loop into precompute: the
isDark()label text-color pick, theline-dash-pattern/lineStyleremap, and shape coercion (ADR20260710-coerce-retired-round-polygon-shapes).Regression guard: assert style-context count stays O(1) regardless of type count.
Related
Umbrella #2091 · caused-with #2103 · architecture #1725 · epic #1677 · spike #1797
Important
Internal only — this issue is maintained by the core team and is not accepting external contributions.