Skip to content

Round polygon node shapes render incorrectly on the canvas and cause edges to disappear #1922

Description

@kmcginnes

Description

Six round-* polygon shapes render as what appears to be round-diamond on the canvas, and edges connecting to these nodes disappear. The broken shapes are:

  • round-triangle
  • round-pentagon
  • round-hexagon
  • round-heptagon
  • round-octagon
  • round-tag

round-rectangle and round-diamond render correctly and are not affected.

These shapes were exposed in the picker via #1886 (the SHAPE_STYLES and NODE_SHAPE lists were expanded). Prior to that PR they were not selectable in the UI, so no user would have had them stored.

Root Cause

Investigated the full pipeline — GE passes valid, distinct shape values to cytoscape untransformed, and cytoscape 3.34.0 (the latest published version) registers each round polygon with its own point list and shape object. The defect is inside cytoscape's round-polygon canvas rendering at small node size (24px). Specifically, cytoscape computes each round polygon's corners once and caches them (getOrCreateCorners), then uses the same cache for two things:

  1. The fill path (drawRoundPolygonPath) — what you see on canvas.
  2. The edge endpoint (roundPolygonIntersectLine) — where the edge connects.

When the corner computation degenerates for these shapes at 24px, the fill renders as a blobby rounded shape (appears to be round-diamond) and the edge-intersection returns no valid point, causing edges to disappear. One broken computation, both symptoms.

No upstream fix exists — 3.34.0 is the latest cytoscape release. The one related upstream bug (cytoscape/cytoscape.js#3282) was already fixed in 3.30.3 and describes a crash, not this visual collapse.

Plan

Remove broken shapes from the picker

Remove the six shapes from NODE_SHAPE in nodeShape.ts so they can no longer be newly selected.

Coerce stored broken shapes at the storage edge

Use the ReadTransform on atomWithLocalForage (landing in PR #1914) to coerce any stored broken shape value to round-rectangle at load time. This keeps the logic at the boundary and avoids leaking it into the app.

Specifically, apply the transform to these atoms:

  • user-vertex-styles
  • shared-vertex-styles

Coerce in the styling import Zod schema

Add a .transform() on the shape field in stylingParser.ts so importing a file with a broken shape produces round-rectangle rather than an import issue.

Shared coercion function

Define the broken-shape set and coercion mapping once (likely next to SHAPE_STYLES in graphStyles.ts) and reuse it across both the ReadTransform and the Zod .transform().

Keep SHAPE_STYLES inclusive

Leave the six values in SHAPE_STYLES (and the ShapeStyle type) so older shared-styles files still parse cleanly. The import validator accepts them on input; they're coerced on render/read, not rejected.

Related Issues

Important

Internal only — this issue is maintained by the core team and is not accepting external contributions.

Metadata

Metadata

Assignees

Labels

customizationCustomization options for rendering graph data in non-default waysinternalSignals that the team will work on this issue internally.

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions