Skip to content

Schema view lockup from per-type Cytoscape style selectors in useGraphStyles #2104

Description

@kmcginnes

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="…"] 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:

  1. Stabilize the effect — memoize the styles object identity so useManageStyles applies once instead of re-firing the recompute.
  2. 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.

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.

Metadata

Metadata

Assignees

Labels

internalSignals that the team will work on this issue internally.performanceIssues relating to performanceschemaIssues related to the schema definition or synchronization

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions