Standalone Component - #622
Conversation
… `layoutTransitionEffect`, and `applyVisualContinuityBeforeLayout` inputs configure rich continuity when a prior graph had nodes, allowing for animations between graph updates. - Breaking: `useLayoutTransitions` (default `true` controls `layout-js-driven`; when `false` it applies only during JS `mode: 'tween'`); - Enhancement: `GraphComponent` `edgePathSampleCount` input (default 48, clamped 2–512) for edge resampling in layout, morph, and `redrawEdge` - Enhancement: `transitionAfterChanges.morphCapture` for prior translate source (model vs main-chart DOM, optional model fallback) and `syncTargetsFromPositionAfterTick` / `snapAddedNodeIds`; `mergeGraphLayoutTransition` merges `morphCapture` with defaults - Enhancement: `drawComplete` emits after a completed draw/tick pass (paths bound, graph ready). Use to hide loading UI or run one-shot center/zoomToFit without flashing before first layout. - Enhancement: Minimap can be displayed on bottom. - Fix: Observable layouts (Cola, D3 force) faster than `afterNextRender`—superseded passes repaint link paths from the current model without full `redrawLines` so layout morph is not cancelled. - Fix: Layout morph keeps `oldLine` / `oldTextPath` on paths that are not resampled-tweening until the tween ends instead of snapping to the new route early. - Fix: Drag `updateEdge` for Dagre and DagreCluster uses orientation-aware paths aligned with DagreNodesOnly. - Chore: Update Storybook with documentation, examples
| ></ng-container> | ||
| } | ||
| @if (!linkTemplate()) { | ||
| <svg:path class="edge line" /> |
There was a problem hiding this comment.
Default link path has no initial d attribute
Medium Severity
The default link template <svg:path class="edge line" /> no longer binds [attr.d]="link.line" (the old template had [attr.d]="link.line"). The d attribute is now set imperatively by D3 in redrawLines, which runs after afterNextRender. This leaves default-template edge paths without geometry for at least one rendered frame, causing a visible flash where edges are invisible before D3 paints them.
Reviewed by Cursor Bugbot for commit 5501254. Configure here.
- fix: blocker for drawing minimap in some instances - fix: restyle minimap colors - fix: drawComplete should fire when all nodes are ready
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 5 total unresolved issues (including 3 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6d503b2. Configure here.
## 12.0.0-alpha.2 - Breaking: `draggingEnabled`, `panningEnabled` renamed to `enableDrag` and `enablePan`. - Breaking: `draggingEnabled`, `panningEnabled`, `enableZoom` converted to model. - Enhancement: `setViewportInteraction` allows toggling pan, drag, and zoom in one imperative method. - Fix: `CompoundNode` and `Cluster` should transition size and position when animations are enabled. - Fix: `tick()` assigns `oldNodes` / `oldClusters` / `oldCompoundNodes` from the current graph **before** the post-tick `requestAnimationFrame`, so `[class.old-node]` is consistent for newly added ids on the same tick (fixes flash on zoom with `mode: 'tween'`, including additive + `snapAddedNodeIds`). - Fix: `#nodeTemplate` / `#linkTemplate` / `#clusterTemplate` outlets reuse a stable `ngTemplateOutletContext` object per graph id (pruned each `tick()`) so consumer templates (e.g. tooltips) are not torn down and recreated on viewport-only updates such as zoom. - Fix: `applyVisualContinuityBeforeLayout` clears `hidden` on nodes/clusters/compound nodes whose id existed in the prior graph so host-owned `[nodes]` references do not keep stale `hidden: true` after `tick()` ran on a different layout object graph (reduces template blink when `update()` runs again). ## 12.0.0-alpha.1 - Breaking: `GraphComponent` is now a standalone component built on signal APIs (`input`, `output`, `model`, `contentChild`, `viewChildren`) instead of decorator-based `@Input` / `@Output` and classic queries. The published `NgxGraphModule` and `GraphModule` wrappers are still there so existing NgModule-based applications can import the graph as before, but those modules are deprecated; new code should import `GraphComponent` (and add it to the consuming component or route `imports` array) the same way you would any other standalone piece. - Breaking: From TypeScript, inputs behave like signal readers: for example, read the current node list with `graph.nodes()` rather than `graph.nodes`. The `layout`, `curve`, and `activeEntries` bindings use `model()` where the graph needs to write back internally; consumers generally keep using normal property bindings, while code inside the component updates via `.set()`. - Breaking: Outputs are `OutputRef` values, not `EventEmitter`, so they do not offer `.pipe()`. To keep using RxJS operators, turn an output into an observable with `outputToObservable` from `@angular/core/rxjs-interop` (in an appropriate injection context), or subscribe to the ref directly. Payload types (such as `NgxGraphStateChangeEvent`) are unchanged; only the subscription shape differs. - Breaking: `@ViewChildren` / `@ContentChild` style access is replaced with signal query functions, so in component code you call `graph.linkElements()` (or the other query methods) instead of keeping a `QueryList` on a property. - Breaking: The in-component `animations: [ trigger(...) ]` definition was removed. Enter styling on the root now uses the framework’s `animate.enter` class binding together with keyframes in the graph stylesheet, which replaces the old opacity `:enter` transition and avoids the deprecated `trigger` API. Angular does not support mixing the legacy `animations` metadata and `animate.enter` / `animate.leave` on the same component. The old `[@.disabled]` host binding for the legacy tree is also gone; it was scoped to the previous animation system and did not drive node positions, but projected templates that relied on that subtree being disabled for their own `[@...]` triggers may need a different approach. - Breaking: Optional viewport inputs `zoomLevel`, `panOffsetX`, and `panOffsetY` are now signal inputs wired through `effect()` to `zoomTo` and `panTo`, so the graph no longer assigns those via a property setter, and the effects run when the parent binding’s value actually changes. If a parent expression changes on every data refresh, you may see extra viewport updates; binding stable values (or leaving these inputs unset) matches the old mental model. Automatic fit and centering still come from the documented `autoZoom`, `autoCenter`, and `zoomToFit$` behavior. If you use `transitionAfterChanges` with full-scope layout morph, whether the post-tick block runs `zoomToFit` or `center` can differ from the additive or instant paths, as before. - Breaking: If node.position is undefined, could cause a template error, ensure node has position via layout or proper handling in template. - Breaking: When using new transitions, any condition wrappers in Angular templates for node and edges could interfere with animations if the condition wraps a container node. - Enhancement: `transitionAfterChanges`, `transitionDuringTransform`, `layoutTransitionEffect`, and `applyVisualContinuityBeforeLayout` inputs configure rich continuity when a prior graph had nodes, allowing for animations between graph updates. - Breaking: `useLayoutTransitions` (default `true` controls `layout-js-driven`; when `false` it applies only during JS `mode: 'tween'`); - Enhancement: `GraphComponent` `edgePathSampleCount` input (default 48, clamped 2–512) for edge resampling in layout, morph, and `redrawEdge` - Enhancement: `transitionAfterChanges.morphCapture` for prior translate source (model vs main-chart DOM, optional model fallback) and `syncTargetsFromPositionAfterTick` / `snapAddedNodeIds`; `mergeGraphLayoutTransition` merges `morphCapture` with defaults - Enhancement: `drawComplete` emits after a completed draw/tick pass (paths bound, graph ready). Use to hide loading UI or run one-shot center/zoomToFit without flashing before first layout. - Enhancement: Minimap can be displayed on bottom. - Fix: Observable layouts (Cola, D3 force) faster than `afterNextRender`—superseded passes repaint link paths from the current model without full `redrawLines` so layout morph is not cancelled. - Fix: Layout morph keeps `oldLine` / `oldTextPath` on paths that are not resampled-tweening until the tween ends instead of snapping to the new route early. - Fix: Drag `updateEdge` for Dagre and DagreCluster uses orientation-aware paths aligned with DagreNodesOnly. - Chore: Update Storybook with documentation, examples ## 12.0.0-alpha.0 - Enhancement: Support for Angular 21 - Chore: Upgrade storybook to v10 * Upgrade prettier and pretty-quick * Upgrade storybook * Upgrade storybook v2 * Fix after project upgrade * Removing yarn.lock * Upgrading swimlane/prettier-config-swimlane * Updating versions * Yarn lock * Standalone Component (#622) - Enhancement: `transitionAfterChanges`, `transitionDuringTransform`, `layoutTransitionEffect`, and `applyVisualContinuityBeforeLayout` inputs configure rich continuity when a prior graph had nodes, allowing for animations between graph updates. - Breaking: `useLayoutTransitions` (default `true` controls `layout-js-driven`; when `false` it applies only during JS `mode: 'tween'`); - Enhancement: `GraphComponent` `edgePathSampleCount` input (default 48, clamped 2–512) for edge resampling in layout, morph, and `redrawEdge` - Enhancement: `transitionAfterChanges.morphCapture` for prior translate source (model vs main-chart DOM, optional model fallback) and `syncTargetsFromPositionAfterTick` / `snapAddedNodeIds`; `mergeGraphLayoutTransition` merges `morphCapture` with defaults - Enhancement: `drawComplete` emits after a completed draw/tick pass (paths bound, graph ready). Use to hide loading UI or run one-shot center/zoomToFit without flashing before first layout. - Enhancement: Minimap can be displayed on bottom. - Fix: Observable layouts (Cola, D3 force) faster than `afterNextRender`—superseded passes repaint link paths from the current model without full `redrawLines` so layout morph is not cancelled. - Fix: Layout morph keeps `oldLine` / `oldTextPath` on paths that are not resampled-tweening until the tween ends instead of snapping to the new route early. - Fix: Drag `updateEdge` for Dagre and DagreCluster uses orientation-aware paths aligned with DagreNodesOnly. - Chore: Update Storybook with documentation, examples - Enhancement: upgrade component to latest - Enhancement: give minimap an optional margin - Fix: blocker for drawing minimap in some instances - Fix: restyle minimap colors - Fix: drawComplete should fire when all nodes are ready * (release): 21.0.0-alpha.1 * Animation and Interactivity Fixes (#623) * fix: cluster and compound node animation * fix: toggle zoom, pan, drag * fix: new nodes were hanging onto hidden flag * fix: run tests in ci * fix: package * (release): 12.0.0-alpha.2 --------- Co-authored-by: Jonathan Avendano <jogaj_26@hotmail.com>


What kind of change does this PR introduce? (check one with "x")
What is the new behavior?
GraphComponentis now a standalone component built on signal APIs (input,output,model,contentChild,viewChildren) instead of decorator-based@Input/@Outputand classic queries. The publishedNgxGraphModuleandGraphModulewrappers are still there so existing NgModule-based applications can import the graph as before, but those modules are deprecated; new code should importGraphComponent(and add it to the consuming component or routeimportsarray) the same way you would any other standalone piece.graph.nodes()rather thangraph.nodes. Thelayout,curve, andactiveEntriesbindings usemodel()where the graph needs to write back internally; consumers generally keep using normal property bindings, while code inside the component updates via.set().OutputRefvalues, notEventEmitter, so they do not offer.pipe(). To keep using RxJS operators, turn an output into an observable withoutputToObservablefrom@angular/core/rxjs-interop(in an appropriate injection context), or subscribe to the ref directly. Payload types (such asNgxGraphStateChangeEvent) are unchanged; only the subscription shape differs.@ViewChildren/@ContentChildstyle access is replaced with signal query functions, so in component code you callgraph.linkElements()(or the other query methods) instead of keeping aQueryListon a property.animations: [ trigger(...) ]definition was removed. Enter styling on the root now uses the framework’sanimate.enterclass binding together with keyframes in the graph stylesheet, which replaces the old opacity:entertransition and avoids the deprecatedtriggerAPI. Angular does not support mixing the legacyanimationsmetadata andanimate.enter/animate.leaveon the same component. The old[@.disabled]host binding for the legacy tree is also gone; it was scoped to the previous animation system and did not drive node positions, but projected templates that relied on that subtree being disabled for their own[@...]triggers may need a different approach.zoomLevel,panOffsetX, andpanOffsetYare now signal inputs wired througheffect()tozoomToandpanTo, so the graph no longer assigns those via a property setter, and the effects run when the parent binding’s value actually changes. If a parent expression changes on every data refresh, you may see extra viewport updates; binding stable values (or leaving these inputs unset) matches the old mental model. Automatic fit and centering still come from the documentedautoZoom,autoCenter, andzoomToFit$behavior. If you usetransitionAfterChangeswith full-scope layout morph, whether the post-tick block runszoomToFitorcentercan differ from the additive or instant paths, as before.transitionAfterChanges,transitionDuringTransform,layoutTransitionEffect, andapplyVisualContinuityBeforeLayoutinputs configure rich continuity when a prior graph had nodes, allowing for animations between graph updates.useLayoutTransitions(defaulttruecontrolslayout-js-driven; whenfalseit applies only during JSmode: 'tween');GraphComponentedgePathSampleCountinput (default 48, clamped 2–512) for edge resampling in layout, morph, andredrawEdgetransitionAfterChanges.morphCapturefor prior translate source (model vs main-chart DOM, optional model fallback) andsyncTargetsFromPositionAfterTick/snapAddedNodeIds;mergeGraphLayoutTransitionmergesmorphCapturewith defaultsdrawCompleteemits after a completed draw/tick pass (paths bound, graph ready). Use to hide loading UI or run one-shot center/zoomToFit without flashing before first layout.afterNextRender—superseded passes repaint link paths from the current model without fullredrawLinesso layout morph is not cancelled.oldLine/oldTextPathon paths that are not resampled-tweening until the tween ends instead of snapping to the new route early.updateEdgefor Dagre and DagreCluster uses orientation-aware paths aligned with DagreNodesOnly.Does this PR introduce a breaking change? (check one with "x")
Note
High Risk
High risk because it introduces breaking public API changes (standalone component, signal-based inputs/outputs/queries) and rewrites core rendering/animation logic for node/edge layout transitions and viewport transforms.
Overview
Migrates
ngx-graphto Angular 20+ standalone + signals.GraphComponentswitches from decorator-based@Input/@Output+EventEmitter+@ViewChildren/@ContentChildto signal APIs (input/model/output,viewChildren/contentChild), andGraphModule/NgxGraphModuleare retained but deprecated and updated to import standalone artifacts.Reworks rendering + transitions. Removes legacy
@angular/animationstriggers in favor ofanimate.enter+ CSS keyframes, adds JS-driven layout morphing via new transition inputs (transitionAfterChanges,useLayoutTransitions,edgePathSampleCount, viewport pan easing, optional layout “flair” effect), and adds adrawCompleteoutput emitted once paths are bound and dims are ready.Improves edge/minimap behavior and adds new utilities/tests. Introduces shared edge-geometry helpers for Dagre/ELK drag routing, extends minimap positioning (upper/lower corners) with margins and corrected pan-to math, adjusts minimap styling, and adds extensive unit tests covering transition merging, drag edge geometry, redraw/resampling, and
drawComplete.Reviewed by Cursor Bugbot for commit 6d503b2. Bugbot is set up for automated code reviews on this repo. Configure here.