Skip to content

Clip edges to node outlines and re-lay out the activity example - #46

Merged
haphantran merged 3 commits into
mainfrom
fix/2d-notation
Oct 13, 2026
Merged

haphantran merged 3 commits into
mainfrom
fix/2d-notation

Conversation

@haphantran

Copy link
Copy Markdown
Collaborator

Summary

Fixes the 2D notation issues reviewers saw in the activity diagram (arrows ending inside nodes, line crossings, horizontal fork/join bars) and several rendering problems found while fixing them. Independent of the other open PRs.

Edge endpoints

  • getEdgeEndpointPair clips each end to the outline the renderer actually draws: ray-box for rectangles and squares (squares are drawn width x width from the top-left), ray-ellipse for circles and ellipses, ray-rhombus for diamonds, bounding box otherwise. Each end heads towards the first or last bend point when the edge has bends, otherwise the other node's centre. Existing parameters still work; options are added.
  • Pins are clipped to their border instead of their centre.
  • The edge preview while drawing starts on the source outline.
  • Bent edges are drawn as straight segments; the tensioned curve overshot corners and looped around nodes.

Renderer fixes (listed per the plan)

  1. The ellipse and diamond shapes offered in the notation editors were not drawn (they fell back to the default box with a title bar); they are drawn now.
  2. Containers were drawn after edges, so their fill hid every edge between their children (the activity containers showed no flows). Containers are now drawn first.
  3. Edge notation labelFormat was editable but ignored, so every activity flow showed the label "flowsTo". It is now honoured: {name} and {attribute} placeholders, and a format whose placeholders are all empty shows no label ([{guard}] shows guards only).
  4. Edge labels are centred on the path midpoint instead of the first/last point midpoint.
  5. Names of narrow nodes (pins, fork bars) wrapped one letter per line; labels below a node now get a minimum width.
  6. New 2D notation field labelPosition (below, inside, hidden), editable in the metaclass and representation notation editors.

Activity example

  • Decision and merge nodes are diamonds; fork and join are thin vertical black bars (configuration: rectangle, 10 x 100 default size, matching per-element size2D); action names are inside actions; initial/final/fork/join/pin names are hidden; flows show only guards.
  • Both bundled views (Order Processing Flow, Happy Path (In Stock)) are re-laid out left to right with no edge crossings; three flows use bend points.
  • activity-example-layout.test.ts checks both views, computed the way the renderer draws them: no crossings, no edge through an unrelated node, no edge label or node name over another edge, vertical bars, left-to-right flow. It fails on the previous layout (7 failures) and passes on the new one.

Verification

  • Frontend: typecheck, 371 tests pass. Backend typecheck and lint pass.
  • Rendered both activity views in the running app and checked them visually.

Edge ends are now clipped to the drawn outline of the node they touch:
ray-box for rectangles and squares, ray-ellipse for circles and
ellipses, ray-rhombus for diamonds, and the bounding box otherwise. Each
end heads towards its adjacent bend point, or the other node when the
edge has none. Pins are clipped to their border instead of their centre,
and the edge preview starts on the source outline. Bent edges are drawn
as straight segments instead of a tensioned curve that overshot corners.

The 2D renderer now draws the ellipse and diamond shapes it already
offered, draws containers before edges so their fill no longer hides the
flows between their children, honours the edge notation's labelFormat
(placeholders for the name and reference attributes; an all-empty format
hides the label), centres edge labels on the path, and keeps names of
narrow nodes from wrapping letter by letter. A new 2D notation field,
labelPosition (below, inside, hidden), is editable in the metaclass and
representation notation editors.

The UML activity example draws decisions as diamonds, fork and join as
vertical bars, action names inside actions, and only guard labels on
flows, and its two views are re-laid out left to right without edge
crossings. A geometry test checks both views for crossings, edges
through unrelated nodes, labels over edges, and flow direction.
Copilot AI balanced review requested due to automatic review settings October 12, 2026 02:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Bend-point handling can discard persisted bends, and coincident nodes can still produce endpoints inside their shapes.

3 open findings
What changed in this PR

Improves 2D activity-diagram rendering, notation, and example layout.

Changes:

  • Clips edges to node outlines and improves shapes, labels, layering, and routing.
  • Adds configurable node-label positioning.
  • Reworks activity examples and adds geometry-focused tests.
File Description
shared/​types/​index.ts Adds shared label-position typing.
frontend/​src/​models/​types.ts Adds frontend label-position typing.
frontend/​src/​examples/​data/​activity-diagram-views.json Resizes example canvases.
frontend/​src/​examples/​data/​activity-diagram-viewpoints.json Updates activity notation.
frontend/​src/​examples/​data/​activity-diagram-model.json Re-lays out activity diagrams.
frontend/​src/​components/​viewpoints/​ViewpointManager.tsx Adds label-position controls.
frontend/​src/​components/​metamodel/​MetaClassNotationEditor.tsx Adds metaclass label controls.
frontend/​src/​components/​diagram/​DiagramEditor.tsx Updates 2D rendering and edges.
frontend/​src/​components/​diagram/​2d/​utils/​appearanceUtils.ts Adds geometry and label utilities.
frontend/​src/​__tests__/​services/​view-projection-containers.test.ts Updates expected container sizes.
frontend/​src/​__tests__/​services/​appearanceUtils.test.ts Tests geometry and formatting.
frontend/​src/​__tests__/​services/​activity-example-layout.test.ts Validates activity layouts.
docs/​user-guide/​viewpoints.md Documents new notation behavior.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +294 to +295
const sourceToward = options.sourceToward || targetGeometry.center;
const targetToward = options.targetToward || sourceGeometry.center;
Comment on lines +1509 to +1512
// Stored edge points keep placeholder ends; only the inner points are bends.
const bendPoints = Array.isArray(element.points) && element.points.length > 2
? element.points.slice(1, -1)
: [];
Comment on lines +43 to +49
/** Proper crossing: the segments intersect at a point interior to both. */
const segmentsCross = ([a, b]: Segment, [c, d]: Segment): boolean => {
const d1 = cross(c, d, a);
const d2 = cross(c, d, b);
const d3 = cross(a, b, c);
const d4 = cross(a, b, d);
return ((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0));
haphantran added a commit that referenced this pull request Oct 12, 2026
Room names are drawn inside the rooms (with #46), so smoke detectors and
the hub move off the room centres. Device icons stay inside their room
in the floor plan, hub links use the default arrow the 2D editor draws,
and the generated device list has one device per line.
…e paths

Edges between nodes whose centres coincide (self-references included)
again leave on the right and arrive on the left instead of collapsing to
the centre. Self-references are created with the stored edge-path form
[source placeholder, ...bends, target placeholder], now documented on
DiagramElement.points, so the renderer keeps all three bends. The
activity layout test also rejects T-junctions and collinear overlaps
between edges, except where edges meet at a node they share.
@haphantran
haphantran merged commit f2ada16 into main Oct 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants