# ngDiagram — Full Documentation > A powerful Angular library for creating interactive diagrams, node-based editors, and visual programming interfaces. > Built for Angular. Supports custom nodes, custom edges, ports, groups, minimap, palette, routing, and more. Homepage: https://ngdiagram.dev GitHub: https://github.com/synergycodes/ng-diagram NPM: https://www.npmjs.com/package/ng-diagram License: Apache-2.0 --- # Getting Started ## Thinking through architecture trade-offs? > Understanding the overall architecture of ngDiagram URL: https://ngdiagram.dev/docs/intro/architecture/ ngDiagram follows a layered architecture that separates concerns and enables extensibility. This design makes it easy to understand, customize, and extend for your specific needs. ## Architecture Flow When a user interacts with the diagram, here's what happens: 1. **User Interaction**: User clicks, drags, or presses keys on diagram components 2. **Event Capture & Processing**: User interactions are captured and processed to determine the appropriate action 3. **Command Emission**: Based on the event, one or more commands are emitted to represent the intended operation 4. **Middleware Pipeline**: Commands flow through middleware chain for validation, transformation, or side effects 5. **Model Update**: Final state changes are applied to the model 6. **UI Reactivity**: Angular signals automatically update the UI to reflect new state This unidirectional flow ensures predictable behavior and makes debugging straightforward. ## Architecture Layers ### Components Layer The user-facing components that render the diagram and handle user interactions: - [**ng-diagram**](/docs/api/components/ngdiagramcomponent): Main component that renders the entire diagram, handles user interactions, and orchestrates all functionality - [**ng-diagram-background**](/docs/api/components/ngdiagrambackgroundcomponent): Background component that renders the diagram's background grid - [**ng-diagram-resize-adornment**](/docs/api/components/ngdiagramnoderesizeadornmentcomponent) and [**ng-diagram-rotate-adornment**](/docs/api/components/ngdiagramnoderotateadornmentcomponent): Utility components that can be embedded in custom node templates to provide resize and rotation functionality - [**ng-diagram-palette-item**](/docs/api/components/ngdiagrampaletteitemcomponent): Drag and drop component that can be placed anywhere in your application to create palette functionality - [**ng-diagram-palette-item-preview**](/docs/api/components/ngdiagrampaletteitempreviewcomponent): Preview component that shows a visual representation of palette items during drag operations - [**ng-diagram-base-edge**](/docs/api/components/ngdiagrambaseedgecomponent): Foundation component for building custom edge templates with advanced styling and behavior - [**ng-diagram-base-edge-label**](/docs/api/components/ngdiagrambaseedgelabelcomponent): Base component for creating custom edge labels with consistent styling and positioning - [**ng-diagram-port**](/docs/api/components/ngdiagramportcomponent): Port component that defines connection points on nodes for edge connections - [**ng-diagram-base-node-template**](/docs/api/components/ngdiagrambasenodetemplatecomponent): Base component for creating custom node templates with default styling and features. ### Service Layer Specialized services provide different levels of control and functionality: - [**NgDiagramService**](/docs/api/services/ngdiagramservice): Core service providing middleware management, routing management, and transaction handling - [**NgDiagramModelService**](/docs/api/services/ngdiagrammodelservice): Handles model operations including node/edge updates, spatial queries, and data access - [**NgDiagramViewportService**](/docs/api/services/ngdiagramviewportservice): Manages viewport state with reactive signals for position, scale, and coordinate transformations - [**NgDiagramSelectionService**](/docs/api/services/ngdiagramselectionservice): Manages selection state with methods for selecting/deselecting nodes and edges - [**NgDiagramNodeService**](/docs/api/services/ngdiagramnodeservice): Provides node-specific operations - [**NgDiagramGroupsService**](/docs/api/services/ngdiagramgroupsservice): Manages group node operations such as member management - [**NgDiagramClipboardService**](/docs/api/services/ngdiagramclipboardservice): Manages copy/paste operations for diagram elements All services are provided through [`provideNgDiagram()`](/docs/api/utilities/providengdiagram), allowing multiple diagrams on the same page to maintain their own isolated state and behavior. Learn more in the [Services documentation](/docs/intro/services). ### Event Layer The event layer captures user interactions and translates them into commands that modify the diagram state. Events are emitted by the [`NgDiagramComponent`](/docs/api/components/ngdiagramcomponent) and can be handled via Angular outputs. **Available events:** - [**DiagramInitEvent**](/docs/api/types/events/diagraminitevent): Fired when the diagram is fully initialized and all nodes, edges, and their internal parts are measured and positioned. - [**EdgeDrawEndedEvent**](/docs/api/types/events/edgedrawendedevent): Fired when an edge draw gesture ends, whether successful or cancelled. - ~~[**EdgeDrawnEvent**](/docs/api/types/events/edgedrawnevent)~~: Deprecated, use `EdgeDrawEndedEvent` instead. - [**SelectionChangedEvent**](/docs/api/types/events/selectionchangedevent): Fired when nodes or edges are selected or deselected. - [**SelectionGestureEndedEvent**](/docs/api/types/events/selectiongestureendedevent): Fired when a selection gesture completes (on pointerup after clicking a node/edge, box selection, or select-all). - [**SelectionMovedEvent**](/docs/api/types/events/selectionmovedevent): Fired continuously on each position change while selected nodes are being dragged on the canvas. - [**SelectionRemovedEvent**](/docs/api/types/events/selectionremovedevent): Fired when selected nodes or edges are removed from the diagram. - [**SelectionRotatedEvent**](/docs/api/types/events/selectionrotatedevent): Fired continuously on each angle change while selected nodes are being rotated. - [**GroupMembershipChangedEvent**](/docs/api/types/events/groupmembershipchangedevent): Fired when nodes are grouped or ungrouped, changing their group membership. - [**ViewportChangedEvent**](/docs/api/types/events/viewportchangedevent): Fired when the viewport changes due to panning or zooming. - [**ClipboardPastedEvent**](/docs/api/types/events/clipboardpastedevent): Fired when nodes and edges are added via paste operations (keyboard shortcut or programmatic paste). - [**NodeResizedEvent**](/docs/api/types/events/noderesizedevent): Fired continuously on each size change while a node or group is being resized. - [**NodeResizeStartedEvent**](/docs/api/types/events/noderesizestartedevent): Fired when a node resize operation begins. - [**NodeResizeEndedEvent**](/docs/api/types/events/noderesizeendedevent): Fired when a node resize operation ends. - [**NodeRotateStartedEvent**](/docs/api/types/events/noderotatestartedevent): Fired when a node rotation operation begins. - [**NodeRotateEndedEvent**](/docs/api/types/events/noderotateendedevent): Fired when a node rotation operation ends. - [**NodeDragStartedEvent**](/docs/api/types/events/nodedragstartedevent): Fired when a node drag operation begins. - [**NodeDragEndedEvent**](/docs/api/types/events/nodedragendedevent): Fired when a node drag operation ends. - [**PaletteItemDroppedEvent**](/docs/api/types/events/paletteitemdroppedevent): Fired when a palette item is dropped onto the diagram to create a new node. Each event provides a strongly-typed payload with relevant details. You can subscribe to these events using Angular outputs (e.g. `(selectionChanged)="..."`) on the [``](/docs/api/components/ngdiagramcomponent) component. See [DiagramEventMap](/docs/api/types/events/diagrameventmap/) for more information on available events and their payloads. ### Command System Commands provide precise, structured instructions for state changes in the diagram. After events are processed, handlers emit commands that represent the intended operation: - **Atomic Operations**: Each command represents a single, well-defined action (select, moveNode, addEdge, etc.) - **Command Emission**: Event handlers analyze user interactions and emit appropriate commands through the CommandHandler - **Transaction Support**: Commands can be grouped into [transactions](/docs/guides/transactions) for atomic execution, ensuring data consistency - **Extensible**: The system supports 40+ built-in commands and can be extended with custom commands The command system acts as the bridge between user interactions (events) and state changes (model updates), ensuring all modifications go through a controlled, predictable pipeline. ### Middleware System Middleware intercepts commands before they reach the model, enabling behavior extension without modifying core code: - **Plugin Architecture**: Add, remove, or modify behaviors without changing core code, making the system highly extensible - **Processing Pipeline**: Middleware processes commands and state updates in sequence, allowing for validation, transformation, and side effects - **Configurable**: Each middleware can be enabled/disabled and configured at runtime, providing flexibility - **Async Support**: Middlewares can perform asynchronous operations like API calls or validations Learn more in the [Middlewares documentation](/docs/guides/middlewares). ### Data Model The foundation that stores diagram state and provides the data layer: - **Nodes**: Visual elements with position, data, and behavior that represent entities in your diagram. See [Nodes documentation](/docs/guides/nodes/nodes) for details. - **Edges**: Connections between nodes with routing and styling that represent relationships. See [Edges documentation](/docs/guides/edges/edges) for details. - **Metadata**: Viewport state, middleware configurations, and other settings that control diagram behavior The default Signal Model uses Angular signals for reactive state management, providing excellent performance and real-time updates. For advanced use cases, custom model adapters can integrate with external data sources like databases or APIs. Learn more in the [State Management documentation](/docs/guides/state-management). --- ## Coordinate System > Understanding the coordinate system used in ngDiagram URL: https://ngdiagram.dev/docs/intro/coordinate-system/ NgDiagram uses a coordinate system that enables precise positioning of all diagram elements. Understanding this system is crucial for creating accurate diagrams and implementing custom behaviors. ## Diagram Origin The diagram has a **global coordinate system** with its origin at the top-left corner of the diagram container. This origin serves as the reference point for all positioning calculations. ### Key Characteristics - **Origin Point**: (0, 0) is located at the top-left corner of the diagram container - **Positive X**: Moving the viewport to the right increases values - **Positive Y**: Moving the viewport down increases values - **Units**: All coordinates are in pixels - Negative values are supported > In other words, as you drag the diagram right or down, the coordinates of elements increase along the X and Y axes. ## Element Positioning ### Nodes Nodes are positioned using **absolute coordinates** relative to the diagram origin: **Positioning Behavior:** - The [`position`](/docs/api/types/model/simplenode#position) property defines the top-left corner of the node - Nodes are positioned using CSS `transform: translate(x, y)` - Position is independent of the node's size or content ### Ports Ports have **absolute positioning** within their parent node: **Default Side Positioning:** - **Left side**: `top: 50%, left: 0` (center of left edge) - **Right side**: `top: 50%, left: 100%` (center of right edge) - **Top side**: `top: 0, left: 50%` (center of top edge) - **Bottom side**: `top: 100%, left: 50%` (center of bottom edge) **Custom Positioning:** Ports can be positioned anywhere within the node using CSS properties: ```html ``` ### Groups Groups follow the same positioning rules as regular nodes: **Group Behavior:** - Groups are positioned the same as nodes - at their top-left corner - Child nodes within groups retain their global positions - their coordinates are not recalculated or adjusted when added to a group - When a group moves, all its children move with it ### Edge Labels Edge labels are positioned using **absolute coordinates** along the edge path: ```typescript { id: 'label1', positionOnEdge: 0.5, // 50% along the edge path (0 = start, 1 = end) position: { x: 0, y: 0 }, // Absolute position relative to viewport's origin (calculated automatically) // ... other properties } ``` **Label Positioning:** - [`positionOnEdge`](/docs/api/types/model/edgelabel#positiononedge): Value from 0 to 1 indicating position along the edge - [`position`](/docs/api/types/model/edgelabel#position): Absolute coordinates calculated by the system - Labels are positioned using `transform: translate(x, y) translate(-50%, -50%)` for center alignment ## Viewport and Scaling ### Viewport Coordinates The viewport represents the visible area of the diagram: ### Coordinate Transformations The [`NgDiagramViewportService`](/docs/api/services/ngdiagramviewportservice) offers methods for converting between different coordinate systems in ngDiagram: **Client to Flow Position:** ```typescript // Convert screen coordinates to diagram coordinates const flowPosition = viewportService.clientToFlowPosition({ x: 150, y: 200 }); ``` **Flow to Client Position:** ```typescript // Convert diagram coordinates to screen coordinates const clientPosition = viewportService.flowToClientPosition({ x: 100, y: 150 }); ``` ### Reading Viewport Data Use the [`NgDiagramViewportService`](/docs/api/services/ngdiagramviewportservice) to access viewport information reactively: **Available Viewport Properties:** - [`x`](/docs/api/types/model/viewport#x), [`y`](/docs/api/types/model/viewport#y): Current pan offset - [`scale`](/docs/api/types/model/viewport#scale): Current zoom level - [`width`](/docs/api/types/model/viewport#width), [`height`](/docs/api/types/model/viewport#height): Viewport dimensions
--- ## MCP Server > Connect AI assistants to ng-diagram documentation and API reference using the Model Context Protocol URL: https://ngdiagram.dev/docs/intro/mcp/ The [ng-diagram MCP server](https://www.npmjs.com/package/@ng-diagram/mcp) connects AI assistants to ng-diagram's documentation and public API. Instead of switching to a browser to look things up, you can ask your AI assistant directly: - _"How do I create custom nodes?"_ - _"What's the signature of `DiagramComponent`?"_ - _"Show me the palette guide"_ The AI searches the docs and API reference behind the scenes and answers with actual documentation content. ## What is MCP? [MCP](https://modelcontextprotocol.io) is an open standard that lets AI assistants access external data sources. The ng-diagram MCP server exposes four tools: - **`search_docs`** - search documentation sections by keyword - **`get_doc`** - retrieve a full documentation page - **`search_symbols`** - search public API symbols (classes, interfaces, functions, types) - **`get_symbol`** - get full details for a specific API symbol ## Setup Add the server to your MCP client config - no installation required: **macOS / Linux:** ```json { "mcpServers": { "ng-diagram-docs": { "command": "npx", "args": ["-y", "@ng-diagram/mcp"] } } } ``` **Windows:** ```json { "mcpServers": { "ng-diagram-docs": { "command": "cmd", "args": ["/c", "npx", "-y", "@ng-diagram/mcp"] } } } ``` Restart your AI assistant after updating the config, then verify by asking i.e.: _"Search the ng-diagram docs for palette"_. ### Config file locations | Client | Config file | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Claude Code | `.mcp.json` in project root (project) or `~/.claude.json` (user) | | Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS), `%APPDATA%\Roaming\Claude\claude_desktop_config.json` (Windows), `~/.config/claude-desktop/claude_desktop_config.json` (Linux) | | Cursor | `.cursor/mcp.json` in project root (project) or `~/.cursor/mcp.json` (global) | | Windsurf | `~/.codeium/windsurf/mcp_config.json` | ## How It Works The AI assistant uses a two-step pattern - **search**, then **retrieve**: 1. AI calls `search_docs("palette")` or `search_symbols("Component")` to find matches 2. AI calls `get_doc("guides/palette.mdx")` or `get_symbol("NgDiagramComponent")` to get full content 3. AI synthesizes the answer for you All documentation and API data is bundled into the npm package - no network calls are made at query time. ## Learn More - [**@ng-diagram/mcp** on npm](https://www.npmjs.com/package/@ng-diagram/mcp) - full API reference and setup details - [**Source code**](https://github.com/synergycodes/ng-diagram/tree/main/tools/mcp-server) - implementation and developer guide --- ## Overview > Essential concepts of ngDiagram - understand the library without diving deep into documentation URL: https://ngdiagram.dev/docs/intro/overview/ A comprehensive overview of ngDiagram's core concepts, helping you understand the library's capabilities without reading the entire documentation. ## Getting Started The simplest way to start is by installing the library, importing the required styles, and creating a component with the [`NgDiagramComponent`](/docs/api/components/ngdiagramcomponent) and [`provideNgDiagram()`](/docs/api/utilities/providengdiagram) in its providers. The diagram component needs a model with nodes and edges to display. [Quick Start Guide](/docs/intro/quick-start) for step-by-step setup ## Model & Data ngDiagram uses a reactive model to manage diagram state. You initialize the model with nodes and edges, each having required properties like ID and position. The model is the single source of truth for your diagram's data. **Key concepts:** - Initialize model with [`initializeModel()`](/docs/api/utilities/initializemodel) - Nodes require: [`id`](/docs/api/types/model/simplenode#id), [`position`](/docs/api/types/model/simplenode#position), [`data`](/docs/api/types/model/simplenode#data) - Edges require: [`id`](/docs/api/types/model/edge#id), [`source`](/docs/api/types/model/edge#source), [`target`](/docs/api/types/model/edge#target), [`data`](/docs/api/types/model/edge#data). Optionally specify [`sourcePort`](/docs/api/types/model/edge#sourceport) and [`targetPort`](/docs/api/types/model/edge#targetport) -omitting them creates [floating edges](/docs/guides/edges/floating-edges) that connect to node borders instead - Custom properties can be stored in the `data` field of [`nodes`](/docs/api/types/model/simplenode/#data) and [`edges`](/docs/api/types/model/edge/#data) - Use [`metadata`](/docs/api/types/model/metadata) for diagram-level custom information You can also implement custom model adapters to connect to external data sources like databases or real-time services. Use [`initializeModelAdapter()`](/docs/api/utilities/initializemodeladapter) to wire up a custom [`ModelAdapter`](/docs/api/types/model/modeladapter/) for use with ngDiagram. [State Management →](/docs/guides/state-management) | [Custom Model Example →](/docs/examples/custom-model) | [Model initialization →](/docs/guides/model-initialization/) ## Service Isolation Every diagram requires [`provideNgDiagram()`](/docs/api/utilities/providengdiagram) in its component's providers array, which supplies all necessary services with proper scope isolation. This architecture allows you to have multiple independent diagrams on the same page, each with its own state and services. **Benefits:** - Isolated service instances per diagram - Independent state management - Multiple diagrams on one page - No conflicts between instances [Architecture Documentation →](/docs/intro/architecture) ## Nodes ngDiagram provides default nodes that work out of the box with built-in features like selection, dragging, and ports. Default nodes display a label and have standard connection points. **Default node features:** - Automatic rendering with label (shows node data label or falls back to node ID) - Built-in selection and hover states - Drag to reposition - Two bidirectional connection ports (left and right) - Resize handles - Rotation handle - Automatic port hover indicators - Automatic sizing by default ([`autoSize: true`](/docs/api/types/model/simplenode#autosize)) - nodes resize to fit their content For specific requirements, you can create custom nodes with any Angular template, form controls, or visual elements you need. **Components for custom nodes:** - [`NgDiagramPortComponent`](/docs/api/components/ngdiagramportcomponent) - Define custom ports with specific IDs, sides, and connection types - [`NgDiagramNodeResizeAdornmentComponent`](/docs/api/components/ngdiagramnoderesizeadornmentcomponent) - Add resize handles to custom nodes - [`NgDiagramNodeRotateAdornmentComponent`](/docs/api/components/ngdiagramnoderotateadornmentcomponent) - Add rotation handle to custom nodes - [`NgDiagramNodeSelectedDirective`](/docs/api/directives/ngdiagramnodeselecteddirective) - Apply selection styling to custom nodes [Nodes Documentation →](/docs/guides/nodes/nodes) | [Custom Nodes →](/docs/guides/nodes/custom-nodes) ## Groups Groups are special nodes that can contain other nodes, helping organize complex diagrams into logical sections. They support nesting and group-aware interactions. **Group capabilities:** - Container for other nodes - Nested groups support - Visual hierarchy - Group-aware dragging - [`NgDiagramGroupHighlightedDirective`](/docs/api/directives/ngdiagramgrouphighlighteddirective) - Apply highlight styling to custom group nodes during drag-over operations [Groups Documentation →](/docs/guides/nodes/groups) ## Edges Edges connect nodes through ports. Default edges automatically calculate paths between nodes and support different routing algorithms. Like nodes, you can create custom edge templates for specialized visualizations. **Edge features:** - Automatic path calculation - Three routing modes (orthogonal, straight, bezier) - Labels support (default edges support labels out of the box) - Custom arrowheads (customizable using SVG markers) - Custom edge templates - Selection and hover states - [Floating edges](/docs/guides/edges/floating-edges) - edges that connect to node borders instead of fixed ports [Edges Documentation →](/docs/guides/edges/edges) | [Custom Edges →](/docs/guides/edges/custom-edges) ## Ports Ports define where edges can connect to nodes. Default nodes have two ports (left and right), but you can define custom ports with specific positions and connection rules in custom node templates. **Port system:** - Default ports: [`port-left`](/docs/api/types/model/port#id), [`port-right`](/docs/api/types/model/port#id) (bidirectional) - Four possible [`sides`](/docs/api/types/model/portside): `top`, `right`, `bottom`, `left` - Three connection [`types`](/docs/api/types/model/port#type): `source` (outgoing only), `target` (incoming only), `both` (bidirectional) - Custom port positions and IDs in custom node templates - Visual hover indicators when dragging connections [Ports Documentation →](/docs/guides/nodes/ports) ## Viewport The viewport is the interactive space where all diagram elements are rendered and manipulated. It determines what part of the diagram is visible and supports navigation and scaling. **Viewport features:** - Zoom in/out for detail or overview - Pan to navigate large diagrams - All elements are positioned relative to the viewport's coordinate system [Viewport Features →](/docs/intro/coordinate-system/#viewport-and-scaling) ## Background The diagram background can display visual patterns to help with alignment and spatial awareness. The [`NgDiagramBackgroundComponent`](/docs/api/components/ngdiagrambackgroundcomponent) needs to be added to your diagram template to display the background. **Background capabilities:** - Built-in patterns: dots, grid with major/minor lines - Customizable via [`background`](/docs/api/types/configuration/features/backgroundconfig) configuration ([`dotSpacing`](/docs/api/types/configuration/features/backgroundconfig#dotspacing), [`cellSize`](/docs/api/types/configuration/features/backgroundconfig#cellsize), [`majorLinesFrequency`](/docs/api/types/configuration/features/backgroundconfig#majorlinesfrequency)) - Support for custom backgrounds via content projection - Automatically scales with viewport zoom [Background Documentation →](/docs/guides/background) ## Minimap The [``](/docs/api/components/ngdiagramminimapcomponent/) component provides a bird's-eye view of the diagram, showing all nodes and the current viewport position. It supports click-and-drag navigation to quickly pan to different areas. **Minimap features:** - Configurable position and size - Click-and-drag viewport navigation - Built-in zoom controls - Custom node styling via callback function or CSS variables - Custom node templates per node type - [`deferNodeUpdates`](/docs/api/components/ngdiagramminimapcomponent/#defernodeupdates) option to reduce overhead in large diagrams [Minimap Documentation →](/docs/guides/minimap) ## Labels and Arrowheads Custom edges can display labels for showing information along connections. You can add multiple labels with different positions in your custom edge templates. Arrowheads are customizable using SVG markers. **Visual enhancements:** - Edge labels in custom edges - Multiple labels per edge - Relative (percentage) and absolute (pixel) label positioning - Custom arrowhead designs - SVG-based customization for arrowheads [Labels Documentation →](/docs/guides/edges/labels) | [Arrowheads →](/docs/guides/edges/arrowheads) ## Interactions Nodes can be configured for different interaction modes. Enable resizing to allow users to change node dimensions, rotation for angular adjustments. Selection state is tracked automatically, but custom components need to implement visual feedback. **Interaction options:** - **Draggable**: Node dragging is enabled by default. Disable globally with [`nodeDraggingEnabled: false`](/docs/api/types/configuration/flowconfig#nodedraggingenabled) or per node with [`draggable: false`](/docs/api/types/model/simplenode#draggable) - **Resizable**: Enable resize handles on nodes by setting [`resizable: true`](/docs/api/types/model/simplenode#resizable) - **Rotatable**: Enable rotation handle on nodes by setting [`rotatable: true`](/docs/api/types/model/simplenode#rotatable) - **Selection**: Click to select nodes and edges - Custom nodes: Use [`NgDiagramNodeSelectedDirective`](/docs/api/directives/ngdiagramnodeselecteddirective) as hostDirective for selection styles - Custom edges: Use [`NgDiagramBaseEdgeComponent`](/docs/api/components/ngdiagrambaseedgecomponent) or implement selection styles manually - Default templates have selection styles built-in - **Box Selection**: Hold Shift and drag to select multiple nodes and edges within a rectangle - Configurable [`partialInclusion`](/docs/api/types/configuration/features/boxselectionconfig/#partialinclusion) and [`realtime`](/docs/api/types/configuration/features/boxselectionconfig/#realtime) behavior - Customizable appearance via CSS variables - **Copy/Paste**: Copy, cut, and paste diagram elements - Programmatic access via [`NgDiagramClipboardService`](/docs/api/services/ngdiagramclipboardservice) - **Keyboard Shortcuts**: All common actions have default keyboard bindings (copy, paste, delete, select all, arrow key movement, zoom, and more). Customize or disable shortcuts via [`configureShortcuts()`](/docs/api/utilities/configureshortcuts) with platform-aware modifier handling (Ctrl/Cmd) [Selection →](/docs/guides/nodes/selection) | [Box Selection →](/docs/guides/box-selection) | [Resizing →](/docs/guides/nodes/resizing) | [Rotation →](/docs/guides/nodes/rotation) | [Keyboard Shortcuts →](/docs/guides/shortcut-manager) ## Configuration Most diagram behavior is configurable through the config object passed to the diagram component. **Configurable aspects:** - [`background`](/docs/api/types/configuration/features/backgroundconfig) - Background dot spacing, cell size, and major lines frequency - [`boxSelection`](/docs/api/types/configuration/features/boxselectionconfig) - Box selection behavior (partial inclusion, real-time selection) - [`computeEdgeId`](/docs/api/types/configuration/flowconfig#computeedgeid) - Function to generate unique edge IDs - [`computeNodeId`](/docs/api/types/configuration/flowconfig#computenodeid) - Function to generate unique node IDs - [`debugMode`](/docs/api/types/configuration/flowconfig#debugmode) - Enable additional console logging - [`edgeRouting`](/docs/api/types/configuration/features/edgeroutingconfig) - Default routing algorithm (orthogonal, bezier, polyline) and routing-specific settings - [`grouping`](/docs/api/types/configuration/features/groupingconfig) - Rules for which nodes can be grouped together - [`linking`](/docs/api/types/configuration/features/linkingconfig) - Edge creation validation, snap distance, and custom edge builders - [`nodeRotation`](/docs/api/types/configuration/features/noderotationconfig) - Rotation snapping angles and default rotatable state - [`resize`](/docs/api/types/configuration/features/resizeconfig) - Minimum node size constraints and default resizable state - [`selectionMoving`](/docs/api/types/configuration/features/selectionmovingconfig) - Edge panning behavior when dragging near viewport edges - [`snapping`](/docs/api/types/configuration/features/snappingconfig) - Grid snapping for dragging and resizing with customizable snap points - [`zIndex`](/docs/api/types/configuration/features/zindexconfig) - Layer management for selected elements and edge-node relationships - [`zoom`](/docs/api/types/configuration/features/zoomconfig) - Min/max zoom levels, zoom step, and zoom-to-fit settings ## Services ngDiagram provides injectable services for all diagram operations. Services are the only way to safely update the model and control diagram behavior programmatically. Every mutating method returns a promise that resolves once the change has been applied to the model, so operations can be sequenced with `await` — see [Awaiting Changes](/docs/guides/state-management/#awaiting-changes). **Core services:** - [**NgDiagramService**](/docs/api/services/ngdiagramservice) - Diagram API access: - Config, events, transactions - Middleware registration - Routing management ([`registerRouting()`](/docs/api/services/ngdiagramservice#registerrouting), [`unregisterRouting()`](/docs/api/services/ngdiagramservice#unregisterrouting), [`getRegisteredRoutings()`](/docs/api/services/ngdiagramservice#getregisteredroutings)) - Programmatic linking ([`startLinking()`](/docs/api/services/ngdiagramservice#startlinking)) - Environment info ([`getEnvironment()`](/docs/api/services/ngdiagramservice#getenvironment)) - Measurement invalidation ([`invalidateMeasurements()`](/docs/api/services/ngdiagramservice#invalidatemeasurements)) - [**NgDiagramModelService**](/docs/api/services/ngdiagrammodelservice) - CRUD operations: - Nodes, edges, and metadata management - Model serialization ([`toJSON()`](/docs/api/services/ngdiagrammodelservice#tojson)) - Reactive signals for [`nodes`](/docs/api/services/ngdiagrammodelservice#nodes), [`edges`](/docs/api/services/ngdiagrammodelservice#edges), [`metadata`](/docs/api/services/ngdiagrammodelservice#metadata) - [**NgDiagramViewportService**](/docs/api/services/ngdiagramviewportservice) - Viewport control: - Zoom, pan, and positioning ([`zoomToFit()`](/docs/api/services/ngdiagramviewportservice#zoomtofit)) - Coordinate conversion ([`clientToFlowPosition()`](/docs/api/services/ngdiagramviewportservice#clienttoflowposition), [`flowToClientPosition()`](/docs/api/services/ngdiagramviewportservice#flowtoclientposition)) - Navigation helpers ([`centerOnNode()`](/docs/api/services/ngdiagramviewportservice#centeronnode), [`centerOnRect()`](/docs/api/services/ngdiagramviewportservice#centeronrect)) - [**NgDiagramSelectionService**](/docs/api/services/ngdiagramselectionservice) - Manage selection state for nodes and edges - [**NgDiagramNodeService**](/docs/api/services/ngdiagramnodeservice) - Node-specific operations (move, resize, rotate) - [**NgDiagramGroupsService**](/docs/api/services/ngdiagramgroupsservice) - Group/ungroup nodes and manage group hierarchies - [**NgDiagramClipboardService**](/docs/api/services/ngdiagramclipboardservice) - Copy/paste/cut operations for diagram elements Services use Angular signals for reactive state management, making it easy to build reactive UI components. [Services Documentation →](/docs/intro/services) ## Transactions Transactions batch multiple state changes into a single atomic operation, improving performance and ensuring consistency. Wrap operations in a transaction to apply all changes at once instead of triggering individual updates. **Transaction capabilities:** - Batch multiple add, remove, and update operations - Async transactions for server-fetched data - Awaitable — the transaction promise resolves once all batched changes are committed - [`waitForMeasurements`](/docs/api/types/middleware/transactionoptions/#waitformeasurements) option to wait for element dimensions before proceeding (e.g., before calling `zoomToFit()`); also available [directly on mutating methods](/docs/guides/transactions/#per-method-option) whose changes get measured - Deterministic operation order - additions before removals, edges removed before their nodes [Transactions Documentation →](/docs/guides/transactions) ## Events The diagram emits events for user interactions and state changes. Subscribe to these events to react to user actions or synchronize with external systems. **Available events:** - [`diagramInit`](/docs/api/types/events/diagraminitevent) - Fired when diagram is fully initialized with all nodes and edges measured - [`edgeDrawEnded`](/docs/api/types/events/edgedrawendedevent) - Fired when an edge draw gesture ends (success or cancel) - ~~[`edgeDrawn`](/docs/api/types/events/edgedrawnevent)~~ - Deprecated, use `edgeDrawEnded` instead - [`selectionChanged`](/docs/api/types/events/selectionchangedevent) - Fired when nodes/edges are selected or deselected - [`selectionGestureEnded`](/docs/api/types/events/selectiongestureendedevent) - Fired when a selection gesture completes (on pointerup after clicking, box selection, or select-all) - [`selectionMoved`](/docs/api/types/events/selectionmovedevent) - Fired continuously on each position change while selected nodes are being dragged - [`selectionRemoved`](/docs/api/types/events/selectionremovedevent) - Fired when selected nodes/edges are removed from the diagram - [`selectionRotated`](/docs/api/types/events/selectionrotatedevent) - Fired continuously on each angle change while selected nodes are being rotated - [`groupMembershipChanged`](/docs/api/types/events/groupmembershipchangedevent) - Fired when nodes are grouped or ungrouped - [`viewportChanged`](/docs/api/types/events/viewportchangedevent) - Fired when viewport is panned or zoomed - [`clipboardPasted`](/docs/api/types/events/clipboardpastedevent) - Fired when elements are pasted from clipboard - [`nodeResized`](/docs/api/types/events/noderesizedevent) - Fired continuously on each size change while a node is being resized - [`nodeResizeStarted`](/docs/api/types/events/noderesizestartedevent) - Fired when a node resize operation begins - [`nodeResizeEnded`](/docs/api/types/events/noderesizeendedevent) - Fired when a node resize operation ends - [`nodeRotateStarted`](/docs/api/types/events/noderotatestartedevent) - Fired when a node rotation operation begins - [`nodeRotateEnded`](/docs/api/types/events/noderotateendedevent) - Fired when a node rotation operation ends - [`nodeDragStarted`](/docs/api/types/events/nodedragstartedevent) - Fired when a node drag operation begins - [`nodeDragEnded`](/docs/api/types/events/nodedragendedevent) - Fired when a node drag operation ends - [`paletteItemDropped`](/docs/api/types/events/paletteitemdroppedevent) - Fired when a palette item is dropped onto the diagram Events can be subscribed to via `@Output` bindings on the [`ng-diagram`](/docs/api/components/ngdiagramcomponent) component or programmatically through [`NgDiagramService.addEventListener()`](/docs/api/services/ngdiagramservice#addeventlistener). ## Edge Routing Edges support multiple routing algorithms for different visual styles. You can control how edges are drawn between nodes using both automatic and manual approaches. **Built-in routing algorithms:** - **Orthogonal** - Right-angle paths between nodes - **Polyline** - Straight line segments between points - **Bezier** - Smooth curved connections with control points **Routing modes:** - **Auto mode** ([`routingMode: 'auto'`](/docs/api/types/model/edge#routingmode)) - Algorithm automatically calculates the path between nodes - **Manual mode** ([`routingMode: 'manual'`](/docs/api/types/model/edge#routingmode)) - You provide custom waypoints in the [`points`](/docs/api/types/model/edge#points) array, algorithm renders the path through your points Set routing per edge with the [`routing`](/docs/api/types/model/edge#routing) property, or globally through configuration with [`edgeRouting.defaultRouting`](/docs/api/types/configuration/features/edgeroutingconfig#defaultrouting). For complete custom routing algorithms, use [`NgDiagramService.registerRouting()`](/docs/api/services/ngdiagramservice#registerrouting). [Routing Documentation →](/docs/guides/edges/routing) ## Palette The palette system enables drag-and-drop node creation. Build your own palette container using the provided components to let users drag items onto the diagram. **Palette components:** - [`NgDiagramPaletteItemComponent`](/docs/api/components/ngdiagrampaletteitemcomponent) - Wrapper for draggable palette items - [`NgDiagramPaletteItemPreviewComponent`](/docs/api/components/ngdiagrampaletteitempreviewcomponent) - Live preview shown while dragging **Palette features:** - Drag-and-drop to create nodes at drop location - Custom item templates and preview templates - Support for creating both regular nodes and group nodes - Visual feedback with live preview during drag [Palette Documentation →](/docs/guides/palette) | [Palette Example →](/docs/examples/custom-node) ## Custom Middlewares ngDiagram uses a middleware system that allows you to intercept and modify any state changes. Register custom middleware via [`NgDiagramService.registerMiddleware()`](/docs/api/services/ngdiagramservice#registermiddleware) to override any aspect of the application and create low-level features. **Middleware capabilities:** - Intercept all state updates before they're applied - Modify or cancel operations - Add custom side effects - Implement complex business logic - Create custom behaviors and constraints [Middleware Documentation →](/docs/guides/middlewares) ## Virtualization For diagrams with hundreds or thousands of elements, virtualization renders only the nodes and edges visible within the current viewport. Elements are dynamically added and removed from the DOM as you pan and zoom. **Virtualization features:** - Configurable viewport padding and idle delay - Dramatically improved rendering performance for large diagrams - Seamless panning and zooming experience [Virtualization Documentation →](/docs/guides/virtualization) ## Touch Gestures ngDiagram supports touch devices out of the box, with gestures for all common interactions. **Supported gestures:** - **Pinch to zoom** - Two-finger pinch to scale the diagram - **Two-finger panning** - Move two fingers together to pan the view - **Long press for box selection** - Press and hold, then drag to select multiple elements - Standard tap, drag, resize, rotate, and linking interactions via single finger [Touch Gestures Documentation →](/docs/guides/touch-gestures) ## Styling System ngDiagram provides a comprehensive CSS variable system for theming and customization. You can override colors, borders, and other visual properties to match your application's design. [Styling Guide →](/docs/intro/styling) --- Explore our [Examples](/docs/examples) to see these concepts in action. --- ## Need a hand getting started? > How to install and set up ngDiagram in your Angular project URL: https://ngdiagram.dev/docs/intro/quick-start/ Get up and running with ngDiagram in minutes. This guide will help you create your first interactive diagram. ## Installation ```bash npm install ng-diagram ``` ## Import Styles ```css @import 'ng-diagram/styles.css'; ``` ## Create Your First Diagram ```typescript @Component({ imports: [NgDiagramComponent], providers: [provideNgDiagram()], template: ` `, styles: ` :host { display: flex; height: 300px; } `, }) export class AppComponent { model = initializeModel({ nodes: [ { id: '1', position: { x: 100, y: 150 }, data: { label: 'Node 1' } }, { id: '2', position: { x: 400, y: 150 }, data: { label: 'Node 2' } }, ], edges: [ { id: '1', source: '1', sourcePort: 'port-right', targetPort: 'port-left', target: '2', data: {}, }, ], }); } ``` That's it! You now have a working diagram with default node and edge templates.
## What's Next? Now that you have a basic diagram working, you can customize it to fit your specific needs. Here are the main areas you can explore: ### Understand the Library Get a comprehensive overview of ngDiagram's core concepts and capabilities: [Explore the Overview →](/docs/intro/overview) ### Customize Your Nodes Create custom node templates with your own styling, content, and interactive elements: [Learn about Custom Nodes →](/docs/guides/nodes/custom-nodes) | [See Example →](/docs/examples/custom-node) ### Create Custom Edges Design custom edge types with unique visual styles and routing: [Learn about Custom Edges →](/docs/guides/edges/custom-edges) | [See Example →](/docs/examples/custom-edge) ### Add a Palette Create a drag-and-drop interface for users to add nodes to your diagram: [Learn about Palette →](/docs/guides/palette) ### Persistence & State Management Save and restore your diagram state: [Learn about State Management →](/docs/guides/state-management) | [See Example →](/docs/examples/save-state) --- **Ready to dive deeper?** Start with [Custom Nodes](/docs/guides/nodes/custom-nodes) or explore our [Examples](/docs/examples) to see ngDiagram in action! --- ## Roadmap > What we are working on right now and what is next for ng-diagram URL: https://ngdiagram.dev/docs/intro/roadmap/ ngDiagram is stable and actively developed. Here's what we're working on right now - and what's next. Have a feature request? Join our [GitHub discussions](https://github.com/synergycodes/ng-diagram/discussions). ## Implementation Status
📋 To Do 🚧 In Progress ✅ Done

Accessibility

Keyboard navigation, focus management, and screen reader support

Hidden Elements

Hide nodes, edges, and ports without breaking measurement or layout

Awaitable Service Methods

Every mutating service call returns a promise you can await

Undo / Redo

Built-in history for diagram changes

Async Event Callbacks

Async support in diagram event callbacks

Resize Snap Offset

Snapping offset for node resize - a community request

Edge Reshaping

Interactive editing of edge paths and waypoints

Assembly Line Template

Demo app for assembly line diagrams

AV Schematic Template

Demo app for audio-video diagrams

Edge Relinking

Reconnect existing edges to other nodes and ports

Single-Line Diagram Template

Demo app for single-line electrical diagrams

Electric Circuit Template

Demo app for electrical circuit diagrams

Library Stabilization

Stable v1.0 release

Invalidate Measurements API

Method to invalidate node/edge measurements programmatically

Orgchart Template

Demo app for organizational charts

MCP Server

Model Context Protocol integration for AI assistants

Touch & Trackpad Input

Improved gesture handling

Minimap

Overview navigation widget

Angular 18 Support

Backwards compatibility for Angular 18 projects

Shortcut Manager

Centralized keyboard shortcut system

Additional Events

New hooks: model loaded, object removed, etc.

Lookup Helpers

Utilities like getConnectedEdges

Default Edge Labels

Label support for built-in edge types

Box Selection

Rectangular multi-select tool

Grid Background

Configurable grid pattern background

Direct Node Connections

Connect nodes without explicit ports

Port Labels

Additional content for port components

## Stay Updated - Check out the [changelog](/docs/changelog/) for detailed release notes - Watch our [GitHub repository](https://github.com/synergycodes/ng-diagram) for [releases](https://github.com/synergycodes/ng-diagram/releases) - Join our community [discussions](https://github.com/synergycodes/ng-diagram/discussions) for feature requests and feedback --- ## Services > Comprehensive guide to ngDiagram services and their usage URL: https://ngdiagram.dev/docs/intro/services/ ngDiagram provides a rich set of injectable services that give you programmatic control over different aspects of your diagram. These services are designed with specific responsibilities and can be combined to build powerful diagram interactions. ## Core Services ### NgDiagramService The main orchestration service that provides access to the action state and middleware management. This is your gateway to advanced diagram control. [API Documentation →](/docs/api/services/ngdiagramservice) **Key Capabilities:** - Manage middleware registration and configuration - Access action state and environment information - Manage edges routing - Manage event listeners - [Invalidate element measurements](/docs/guides/nodes/ports#port-measurement) after CSS-driven position changes **Usage Example:** ```typescript @Component({ selector: 'app-toolbar', template: ` `, }) export class ToolbarComponent { private diagramService = inject(NgDiagramService); toggleMiddleware() { // Update configuration this.diagramService.updateConfig({ zIndex: { enabled: true } }); } } ``` ### NgDiagramModelService Handles all model-related operations including node and edge updates, spatial queries, and direct access to the underlying data model. [API Documentation →](/docs/api/services/ngdiagrammodelservice) **Key Capabilities:** - Update node and edge data - Perform spatial queries to find nearby elements - Access nodes, edges, and metadata as reactive signals - Find elements by ID Every mutating method returns a promise that resolves once the change has been applied to the model, so operations can be sequenced with `await` — see [Awaiting Changes](/docs/guides/state-management/#awaiting-changes). **Usage Example:** ```typescript @Component({ selector: 'app-properties-panel', template: ` @if (hasNodes()) {

Total nodes: {{ nodeCount() }}

Total edges: {{ edgeCount() }}

} `, }) export class PropertiesPanelComponent { private modelService = inject(NgDiagramModelService); // Reactive access to model data nodes = this.modelService.nodes; edges = this.modelService.edges; metadata = this.modelService.metadata; // Computed signals nodeCount = computed(() => this.nodes().length); edgeCount = computed(() => this.edges().length); hasNodes = computed(() => this.nodeCount() > 0); updateSelectedNode() { // Update node data this.modelService.updateNodeData('node-1', { label: 'Updated Label', color: '#ff0000', }); // Update node properties this.modelService.updateNode('node-1', { x: 150, y: 200, width: 120, height: 80, }); } findNearbyNodes() { // Spatial query to find nodes near a point const nearbyNodes = this.modelService.getNodesInRange( { x: 100, y: 100 }, 150 // range in pixels ); console.log('Found nearby nodes:', nearbyNodes); } } ``` ### NgDiagramViewportService Manages viewport operations, coordinate transformations, and provides reactive access to zoom and pan state. [API Documentation →](/docs/api/services/ngdiagramviewportservice) **Key Capabilities:** - Reactive viewport position and scale signals - Convert between client and flow coordinates - Programmatic zoom and pan operations **Usage Example:** ```typescript @Component({ selector: 'app-viewport-controls', template: `

Zoom: {{ zoomPercentage() }}%

Position: {{ position() }}

`, }) export class ViewportControlsComponent { private viewportService = inject(NgDiagramViewportService); // Reactive viewport data viewport = this.viewportService.viewport; scale = this.viewportService.scale; // Computed values for display zoomPercentage = computed(() => Math.round(this.scale() * 100)); position = computed(() => { const vp = this.viewport(); return `(${Math.round(vp.x)}, ${Math.round(vp.y)})`; }); zoomIn() { const currentScale = this.scale(); this.viewportService.zoom(currentScale * 1.2); } zoomOut() { const currentScale = this.scale(); this.viewportService.zoom(currentScale * 0.8); } centerView() { this.viewportService.moveViewport(0, 0); } resetZoom() { this.viewportService.zoom(1); } // Coordinate conversion examples // onMouseClick(event: MouseEvent) { // Convert click position to diagram coordinates const flowPosition = this.viewportService.clientToFlowPosition({ x: event.clientX, y: event.clientY, }); console.log('Clicked at diagram position:', flowPosition); } } ``` ## Selection and Interaction Services ### NgDiagramSelectionService Manages the selection state of nodes and edges, providing both reactive access to current selection and methods to modify it. [API Documentation →](/docs/api/services/ngdiagramselectionservice) **Key Capabilities:** - Reactive selection state with nodes and edges - Select/deselect individual or multiple elements - Clear all selections **Usage Example:** ```typescript @Component({ selector: 'app-selection-toolbar', template: `

Selected: {{ selectionSummary() }}

@if (hasSelection()) {
} `, }) export class SelectionToolbarComponent { private selectionService = inject(NgDiagramSelectionService); private modelService = inject(NgDiagramModelService); // Reactive selection data selection = this.selectionService.selection; // Computed selection info hasSelection = computed(() => { const sel = this.selection(); return sel.nodes.length > 0 || sel.edges.length > 0; }); selectionSummary = computed(() => { const sel = this.selection(); return `${sel.nodes.length} nodes, ${sel.edges.length} edges`; }); selectAll() { // Select specific nodes and edges this.selectionService.select(['node-1', 'node-2'], ['edge-1']); } clearSelection() { this.selectionService.deselectAll(); } deleteSelected() { // Delete all currently selected elements this.selectionService.deleteSelection(); } // Programmatic selection based on criteria selectByType(nodeType: string) { const nodes = this.modelService.nodes(); const matchingIds = nodes.filter((node) => node.data?.type === nodeType).map((node) => node.id); this.selectionService.select(matchingIds); } } ``` ### NgDiagramClipboardService Handles copy, cut, and paste operations for diagram elements with support for position-aware pasting. [API Documentation →](/docs/api/services/ngdiagramclipboardservice) **Key Capabilities:** - Copy selected elements to clipboard - Cut elements (copy + delete) - Paste elements at specific positions **Usage Example:** ```typescript @Component({ selector: 'app-context-menu', template: `
`, }) export class ContextMenuComponent { private clipboardService = inject(NgDiagramClipboardService); private viewportService = inject(NgDiagramViewportService); menuPosition = input.required(); copy() { this.clipboardService.copy(); this.closeMenu(); } cut() { this.clipboardService.cut(); this.closeMenu(); } paste(event: MouseEvent) { // Convert mouse position to diagram coordinates const position = this.viewportService.clientToFlowPosition({ x: event.clientX, y: event.clientY, }); // Paste at the clicked position this.clipboardService.paste(position); this.closeMenu(); } private closeMenu() { // Close menu logic } } ``` ## Specialized Services ### NgDiagramNodeService Provides node-specific operations with focus on transformations. [View API Documentation →](/docs/api/services/ngdiagramnodeservice) **Key Capabilities:** - Node-specific transformations **Usage Example:** ```typescript @Component({ selector: 'app-custom-node', template: `

{{ node().data?.title }}

@for (port of node().ports; track port.id) {
}
`, }) export class CustomNodeComponent { private nodeService = inject(NgDiagramNodeService); node = input.required(); handleClick() { // Bring node to front when clicked this.nodeService.bringToFront([this.node().id]); } handleDoubleClick() { // Rotate node on double click this.nodeService.rotateNodeTo(this.node().id, 45); } onResize(newSize: Size) { // Handle node resizing this.nodeService.resizeNode(this.node().id, newSize); } } ``` --- ## Designing the look and feel of your diagram? > How to style and customize ngDiagram components URL: https://ngdiagram.dev/docs/intro/styling/ ngDiagram provides a **default** well-structured design system with a clear separation of concerns. Its styling is based on a minimal yet sufficient set of primitives, tokens, and component-level variables that support consistent theming and easy customization across all library components. In addition to the design system, the library includes components, directives, and CSS classes to help you build consistent and interactive diagram interfaces. ## Design System Architecture The styling system consists of three distinct layers: ### Primitives Base color values and fundamental design tokens defined in `primitives`. These are the foundation colors that power the entire design system: ```css :root { /* Gray scale */ --ngd-colors-gray-100: /* white */; --ngd-colors-gray-200: /* near white */; --ngd-colors-gray-300: /* light gray */; --ngd-colors-gray-400: /* medium light gray */; --ngd-colors-gray-450: /* medium gray light */; --ngd-colors-gray-500: /* medium gray */; --ngd-colors-gray-600: /* medium dark gray */; --ngd-colors-gray-650: /* dark gray */; --ngd-colors-gray-700: /* darker gray */; --ngd-colors-gray-800: /* darkest gray */; --ngd-colors-gray-900-5: /* near black with 5% opacity */; --ngd-colors-gray-900-20: /* near black with 20% opacity */; --ngd-colors-gray-900-50: /* near black with 50% opacity */; /* Primary accent */ --ngd-colors-acc1-400: /* primary accent light */; --ngd-colors-acc1-500: /* primary accent */; --ngd-colors-acc1-500-40: /* primary accent with 40% opacity */; --ngd-colors-acc1-500-50: /* primary accent with 50% opacity */; --ngd-colors-acc1-600: /* primary accent dark */; /* Secondary accent */ --ngd-colors-acc4-500: /* secondary accent */; } ``` ### Tokens Semantic design tokens that map primitives to specific use cases, supporting themes: ```css :root { --ngd-node-bg-primary-default: var(--ngd-colors-gray-100); --ngd-node-stroke-primary-default: var(--ngd-colors-gray-400); --ngd-node-stroke-primary-hover: var(--ngd-colors-acc1-500); /* ... more tokens */ } html[data-theme='dark'] { --ngd-node-bg-primary-default: var(--ngd-colors-gray-700); --ngd-node-stroke-primary-default: var(--ngd-colors-gray-600); --ngd-node-stroke-primary-hover: var(--ngd-colors-acc1-400); /* ... more tokens */ } ``` ### Component Variables Component-specific CSS variables that use tokens for consistent styling: ```css :root { --ngd-node-background-color: var(--ngd-node-bg-primary-default); --ngd-node-border-color: var(--ngd-node-stroke-primary-default); --ngd-node-border-color-hover: var(--ngd-node-stroke-primary-hover); /* ... more component variables */ } ``` ## Theming ### Default Themes ngDiagram supports both light and dark themes **out of the box by default**: - **Light theme** - Applied by default (no HTML attribute needed) - **Dark theme** - Applied when `data-theme="dark"` is set on the `html` element ```html ``` ### Customization #### Global Color Override To quickly adapt to your design system, override primitives: ```css :root { --ngd-colors-acc1-500: #your-primary-color; --ngd-colors-gray-500: #your-gray-color; /* Override other primitives as needed */ } ``` #### Per-Component For precise control, override component variables: ```css :root { --ngd-node-border-radius: 0.5rem; --ngd-node-border-size: 0.125rem; --ngd-group-border-radius: 1rem; /* Customize specific component properties */ } ``` ## Utility Classes ### Port Highlighting #### `.ng-diagram-port-hoverable-over-node` Applied to node containers. When the cursor hovers over the node, all ports are highlighted with the default node styling. #### `.ng-diagram-port-hoverable` Applied to node containers as well. The port is highlighted only when the cursor hovers directly over it. ```html
``` ## Directives Directives require access to node/group data. When used outside of node templates, they won't work. For manual control, use CSS classes instead. ### NgDiagramNodeSelectedDirective Automatically adds selection styling based on the node's [`selected`](/docs/api/types/model/simplenode/#selected) property: ```html
``` **Applied styling:** - Adds `ng-diagram-node-selected` class when [`selected`](/docs/api/types/model/simplenode/#selected) is `true` - Provides focus ring and outline styling - Works for both nodes and groups ### NgDiagramGroupHighlightedDirective Adds highlight styling to groups based on the `highlighted` property: ```html
``` **Applied styling:** - Adds `ng-diagram-group-highlight` class when [`highlighted`](/docs/api/types/model/groupnode/#highlighted) is `true` - Provides inner outline and background highlight - Indicates when dragging elements can be added to the group ### Manual CSS Classes For cases where directives can't be used (outside node templates), you can apply styling manually: - `ng-diagram-node-selected` - `ng-diagram-group-highlight` ```html
``` ## Best Practices 1. **Use primitives for global color changes** - Override `--ngd-colors-*` variables for brand consistency 2. **Use component variables for specific adjustments** - Override `--ngd-*` variables for precise control 3. **Leverage utility classes** - Use provided classes for consistent behavior 4. **Use directives for visual state management** - Let directives handle selection and highlight states 5. **Maintain layer separation** - Use component variables instead of applying primitives or tokens directly within components. --- # Guides ## Background > Example of how to set a background in ngDiagram URL: https://ngdiagram.dev/docs/guides/background/ The background of your diagram canvas can be easily customized in ngDiagram.\ You can use the built-in patterns of the background component (`dots`, `grid`), set a solid color via CSS, or provide your own custom background. ## Available Background Types ### Solid Color You can set a solid color background by overriding the background color of the diagram container. To do this, simply override the CSS variable or set the background style directly on the [`ng-diagram`](/docs/api/components/ngdiagramcomponent/) component. To use solid background, you don't need to add the [``](/docs/api/components/ngdiagrambackgroundcomponent/) component. **Example:** ```css --ngd-diagram-background-color: darkgray; ``` or ```css ng-diagram { background: darkgray; /* Your desired color */ } ``` ### Grid Background The **grid** background displays a grid pattern with minor and major lines. Grid backgrounds are commonly used in design, industry, and technical diagramming applications to provide a visual reference for layout and spacing. Our grid pattern is fully customizable, allowing you to adjust preferences. **Usage:** ```html ``` **Configurable settings:** - **Minor cell size**: Size of the smallest grid cell (used for minor grid lines). Controlled via the diagram config [BackgroundConfig.cellSize](/docs/api/types/configuration/features/backgroundconfig/#cellsize) - **Major line frequency**: How often a major line appears [BackgroundConfig.majorLinesFrequency](/docs/api/types/configuration/features/backgroundconfig/#majorlinesfrequency) - **Line colors, widths, and opacity**: Controlled via CSS variables. **CSS Variables:** ```css :root { --ngd-background-line-minor-color: #c2c0c0; /* Color of minor grid lines */ --ngd-background-line-major-color: #6f7480; /* Color of major grid lines */ --ngd-background-line-minor-width: 0.5; /* Width of minor grid lines */ --ngd-background-line-major-width: 1; /* Width of major grid lines */ --ngd-background-line-minor-opacity: 0.5; /* Opacity of minor grid lines */ --ngd-background-line-major-opacity: 0.6; /* Opacity of major grid lines */ } ``` ### Dotted Background The **dotted** background displays a repeating pattern of dots. This is the default background type. **Usage:** ```html ``` **Configurable settings:** - **Dot spacing**: Controlled via the diagram config [BackgroundConfig.dotSpacing](/docs/api/types/configuration/features/backgroundconfig/#dotspacing) - **Dot color**: Controlled via CSS variable. **CSS Variables:** ```css :root { --ngd-background-dot-color: #6f7480; /* Dot color */ } ``` ### Custom Background You can provide any custom SVG, HTML, or image as the background by projecting content into the [``](/docs/api/components/ngdiagrambackgroundcomponent/) component. When you apply a custom background, it will completely replace any built-in patterns. **Usage:** ```html ``` Custom background will be stretched to cover the entire diagram area. Such background would not be panned or zoomed along with the diagram content. You can write a custom logic to achieve that if needed. ## Example --- --- ## Box Selection > Selecting multiple nodes using box selection in ngDiagram URL: https://ngdiagram.dev/docs/guides/box-selection/ The **box selection** feature in ngDiagram allows users to select multiple nodes and edges on the canvas by drawing a rectangle around them. ## Usage To activate box selection, hold down the `Shift` key and click and drag on the canvas. If two selected nodes are connected by an edge, the edge will also be included in the selection. ## Configuration Box selection behavior can be configured via the [`boxSelection`](/docs/api/types/configuration/features/boxselectionconfig/) property. Available options: - [`partialInclusion`](/docs/api/types/configuration/features/boxselectionconfig/#partialinclusion): If set to `true`, nodes that are partially within the selection rectangle will be included in the selection. Default: `true` - [`realtime`](/docs/api/types/configuration/features/boxselectionconfig/#realtime): If set to `true`, the selection rectangle will update the selection in real-time as the user drags the mouse. If `false` the selection will happen after releasing the mouse button. Default: `true` [Read more about global configuration in ngDiagram →](/docs/guides/configuration/) ## Customization You can customize the appearance of the box selection rectangle by using predefined CSS variables:
## Touch Devices On touch devices, box selection is triggered by a long press gesture instead of holding `Shift`. Press and hold on the canvas, then drag to create a selection box. [Learn more about touch gestures →](/docs/guides/touch-gestures/) --- ## Arrowheads > Understanding how arrowheads work in NgDiagram URL: https://ngdiagram.dev/docs/guides/edges/arrowheads/ Arrowheads in NgDiagram are visual markers that indicate the start or end of the edge. They are implemented using SVG markers and can be applied to either the source end [`sourceArrowhead`](/docs/api/types/model/edge/#sourcearrowhead) or target end [`targetArrowhead`](/docs/api/types/model/edge/#targetarrowhead) of an edge. ## Default Arrowhead NgDiagram provides a built-in arrowhead called `ng-diagram-arrow` that can be used out of the box. This default arrowhead is an outlined arrow with rounded edges that adapts to the edge's stroke color.
To use the default arrowhead, specify it in your edge configuration: ## Custom Arrowhead You can create custom arrowheads by defining SVG markers with unique IDs. Custom arrowheads allow you to create distinctive visual styles that match your application's design requirements.
Custom arrowheads need to be defined as SVG `` elements within a `` section. Each marker needs a unique ID that you'll reference in your edge configuration: When marker is defined in the SVG `` section, it can be referenced in your edge configuration to apply the custom arrowhead to the edge. See [``](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/marker) documentation on MDN for more details. ## Overriding arrowheads in Custom Edges When implementing custom edges, you can override the default arrowhead with a custom one by specifying the [`sourceArrowhead`](/docs/api/components/ngdiagrambaseedgecomponent/#sourcearrowhead) and [`targetArrowhead`](/docs/api/components/ngdiagrambaseedgecomponent/#targetarrowhead) inputs of [`NgDiagramBaseEdgeComponent`](/docs/api/components/ngdiagrambaseedgecomponent). Thanks to it you don't have to specify the arrowhead in the data of each edge. [Custom Edges →](/docs/guides/edges/custom-edges) --- ## Designing custom edge templates? > How to create and implement custom edges in ngDiagram URL: https://ngdiagram.dev/docs/guides/edges/custom-edges/ When ngDiagram's default edge customizations are not sufficient, you can create custom edges that provide more precise control over edge rendering, including routing. You can create a custom edge by writing a component that implements the [`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate) interface and renders [`NgDiagramBaseEdgeComponent`](/docs/api/components/ngdiagrambaseedgecomponent) in its template. ## Registration Custom edge types need to be registered in the [`edgeTemplateMap`](/docs/api/components/ngdiagramcomponent/#edgetemplatemap) and passed to the [`ngDiagram`](/docs/api/components/ngdiagramcomponent) component. After registering the custom edge, you can use it in your diagram model by specifying the [`type`](/docs/api/types/model/edge/#type) property of the edge. :::tip[Using Custom Edges for User-Created Edges] By default, edges created via linking use the default edge template and routing. To use your custom edge type for edges created by users, set the `type` property in [`finalEdgeDataBuilder`](/docs/api/types/configuration/features/linkingconfig/#finaledgedatabuilder) (and optionally [`temporaryEdgeDataBuilder`](/docs/api/types/configuration/features/linkingconfig/#temporaryedgedatabuilder) for the preview edge): ```typescript config: NgDiagramConfig = { linking: { finalEdgeDataBuilder: (defaultEdge) => ({ ...defaultEdge, type: 'custom', // use the custom edge template registered above }), }, }; ``` [Read more about customizing user-created edges →](/docs/guides/edges/edges/#user-created-edges) ::: ## Styling Custom Edges Custom edges can be styled using CSS variables that the [`NgDiagramBaseEdgeComponent`](/docs/api/components/ngdiagrambaseedgecomponent) exposes. This approach provides a clean way to customize edge appearance without breaking encapsulation. ### Available CSS Variables - `--edge-stroke` - Stroke color - `--edge-stroke-width` - Stroke width - `--edge-stroke-opacity` - Stroke opacity - `--edge-stroke-dasharray` - Stroke dash pattern (e.g., `5 5` for dashed line) - `--edge-stroke-transition` - Transition for stroke changes (e.g., `stroke 0.1s ease-in-out`) ### Example: Styled Custom Edge ```scss ng-diagram-base-edge { --edge-stroke: #334155; --edge-stroke-width: 2; --edge-stroke-dasharray: 5 5; // Dashed line } ng-diagram-base-edge.selected { --edge-stroke: #3b82f6; --edge-stroke-width: 3; --edge-stroke-dasharray: 8 4; // Different dash pattern when selected } ng-diagram-base-edge:hover:not(.selected) { --edge-stroke: #64748b; } ``` ### Alternative: Component Inputs You can also pass styling properties directly to the [`NgDiagramBaseEdgeComponent`](/docs/api/components/ngdiagrambaseedgecomponent): ```typescript @Component({ selector: 'custom-edge', template: ``, imports: [NgDiagramBaseEdgeComponent], }) export class CustomEdgeComponent implements NgDiagramEdgeTemplate { edge = input.required(); } ``` ## Custom Routing Custom routing is an extensible mechanism that allows you to create sophisticated edge paths tailored to your specific needs. You can implement custom routing algorithms, create dynamic paths based on node positions, or define manual waypoints for precise control. [Routing →](/docs/guides/edges/routing) ## Adding Edge Labels To add labels to your custom edges, integrate the [`NgDiagramBaseEdgeLabelComponent`](/docs/api/components/ngdiagrambaseedgelabelcomponent) within your custom edge component.\ Here's an implementation example:
[Edge Labels →](/docs/guides/edges/labels) --- ## Edges > Understanding how edges work in ngDiagram URL: https://ngdiagram.dev/docs/guides/edges/edges/ Edges are the connections between nodes in ngDiagram. They represent relationships, data flow, or dependencies between different components in your diagram. ## Edge Properties Edges have numerous parameters affecting their appearance and behavior. Here are the core properties of an edge: ```typescript interface Edge { id: string; // ID of the edge source: string; // ID of the source node target: string; // ID of the target node data: T; // Custom data associated with the edge sourcePort?: string; // Optional ID of the port on the source node targetPort?: string; // Optional ID of the port on the target node // ...optional properties } ``` `sourcePort` and `targetPort` are optional — when you omit them, the edge connects to the node border as a [floating edge](/docs/guides/edges/floating-edges). [Edge API Reference →](/docs/api/types/model/edge) ## Adding Edges to a Diagram To add edges to your diagram, include them in the [`edges`](/docs/api/types/model/model/#edges) array of your model: ## Default Edge NgDiagram provides a default edge implementation that handles most common use cases. The default edge: - Automatically calculates the path between connected nodes - Supports three [built-in routing algorithms](/docs/guides/edges/routing) - Can display arrowheads at either end - Supports [`labels`](/docs/guides/edges/labels) for displaying text on edges ### Customization NgDiagram's default edges offer several customization options: - Custom arrowheads (defined as SVG markers) - CSS variable based styling (stroke, hover / selection states etc.) - [Built-in routing algorithms](/docs/guides/edges/routing)
#### CSS Variables Default edges can be styled using CSS variables. You can customize these in your global styles: ```scss // Override default edge styling ng-diagram-base-edge.default-edge { --edge-stroke: #334155; --edge-stroke-width: 3; --edge-stroke-dasharray: 5 5; // Dashed line --edge-stroke-transition: stroke 0.2s ease; } ng-diagram-base-edge.default-edge:hover:not(.selected) { --edge-stroke: #64748b; } ng-diagram-base-edge.default-edge.selected { --edge-stroke: #3b82f6; --edge-stroke-width: 4; } // Draw preview shown while the user is dragging a new connection ng-diagram-base-edge.default-edge.temporary { --edge-stroke-opacity: 0.8; } ``` **Available CSS variables:** - `--edge-stroke` - Stroke color - `--edge-stroke-width` - Stroke width - `--edge-stroke-opacity` - Stroke opacity - `--edge-stroke-dasharray` - Stroke dash pattern (e.g., `5 5` for dashed line) - `--edge-stroke-transition` - Transition for stroke changes The default edge also uses these semantic variables that map to the design system: - `--ngd-default-edge-stroke` - Base stroke color (default state) - `--ngd-default-edge-stroke-hover` - Stroke color on hover - `--ngd-default-edge-stroke-selected` - Stroke color when selected ### Available Host Classes The base edge component exposes these classes for styling: - `.selected` - Applied when the edge is selected - `.temporary` - Applied when the edge is being drawn (preview state) See [Edge Selection](/docs/guides/edges/selection) for more details on customizing selection styles. ### Dynamic Styling For complex or programmatic styling, you can use computed properties with the base edge inputs: Use Custom Edges for even more control over edge look and functionality [Custom Edges →](/docs/guides/edges/custom-edges) | [Arrowheads →](/docs/guides/edges/arrowheads) ## Ports Ports are connection points on nodes where edges can start or end. Each port has an ID unique within its node. These IDs (along with their parent node IDs) are used to specify the exact position where edges should be attached. [Ports →](/docs/guides/nodes/ports) ## Routing Edges can be routed using three [built-in routing algorithms](/docs/guides/edges/routing): - [`polyline`](/docs/api/types/routing/edgeroutingname): Draws a polyline (straight line by default) - [`orthogonal`](/docs/api/types/routing/edgeroutingname): Draws a series of horizontal and vertical lines - [`bezier`](/docs/api/types/routing/edgeroutingname): Draws a bezier curve
[Routing →](/docs/guides/edges/routing) ## User-Created Edges When users create edges by dragging between ports, you can customize both the temporary edge shown during dragging and the final edge that gets created. This is done through the [`linking`](/docs/api/types/configuration/flowconfig/#linking) configuration in your diagram's config. ### Customization The [`linking`](/docs/api/types/configuration/features/linkingconfig) configuration provides two builder functions: - **[`temporaryEdgeDataBuilder`](/docs/api/types/configuration/features/linkingconfig/#temporaryedgedatabuilder)** - Customizes the edge shown while dragging - **[`finalEdgeDataBuilder`](/docs/api/types/configuration/features/linkingconfig/#finaledgedatabuilder)** - Customizes the final edge when connection is completed ```typescript export class MyDiagramComponent { model = initializeModel({/* ... */}); config: NgDiagramConfig = { linking: { temporaryEdgeDataBuilder: (defaultEdge) => ({ ...defaultEdge, routing: 'bezier', // Use bezier routing for temporary edge type: 'preview', // Use a custom edge template }), finalEdgeDataBuilder: (defaultEdge) => ({ ...defaultEdge, data: { ...defaultEdge.data, createdAt: new Date(), status: 'active', }, type: 'custom', routing: 'orthogonal', }), }, }; } ``` This allows you to: - Set different edge types for preview vs final edges - Add custom data to newly created edges - Apply specific routing algorithms - Control the visual appearance and behavior [Read more about global configuration in ngDiagram →](/docs/guides/configuration/) ## Edge Draw Events Use the [`edgeDrawEnded`](/docs/api/types/events/edgedrawendedevent) event to react to edge draw completions. It fires for both successful and cancelled draws: ```html ``` ```typescript onEdgeDrawEnded(event: EdgeDrawEndedEvent) { if (event.success) { console.log('Edge created:', event.edge!.id); } else { console.log('Edge draw cancelled:', event.reason); } } ``` ## Selection During Linking By default, pressing a port to start linking also selects the parent node. To decouple selection from linking gestures, set [`selectNodeOnPortPress`](/docs/api/types/configuration/features/linkingconfig/#selectnodeonportpress) to `false`: ```typescript config: NgDiagramConfig = { linking: { selectNodeOnPortPress: false, }, }; ``` ## Further reading [Labels →](/docs/guides/edges/labels) [Floating Edges →](/docs/guides/edges/floating-edges) --- ## Floating Edges > Understanding how floating edges work in ngDiagram URL: https://ngdiagram.dev/docs/guides/edges/floating-edges/ Floating edges are connections between nodes that don't use specific ports. Instead of connecting to fixed port positions, floating edges automatically calculate their connection points on the node borders based on the positions of the connected nodes. ## How Floating Edges Work When an edge doesn't specify the `sourcePort` or `targetPort`, the corresponding connection point is calculated dynamically. ## Declaring Floating Edges To declare a floating edge, simply omit the `sourcePort` and `targetPort` properties when defining your edge:
## Mixed Port and Floating Edges You can mix floating and port-based connections. An edge can have a specific port on one end and float on the other by specifying only one of the ports. ```typescript edges: [ { id: '1', source: '1', sourcePort: undefined, target: '2', targetPort: 'port-left', data: {}, }, ], ```
## Routing Types with Floating Edges Floating edges work seamlessly with different routing types. You can specify the routing type for floating edges just like you would for port-based edges. ```typescript edges: [ { id: '1', source: '1', sourcePort: undefined, target: '2', targetPort: 'port-left', routing: 'bezier', data: {}, }, ], ```
## Creating Floating Edges To create floating edges by using the diagram's linking feature you need to customize the diagram config. For example: Setting `sourcePort` in `temporaryEdgeDataBuilder` ensures that the temporary edge being drawn is a floating edge. After completing the edge creation the both ports are set to `undefined` in `finalEdgeDataBuilder` to create a floating edge on both ends of the edge. In the example below try to connect Node 1 to Node 3:
The config can be adjusted to fit your specific requirements based on node types, starting ports, and other criteria. ## Related Topics [Routing →](/docs/guides/edges/routing) | [Ports →](/docs/guides/nodes/ports) --- ## Labels > Understanding how labels on edges work in ngDiagram URL: https://ngdiagram.dev/docs/guides/edges/labels/ Labels are visual elements attached to edges that can display text, buttons, or any custom content. They automatically position themselves along the edge path and follow the edge as it moves or changes shape. Each edge has a [`measuredLabels`](/docs/api/types/model/edge/#measuredlabels) property that provides information about its labels and their computed [`position`](/docs/api/types/model/edgelabel/#position) and [`size`](/docs/api/types/model/edgelabel/#size). This property is read-only and should not be modified. ## Using Labels in Default Edges To display a label on a **default edge**, add a `label` property to the edge's [`data`](/docs/api/types/model/edge/#data). You can also control the label position by setting the `positionOnEdge` data property (defaults to `0.5` — centered).
### CSS Variables Default labels can be styled using CSS variables. You can customize these in your global styles: ```scss ng-diagram-default-edge-label { --edge-label-padding: 10px; --edge-label-border-radius: 8px; --edge-label-font-size: 14px; --edge-label-background-color: #f3f4f6; --edge-label-text-color: #1e293b; --edge-label-border-width: 2px; --edge-label-border-color: #334155; --edge-label-border-transition: border-color 0.1s ease-in-out; } ``` **Available CSS variables:** - `--edge-label-padding` - Label padding - `--edge-label-border-radius` - Label border radius - `--edge-label-font-size` - Label font size - `--edge-label-background-color` - Label background color - `--edge-label-text-color` - Label text color - `--edge-label-border-width` - Label border width - `--edge-label-border-color` - Label border color - `--edge-label-border-color-hover` - Label border color while the edge is hovered - `--edge-label-border-color-selected` - Label border color while the edge is selected - `--edge-label-border-transition` - Transition for border changes The default label also uses these semantic variables that map to the design system: - `--ngd-default-edge-label-color` - Label text color - `--ngd-default-edge-label-background-color` - Label background color - `--ngd-default-edge-label-border-color` - Label border color The default edge applies different styles to labels based on the edge state (normal, hover, selected). You can customize these styles by modifying the following CSS: ```scss ng-diagram-base-edge.default-edge:hover:not(.selected) { --edge-label-border-color: #2563eb; } ng-diagram-base-edge.default-edge.selected { --edge-label-border-color: #3b82f6; } ``` ## Custom Labels To display a custom label on an edge, use the [`NgDiagramBaseEdgeLabelComponent`](/docs/api/components/ngdiagrambaseedgelabelcomponent) in an implementation of your **custom edge** component:
### Reusing the Default Label To give a custom edge the same label look as the default edge, wrap your content in [`NgDiagramDefaultEdgeLabelComponent`](/docs/api/components/ngdiagramdefaultedgelabelcomponent/) instead of copying its styles: ```html {{ label() }} ``` The two elements have separate jobs: `ng-diagram-base-edge-label` places the label along the edge path and measures it, while `ng-diagram-default-edge-label` only gives the content its look. The chip keeps the theme colors, responds to the CSS variables listed above, and highlights its border while the edge is hovered or selected — the same states as in the default edge. Use `--edge-label-border-color-hover` and `--edge-label-border-color-selected` to change the highlight colors. ## Label Positioning The [`positionOnEdge`](/docs/api/types/model/edgelabel/#positiononedge) property determines where the label appears along the edge path. Labels automatically follow the edge path, regardless of the used [routing algorithm](/docs/guides/edges/routing). ### Relative Positioning A number between `0` and `1` places the label at a percentage along the path. `0` is the source, `1` is the target, and `0.5` is the midpoint. ```html Midpoint ``` ### Absolute Positioning A string with a `px` suffix places the label at a fixed pixel distance along the path. Positive values measure from the source, negative values measure from the target. ```html Near Source Near Target ``` Absolute values are clamped to the path length — `'500px'` on a 300px edge resolves to the target end, and `'-500px'` resolves to the source end. | Value | Mode | Meaning | | --------- | -------- | ----------------------------------- | | `0.5` | Relative | 50% along the path (midpoint) | | `0` | Relative | At the source | | `1` | Relative | At the target | | `'30px'` | Absolute | 30px from the source along the path | | `'-20px'` | Absolute | 20px from the target along the path | | `'0px'` | Absolute | At the source | | `'-0px'` | Absolute | At the target | ## Label Measurement ngDiagram automatically measures label dimensions using a `ResizeObserver`. Measurements update automatically when: - A label's content changes size - The [`positionOnEdge`](/docs/api/types/model/edgelabel/#positiononedge) property is updated If you alter a label's layout through CSS in a way that doesn't trigger a size change, call [`invalidateMeasurements()`](/docs/api/services/ngdiagramservice/#invalidatemeasurements) to force re-measurement. `await` it when you need the fresh `measuredLabels` right away: ```typescript await this.ngDiagramService.invalidateMeasurements({ edges: [{ edgeId: 'edge-1' }], }); ``` See [Port Measurement](/docs/guides/nodes/ports#port-measurement) for more details on when this is needed. ## Adding labels Labels can be added and modified dynamically. One way to achieve this is by using diagram's model. The `ModifiableLabelEdgeComponent` (see below) shows how to map such data into an actual label implementation. Click on an edge to select it in the example below. Then fill the label's name and click "Set Label".
## Handling Interactive Elements in Labels When adding interactive elements like inputs to edge labels, dragging on these elements might trigger unwanted diagram behaviors. You can control this using special data attributes: - **`data-no-pan="true"`** - Prevents the diagram canvas from panning when the user clicks and drags on the element - **`data-no-drag="true"`** - Prevents nodes from being dragged when the user clicks and drags on the element ```html ``` ## Multiple Labels NgDiagram supports multiple labels and they can be used to display images, shapes, or any other content. The example below demonstrates how to add multiple labels to an edge to create a flow animation.
--- ## Need a routing algorithm tailored to your domain? > Understanding how edge routing works in ngDiagram URL: https://ngdiagram.dev/docs/guides/edges/routing/ Edge routing determines how connections between nodes are drawn in your diagram. NgDiagram provides flexible routing where each routing algorithm: - Calculates the points that define the edge path - Draws the SVG path from those points - Computes positions along the path for labels and decorations Routing algorithms automatically calculate optimal paths, with an option to provide predefined waypoints for static edge paths. ## Built-in Algorithms NgDiagram includes three routing algorithms: ### Polyline The simplest routing that connects points with straight line segments. In auto mode, it creates a direct line between source and target. In manual mode, it can create multi-segment paths by connecting user-provided waypoints with straight lines. ### Orthogonal Creates paths using only horizontal and vertical segments, ideal for technical diagrams and flowcharts. Supports configurable segment lengths and optional rounded corners. ### Bezier Produces smooth curved connections using cubic Bézier curves.
## Using Routing To specify a routing algorithm for an edge, set the [`routing`](/docs/api/types/model/edge/#routing) property in the edge data: When no routing is specified, the default routing algorithm (orthogonal) is used. The default can be changed through configuration. For custom edge components, you can provide routing directly in the template using [`NgDiagramBaseEdgeComponent`](/docs/api/components/ngdiagrambaseedgecomponent/): ```typescript ``` ## Routing Modes Each edge can operate in one of two [`routingMode`](/docs/api/types/model/edge/#routingmode) options: ### Auto Mode (Default) In auto mode, the routing algorithm automatically calculates the path between nodes. The list of [`points`](/docs/api/types/model/edge/#points) is calculated by the routing algorithm and should be treated as read-only. The path updates automatically when nodes move or resize. ```typescript const edge = { id: 'edge1', source: 'node1', target: 'node2', routing: 'orthogonal', routingMode: 'auto', // or omit for default data: {}, }; ``` ### Manual Mode Manual mode gives you full control over the edge path by allowing you to provide your own list of points. The routing algorithm is still used to draw the SVG path from these points and calculate label positions. When nodes move, you control what happens - the path can remain unchanged, or you can programmatically update the [`points`](/docs/api/types/model/edge/#points) as needed. Try moving the nodes in the example below - notice how the edge path remains fixed:
This is useful for creating custom edge behaviors, fixed connection paths, or implementing your own edge update logic. ## Configuration You can configure routing behavior globally through the diagram's [configuration](/docs/api/types/configuration/ngdiagramconfig/): ## Custom Routing Algorithms NgDiagram's routing system is extensible. You can create custom routing algorithms by implementing the [`EdgeRouting`](/docs/api/types/routing/edgerouting/) interface, or by creating custom edge components that generate their own paths using manual mode. ### Manual Mode Approach You can create dynamic custom paths by computing points in your edge component and using manual routing mode. Here's an example of a sinusoid edge that updates its path dynamically as nodes move:
This approach is ideal when you want the path to update automatically based on node positions and when you just need to compute points - the SVG path can be computed by a built-in routing algorithm (in this case, polyline was sufficient). ### Registering New Routing in the Library For more control and reusability across different edge types, you can create a custom routing algorithm by implementing the [`EdgeRouting`](/docs/api/types/routing/edgerouting/) interface and registering it via [`NgDiagramService.registerRouting()`](/docs/api/services/ngdiagramservice/#registerrouting). Once registered, the routing becomes available globally across all edges in your diagram. Here's a complete example of an arc routing that uses SVG elliptical arcs to create curved connections:
This approach gives you full control over path generation, configuration options, and point calculations. The three required methods work together: [`computePoints`](/docs/api/types/routing/edgerouting/#computepoints) defines the geometric points, [`computeSvgPath`](/docs/api/types/routing/edgerouting/#computesvgpath) renders them as SVG, and [`computePointOnPath`](/docs/api/types/routing/edgerouting/#computepointonpath) positions labels and decorations along the path. ## Related Topics [Edges Overview →](/docs/guides/edges/edges) | [Custom Edges →](/docs/guides/edges/custom-edges) | [Edge Labels →](/docs/guides/edges/labels) --- ## Selection > Understanding how edge selection works in ngDiagram URL: https://ngdiagram.dev/docs/guides/edges/selection/ The **edge selection** feature in ngDiagram allows users to select edges on the diagram canvas. Selected edges are visually highlighted, making it easier to identify and interact with connections between nodes. ## How It Works - Edges can be selected by clicking on them. - The selected state is managed by ngDiagram and can be accessed via the edge's [`selected`](/docs/api/types/model/edge/#selected) property. - Selection styles can be applied automatically or customized. ## Default Selection Default edge selection uses built-in styles and logic provided by ngDiagram. The default edge template automatically highlights selected edges.
## Customizing Defaults You can customize edge selection styles. Here are the CSS variables you can use to style the selection highlight: ``` --ngd-default-edge-stroke // Stroke color for default edge --ngd-default-edge-stroke-hover // Stroke color for default edge on hover --ngd-default-edge-stroke-selected // Stroke color for selected default edge ``` You can override these variables in your styles to customize the appearance of selected edges.
## Custom Edge Selection Custom edges can easily apply selection styles using CSS variables. The base edge component exposes selection state through CSS classes, allowing you to style edges without breaking encapsulation. ### How It Works When an edge is selected, the [`NgDiagramBaseEdgeComponent`](/docs/api/components/ngdiagrambaseedgecomponent) automatically adds the `.selected` class to its host element. You can use this class to change CSS variables that control the edge appearance. ### Example: Custom Edge with Selection Styling
More information about CSS variables and styling can be found in the [Edges Customization](/docs/guides/edges/edges/#css-variables) section. ### Alternative: Dynamic Styling [Dynamic Edge Styling →](/docs/guides/edges/edges/#dynamic-styling) ## Further Reading [Edges Overview →](/docs/guides/edges/edges) | [Custom Edges →](/docs/guides/edges/custom-edges) | [Edge Labels →](/docs/guides/edges/labels) --- ## Global Configuration URL: https://ngdiagram.dev/docs/guides/flow-config/ The configuration system in ngDiagram is the central mechanism for customizing and orchestrating the behavior, appearance, and interaction logic of your diagrams. It empowers developers to fine-tune many aspects of the diagram engine. ## What is the Configuration? The configuration (commonly referred to as [`config`](/docs/api/types/configuration/flowconfig)) is a comprehensive object that defines how your diagram should behave and look. It encapsulates all available options for the diagram engine, allowing you to: - **Shape the user experience**: Control zoom, selection, snapping, and more. - **Customize visuals**: Adjust backgrounds, z-index layering, and node/edge behaviors. - **Enable advanced behaviors**: Configure routing algorithms, grouping, resizing, and keyboard shortcuts. By leveraging the configuration, you gain full control over the diagram's capabilities, ensuring it fits seamlessly into your application's requirements. ## How to Initialize the Configuration To initialize the configuration, define a [`config`](/docs/api/types/configuration/flowconfig/) object in your Angular component using the [NgDiagramConfig](/docs/api/types/configuration/ngdiagramconfig/) type.\ Only specify the properties you wish to override; all others will use sensible defaults. ```typescript const config: NgDiagramConfig = { zoom: { max: 3 }, edgeRouting: { defaultRouting: 'bezier' }, }; ``` Assign the configuration to the [``](/docs/api/components/ngdiagramcomponent/) component using the `[config]` input: ```html ``` ## Configuration Type ngDiagram uses the [NgDiagramConfig](/docs/api/types/configuration/ngdiagramconfig/) type, which is a `DeepPartial` of [FlowConfig](/docs/api/types/configuration/flowconfig/). This means every property is optional, and you can override only what you need. ## Signals in Configuration The configuration is exposed as a **readonly signal** via [NgDiagramService.config](/docs/api/services/ngdiagramservice/#config). This enables reactive programming patterns—your UI can automatically respond to configuration changes, and you can subscribe to updates for advanced scenarios. ## Updating Configuration at Runtime ngDiagram supports dynamic configuration updates. If your application allows users to change diagram settings (e.g., toggling grid snapping, switching routing algorithms), you can update the config reactively using the [NgDiagramService](/docs/api/services/ngdiagramservice/): ```typescript private ngDiagramService = inject(NgDiagramService); // Update configuration dynamically this.ngDiagramService.updateConfig({ zoom: { step: 0.1 } }); ``` The configuration changes are immediately reflected in the diagram UI. ## Main Configuration Categories ngDiagram's configuration is organized into logical categories, each controlling a specific aspect of the diagram engine. The most important categories include: - [`background`](/docs/api/types/configuration/features/backgroundconfig): Configures background visuals (grid, dot spacing, cell size). - [`boxSelection`](/docs/api/types/configuration/features/boxselectionconfig): Configures box selection behavior. - [`debugMode`](/docs/api/types/configuration/flowconfig/#debugmode): Enables verbose logging for development and debugging. - [`edgeRouting`](/docs/api/types/configuration/features/edgeroutingconfig): Defines edge routing algorithms and their parameters. - [`grouping`](/docs/api/types/configuration/features/groupingconfig): Enables node grouping and related logic. - [`linking`](/docs/api/types/configuration/features/linkingconfig): Customizes edge creation and connection validation. - [`nodeRotation`](/docs/api/types/configuration/features/noderotationconfig): Enables and customizes node rotation and snapping. - [`resize`](/docs/api/types/configuration/features/resizeconfig): Manages node resizing logic, minimum sizes, and resizability. - [`shortcuts`](/docs/api/types/configuration/shortcuts/shortcutdefinition): Defines keyboard shortcuts for diagram actions. - [`snapping`](/docs/api/types/configuration/features/snappingconfig): Controls snapping for node movement and resizing. - [`zIndex`](/docs/api/types/configuration/features/zindexconfig): Manages layering and stacking order of diagram elements. - [`zoom`](/docs/api/types/configuration/features/zoomconfig): Controls zooming behavior, limits, and zoom-to-fit options. For detailed options and advanced usage, refer to the documentation for each category in [FlowConfig](/docs/api/types/configuration/flowconfig/). ## Example ```typescript const config: NgDiagramConfig = { zoom: { max: 4, zoomToFit: { onInit: true, padding: 100 }, }, background: { dotSpacing: 30, }, edgeRouting: { defaultRouting: 'bezier', bezier: { bezierControlOffset: 50 }, }, resize: { defaultResizable: false, getMinNodeSize: () => ({ width: 50, height: 50 }), }, debugMode: true, }; ``` ## Further Reading [NgDiagramConfig →](/docs/api/types/configuration/ngdiagramconfig/) | [FlowConfig →](/docs/api/types/configuration/flowconfig/) | [NgDiagramService →](/docs/api/services/ngdiagramservice/) | [NgDiagramComponent →](/docs/api/components/ngdiagramcomponent/) --- --- ## Building custom logic on top of the pipeline? > Understanding how middlewares work in ngDiagram URL: https://ngdiagram.dev/docs/guides/middlewares/ Middlewares provide a powerful plugin architecture for extending ngDiagram behavior. They intercept state changes before they reach the model, allowing you to transform data, add custom logic, and implement features without modifying core code. ## How Middlewares Work When any change occurs in the diagram (adding nodes, moving elements, changing selections), the change goes through a middleware pipeline before reaching the model. Each middleware can: - **Inspect** the current state and what's being changed - **Transform** the data being applied - **Add** additional changes to the state - **Cancel** the operation entirely - **Perform** asynchronous operations Middlewares execute in sequence, with each middleware receiving the output of the previous one. This creates a powerful composition system where multiple behaviors can be combined. ## Middleware API ### Middleware Action Types The [`ModelActionType`](/docs/api/types/middleware/modelactiontype/) type lists all possible actions that can trigger middleware execution. These represent every operation that modifies the diagram state, such as adding nodes, moving elements, deleting selections, resizing, linking, rotating, and more. ### Middleware Interface Each middleware implements the [`Middleware`](/docs/api/types/middleware/middleware/) interface: ```typescript interface Middleware { name: TName; execute: ( context: MiddlewareContext, next: (stateUpdate?: FlowStateUpdate) => Promise, cancel: () => void ) => Promise | void; } ``` ### Middleware Context The **context** object passed to middleware functions provides comprehensive access to the diagram state and metadata: - [`initialState`](/docs/api/types/middleware/middlewarecontext/#initialstate) – The state before any modifications - [`state`](/docs/api/types/middleware/middlewarecontext/#state) – The current state after all previous modifications. - [`nodesMap`](/docs/api/types/middleware/middlewarecontext/#nodesmap) / [`edgesMap`](/docs/api/types/middleware/middlewarecontext/#edgesmap) – Maps for quick lookup of nodes and edges by ID - [`initialNodesMap`](/docs/api/types/middleware/middlewarecontext/#initialnodesmap) / [`initialEdgesMap`](/docs/api/types/middleware/middlewarecontext/#initialedgesmap) – Maps for accessing nodes/edges before any changes - [`modelActionType`](/docs/api/types/middleware/middlewarecontext/#modelactiontype) – (**deprecated**) The action that triggered the middleware. - [`modelActionTypes`](/docs/api/types/middleware/middlewarecontext/#modelactiontypes) - Actions that triggered the middleware (multiple if transaction is active) - [`helpers`](/docs/api/types/middleware/middlewarecontext/#helpers) – Utility functions for inspecting what changed - [`history`](/docs/api/types/middleware/middlewarecontext/#history) – Array of all state updates made by previous middlewares in the chain. - [`actionStateManager`](/docs/api/types/middleware/middlewarecontext/#actionstatemanager) – Manager for temporary action states. - [`edgeRoutingManager`](/docs/api/types/middleware/middlewarecontext/#edgeroutingmanager) – Manager for edge routing algorithms. - [`initialUpdate`](/docs/api/types/middleware/middlewarecontext/#initialupdate) – The initial state update that triggered the middleware chain. - [`config`](/docs/api/types/middleware/middlewarecontext/#config) – Current diagram configuration. - [`environment`](/docs/api/types/middleware/middlewarecontext/#environment) – Environment information (browser, rendering engine, etc.). ### Middleware Helpers The [`helpers`](/docs/api/types/middleware/middlewarecontext/#helpers) object provides optimized functions to inspect all cumulative changes from the initial update and previous middlewares: - [`checkIfNodeChanged(id)`](/docs/api/types/middleware/middlewarehelpers/#checkifnodechanged) – Was this node modified? - [`checkIfEdgeChanged(id)`](/docs/api/types/middleware/middlewarehelpers/#checkifedgechanged) – Was this edge modified? - [`checkIfNodeAdded(id)`](/docs/api/types/middleware/middlewarehelpers/#checkifnodeadded) / [`checkIfNodeRemoved(id)`](/docs/api/types/middleware/middlewarehelpers/#checkifnoderemoved) – Was this node added/removed? - [`checkIfEdgeAdded(id)`](/docs/api/types/middleware/middlewarehelpers/#checkifedgeadded) / [`checkIfEdgeRemoved(id)`](/docs/api/types/middleware/middlewarehelpers/#checkifedgeremoved) – Was this edge added/removed? - [`checkIfAnyNodePropsChanged(['prop1', 'prop2'])`](/docs/api/types/middleware/middlewarehelpers/#checkifanynodepropschanged) – Did any node have these properties changed? - [`checkIfAnyEdgePropsChanged(['prop1', 'prop2'])`](/docs/api/types/middleware/middlewarehelpers/#checkifanyedgepropschanged) – Did any edge have these properties changed? - [`anyNodesAdded()`](/docs/api/types/middleware/middlewarehelpers/#anynodesadded) / [`anyEdgesAdded()`](/docs/api/types/middleware/middlewarehelpers/#anyedgesadded) – Were any nodes/edges added? - [`anyNodesRemoved()`](/docs/api/types/middleware/middlewarehelpers/#anynodesremoved) / [`anyEdgesRemoved()`](/docs/api/types/middleware/middlewarehelpers/#anyedgesremoved) – Were any nodes/edges removed? - [`getAffectedNodeIds(['prop1', 'prop2'])`](/docs/api/types/middleware/middlewarehelpers/#getaffectednodeids) – Get IDs of nodes with specified properties changed. - [`getAffectedEdgeIds(['prop1', 'prop2'])`](/docs/api/types/middleware/middlewarehelpers/#getaffectededgeids) – Get IDs of edges with specified properties changed. - [`getAddedNodes()`](/docs/api/types/middleware/middlewarehelpers/#getaddednodes) / [`getAddedEdges()`](/docs/api/types/middleware/middlewarehelpers/#getaddededges) – Get instances of added nodes/edges. - [`getRemovedNodes()`](/docs/api/types/middleware/middlewarehelpers/#getremovednodes) / [`getRemovedEdges()`](/docs/api/types/middleware/middlewarehelpers/#getremovededges) – Get instances of removed nodes/edges (from initial state). - [`getChangedNodeIds()`](/docs/api/types/middleware/middlewarehelpers/#getchangednodeids) / [`getChangedEdgeIds()`](/docs/api/types/middleware/middlewarehelpers/#getchangededgeids) – Get IDs of all nodes/edges with any property changes. These helpers allow you to efficiently check what changed during the middleware execution chain. #### Example: Using Helpers ```typescript // Example with a middleware that checks if any node was added into a group export const myMiddleware: Middleware = { name: 'group-node-checker', execute: async (context, next) => { const { helpers } = context; if (helpers.checkIfAnyNodePropsChanged(['groupId'])) { const affectedNodeIds = helpers.getAffectedNodeIds(['groupId']); console.log('Nodes were added to groups:', affectedNodeIds); } next(); // Continue to next middleware }, }; ``` ### Middleware History The [`history`](/docs/api/types/middleware/middlewarecontext/#history) array in the context tracks all state updates made by previous middlewares, including the name of the middleware and the specific state update applied.\ This is useful for auditing or debugging complex middleware chains. ## Managing Middlewares ### Initial Registration The primary way to configure middlewares is using the [`createMiddlewares`](/docs/api/utilities/createmiddlewares) helper and passing them to the [``](/docs/api/components/ngdiagramcomponent) component: ```typescript // Use all default middlewares const middlewares = createMiddlewares((defaults) => defaults); // Add custom middleware to the chain const middlewares = createMiddlewares((defaults) => [...defaults, myCustomMiddleware]); // Remove specific middleware const middlewares = createMiddlewares((defaults) => defaults.filter((m) => m.name !== 'logger')); ``` Then pass them to your diagram component: ```typescript @Component({ template: ` `, }) export class MyDiagramComponent { middlewares = createMiddlewares((defaults) => [...defaults, myMiddleware]); // ... } ``` ### Runtime Registration You can also register and unregister middlewares dynamically using the [`NgDiagramService`](/docs/api/services/ngdiagramservice/).\ **Note**: This can only be done when the diagram is initialized, which you can check using [`isInitialized`](/docs/api/services/ngdiagramservice/#isinitialized) signal: ```typescript @Component({...}) export class MyComponent { private ngDiagram = inject(NgDiagramService); addMiddleware() { // Check if diagram is initialized first if (!this.ngDiagram.isInitialized()) { console.warn('Cannot register middleware: diagram not initialized'); return; } // Register returns an unregister function const unregister = this.ngDiagram.registerMiddleware(myMiddleware); // Later you can unregister the middleware by invoking the returned function // unregister(); } removeMiddleware() { if (!this.ngDiagram.isInitialized()) { console.warn('Cannot unregister middleware: diagram not initialized'); return; } // You can also unregister the middleware by name this.ngDiagram.unregisterMiddleware('my-middleware-name'); } } ``` ## Creating Custom Middlewares ### Basic Middleware Structure Here's the basic structure for a custom middleware: ```typescript export const myMiddleware: Middleware = { name: 'my-middleware', execute: async (context, next) => { const { state, modelActionTypes } = context; // Check if this middleware should run if (!modelActionTypes.includes('updateNode')) { next(); // Pass through without changes return; } // Your custom logic here console.log('Nodes being updated:', state.nodes); // Continue to next middleware next(); }, }; ``` ### Example For a complete example of creating custom middleware, see the [Custom Middleware example](/docs/examples/custom-middleware/) which demonstrates how to implement a read-only mode middleware that prevents certain operations while allowing others. ### Advanced Middleware Features #### Modifying State Middlewares can modify the diagram state by passing a [`FlowStateUpdate`](/docs/api/types/middleware/flowstateupdate/) object to `next()`: ```typescript interface FlowStateUpdate { nodesToAdd?: Node[]; nodesToUpdate?: (Partial & { id: Node['id'] })[]; nodesToRemove?: string[]; edgesToAdd?: Edge[]; edgesToUpdate?: (Partial & { id: Edge['id'] })[]; edgesToRemove?: string[]; metadataUpdate?: Partial; } ``` This allows you to add, update, or remove nodes/edges, and update metadata in a granular way. #### Example: Rotating New Nodes ```typescript export const myCustomMiddleware: Middleware = { name: 'rotate-middleware', execute: async (context, next) => { const { helpers } = context; // Check if this middleware should run if (!helpers.anyNodesAdded()) { next(); // Pass through without changes return; } // Rotate all new nodes and change label const stateUpdate = { nodesToUpdate: context.state.nodes .filter((node) => helpers.checkIfNodeAdded(node.id)) .map((node) => ({ ...node, angle: 45, data: { ...node.data, label: `rotated via middleware` }, })), }; // Continue to next middleware next(stateUpdate); }, }; ``` #### Asynchronous Operations Middlewares can perform async operations: ```typescript export const myCustomMiddleware: Middleware = { name: 'validation', execute: async (context, next, cancel) => { const { helpers } = context; if (!helpers.anyNodesAdded()) { next(); return; } // Simulated API validation function const validateNodesWithAPI = () => { return new Promise((resolve, reject) => { setTimeout(() => { const isValid = Math.random() > 0.5; // 50% chance of success if (isValid) { resolve(); } else { reject(new Error('Random validation failure')); } }, 1000); // 1 second delay — after this time the node will be added if valid, or an alert/error will be displayed if invalid }); }; try { await validateNodesWithAPI(); next(); // Validation passed } catch (error) { alert(`Validation failed: ${error}`); cancel(); // Cancel the operation } }, }; ``` However, you should avoid long-running async operations in middlewares as they can block the UI. An uncaught error thrown inside a middleware rejects the in-flight update: the promise returned by the mutating service call rejects and the update is discarded, while the diagram keeps working. Prefer handling expected failures yourself and calling `cancel()`, as shown above. :::danger[Never await mutating calls from inside a middleware] The middleware chain runs inside a non-reentrant update lock. Since promises returned by mutating service methods and `emit` resolve only after the state has been committed, awaiting one of them from inside a middleware waits on the very lock your middleware is holding — the update never completes and the diagram freezes. ```typescript export const badMiddleware: Middleware = { name: 'deadlock', execute: async (context, next) => { // ❌ Deadlock: this promise resolves only after the current update // finishes, but the current update is waiting for this middleware. await modelService.updateNode('node-1', { data: { flagged: true } }); next(); }, }; export const goodMiddleware: Middleware = { name: 'fire-and-forget', execute: (context, next) => { // ✅ Fire-and-forget: the update queues safely behind the current one. void modelService.updateNode('node-1', { data: { flagged: true } }); // ✅ Or better: modify the current update directly. next({ nodesToUpdate: [{ id: 'node-1', data: { flagged: true } }] }); }, }; ``` To transform the update that is currently in flight, pass a `FlowStateUpdate` to `next()` instead. ::: ## Best Practices ### Performance - **Check conditions early**: Return `next()` immediately if your middleware doesn't need to run - **Use helpers efficiently**: The helper functions are optimized for checking what changed - **Avoid heavy computations**: Keep middleware logic lightweight, especially for frequently-triggered actions ### Middleware Ordering - **Validation middlewares** should run early to fail fast - **Data transformation middlewares** should run before built-in middlewares that depend on the data - **Logging middlewares** typically run last to capture the final state --- ## Minimap > How to use and customize the minimap component in ngDiagram URL: https://ngdiagram.dev/docs/guides/minimap/ The [``](/docs/api/components/ngdiagramminimapcomponent/) component provides a bird's-eye view of your diagram, showing all nodes and the current viewport position. It supports click-and-drag navigation to quickly pan to different areas of your diagram. :::note The minimap displays only nodes. Edges are not rendered in the minimap view. ::: ## Basic Usage Add the [``](/docs/api/components/ngdiagramminimapcomponent/) component inside your diagram container: ```html
``` :::note[Service Access] The minimap can be placed anywhere in your template, but it requires access to ngDiagram services. Make sure the component is within a context where [`provideNgDiagram()`](/docs/api/utilities/providengdiagram/) has been provided. ::: :::note[Container Positioning] The minimap uses `position: absolute` for corner placement via the `position` input. Ensure the parent container has `position: relative` for proper positioning: ```css .diagram-container { position: relative; } ``` ::: ## Configuration ### Position and Size The minimap can be positioned in any corner using the [`position`](/docs/api/components/ngdiagramminimapcomponent/#position) input and sized with [`width`](/docs/api/components/ngdiagramminimapcomponent/#width) and [`height`](/docs/api/components/ngdiagramminimapcomponent/#height): ```html ``` See [`NgDiagramPanelPosition`](/docs/api/types/ngdiagrampanelposition/) for available position values. ### Zoom Controls By default, zoom controls are displayed below the minimap. To hide them: ```html ``` ### Deferred Node Updates For large diagrams, minimap updates during drag, resize, and rotation operations can add overhead. Enable [`deferNodeUpdates`](/docs/api/components/ngdiagramminimapcomponent/#defernodeupdates) to freeze minimap node positions while the user is interacting, updating them only when the operation ends: ```html ``` The viewport indicator rectangle always updates in real-time, so users still see their current position in the diagram. ## Customization via CSS Variables :::tip[Theming] Some CSS variables reference design tokens to support light/dark themes. For proper multi-theme customization, see the [Styling guide](/docs/intro/styling/) to understand how tokens and primitives work. ::: ### General Appearance You can customize the minimap container appearance using CSS variables: ```css :root { /* Container styling */ --ngd-minimap-background: ...; --ngd-minimap-border-color: ...; --ngd-minimap-border-radius: 1rem; --ngd-minimap-padding: 0.5rem; --ngd-minimap-margin: 1rem; --ngd-minimap-shadow-color: ...; /* Viewport indicator */ --ngd-minimap-viewport-stroke-color: ...; --ngd-minimap-viewport-stroke-width: 1; } ``` ### Node Styling Default node appearance in the minimap can be controlled via CSS variables: ```css :root { --ngd-minimap-node-color: ...; --ngd-minimap-node-opacity: 0.8; } ``` ### Zoom Controls The zoom controls appearance can be customized with these CSS variables: ```css :root { /* Zoom controls text */ --ngd-zoom-controls-font-size: 0.8125rem; --ngd-zoom-controls-font-weight: 500; --ngd-zoom-controls-color: ...; /* Navigation buttons (zoom in/out) */ --ngd-nav-button-color: ...; --ngd-nav-button-size: 1.25rem; --ngd-nav-button-border-radius: 0.5rem; --ngd-nav-button-padding: 0.6875rem; --ngd-nav-button-background-color-hover: ...; --ngd-nav-button-color-active: ...; --ngd-nav-button-color-disabled: ...; } ``` ## Customization via Style Function For dynamic node styling based on [`Node`](/docs/api/types/model/node/) properties, use the [`nodeStyle`](/docs/api/components/ngdiagramminimapcomponent/#nodestyle) input. This accepts a [`MinimapNodeStyleFn`](/docs/api/types/minimap/minimapnodestylefn/) callback: ```typescript nodeStyle = (node: Node): MinimapNodeStyle => { const style: MinimapNodeStyle = {}; // Different shape for specific nodes if (node.type === 'database') { style.shape = 'circle'; } // Highlight selected nodes if (node.selected) { style.stroke = '#2196F3'; style.strokeWidth = 2; } // Custom fill based on node data if (node.data?.status === 'error') { style.fill = '#f44336'; } return style; }; ``` ```html ``` See [`MinimapNodeStyle`](/docs/api/types/minimap/minimapnodestyle/) for all available style properties. ## Customization via Templates For complete control over node rendering, you can provide custom Angular components per node type using [`minimapNodeTemplateMap`](/docs/api/components/ngdiagramminimapcomponent/#minimapnodetemplatemap). This is useful when you need to display icons, images, or complex visuals in the minimap. :::caution[Performance Consideration] Custom templates use `foreignObject` and Angular components, which can impact performance with large diagrams. Use templates sparingly and only for node types that truly require custom rendering. For simple styling changes, prefer the `nodeStyle` function or CSS variables. ::: ### Creating a Custom Template Your component must implement the [`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/) interface: ```typescript @Component({ selector: 'app-image-minimap-node', standalone: true, template: ``, styles: [ ` :host { display: contents; img { width: 100%; height: 100%; object-fit: cover; display: block; } } `, ], changeDetection: ChangeDetectionStrategy.OnPush, }) export class ImageMinimapNodeComponent implements NgDiagramMinimapNodeTemplate { node = input.required(); nodeStyle = input(); get imageUrl(): string { const data = this.node().data as { imageUrl?: string }; return data?.imageUrl ?? 'placeholder.png'; } } ``` ### Registering Templates Create a [`NgDiagramMinimapNodeTemplateMap`](/docs/api/types/minimap/ngdiagramminimapnodetemplatemap/) and pass it to the minimap: ```typescript minimapNodeTemplateMap = new NgDiagramMinimapNodeTemplateMap([ ['image', ImageMinimapNodeComponent], ['custom-type', CustomMinimapNodeComponent], ]); ``` ```html ``` Nodes with types not in the map will use the default rectangle rendering. ## Example --- --- ## Model Initialization > Learn how to properly initialize and reinitialize models, and when to run your logic during the initialization process URL: https://ngdiagram.dev/docs/guides/model-initialization/ Model initialization and reinitialization are crucial concepts in ngDiagram that determine when and how your diagram data is set up and when it's safe to perform operations on the model. Understanding these mechanisms is essential for building robust applications that handle dynamic data loading and model switching. There are various scenarios when and how to initialize a model, depending on your application's requirements and data flow. For comprehensive information about state management patterns and model operations, see [State Management](/docs/guides/state-management/). ## Model Initialization The [`initializeModel`](/docs/api/utilities/initializemodel) function is the primary way to create a model for use in ngDiagram. It creates a model instance that wraps your diagram data and provides reactive state management. ### Basic Model Creation ```typescript // Create a model with default values (empty nodes, edges, and default metadata) const model = initializeModel(); // Create a model with initial data const model = initializeModel({ nodes: [ { id: '1', position: { x: 100, y: 150 }, data: { label: 'Node 1' }, }, { id: '2', position: { x: 400, y: 150 }, data: { label: 'Node 2' }, }, ], edges: [ { id: 'edge-1', source: '1', target: '2', sourcePort: 'port-right', targetPort: 'port-left', data: {}, }, ], metadata: { viewport: { x: 0, y: 0, scale: 1 }, }, }); ``` ### Custom Model Adapter If you have a custom [`ModelAdapter`](/docs/api/types/model/modeladapter/) implementation (e.g., backed by localStorage, NgRx, or an external store), use [`initializeModelAdapter`](/docs/api/utilities/initializemodeladapter) instead. It prepares all nodes and edges in the adapter for use with ng-diagram. ```typescript // Initialize a custom adapter model = initializeModelAdapter(new MyCustomModelAdapter()); // Optionally seed the adapter with initial data model = initializeModelAdapter(new MyCustomModelAdapter(), { nodes: [ { id: '1', position: { x: 100, y: 150 }, data: { label: 'Node 1' }, }, ], edges: [], }); ``` For a complete example, see the [Custom Model example](/docs/examples/custom-model/). ## Model Reinitialization Sometimes you need to replace the entire model with new data. This commonly happens when: - **Loading data asynchronously** - Fetching diagram data from an API - **Switching between different diagrams** - User selects a different model from a list - **Resetting the diagram** - Clearing all data and starting fresh ### Reinitializing with New Data ```typescript export class MyComponent { private readonly injector = inject(Injector); model = initializeModel(); async loadDiagramFromAPI(diagramId: string) { // Fetch data asynchronously const diagramData = await this.dataService.getDiagramData(diagramId); // Reinitialize model with new data this.model = initializeModel(diagramData, this.injector); } switchToDiagram(diagramData: Partial ## Using in Reactive Contexts `initializeModel` can be safely called inside reactive contexts such as `computed`, `effect`, or `linkedSignal`. This allows you to derive the diagram model reactively from a signal source, automating the reinitialization shown above: ```typescript export class MyComponent { private readonly injector = inject(Injector); // Source data — could come from an API, route params, etc. diagramData = signal ## Timing and Events When a model is reinitialized, the diagram goes through a complete initialization process. All nodes and edges need to be measured and positioned before the diagram is fully ready. You need to wait for this process to complete before performing operations on the model. ### Initialization Process The initialization process involves several steps: 1. **Model Assignment** – A new model is assigned to the diagram component. 2. **Logic Recreation** – The internal core logic is destroyed and recreated. Because the logic is recreated, the [`isInitialized`](/docs/api/services/ngdiagramservice/#isinitialized) signal has its default value (`false`). 3. **Element Measurement** – All nodes, edges, and their internal parts are measured. 4. **Layout Calculation** – Positions and sizes are calculated. 5. **Event Emission & Signal Update** – The [`diagramInit`](/docs/api/types/events/diagraminitevent/) event is emitted when everything is ready, and the [`isInitialized`](/docs/api/services/ngdiagramservice/#isinitialized) signal is set to `true`. ### Waiting for Initialization There are three main ways to detect when the diagram is fully initialized: #### Using the diagramInit Event The most convenient way is to listen for the [`diagramInit`](/docs/api/types/events/diagraminitevent/) event from the [`ng-diagram`](/docs/api/components/ngdiagramcomponent) component: ```typescript export class MyComponent { model = initializeModel(); private injector = inject(Injector); onDiagramInit(event: DiagramInitEvent): void { console.log('Diagram is fully initialized'); console.log('Nodes:', event.nodes); console.log('Edges:', event.edges); console.log('Viewport:', event.viewport); // Now it's safe to perform operations this.performPostInitializationLogic(); } private performPostInitializationLogic() { // Your logic here - diagram is fully ready this.modelService.addNodes([...]); this.modelService.updateNodeData('node-1', { ... }); } } ``` ```html ``` #### Using the isInitialized Signal You can also check the [`isInitialized`](/docs/api/services/ngdiagramservice/#isinitialized) signal from [`NgDiagramService`](/docs/api/services/ngdiagramservice): ```typescript export class MyComponent { private ngDiagramService = inject(NgDiagramService); private modelService = inject(NgDiagramModelService); constructor() { effect(() => { if (this.ngDiagramService.isInitialized()) { this.performPostInitializationLogic(); } }); } } ``` #### Using Event Listener Registration For more advanced scenarios, you can register event listeners programmatically: ```typescript export class MyComponent { private ngDiagramService = inject(NgDiagramService); private modelService = inject(NgDiagramModelService); ngOnInit() { // Register a one-time listener for diagram initialization. // Alternatively, you can use addEventListener, but make sure to // unregister it when no longer needed to avoid memory leaks. this.ngDiagramService.addEventListenerOnce('diagramInit', (event) => { console.log('Diagram initialized via event listener'); this.performPostInitializationLogic(event); }); } private performPostInitializationLogic(event: DiagramInitEvent) { // Your logic here — at this stage you can safely read the measured // nodes, edges and their internal parts (positions, sizes, points, etc.). } } ``` ## Best Practices ### Always Wait for Initialization ```typescript // ❌ Don't do this - operations may fail or be ignored this.model = initializeModel(newData, this.injector); this.modelService.addNodes([...]); // This might not work! // ✅ Do this instead this.model = initializeModel(newData, this.injector); // Wait for onDiagramInit() to be called, then perform operations ``` ### Use Transactions When performing multiple operations after initialization, wrap them in a transaction: ```typescript onDiagramInit(event: DiagramInitEvent): void { this.ngDiagramService.transaction(() => { this.modelService.addNodes([...]); this.modelService.addEdges([...]); this.modelService.updateMetadata({ ... }); }); } ``` ### Memory Management When switching between models frequently, be aware of memory usage: ```typescript export class MemoryConsciousComponent { model = initializeModel(); private injector = inject(Injector); private currentDiagramId: string | null = null; async switchToDiagram(diagramId: string) { // Avoid unnecessary reinitializations if (this.currentDiagramId === diagramId) { return; } this.currentDiagramId = diagramId; const diagramData = await this.diagramAPI.getDiagram(diagramId); this.model = initializeModel(diagramData, this.injector); } } ``` ## Troubleshooting ### Common Issues **Operations not working after model reinitialization:** - Ensure you're waiting for the [`diagramInit`](/docs/api/types/events/diagraminitevent/) event - Check that you're using the model service, not the model directly **Initialization events not firing:** - Verify that the diagram component is properly rendered - Check that the model is actually changing (not the same reference) Understanding model initialization and reinitialization is key to building robust ngDiagram applications that can handle dynamic data loading and model switching while maintaining proper timing and state management. --- ## Building groups with complex interactions? > Creating and configuring custom group templates in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/custom-groups/ You can create custom group templates, similar to custom nodes. All you need to do is write a component that implements [`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate) and register it in the [`nodeTemplateMap`](/docs/api/types/templates/ngdiagramnodetemplatemap) with a unique [`type`](/docs/api/types/model/simplenode#type). Remember that in your diagram model, the group node must have [`isGroup: true`](/docs/api/types/model/groupnode#isgroup) set to function as a group. ```typescript {22} GroupNode, NgDiagramGroupHighlightedDirective, NgDiagramGroupNodeTemplate, NgDiagramNodeResizeAdornmentComponent, NgDiagramNodeSelectedDirective, } from 'ng-diagram'; @Component({ imports: [NgDiagramNodeResizeAdornmentComponent, NgDiagramGroupHighlightedDirective, NgDiagramNodeSelectedDirective], template: `
Group header
...
`, // styleUrl: './custom-group.component.scss' }) export class CustomGroupComponent implements NgDiagramGroupNodeTemplate { node = input.required(); } ``` Register your custom group in the [`nodeTemplateMap`](/docs/api/types/templates/ngdiagramnodetemplatemap) and assign its [`type`](/docs/api/types/model/simplenode#type) to the group node. [Registering Custom Types →](/docs/guides/nodes/custom-nodes/#registration) ## Resizing Custom Group For more information on resizing, see [Resizing →](/docs/guides/nodes/resizing) ## Highlighting Custom Group Use [`NgDiagramGroupHighlightedDirective`](/docs/api/directives/ngdiagramgrouphighlighteddirective) for highlight styles. ```html
``` ## Selecting Custom Group Use [`NgDiagramNodeSelectedDirective`](/docs/api/directives/ngdiagramnodeselecteddirective) for selection styles. ```html
``` ## Rotation For more information on rotation, see [Rotation →](/docs/guides/nodes/rotation). ## See Also [Groups →](/docs/guides/nodes/groups) | [Custom Nodes →](/docs/guides/nodes/custom-nodes) --- ## Designing advanced node templates? > How to create and implement custom nodes in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/custom-nodes/ When ngDiagram's default node is not sufficient, you can create custom nodes that provide the flexibility to render any kind of content, such as shapes, icons, Angular components, images, buttons, or even more advanced structures. This allows you to build interactive and highly customized flow elements. You can create a custom node by writing a component that implements the [`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate) interface.
[Custom Node Example →](/docs/examples/custom-node) ## Using the Default Node as a base If you don't want to start from scratch, you can use the [`NgDiagramBaseNodeTemplateComponent`](/docs/api/components/ngdiagrambasenodetemplatecomponent) component as a way to add custom content into the default node. Simply wrap your custom content inside the `` component.
## Registration To register a custom node, you need to add it to the [`nodeTemplateMap`](/docs/api/types/templates/ngdiagramnodetemplatemap). The map associates a string key, such as `myType`, with a value like `CustomNodeComponent`, which is a reference to an Angular component class. After registering, you need to pass the map to the [`ng-diagram`](/docs/api/components/ngdiagramcomponent) component. ## Setting Node Type Assigning the [`type`](/docs/api/types/model/simplenode#type) property as `myType` for the node allows you to precisely control which template is used to render each node. This approach makes your diagram highly extensible and flexible, as you can easily introduce new node types and associate them with different components. ## Custom Appearance Above component receives the node data as input and provides its own template and styles for rendering. In the example, the node displays a header and some content, but you can fully customize its appearance and behavior. ## Node Properties By using this approach—creating custom node components that implement [`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate) and receive the node data as input—you gain full access to the Node definition and all its properties. This means your custom node can leverage any property defined in the Node interface, such as: ```typescript interface SimpleNode { id: string; // The unique identifier for the node. position: Point; // The position of the node in the diagram. data: T; // The data associated with the node. type?: string; // The type of the node declared in nodeTemplateMap. selected?: boolean; // Whether the node is selected. size?: Size; // The size of the node. autoSize?: boolean; // Whether the size of the node is automatically resized based on the content. zOrder?: number; // The z-order of the node. readonly computedZIndex?: number; // The z-index of the node. This value is set automatically. readonly measuredPorts?: Port[]; // The ports of the node. This value is set automatically. resizable?: boolean; // Whether the node is resizable. rotatable?: boolean; // Whether the node is rotatable. angle?: number; // The angle of the node from 0 to 360. groupId?: Node['id']; // The id of the parent node. } ``` [SimpleNode API Reference →](/docs/api/types/model/simplenode) ## Handling Interactive Elements When adding interactive elements like inputs to your custom nodes, dragging on these elements might trigger unwanted diagram behaviors. You can control this using special data attributes: - **`data-no-pan="true"`** - Prevents the diagram canvas from panning when the user clicks and drags on the input - **`data-no-drag="true"`** - Prevents the node itself from being dragged when the user clicks and drags on the input ```html ``` ## Adding Features We also expose advanced behaviors like resizing, rotating, or customizing ports, enhancing the user experience with minimal effort. Integrating these functionalities is straightforward simply place the corresponding components in your node's template. As a result, your custom nodes are not only visually flexible, but also deeply integrated with the diagram's data model, making them powerful and adaptable for complex scenarios. [Resizing →](/docs/guides/nodes/resizing) | [Rotating →](/docs/guides/nodes/rotation) | [Custom Ports →](/docs/guides/nodes/ports) --- ## Groups > Understanding how groups work in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/groups/ Groups in **ngDiagram** are containers for other nodes, allowing you to organize, move, and manage multiple nodes as a single unit. They are essential for structuring complex diagrams, enabling collective operations and visual grouping. [GroupNode API Reference →](/docs/api/types/model/groupnode) ## What is a Group? A group is a node that can contain other nodes (children), serving as both a visual and logical container. Groups support most node features but have unique behaviors for layout and interaction. **Key Concepts:** - **Container Node:** Groups encapsulate other nodes, but child nodes retain their global coordinates. - **Visual Organization:** Useful for representing subsystems, clusters, or logical groupings. - **Interactive:** Groups can be moved, resized, selected, and highlighted. To add a node to a group, simply select the node and drag and drop it into the group. To remove a node from a group, drag the node out of the group. ## Creating a Group To create a group, add a node with [`isGroup: true`](/docs/api/types/model/groupnode#isgroup) to your diagram model. Child nodes reference their parent group via the [`groupId`](/docs/api/types/model/simplenode#groupid) property. ```typescript {3,11} { id: 'group1', isGroup: true, position: { x: 300, y: 400 }, data: { title: 'My Group' }, // Optional: size, autoSize, resizable }, { id: 'node1', position: { x: 350, y: 450 }, groupId: 'group1', data: { label: 'Child Node' } } ``` ## Default Group ngDiagram provides a default group template with built-in styling and resizing. If you do not specify a custom type, the default group template is used. **Features:** - Styled container with content area - Supports resizing and selection - Highlighted when nodes are dragged over
## Resizing Groups Groups can be resized interactively on selection. The resize adornment appears, allowing users to adjust the group's dimensions. For more details, see the [Group Resizing via diagram config](/docs/guides/nodes/groups/#resizing-configuration). ### Resizing Configuration You can control resizing behavior globally via the [`resize`](/docs/api/types/configuration/features/resizeconfig) config in [`NgDiagramConfig`](/docs/api/types/configuration/ngdiagramconfig). - **Minimum size:** Use [`getMinNodeSize`](/docs/api/types/configuration/features/resizeconfig#getminnodesize) to set minimum dimensions for groups (and nodes). - **Prevent resizing below children:** By default, groups can be resized smaller than their children's bounding box, which means child nodes can visually overflow outside the group. Set [`allowResizeBelowChildrenBounds`](/docs/api/types/configuration/features/resizeconfig/#allowresizebelowchildrenbounds) to `false` to prevent the group from being resized smaller than its children. The [`grouping`](/docs/api/types/configuration/features/groupingconfig) configuration in [`NgDiagramConfig`](/docs/api/types/configuration/ngdiagramconfig) lets you control advanced grouping behavior: - **canGroup callback:** Use the [`canGroup`](/docs/api/types/configuration/features/groupingconfig#cangroup) function to control which nodes can be grouped together. This callback receives the group node and the candidate child node, and should return `true` if grouping is allowed. ```typescript {3-4,7} config = { resize: { allowResizeBelowChildrenBounds: false, getMinNodeSize: (node: Node) => (node.isGroup ? { width: 200, height: 120 } : { width: 80, height: 40 }), }, grouping: { canGroup: (node: Node, group: Node) => true, }, }; ``` [Read more about global configuration in ngDiagram →](/docs/guides/configuration/) ## Highlighting Groups Groups can be visually highlighted when nodes are dragged over them or programmatically via the [`highlighted`](/docs/api/types/model/groupnode#highlighted) property. ## Selecting Groups Groups can be visually selected with built-in functionality. [Selection →](/docs/guides/nodes/selection) ## Coordinate System All group and child node positions are defined in the **global coordinate system**. Adding a node to a group does **not** change its coordinates. When a group moves, all its children move by the same delta, preserving their relative positions. --- ## Custom Groups See [Custom Groups](/docs/guides/nodes/custom-groups) for information on creating your own group templates, registering them, and handling advanced behaviors. --- ## Further Reading [Nodes →](/docs/guides/nodes/nodes) | [Custom Nodes →](/docs/guides/nodes/custom-nodes) | [Resizing →](/docs/guides/nodes/resizing) --- ## Nodes > Understanding how nodes work in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/nodes/ Nodes are the fundamental building blocks of a diagram in ngDiagram. They represent entities such as components, processes, or data sources within your system. Each node can contain metadata, inputs, outputs, or custom content, and can be styled or configured to fit your use case. ```typescript interface Node { id: string; // Unique ID of the node position: Point; // The position of the node in the diagram data: T; // Custom data associated with the node // ...optional properties } ``` [Node API Reference →](/docs/api/types/model/simplenode) ## Adding Nodes to a Diagram To add nodes to your diagram, include them in the [`nodes`](/docs/api/services/ngdiagrammodelservice#nodes) array of your model: ## Default Node NgDiagram provides a default node implementation that covers the most common scenarios.\ The default node provides the following features: - **Fully styled component** — Represents a visual entity with one input and one output. - **Rotation and resizing support** — Enabled by default through [`resize.defaultResizable`](/docs/api/types/configuration/features/resizeconfig#defaultresizable) and [`nodeRotation.defaultRotatable`](/docs/api/types/configuration/features/noderotationconfig#defaultrotatable). - **Label display** — Shows a label, provided by convention in `data.label`. - **Interactive states** — Responds to hover and selection for better interactivity. - **Simplicity** — Ideal for representing simple text-based entities. To use the default node template, leave the node's [`type`](/docs/api/types/model/simplenode#type) property **empty**. ### Features The default node comes with built-in support for resizing and rotating through interactive adornments. By default, these features are enabled through the [`resize.defaultResizable`](/docs/api/types/configuration/features/resizeconfig#defaultresizable) and [`nodeRotation.defaultRotatable`](/docs/api/types/configuration/features/noderotationconfig#defaultrotatable) configuration options, but can be overridden per node using the [`resizable`](/docs/api/types/model/simplenode#resizable) and [`rotatable`](/docs/api/types/model/simplenode#rotatable) properties. These features can also be enabled in custom nodes by adding the adornments to their templates.
[Resizing →](/docs/guides/nodes/resizing) | [Rotation →](/docs/guides/nodes/rotation) ### Ports Nodes can expose one or more **ports**, which define the connection points for edges. By convention, the default node includes a single input and a single output port. You can remove the ports using global configuration with [`removePorts: true`](/docs/api/types/configuration/features/defaultnodetemplateconfig/#removeports) . If you want to customize the number, placement, and appearance of ports, you need to create your own node templates. :::note Nodes can have no ports at all, yet users won't be able to manually draw new edges between nodes. Without ports, we can still render existing edges - check [Floating edges](/docs/guides/edges/floating-edges/) for reference ::: [Ports →](/docs/guides/nodes/ports) ### Customization When the default appearance is too generic, you can easily customize it using CSS variables. This allows you to adjust colors, borders, and other visual properties without creating a new node type from scratch.
For deeper customization, you can also define your own node templates, giving you full control over the node's structure and behavior. [Custom Nodes →](/docs/guides/nodes/custom-nodes) ## Position A node's position can be set manually through the [`position`](/docs/api/types/model/simplenode#position) property: ```typescript { id: 'node-1', data: { label: 'My Node' }, position: { x: 100, y: 100 } } ``` The position is defined in **diagram coordinates**. If you want to learn more about how the coordinate system works, see the [Coordinate system](/docs/intro/coordinate-system) The position also updates automatically when a user **moves the node** by dragging it in the diagram. You can listen for drag lifecycle events via [`nodeDragStarted`](/docs/api/types/events/nodedragstartedevent), [`selectionMoved`](/docs/api/types/events/selectionmovedevent), and [`nodeDragEnded`](/docs/api/types/events/nodedragendedevent). ### Disabling Dragging Node dragging is enabled by default. You can disable it per node with [`draggable: false`](/docs/api/types/model/simplenode#draggable) or globally with [`nodeDraggingEnabled: false`](/docs/api/types/configuration/flowconfig#nodedraggingenabled) in the diagram configuration. The per-node [`draggable`](/docs/api/types/model/simplenode#draggable) property takes priority over the global setting. ## Size NgDiagram provides two main approaches to control node sizing: - **Manual sizing** – explicitly set the node's dimensions with the [`size`](/docs/api/types/model/simplenode#size) property. - **Automatic sizing** – let the node adjust to its content automatically. The [`size`](/docs/api/types/model/simplenode#size) property is **optional**. If not provided, the size will be calculated based on the content of the node. To precisely control the size of a node, use the [`size`](/docs/api/types/model/simplenode#size) property: ```typescript { id: 'node-1', data: { label: 'My Node' }, size: { width: 120, height: 60 }, autoSize: false } ``` :::note By default, nodes use **automatic sizing** ([`autoSize: true`](/docs/api/types/model/simplenode#autosize)). In this mode, the provided [`size`](/docs/api/types/model/simplenode#size) property is ignored, and the node resizes itself to fit its content. The [`size`](/docs/api/types/model/simplenode#size) property is then updated with the **measured values**. To set a manual size for a node, you must explicitly set [`autoSize: false`](/docs/api/types/model/simplenode#autosize). Without this, the [`size`](/docs/api/types/model/simplenode#size) property will be overridden by the automatic sizing behavior. ::: --- ## Ports > Understanding how ports work in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/ports/ Ports are connection points on Nodes that allow Edges to link different entities in your diagram. You can define where and how connections can be made, enabling flexible and interactive diagrams. A port is defined by several key properties: - **id**: Uniquely identifies the port within the diagram. - **type**: Determines if the port is a source, target, or both for edge connections. - **side**: Specifies which side of the node the port appears on (e.g., left, right, top, bottom). - **originPoint**: Controls the transform origin of the port for precise placement. Each node has a [`measuredPorts`](/docs/api/types/model/simplenode/#measuredports) property that provides information about its ports and their computed position and dimensions. This property is read-only and should not be modified. ## Styling Ports Ports are rendered using the [``](/docs/api/components/ngdiagramportcomponent) component. You can customize their appearance by overriding CSS variables, adding inline styles, custom classes, **or by providing custom content directly inside the port**. ### Custom Content You can render any content inside a port, such as text, images, SVGs, or any icons. ```html
icon Custom
``` Custom content automatically disables the default circular style and allows full control over the port's appearance. ### Port positioning with Origin Point You can use the [`originPoint`](/docs/api/components/ngdiagramportcomponent#originpoint) input to precisely control the transform origin of each port. Supported values: `topLeft`, `centerLeft`, `bottomLeft`, `topCenter`, `center`, `bottomCenter`, `topRight`, `centerRight`, `bottomRight`. Example usage: ```html
icon
``` This applies the corresponding CSS transform for accurate port placement. If you need further customization of port placement, you can use CSS styling by adding styles directly to the port or via a [custom class](/docs/guides/nodes/ports/#custom-css). ```html
icon
``` ### Default CSS Variables The following CSS variables can be overridden to change the look and feel of ports: ```scss --ngd-port-size: 0.25rem; --ngd-port-background-color: #fff; --ngd-port-background-color-hover: #9140ff; // based on theme --ngd-port-border-size: 2px; --ngd-port-border-color: #6f7480; // based on theme --ngd-port-border-radius: 50%; // makes the port circular for default style ``` > **Note:** `--ngd-port-size` property is only for default ports. > When using custom content, the port size automatically adjusts to fit the content. > When using circular shapes in custom content, use `--ngd-port-border-radius` to control the hover roundness. ### Custom CSS To create a custom style, define a CSS class and assign it to a port: ```scss .some-custom-class { --ngd-port-size: 18px; --ngd-port-background-color: #7dd184; --ngd-port-border-size: 0px; /* Change to custom position of port */ transform: translate(-10%, -95%); } ``` ```typescript
...
... ``` ### Hover style You can enable default hover styles on ports by adding the following code into your component: ## Port Measurement ngDiagram automatically measures port positions and sizes using a `ResizeObserver`. In most cases, you don't need to do anything - measurements update automatically when: - A port or its node is **resized** (content change, node resize, etc.) - A port's [`side`](/docs/api/components/ngdiagramportcomponent#side) or [`originPoint`](/docs/api/components/ngdiagramportcomponent#originpoint) input changes However, `ResizeObserver` only detects **size** changes, not **position** changes. If you reposition ports through CSS without changing their size - for example by toggling classes, changing `style.top`/`style.left` bindings, or reordering a data-driven port list - ngDiagram has no way to detect this automatically. In these cases, call [`invalidateMeasurements()`](/docs/api/services/ngdiagramservice/#invalidatemeasurements) to tell the library to re-measure: ```typescript // Update node data that causes ports to shift via CSS this.ngDiagramModelService.updateNodes([{ id: 'node-1', data: { ports: reorderedPorts } }]); // Tell ngDiagram to re-measure the affected node and its ports this.ngDiagramService.invalidateMeasurements({ nodes: [{ nodeId: 'node-1' }], }); ``` You can also call it without arguments to re-measure the entire diagram: ```typescript this.ngDiagramService.invalidateMeasurements(); ``` ## Example Usage To add ports to a node, render them in your node template: ## Live example
## Customization You can fully customize port appearance and behavior by: - Overriding CSS variables for color, size, and border - Applying custom classes for unique effects - Providing custom content for advanced visuals [Custom Ports Example →](/docs/examples/custom-ports) --- ## Resizing > Understanding how resizing works in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/resizing/ The **resizing** feature in ngDiagram allows users to interactively change the size of nodes on the diagram canvas. Resizable nodes display resize handles and lines that users can drag to adjust the node's width and height. The new size is reflected in the node's appearance and can be used to create flexible, dynamic diagrams.
## How It Works - Nodes can be resized by dragging the resize handles or lines. - The node's size is updated in its data model. - Resizing can be enabled per node, per custom template, or globally in the configuration. It can also be configured through the global configuration. ## Custom Node Setup To make a custom node resizable, wrap your node with [``](/docs/api/components/ngdiagramnoderesizeadornmentcomponent) in your node template and import the [`NgDiagramNodeResizeAdornmentComponent`](/docs/api/components/ngdiagramnoderesizeadornmentcomponent). ## Limiting Which Sides Resize By default all four sides and all four corners of a node can be dragged. Use the [`activeSides`](/docs/api/components/ngdiagramnoderesizeadornmentcomponent/#activesides) input to narrow that down — useful for nodes anchored on one side, such as swimlanes stacked from the top-left corner, where dragging the top or left side fights the layout that keeps them anchored: ```html ``` - All four lines keep rendering, because they also draw the node's selection frame. Lines for sides you leave out are inert: they do not start a resize and show no resize cursor. - A corner handle appears only when both of its sides are listed, so `['right', 'bottom']` leaves only the bottom-right handle. - An empty array keeps the selection frame without any interactive resize. ## Customization ### Resize Handle Here are the CSS variables you can use to style the resize handle: ``` --ngd-resize-handle-background-color // Background color of the handle --ngd-resize-handle-background-color-hover // Background color on hover or focus --ngd-resize-handle-background-color-active // Background color when active or resizing --ngd-resize-handle-size // Size (width and height) of the handle --ngd-resize-handle-top // Positioning of the handle --ngd-resize-handle-right // Positioning of the handle --ngd-resize-handle-bottom // Positioning of the handle --ngd-resize-handle-left // Positioning of the handle ``` ### Resize Line Here are the CSS variables you can use to style the resize line: ``` --ngd-resize-line-border-width // Border width of the line --ngd-resize-line-border-style // Border style of the line (e.g. solid, dashed) --ngd-resize-line-border-color // Border color of the line ``` You can override these variables in your styles to customize the appearance and position of the resize handles and lines. ## Configuration ### Resizing Settings You can further customize resizing behavior using the [`resize`](/docs/api/types/configuration/flowconfig/#resize) configuration in [`NgDiagramConfig`](/docs/api/types/configuration/flowconfig): - **[`defaultResizable`](/docs/api/types/configuration/features/resizeconfig/#defaultresizable)** – Controls whether resizing is enabled by default for all nodes. Default is `true`. - **[`getMinNodeSize`](/docs/api/types/configuration/features/resizeconfig/#getminnodesize)** – Returns the minimum size for a node during resizing. Default is 20x20px. - **[`allowResizeBelowChildrenBounds`](/docs/api/types/configuration/features/resizeconfig/#allowresizebelowchildrenbounds)** – By default, groups can be resized to any size, even smaller than their children. If you want to prevent resizing a group smaller than its children (so all children always remain fully contained), set this option to `false`. You can set these options in your diagram configuration and pass them to the [`ng-diagram`](/docs/api/components/ngdiagramcomponent) component: ### Resizing Setting Priority The [`resizable`](/docs/api/types/model/simplenode/#resizable) property controls whether a node can be resized. This property can be defined at several levels, and when multiple levels specify it, the one with the highest priority takes effect. The following list shows the order of priority — from highest to lowest: 1. **Node-level setting** – Directly set the [`resizable`](/docs/api/types/model/simplenode/#resizable) property on the node data object. ```typescript const node: Node = { id: 'my-id', resizable: true, // other node properties }; ``` This setting applies specifically to that node and overrides all other defaults. 2. **Template-level setting** – Use the [`defaultResizable`](/docs/api/components/ngdiagramnoderesizeadornmentcomponent/#defaultresizable) input on the [`NgDiagramNodeResizeAdornmentComponent`](/docs/api/components/ngdiagramnoderesizeadornmentcomponent) within your custom node template. ```html ``` This defines the default resizing behavior for all nodes that use that template. 3. **Global configuration** – Define the global [`defaultResizable`](/docs/api/types/configuration/features/resizeconfig/#defaultresizable) setting inside your [`NgDiagramConfig`](/docs/api/types/configuration/flowconfig): ```typescript const config: NgDiagramConfig = { resize: { defaultResizable: false, }, }; ``` This establishes the fallback behavior for all nodes unless overridden by a template or individual node. [Read more about global configuration in ngDiagram →](/docs/guides/configuration/) ## Events The diagram emits several events related to resizing that you can subscribe to via `@Output` bindings on the [`ng-diagram`](/docs/api/components/ngdiagramcomponent) component or programmatically through [`NgDiagramService.addEventListener()`](/docs/api/services/ngdiagramservice#addeventlistener): - [`nodeResizeStarted`](/docs/api/types/events/noderesizestartedevent) - Fired once when the user starts resizing a node by dragging a resize handle. - [`nodeResized`](/docs/api/types/events/noderesizedevent) - Fired continuously on each size change while the user is resizing a node. - [`nodeResizeEnded`](/docs/api/types/events/noderesizeendedevent) - Fired when the user releases the pointer after resizing a node. The node will have its final size when this event is received. ## Further Reading [Nodes →](/docs/guides/nodes/nodes) | [Custom Nodes →](/docs/guides/nodes/custom-nodes) --- ## Rotation > Understanding how rotation works in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/rotation/ The **rotation** feature in ngDiagram allows users to interactively rotate nodes on the diagram canvas. Rotatable nodes display a rotation handle that users can drag to change the node's angle. The rotation is reflected in the node's appearance and can be used to create various diagrams.
## How It Works - Nodes can be rotated by dragging the rotation handle. - The rotation angle is stored in the node's [`angle`](/docs/api/types/model/simplenode/#angle) property. - Rotation can be enabled per node, per custom template, or globally in the configuration. It can also be configured through the global configuration. ## Custom Node Setup To make a custom node rotatable, include [``](/docs/api/components/ngdiagramnoderotateadornmentcomponent) in your node template and import the [`NgDiagramNodeRotateAdornmentComponent`](/docs/api/components/ngdiagramnoderotateadornmentcomponent) reference. ## Customization ### Rotate Handle Here are the CSS variables you can use to style the rotation handle: ``` --ngd-rotate-handle-background-color // Background color of the handle --ngd-rotate-handle-background-color-hover // Background color on hover or focus --ngd-rotate-handle-background-color-active // Background color when active or rotating --ngd-rotate-handle-size // Size (width and height) of the handle --ngd-rotate-handle-top // Positioning of the handle --ngd-rotate-handle-right // Positioning of the handle --ngd-rotate-handle-bottom // Positioning of the handle --ngd-rotate-handle-left // Positioning of the handle ``` You can override these variables in your styles to customize the appearance and position of the rotation handle. ### Custom Handle If you want to use a custom icon as a handle, simply place your SVG or Angular component inside [``](/docs/api/components/ngdiagramnoderotateadornmentcomponent). The content you provide will be rendered inside the handle. ```typescript ... ``` If you do not provide any content inside [``](/docs/api/components/ngdiagramnoderotateadornmentcomponent), the component will automatically display its built-in default rotation icon. ## Configuration ### Rotation Settings You can further customize rotation behavior using the [`nodeRotation`](/docs/api/types/configuration/flowconfig/#noderotation) configuration in [`NgDiagramConfig`](/docs/api/types/configuration/flowconfig): - **[`defaultRotatable`](/docs/api/types/configuration/features/noderotationconfig/#defaultrotatable)** – Controls whether rotation is enabled by default for all nodes. Default is `true`. - **[`computeSnapAngleForNode`](/docs/api/types/configuration/features/noderotationconfig/#computesnapanglefornode)** - Computes the snap angle for a node's rotation. - **[`defaultSnapAngle`](/docs/api/types/configuration/features/noderotationconfig/#defaultsnapangle)** - The default snap angle in degrees, used if `computeSnapAngleForNode` returns null. - **[`shouldSnapForNode`](/docs/api/types/configuration/features/noderotationconfig/#shouldsnapfornode)** - Determines whether rotation snapping should be enabled for a node. You can set these options in your diagram by passing the configuration to the [`ng-diagram`](/docs/api/components/ngdiagramcomponent) component: ### Rotation Setting Priority The [`rotatable`](/docs/api/types/model/simplenode/#rotatable) property controls whether a node can be rotated. This property can be defined at several levels, and when multiple levels specify it, the one with the highest priority takes effect. The following list shows the order of priority — from highest to lowest: 1. **Node-level setting** – Directly set the [`rotatable`](/docs/api/types/model/simplenode/#rotatable) property on the node data object. ```typescript const node: Node = { id: 'my-id', rotatable: true, // other node properties }; ``` This setting applies specifically to that node and overrides all other defaults. 2. **Template-level setting** – Use the [`defaultRotatable`](/docs/api/components/ngdiagramnoderotateadornmentcomponent/#defaultrotatable) input on the [`NgDiagramNodeRotateAdornmentComponent`](/docs/api/components/ngdiagramnoderotateadornmentcomponent) within your custom node template. ```html ``` This defines the default rotation behavior for all nodes that use that template. 3. **Global configuration** – Define the global [`defaultRotatable`](/docs/api/types/configuration/features/noderotationconfig/#defaultrotatable) setting inside your [`NgDiagramConfig`](/docs/api/types/configuration/flowconfig). ```typescript const config: NgDiagramConfig = { nodeRotation: { defaultRotatable: false, }, }; ``` This establishes the fallback behavior for all nodes unless overridden by a template or individual node. [Read more about global configuration in ngDiagram →](/docs/guides/configuration/) ## Events The diagram emits several events related to rotation that you can subscribe to via `@Output` bindings on the [`ng-diagram`](/docs/api/components/ngdiagramcomponent) component or programmatically through [`NgDiagramService.addEventListener()`](/docs/api/services/ngdiagramservice#addeventlistener): - [`nodeRotateStarted`](/docs/api/types/events/noderotatestartedevent) - Fired once when the user starts rotating a node by dragging the rotation handle. - [`selectionRotated`](/docs/api/types/events/selectionrotatedevent) - Fired continuously on each angle change while the user is rotating nodes. - [`nodeRotateEnded`](/docs/api/types/events/noderotateendedevent) - Fired when the user releases the pointer after rotating a node. The node will have its final angle when this event is received. ## Further Reading [Nodes →](/docs/guides/nodes/nodes) | [Custom Nodes →](/docs/guides/nodes/custom-nodes) --- ## Selection > Understanding how selection works in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/selection/ The **selection** feature in ngDiagram allows users to select nodes on the diagram canvas. Selected nodes are visually highlighted, making it easier to identify and interact with them. ## How It Works - Nodes can be selected by clicking on them. - When a node is selected, it will be visually highlighted according to the styles defined in your application. - The selected state is managed by ngDiagram and can be accessed via the node's [`selected`](/docs/api/types/model/simplenode/#selected) property. - Default selection style can be enabled per node using a directive provided by ngDiagram. ## Custom Node Styling Selection can be fully customized by using the [`selected`](/docs/api/types/model/simplenode/#selected) property from the node to control its state. You can assign any CSS class you prefer based on this property and define your own styles for selected nodes. This allows you to tailor the selection appearance and behavior to fit your application's needs.
## Using Default Styles To make a custom node selectable with default functionality, add the [`NgDiagramNodeSelectedDirective`](/docs/api/directives/ngdiagramnodeselecteddirective) as a host directive in your node component. There is no need to define anything else in your node or to provide custom selection styles. :::note The host element must have `display: block` or `display: flex` set in its styles for the selection box-shadow to render properly. Without this, the selection effect may be invisible or barely visible. :::
## Customizing Defaults If you want to use the default selection functionality, you can still customize its styles. Here is a CSS variable you can use to style the selection highlight: ``` --ngd-selected-node-box-shadow // Box shadow for selected node ``` You can override this variable in your styles to customize the appearance of selected nodes. ## Events The diagram emits several events related to selection that you can subscribe to via `@Output` bindings on the [`ng-diagram`](/docs/api/components/ngdiagramcomponent) component or programmatically through [`NgDiagramService.addEventListener()`](/docs/api/services/ngdiagramservice#addeventlistener): - [`selectionChanged`](/docs/api/types/events/selectionchangedevent) - Fired when the selection state changes (nodes or edges are selected or deselected). This fires on pointerdown when clicking elements. - [`selectionGestureEnded`](/docs/api/types/events/selectiongestureendedevent) - Fired when a selection gesture completes (on pointerup after clicking a node/edge, box selection, or select-all). Use this to trigger actions after the user finishes selecting, such as showing toolbars or updating panels. ## Further Reading [Nodes →](/docs/guides/nodes/nodes) | [Custom Nodes →](/docs/guides/nodes/custom-nodes) --- ## Snapping > Understanding how snapping works in ngDiagram URL: https://ngdiagram.dev/docs/guides/nodes/snapping/ The **snapping** feature in ngDiagram allows nodes to be moved and resized in steps, making it easier to align elements on the diagram canvas. ## Snap Drag Configuration The following configuration options are available for snapping nodes during drag operations: ```typescript const config = { snapping: { shouldSnapDragForNode: (node) => true, computeSnapForNodeDrag: (node) => ({ width: 10, height: 10 }), defaultDragSnap: { width: 10, height: 10 }, }, } satisfies NgDiagramConfig; ``` - [`shouldSnapDragForNode`](/docs/api/types/configuration/features/snappingconfig/#shouldsnapdragfornode) determines whether a node should snap to a grid when being dragged. When this function returns `true` for a given node, the node's position will align to the nearest snap points during drag operations. - [`computeSnapForNodeDrag`](/docs/api/types/configuration/features/snappingconfig/#computesnapfornodedrag) defines the snap step for dragging nodes. - [`defaultDragSnap`](/docs/api/types/configuration/features/snappingconfig/#defaultdragsnap) sets a default snap step for dragging nodes if [`computeSnapForNodeDrag`](/docs/api/types/configuration/features/snappingconfig/#computesnapfornodedrag) is not provided.\ The default value is `{ width: 10, height: 10 }`.

## Snap Resize Configuration The following configuration options allow you to configure snapping when resizing nodes: ```typescript const config = { snapping: { shouldSnapResizeForNode: (node) => true, computeSnapForNodeSize: (node) => ({ width: 10, height: 10 }), defaultResizeSnap: { width: 10, height: 10 }, computeSnapOffsetForNodeSize: (node) => ({ width: 0, height: 0 }), defaultResizeSnapOffset: { width: 0, height: 0 }, }, } satisfies NgDiagramConfig; ``` - [`shouldSnapResizeForNode`](/docs/api/types/configuration/features/snappingconfig/#shouldsnapresizefornode) determines whether a node should snap to a grid when being resized. When this function returns `true` for a given node, the node's size will align to the nearest snap points during resize operations. - [`computeSnapForNodeSize`](/docs/api/types/configuration/features/snappingconfig/#computesnapfornodesize) defines the snap step for resizing nodes. - [`defaultResizeSnap`](/docs/api/types/configuration/features/snappingconfig/#defaultresizesnap) sets a default snap step for resizing nodes if [`computeSnapForNodeSize`](/docs/api/types/configuration/features/snappingconfig/#computesnapfornodesize) is not provided.\ The default value is `{ width: 10, height: 10 }`. - [`computeSnapOffsetForNodeSize`](/docs/api/types/configuration/features/snappingconfig/#computesnapoffsetfornodesize) and [`defaultResizeSnapOffset`](/docs/api/types/configuration/features/snappingconfig/#defaultresizesnapoffset) shift the sequence of snapped sizes: sizes land on `offset + n * snap`, so a node with a 60px header and a 50px vertical snap can snap to 60, 110, 160, … instead of 50, 100, 150, ….\ The default offset is `{ width: 0, height: 0 }`.

## Usage with Background Grid Snapping can be configured to work in conjunction with the background grid feature. When both the grid and snapping are using multiples of the same size, dragged nodes align to the grid lines, and resized nodes keep their sizes on the grid — so a node whose position sits on the grid stays aligned to the grid lines through every resize.


[Background reference →](/docs/guides/background) | [Read more about global configuration in ngDiagram →](/docs/guides/configuration/) --- ## Palette > Understanding how the palette works in ngDiagram URL: https://ngdiagram.dev/docs/guides/palette/ NgDiagram provides a comprehensive palette system that allows users to create custom drag-and-drop interfaces for adding nodes to diagrams. The palette system consists of built-in components that can be customized to create your own palette. ## Palette Items The core building block of the palette is the [``](/docs/api/components/ngdiagrampaletteitemcomponent) component. It transforms any content into a draggable palette item. This wrapper provides drag-and-drop capabilities without imposing visual constraints on the content itself. A palette item is defined by an [`NgDiagramPaletteItem`](/docs/api/types/palette/ngdiagrampaletteitem/): ```typescript interface NgDiagramPaletteItem { type?: string; data: Data; resizable?: boolean; rotatable?: boolean; angle?: number; size?: Size; autoSize?: boolean; zOrder?: number; } ``` A palette item is essentially a definition of a [`node`](/docs/api/types/model/node). You can specify its data or other properties that will be used when the node is initialized on the diagram. Think of it as similar to an Angular component definition: - The definition in the palette describes how the node should be created. - The instance dropped into the diagram becomes a live node. > **Note:** You can use your node templates directly inside the palette to represent items. > However, ports will not be rendered in the palette or its preview. Ports only render within the diagram canvas context, so outside of it (e.g. palette or preview), they will not appear. ## Custom content When using [``](/docs/api/components/ngdiagrampaletteitemcomponent), you can pass any HTML or Angular template as its content to represent the item in the palette. For example, this could be plain text, an image, or a more complex Angular component. ## Previews When dragging, a preview of the node is shown. To define the preview, wrap your content in [``](/docs/api/components/ngdiagrampaletteitempreviewcomponent) inside [``](/docs/api/components/ngdiagrampaletteitemcomponent). The preview itself can be any HTML or Angular component. --- ## Keyboard Shortcuts > Learn how to customize and use keyboard shortcuts in ngDiagram URL: https://ngdiagram.dev/docs/guides/shortcut-manager/ The keyboard shortcuts system in ngDiagram lets users perform common actions quickly using customizable key combinations. It supports platform-specific modifier keys (automatically handling Ctrl/Cmd differences), multiple shortcuts per action, and dynamic runtime updates. ## Available Actions All available shortcut actions with their default key bindings. See [`ShortcutActionName`](/docs/api/types/configuration/shortcuts/shortcutactionname) for the complete type reference. | Action | Default Shortcut | Description | | ---------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | `boxSelection` | Shift held | Enable box selection mode (pointer only) | | `cancelInteraction` | Escape | Cancel the in-progress interaction (linking, drag, resize, rotate, pan) | | `copy` | Ctrl/Cmd + C | Copy selected elements to clipboard | | `cut` | Ctrl/Cmd + X | Cut selected elements to clipboard | | `deleteSelection` | Delete or Backspace | Delete currently selected elements | | `keyboardMoveSelectionDown` | | Move selected elements down | | `keyboardMoveSelectionLeft` | | Move selected elements left | | `keyboardMoveSelectionRight` | | Move selected elements right | | `keyboardMoveSelectionUp` | | Move selected elements up | | `keyboardPanDown` | | Pan viewport down | | `keyboardPanLeft` | | Pan viewport left | | `keyboardPanRight` | | Pan viewport right | | `keyboardPanUp` | | Pan viewport up | | `keyboardZoomIn` | = | Increase diagram viewport scale | | `keyboardZoomOut` | - | Decrease diagram viewport scale | | `multiSelection` | Ctrl/Cmd held | Multi-selection mode (pointer only) | | `paste` | Ctrl/Cmd + V | Paste elements from clipboard | | `redo` | Ctrl/Cmd + Y | Redo last undone action (not implemented by default; requires custom model) | | `selectAll` | Ctrl/Cmd + A | Select all elements in the diagram | | `undo` | Ctrl/Cmd + Z | Undo last action (not implemented by default; requires custom model) | | `zoom` | Ctrl/Cmd + Wheel | Increase or decrease diagram viewport scale | ## Basic Usage To override, disable, or extend default shortcuts, use the [`configureShortcuts()`](/docs/api/utilities/configureshortcuts) helper: ```typescript const config = { shortcuts: configureShortcuts([ // Override: Change paste to Ctrl+B { actionName: 'paste', bindings: [{ key: 'b', modifiers: { primary: true } }], }, // Disable: Empty bindings array { actionName: 'undo', bindings: [], }, // Multiple bindings: WSAD + Arrow keys { actionName: 'keyboardMoveSelectionUp', bindings: [{ key: 'w' }, { key: 'ArrowUp' }], }, ]), }; ``` You can also merge custom shortcuts with existing ones at runtime: ```typescript // Get current shortcuts from the service const currentShortcuts = ngDiagramService.config().shortcuts; // Merge custom shortcuts with existing ones const updatedShortcuts = configureShortcuts( [ { actionName: 'paste', bindings: [{ key: 'b', modifiers: { primary: true } }], }, ], currentShortcuts // Pass existing shortcuts as base ); // Update the configuration ngDiagramService.updateConfig({ shortcuts: updatedShortcuts }); ``` [`configureShortcuts(customShortcuts, baseShortcuts?)`](/docs/api/utilities/configureshortcuts/) merges your custom shortcuts with defaults: - **First parameter:** Custom shortcuts (overrides actions with matching `actionName`) - **Second parameter:** Optional base shortcuts. Defaults are used if omitted. - **Returns:** A merged shortcuts array Unspecified actions retain their existing shortcuts. ## Configuration Reference ### Shortcut Structure Keyboard and pointer shortcuts in ngDiagram are defined through the ShortcutDefinition interface. A shortcut definition maps an action name to one or more key bindings (keyboard or modifier-only combinations). Each shortcut may include: - **One or more keyboard bindings** (e.g., Ctrl + C) - **Or one or more modifier-only bindings** (e.g., Shift + click for box selection) See [`ShortcutDefinition`](/docs/api/types/configuration/shortcuts/shortcutdefinition/) API reference. ### Available Modifiers ```typescript interface InputModifiers { primary: boolean; // Ctrl (Windows/Linux) OR Cmd (macOS) - auto-normalized secondary: boolean; // Alt key shift: boolean; // Shift key meta: boolean; // Windows key or Cmd key } ``` **Platform normalization:** The `primary` modifier automatically maps to **Ctrl** on Windows/Linux and **Cmd** on macOS, allowing you to define shortcuts once that work seamlessly across platforms. ### Key Names Use standard browser key names: `'a'`, `'b'`, `'Delete'`, `'Backspace'`, `'ArrowUp'`, `'ArrowDown'`, `'ArrowLeft'`, `'ArrowRight'`, etc. Keys are case-sensitive. See [MDN KeyboardEvent.key documentation](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values) for the complete list of valid key values. ### Modifier-Only Shortcuts Modifier-only shortcuts (bindings without a `key`) are used for pointer-based interactions, such as holding Shift for box selection or holding Ctrl/Cmd and using mouse wheel for zoom in and zoom out. ```typescript { modifiers: { shift: true, } } // Matches when Shift held during click ``` These shortcuts ensure that typing keys won't accidentally trigger diagram actions. ## Example --- ## State Management > Learn how to create models, access the model service, and perform operations on your diagram data URL: https://ngdiagram.dev/docs/guides/state-management/ ngDiagram uses a reactive state management system that allows you to create, access, and modify diagram data efficiently. Understanding this system is essential for building dynamic, interactive diagrams. ## Creating a Model The model is the core data structure that holds all your diagram information including nodes, edges, and metadata. Use the [`initializeModel`](/docs/api/utilities/initializemodel) function to create a new model with initial data. For more information about model initialization scenarios and best practices, see [Model Initialization](/docs/guides/model-initialization/). ### Basic Model Creation ```typescript const model = initializeModel({ nodes: [ { id: '1', position: { x: 100, y: 150 }, data: { label: 'Node 1' }, }, { id: '2', position: { x: 400, y: 150 }, data: { label: 'Node 2' }, }, ], edges: [ { id: '1', source: '1', sourcePort: 'port-right', targetPort: 'port-left', target: '2', data: {}, }, ], }); ``` ### Model with Metadata You can also initialize your model with metadata such as viewport settings: ```typescript const model = initializeModel({ metadata: { viewport: { x: 100, y: 50, scale: 0.8 }, }, nodes: [ // ... your nodes ], edges: [ // ... your edges ], }); ``` Despite preconfigured metadata, you can keep there any additional custom properties that you may need in your application. ### TypeScript Support For better type safety with custom data types, you can specify them when creating your model: ```typescript interface CustomNodeData { label: string; category: 'input' | 'output' | 'process'; } interface CustomEdgeData { label?: string; style?: 'solid' | 'dashed'; } const model = initializeModel({ nodes: [ { id: '1', position: { x: 100, y: 150 }, data: { label: 'Process Node', category: 'process' } as CustomNodeData, }, // ... your nodes ], edges: [ { id: '1', source: '1', sourcePort: 'port-right', targetPort: 'port-left', target: '2', data: { label: 'Connection', style: 'solid' } as CustomEdgeData, }, // ... your edges ], }); ``` ## Model Service The [`NgDiagramModelService`](/docs/api/services/ngdiagrammodelservice) provides a reactive interface to interact with your diagram's state. \ It becomes available once you register [`provideNgDiagram()`](/docs/api/utilities/providengdiagram) and can then be injected into your components. ### Injecting the Service ```typescript @Component({ // ... }) export class MyComponent { private modelService = inject(NgDiagramModelService); } ``` ### Reactive Data The model service provides reactive signals for nodes, edges, and metadata: ```typescript export class MyComponent { private modelService = inject(NgDiagramModelService); // Reactive signals nodes = this.modelService.nodes; edges = this.modelService.edges; metadata = this.modelService.metadata; constructor() { // Access current values effect(() => { console.log('Current nodes:', this.nodes()); console.log('Current edges:', this.edges()); console.log('Current viewport:', this.metadata().viewport); }); } } ``` ### Using in Templates You can bind directly to the reactive signals in your templates: ```html

Total nodes: {{ nodes().length }}

Total edges: {{ edges().length }}

Current scale: {{ metadata().viewport.scale }}

``` ## Performing Operations The model service provides comprehensive methods for adding, updating, deleting, and querying diagram elements. ### Awaiting Changes Every mutating service method returns a `Promise` that resolves once the change has been applied to the model — the next line of code reads the updated state: ```typescript await this.modelService.deleteNodes(['node-1']); // The model is already updated here — safe to act on it: this.viewportService.zoomToFit(); ``` Awaiting is optional — a call whose promise you ignore applies the change all the same. Await when the next step depends on the change being applied: sequencing operations, reading the model right after a mutation, or reacting to a rejected update (a failing [middleware](/docs/guides/middlewares/) rejects the returned promise). In projects using the `@typescript-eslint/no-floating-promises` lint rule, mark intentional fire-and-forget calls with the `void` operator: `void this.modelService.addNodes([node]);`. Inside a [transaction](/docs/guides/transactions/) the promise resolves right away and the change is applied when the transaction commits. ### Adding Elements Add new nodes and edges to your diagram: ```typescript // Add new nodes this.modelService.addNodes([ { id: 'new-node', position: { x: 200, y: 200 }, data: { label: 'New Node' }, }, ]); // Add new edges this.modelService.addEdges([ { id: 'new-edge', source: '1', target: 'new-node', sourcePort: 'port-right', targetPort: 'port-left', data: {}, }, ]); ``` ### Updating Elements Update properties of existing nodes and edges: ```typescript // Update entire node this.modelService.updateNode('node-1', { position: { x: 300, y: 300 }, data: { label: 'Updated Node' }, }); // Update only node data this.modelService.updateNodeData('node-1', { label: 'New Label', color: 'blue', }); // Update multiple nodes at once this.modelService.updateNodes([ { id: '1', position: { x: 100, y: 100 } }, { id: '2', position: { x: 200, y: 200 } }, ]); // Update edge properties this.modelService.updateEdge('edge-1', { data: { label: 'Updated Edge' }, }); // Update only edge data this.modelService.updateEdgeData('edge-1', { label: 'Connection', style: 'dashed', }); ``` ### Deleting Elements Remove nodes and edges from your diagram: ```typescript // Delete nodes this.modelService.deleteNodes(['node-1', 'node-2']); // Delete edges this.modelService.deleteEdges(['edge-1', 'edge-2']); ``` ### Querying Elements Find and retrieve specific elements: ```typescript // Get element by ID const node = this.modelService.getNodeById('node-1'); const edge = this.modelService.getEdgeById('edge-1'); // Find nearest node to a point const nearestNode = this.modelService.getNearestNodeInRange( { x: 150, y: 150 }, 50 // range in pixels ); // Find nearest port to a point const nearestPort = this.modelService.getNearestPortInRange({ x: 150, y: 150 }, 30); // Get all nodes in a range const nodesInRange = this.modelService.getNodesInRange({ x: 150, y: 150 }, 100); ``` ### Model Serialization Save and restore your diagram state: ```typescript // Angular injector placed in component to initialize model from saved state private injector = inject(Injector); saveModel() { // Export model to JSON const jsonString = this.modelService.toJSON(); // Store in localStorage localStorage.setItem('diagram-state', jsonString); } openModel() { // Load from localStorage const savedState = localStorage.getItem('diagram-state'); if (savedState) { const parsedModel = JSON.parse(savedState); // Create new model from saved state this.model = initializeModel(parsedModel, this.injector); } } ``` ## Best Practices ### Reactive Updates Always use the model service methods rather than directly modifying the model: ```typescript // ❌ Don't modify directly this.model.nodes[0].position = { x: 100, y: 100 }; // ❌ Also don't use model methods directly this.model.updateNode('node-id', { position: { x: 100, y: 100 } }); // ✅ Use model service methods this.modelService.updateNode('node-id', { position: { x: 100, y: 100 }, }); ``` ### TypeScript Types Leverage TypeScript for better development experience: ```typescript interface NodeData { label: string; color?: string; category: 'input' | 'output' | 'process'; } interface EdgeData { label?: string; style?: 'solid' | 'dashed'; } // Type your updates this.modelService.updateNodeData('node-1', { label: 'Process Node', category: 'process', }); this.modelService.updateEdgeData('edge-1', { style: 'dashed', }); ``` ### Performance Considerations For bulk operations, use batch methods when available: ```typescript // ✅ Better performance for multiple updates this.modelService.updateNodes([ { id: '1', position: { x: 100, y: 100 } }, { id: '2', position: { x: 200, y: 200 } }, { id: '3', position: { x: 300, y: 300 } }, ]); // ❌ Less efficient for multiple updates this.modelService.updateNode('1', { position: { x: 100, y: 100 } }); this.modelService.updateNode('2', { position: { x: 200, y: 200 } }); this.modelService.updateNode('3', { position: { x: 300, y: 300 } }); ``` The state management system provides a robust foundation for building dynamic diagrams that can respond to user interactions and external data changes while maintaining excellent performance and type safety. ## Custom Models The [`NgDiagramComponent`](/docs/api/components/ngdiagramcomponent) accepts any object that implements the [`ModelAdapter`](/docs/api/types/model/modeladapter/) interface, which means you can create your own custom model implementations beyond the default `SignalModelAdapter` provided by [`initializeModel`](/docs/api/utilities/initializemodel). Use [`initializeModelAdapter`](/docs/api/utilities/initializemodeladapter) to prepare a custom adapter for use with ngDiagram.\ This allows for advanced use cases like connecting to external data sources, implementing custom persistence layers, or integrating with existing state management solutions. ### ModelAdapter Interface The [`ModelAdapter`](/docs/api/types/model/modeladapter/) interface defines the contract that any model implementation must fulfill. The key methods include data access ([`getNodes`](/docs/api/types/model/modeladapter/#getnodes), [`getEdges`](/docs/api/types/model/modeladapter/#getedges), [`getMetadata`](/docs/api/types/model/modeladapter/#getmetadata)), data modification ([`updateNodes`](/docs/api/types/model/modeladapter/#updatenodes), [`updateEdges`](/docs/api/types/model/modeladapter/#updateedges), [`updateMetadata`](/docs/api/types/model/modeladapter/#updatemetadata)), change notification system ([`onChange`](/docs/api/types/model/modeladapter/#onchange), [`unregisterOnChange`](/docs/api/types/model/modeladapter/#unregisteronchange)), and lifecycle management ([`destroy`](/docs/api/types/model/modeladapter/#destroy), [`undo`](/docs/api/types/model/modeladapter/#undo), [`redo`](/docs/api/types/model/modeladapter/#redo), [`toJSON`](/docs/api/types/model/modeladapter/#tojson)). For a complete example of implementing a custom model adapter, see the [Custom Model example](/docs/examples/custom-model/). ### Advanced Use Cases Custom model implementations enable several advanced scenarios: #### Real-time Collaboration Multi-user collaboration requires synchronizing diagram changes across different clients in real-time. A collaborative model adapter would typically integrate with WebSocket connections, services like Socket.IO or libraries like Yjs to broadcast changes and apply remote updates while handling conflict resolution. #### State Management Integration When working with complex Angular applications that use state management libraries like NgRx or Akita, you can create model adapters that integrate seamlessly with your existing store architecture. These adapters would dispatch actions for diagram changes and subscribe to state selections, ensuring that diagram data follows your application's established data flow patterns and benefits from features like time-travel debugging and state persistence. ```typescript // Sketch — a real adapter implements every ModelAdapter member; // see the Custom Model example for a complete implementation. class NgRxModelAdapter implements ModelAdapter { private store = inject(Store); updateNodes(nodes: Node[]): void { this.store.dispatch(DiagramActions.updateNodes({ nodes })); } onChange(callback: (changes: ModelChanges) => void): void { this.store.select(selectDiagramData).subscribe(callback); } // ...remaining ModelAdapter members } // Wire up the custom adapter with initializeModelAdapter model = initializeModelAdapter(new NgRxModelAdapter()); ``` Custom model implementations provide the flexibility to integrate NgDiagram with any data architecture while maintaining full compatibility with all diagram features and the model service API. --- ## Touch Gestures > Using ngDiagram on touch devices with native gesture support URL: https://ngdiagram.dev/docs/guides/touch-gestures/ ngDiagram supports touch devices out of the box, making it easy to build diagram applications for tablets, phones, and other touch-enabled screens. ## Gestures ngDiagram recognizes the following touch gestures for navigation and interaction. ### Pinch to Zoom Use two fingers to pinch in or out anywhere on the canvas to zoom the diagram. This works the same as zooming with a scroll wheel on desktop. ### Two-Finger Panning Place two fingers on the canvas and move them together to pan the view. This allows you to navigate large diagrams without changing the zoom level. ### Long Press for Box Selection Press and hold on the canvas, then drag to create a selection box. Any nodes within the box will be selected. ### Standard Touch Interactions Many interactions work just like on desktop, using a single finger instead of a mouse: - **Select a node** — Tap on a node to select it - **Clear selection** — Tap on an empty area of the canvas to deselect all nodes - **Drag nodes** — Touch and drag a node to move it on the canvas - **Drag from palette** — Touch and drag items from the palette onto the canvas - **Resize and rotate** — Touch and drag the resize or rotation handles on a selected node - **Create connections** — Touch a port and drag to another port to create an edge ## Gesture Priorities When gestures could overlap, ngDiagram uses the following priority order to determine which action takes effect: 1. Pinch zoom 2. Two-finger panning 3. Resize/rotate/link 4. Drag node 5. Box selection This ensures that common viewport gestures (zoom and pan) always work, while node manipulation and selection remain accessible. ## Linking Mode In addition to creating connections by dragging from port to port, you can trigger the linking mode programmatically using the [`startLinking`](/docs/api/services/ngdiagramservice/#startlinking) method — for example, via a button in your UI. Once activated, the connection line follows the user's finger as they drag across the canvas. Lifting the finger over a compatible port completes the connection. If the finger is released elsewhere on the canvas, the linking action is cancelled without creating an edge. ## Actions Without Touch Gestures The following common editing actions are best handled through on-screen buttons or menus in your application: - Copy - Paste - Cut - Delete - Undo - Redo --- ## Orchestrating complex state changes? > Understanding how transactions work in ngDiagram URL: https://ngdiagram.dev/docs/guides/transactions/ Transactions in ngDiagram provide a mechanism for batching multiple state changes into atomic operation. This is particularly useful for complex operations that involve multiple nodes and edges, ensuring better performance. ## Usage The transaction API is straightforward - simply wrap your operations in a callback. ```typescript this.ngDiagramService.transaction(() => { this.ngDiagramModelService.addNodes([node1, node2]); this.ngDiagramModelService.addEdges([edge1]); }); ``` ## Async Transactions Transactions support async callbacks, allowing you to perform asynchronous operations like fetching data from a server before modifying the diagram state. ```typescript await this.ngDiagramService.transaction(async () => { // Fetch data from server const nodes = await this.nodeService.fetchNodes(); // Add nodes after data is fetched this.ngDiagramModelService.addNodes(nodes); }); console.log('Transaction complete - all nodes added'); ``` The transaction promise resolves after all operations inside the callback are complete and the state has been updated. ## Transaction Options Transactions accept an optional second parameter for additional configuration. ### waitForMeasurements When adding nodes or edges, the diagram needs to measure their dimensions before they're fully rendered. By default, the transaction resolves immediately after the state update, before measurements complete. Use [`waitForMeasurements: true`](/docs/api/types/middleware/transactionoptions/#waitformeasurements) when you need to perform operations that depend on measured values, such as zooming to fit new nodes: ```typescript // Add nodes and wait for their dimensions to be measured await this.ngDiagramService.transaction( () => { this.ngDiagramModelService.addNodes([newNode]); }, { waitForMeasurements: true } ); // Now safe to zoom - node dimensions are known this.ngDiagramViewportService.zoomToFit(); ``` This works with both sync and async transactions: ```typescript // Async transaction with measurements await this.ngDiagramService.transaction( async () => { const data = await fetchNodeDataFromServer(); const newNode: Node = { id: 'fetched-node', type: 'default', position: { x: 1000, y: 1000 }, data, }; this.ngDiagramModelService.addNodes([newNode]); }, { waitForMeasurements: true } ); // Zoom to include the new node with correct dimensions this.ngDiagramViewportService.zoomToFit(); ``` #### Per-method option Methods that can change what gets measured also accept `waitForMeasurements` directly — no explicit transaction needed: - [`NgDiagramModelService`](/docs/api/services/ngdiagrammodelservice/): `addNodes`, `addEdges`, `updateNode`, `updateNodes`, `updateNodeData`, `updateEdge`, `updateEdges`, `updateEdgeData` - [`NgDiagramNodeService`](/docs/api/services/ngdiagramnodeservice/): `resizeNode` - [`NgDiagramClipboardService`](/docs/api/services/ngdiagramclipboardservice/): `paste` ```typescript await this.ngDiagramModelService.addNodes([newNode], { waitForMeasurements: true }); this.ngDiagramViewportService.zoomToFit(); ``` Other mutating methods (`deleteNodes`, `deleteEdges`, `addToGroup`, `removeFromGroup`, `rotateNodeTo`, selection and viewport operations) deliberately do not take the option: they change only model state, and everything derived from it — group membership, z-order, rotated bounds, edge routing — is computed within the same update pass, so awaiting the returned promise is already enough. Rotation, for example, is applied as a CSS transform: the element's size does not change, so there is nothing new to measure. ## How Transactions Work Understanding how transactions are applied internally helps you write better code and reason about your diagram state changes. When a transaction is committed, operations are executed in a specific sequence to maintain data integrity: ```typescript stateUpdate.nodesToAdd?.forEach((node) => this.addNode(node)); stateUpdate.edgesToAdd?.forEach((edge) => this.addEdge(edge)); stateUpdate.edgesToRemove?.forEach((id) => this.removeEdge(id)); stateUpdate.nodesToRemove?.forEach((id) => this.removeNode(id)); stateUpdate.nodesToUpdate?.forEach((node) => this.updateNode(node)); stateUpdate.edgesToUpdate?.forEach((edge) => this.updateEdge(edge)); if (stateUpdate.metadataUpdate) { this.metadata = { ...this.metadata, ...stateUpdate.metadataUpdate }; } ``` This fixed order ensures that: - **Nodes are added first**, making them available before edges that might reference them - **Edges are added next**, after all required nodes exist - **Edges are removed before nodes**, preventing dangling edge references - **Nodes are removed after edges**, ensuring no edges point to non-existent nodes - **Updates are applied after all additions and removals**, ensuring the structure is stable before modifying properties - **Metadata is merged last**, after all other operations are complete ## Benefits ### Performance Transactions batch multiple operations together, reducing the number of state updates and re-renders. Instead of triggering change detection for each individual operation, all changes are applied at once. ### Consistency All operations within a transaction succeed together, preventing partial state updates that could leave your diagram in an inconsistent state. ## When to Use Transactions Use transactions for: - **Complex multi-step operations** - Creating multiple related nodes and edges - **Bulk operations** - Adding or updating many elements at once - **Performance optimization** - Reducing the number of state updates - **Operations requiring measurements** - When you need to zoom to fit or center on newly added elements ## Best Practices Prefer `await`-ing transactions over running them fire-and-forget. Overlapping un-awaited transactions each still commit their own updates, but the overlap logs a console warning — awaiting keeps the commits explicitly ordered. Group related operations together, but avoid making transactions too large or complex: ```typescript // ✅ Good - related operations grouped together this.ngDiagramService.transaction(() => { this.ngDiagramModelService.addNodes([node1, node2, node3]); this.ngDiagramModelService.addEdges([edge1, edge2]); }); // ❌ Avoid - unrelated operations in same transaction this.ngDiagramService.transaction(() => { this.ngDiagramModelService.addNodes([...]); this.updateUserPreferences(); // Unrelated operation this.updateDiagramName(); // Another unrelated operation }); ``` Wrap the entire loop in a single transaction instead of starting one for every iteration to minimize overhead ```typescript // ✅ Good - loop inside transaction this.ngDiagramService.transaction(() => { for (const node of nodes) { this.ngDiagramModelService.updateNodeData(node); } }); // ❌ Avoid - transactions inside a loop for (const node of nodes) { this.ngDiagramService.transaction(() => { this.ngDiagramModelService.updateNodeData(node); // Each iteration creates a separate transaction }); } ``` ## Example [Read more about global configuration in ngDiagram →](/docs/guides/configuration/) Whether you're building simple diagrams or complex applications, transactions help ensure data consistency and optimal performance. --- ## Scaling to thousands of nodes? > Optimizing performance for large diagrams with viewport virtualization URL: https://ngdiagram.dev/docs/guides/virtualization/ Virtualization is a performance optimization technique that renders only the nodes and edges visible within the current viewport. For diagrams with hundreds or thousands of elements, this dramatically improves rendering performance and responsiveness. ## How It Works When virtualization is enabled, ngDiagram calculates which elements are visible in the current viewport (plus a configurable padding area) and only renders those elements. As you pan or zoom around the diagram, elements are dynamically added and removed from the DOM. **What to expect:** - Nodes and edges outside the viewport are not rendered until you pan to them - During fast panning, you may briefly see empty areas before elements appear - Elements are rendered after a short idle delay once panning stops - The virtual viewport (rendering area) extends beyond the visible viewport by a configurable padding :::note The `zoomToFit` command is disabled when virtualization is enabled, as it requires all elements to calculate bounds. ::: ## Enabling Virtualization To enable virtualization, set the `enabled` property in your diagram configuration: ```typescript const config: NgDiagramConfig = { virtualization: { enabled: true, }, }; ``` ## Changing Virtualization at Runtime The virtualization setting is applied during diagram initialization. To change the virtualization mode at runtime, you must update the config and reinitialize the model: ```typescript // Update config and reinitialize model this.config = { ...this.config, virtualization: { enabled: true }, }; this.model = initializeModel(getModel(), this.injector); ``` ## Configuration Options Virtualization behavior can be configured via the [`virtualization`](/docs/api/types/configuration/flowconfig/#virtualization) property in your diagram config. The following options are available: ### enabled Whether viewport virtualization is active. ```typescript virtualization: { enabled: true, // default: false } ``` ### padding Controls the size of the virtual viewport beyond the visible area. This is a multiplier relative to viewport size. For example, `0.5` means the rendering area extends by 50% of the viewport size in each direction. ```typescript virtualization: { enabled: true, padding: 0.5, // default: 0.5 } ``` A larger padding value means more elements are pre-rendered outside the visible area, reducing the chance of seeing empty spaces during panning. However, this comes at the cost of rendering more elements, which may impact performance. ### idleDelay The delay in milliseconds after panning stops before re-rendering visible nodes. ```typescript virtualization: { enabled: true, idleDelay: 100, // default: 100 } ``` ## Performance Considerations When configuring virtualization, consider these trade-offs: | Setting | Higher Value | Lower Value | | ----------- | ----------------------------------------------------------------- | ---------------------------------------------------------------- | | `padding` | More pre-rendered elements, smoother panning, higher memory usage | Fewer elements rendered, may see empty areas during fast panning | | `idleDelay` | Longer wait before rendering, fewer intermediate renders | Faster visual feedback, more frequent renders | For most use cases, the default values provide a good balance between performance and visual smoothness. --- ## Z-Ordering > How z-index layering works for nodes and edges in ngDiagram URL: https://ngdiagram.dev/docs/guides/z-ordering/ ngDiagram automatically manages the rendering order (z-index) of nodes and edges. The **desired ordering** is controlled via `zOrder`, and the system computes the **final z-index** (`computedZIndex`) that gets applied to the DOM. ## Key Concepts ### `zOrder` vs `computedZIndex` - **`zOrder`**: a value on nodes or edges that controls their relative ordering. It can be set manually or via `bringToFront` / `sendToBack` commands. - **`computedZIndex`**: the final CSS z-index computed by the system. It accounts for `zOrder`, group hierarchy depth, and selection elevation. This property is read-only. ### How `computedZIndex` Is Computed For **root nodes** (no parent group), `zOrder` maps directly to `computedZIndex`. Negative values are allowed (useful for `sendToBack`). For **grouped nodes**, `computedZIndex` is always higher than the parent's. Each nesting level adds +1 per child, and `zOrder` acts as a minimum floor that cannot push a child below its parent. Among siblings, higher `zOrder` renders on top. For **nodes without `zOrder`**, the system treats them as `zOrder: 0`. Their position is determined by their order among siblings relative to those with explicit `zOrder` values. For **edges** without `zOrder`, the z-index is derived from the connected nodes: `max(source, target)`. Setting an explicit `zOrder` on an edge overrides this, but the system still adds connected node elevation when those nodes are selected. ## Group Hierarchy Children are **always rendered above their parent group**. This is enforced regardless of `zOrder` values. A child with `zOrder: -100` inside a group will still appear above the group. Among siblings within a group, nodes are sorted by `zOrder`. When any sibling's `zOrder`, selection, or group membership changes, all siblings in that group are re-sorted to maintain correct ordering. With appropriate `zOrder` values, it is also possible to influence ordering across different hierarchy levels. Each nesting level adds +1 to the computed z-index per child, so this offset should be accounted for when setting cross-hierarchy values. ## Selection Elevation When [`elevateOnSelection`](/docs/api/types/configuration/features/zindexconfig#elevateonselection) is enabled, selecting a node adds [`selectedZIndex`](/docs/api/types/configuration/features/zindexconfig#selectedzindex) to its `computedZIndex`. This ensures selected elements appear above non-selected ones. Elevation is **cumulative** in nested groups. If a parent group and its child are both selected, the child receives the elevation twice: once inherited from the parent, and once from its own selection. This keeps the child visually above siblings that only inherit the parent's elevation. Children of a selected group inherit the parent's elevation even if they are not selected themselves. Among siblings, selected children are sorted after non-selected ones, ensuring they render on top. ### Configuration You can configure z-index behavior via the [`zIndex`](/docs/api/types/configuration/features/zindexconfig) property in your diagram config: ```typescript config: NgDiagramConfig = { zIndex: { enabled: true, selectedZIndex: 10000, elevateOnSelection: true, edgesAboveConnectedNodes: false, temporaryEdgeZIndex: 2147483647, }, }; ``` ```html ``` See [`ZIndexConfig`](/docs/api/types/configuration/features/zindexconfig) for full reference. ## Bring to Front / Send to Back [`NgDiagramNodeService`](/docs/api/services/ngdiagramnodeservice) provides methods to reorder elements programmatically: ```typescript const nodeService = inject(NgDiagramNodeService); // Bring nodes/edges to front nodeService.bringToFront(['node-1', 'node-2'], ['edge-1']); // Send nodes/edges to back nodeService.sendToBack(['node-3']); ``` If no IDs are provided, the current selection is used. ### Hierarchy Behavior **`bringToFront`** sets a `zOrder` above all other elements. When applied to a grouped node, descendants receive incrementing `zOrder` values that preserve their internal hierarchy ordering. **`sendToBack`** sets a `zOrder` below all other elements. It also applies progressively lower values to the node's parent chain, ensuring the entire ancestor hierarchy is sent behind its siblings at each level. ## Edge Z-Index Edges without an explicit `zOrder` derive their z-index from their connected nodes (`max(source, target)`). This means they automatically follow the nodes they connect to. When `zOrder` is set on an edge (via `bringToFront` or manually), the edge uses that value as its base. If a connected node is selected, the node's elevation is added to the edge so it remains visible above elevated nodes. A selected edge adds `selectedZIndex` on top of its computed base. Setting [`edgesAboveConnectedNodes`](/docs/api/types/configuration/features/zindexconfig#edgesaboveconnectednodes) to `true` adds +1 to every edge's z-index relative to its connected nodes, ensuring edges are always drawn above the nodes they connect. ## Further Reading [Groups](/docs/guides/nodes/groups) | [Selection](/docs/guides/nodes/selection) | [Configuration](/docs/guides/configuration) --- # Examples ## Angular Material Node > Example of how to use Angular Material components with ngDiagram URL: https://ngdiagram.dev/docs/examples/angular-material-node/ This example demonstrates how to use Angular Material components in your custom node.
**Learn more:** [Custom Nodes guide →](/docs/guides/nodes/custom-nodes/) --- ## Context Menu Example > Example of how to implement a context menu in ngDiagram URL: https://ngdiagram.dev/docs/examples/context-menu/ This example demonstrates how to implement a context menu that adapts its options based on the context—showing node-specific actions when a node is right-clicked, and diagram-wide actions otherwise. ## Additional Explanation - **Context Awareness:** Menu options change depending on whether a node or the diagram background is right-clicked. - **Positioning:** The menu appears at the exact cursor location using viewport coordinates. - **Integration:** Uses Angular signals and services for reactive state management. ### Key Concepts - **Node Right-Click Handling:** Nodes handle right-click events to show the context menu and select the node. - **Diagram Right-Click Handling:** Right-clicking the diagram background shows the diagram-wide menu. - **Menu Positioning:** The menu position is calculated using viewport coordinates. - **Context Menu Service:** The service manages the menu’s visibility, position, and context (node or diagram). - **Menu Component:** The menu component displays options based on the context and stores information about menu positioning. ### Actions - **Copy:** Copies the selected node(s) to the clipboard. - **Paste:** Pastes copied nodes at the cursor position. - **Delete:** Removes the selected node(s). - **Select All:** Selects all nodes in the diagram. **Learn more:** [Services overview →](/docs/intro/services/) --- ## Custom Edge Example > Example of how to create a custom edge in ngDiagram URL: https://ngdiagram.dev/docs/examples/custom-edge/ This example demonstrates how to create custom edges in ngDiagram with unique visual styles and interactive elements.
## Additional Explanation Example showcases three different edge types: 1. **Default Edge**: - a standard edge parametrized through model data - enhanced with a custom circular arrowhead marker defined in SVG 2. **Labeled Edge**: - a custom edge with adjusted stroke width dynamically changing on selection - features interactive button label positioned at its midpoint 3. **Sinusoid Edge**: - a custom wave-shaped edge with adjusted stroke color - renders a sinusoidal curve between nodes ### Key Concepts - Creating custom edge components that implement `NgDiagramEdgeTemplate` - Adjusting parameters of [`NgDiagramBaseEdgeComponent`](/docs/api/components/ngdiagrambaseedgecomponent) in custom edges - Registering edge types using the [`edgeTemplateMap`](/docs/api/components/ngdiagramcomponent/#edgetemplatemap) - Defining custom SVG markers for arrowheads - Adding interactive elements with [`NgDiagramBaseEdgeLabelComponent`](/docs/api/components/ngdiagrambaseedgelabelcomponent) - Generating complex path calculations for non-standard edge shapes **Learn more:** [Custom Edges guide →](/docs/guides/edges/custom-edges/) --- ## Custom Middleware Example > Example of how to create a custom middleware in ngDiagram URL: https://ngdiagram.dev/docs/examples/custom-middleware/ This example demonstrates how to create a custom middleware that implements read-only functionality for ngDiagram. Middlewares provide a powerful plugin architecture for extending diagram behavior by intercepting state changes before they reach the model. ## Additional Explanation ### Key Concepts - **Action Blocking:** Block specific actions based on configuration. - **Allowlist:** Permit selective operations through an allowlist. - **Operation Cancellation:** Cancel operations to prevent unwanted state changes. - **Logging:** Log warnings for blocked actions. **Learn more:** [Middlewares guide →](/docs/guides/middlewares/) --- ## Custom Model Example > Example of how to create a custom model implementation in ngDiagram URL: https://ngdiagram.dev/docs/examples/custom-model/ This example demonstrates how to create a custom [`model`](/docs/api/types/model/model/) implementation that persists data directly to localStorage, providing automatic persistence without keeping local copies in memory.
## Additional Explanation ### Custom Model Overview The [`NgDiagramComponent`](/docs/api/components/ngdiagramcomponent) accepts any object, via the [`model`](/docs/api/components/ngdiagramcomponent/#model) input property (e.g. `[model]="customModelAdapter"`), that implements the [`ModelAdapter`](/docs/api/types/model/modeladapter/) interface. This means you can create your own custom model implementations beyond the default `SignalModelAdapter` provided by [`initializeModel`](/docs/api/utilities/initializemodel/). Use [`initializeModelAdapter`](/docs/api/utilities/initializemodeladapter/) to prepare a custom adapter for use with ng-diagram. This allows for advanced use cases like connecting to external data sources, implementing custom persistence layers, or integrating with existing state management solutions. #### Key Features - **Direct localStorage Persistence**: All data is read from and written directly to localStorage - **Single Source of Truth**: No local copies of data are maintained in memory - **Automatic Synchronization**: Changes are immediately persisted - **Error Handling**: Robust error handling for storage operations ### Implementation Details #### Understanding the ModelAdapter Interface The [`ModelAdapter`](/docs/api/types/model/modeladapter/) interface defines the contract that any model implementation must fulfill. You can find the complete interface documentation in the [API reference](/docs/api/types/model/modeladapter/). The key methods include: - **Data access**: [`getNodes`](/docs/api/types/model/modeladapter/#getnodes), [`getEdges`](/docs/api/types/model/modeladapter/#getedges), [`getMetadata`](/docs/api/types/model/modeladapter/#getmetadata) - **Data modification**: [`updateNodes`](/docs/api/types/model/modeladapter/#updatenodes), [`updateEdges`](/docs/api/types/model/modeladapter/#updateedges), [`updateMetadata`](/docs/api/types/model/modeladapter/#updatemetadata) - **Change notification**: [`onChange`](/docs/api/types/model/modeladapter/#onchange), [`unregisterOnChange`](/docs/api/types/model/modeladapter/#unregisteronchange) - **Lifecycle management**: [`destroy`](/docs/api/types/model/modeladapter/#destroy), [`undo`](/docs/api/types/model/modeladapter/#undo), [`redo`](/docs/api/types/model/modeladapter/#redo), [`toJSON`](/docs/api/types/model/modeladapter/#tojson) #### LocalStorageModelAdapter Implementation This example demonstrates a custom model adapter that persists diagram data to localStorage. The data will survive page refreshes and browser sessions. You can try it by adding nodes and edges, then refreshing the page to see that your changes are retained. ### When to Use This Approach A custom `ModelAdapter` makes your storage layer the single source of truth — every change goes straight to it. If you only need save/load buttons on top of the default model, snapshotting with `toJSON()` is much simpler — see the [Save Persistence example](/docs/examples/save-state/). **Learn more:** [State Management guide →](/docs/guides/state-management/) --- ## Custom Node Example > Example of how to create a custom node in ngDiagram URL: https://ngdiagram.dev/docs/examples/custom-node/ This example demonstrates how to create a custom node with your own template and form controls.
**Learn more:** [Custom Nodes guide →](/docs/guides/nodes/custom-nodes/) --- ## Custom Ports Example > Example of how to create custom ports in ngDiagram URL: https://ngdiagram.dev/docs/examples/custom-ports/ This example demonstrates how to create custom ports in ngDiagram by providing any custom content (text, images, SVGs, or Angular components) and customizing their appearance and behavior.
## Additional Explanation ### Key Concepts - **Custom Port Content:** You can provide any custom content inside a port. The default style is disabled and the port adapts to the content's size and shape. - **Custom Port Styling:** Ports can be styled individually using CSS classes, inline styles, or by overriding CSS variables used in port styling. - **Dynamic Port Rendering:** Ports are rendered using the [``](/docs/api/components/ngdiagramportcomponent) component, which supports various attributes. - **Node Template Customization:** The `NodeComponent` template defines the arrangement and styling of ports within each node. - **Custom Content Rendering:** You can render any content inside a port, such as text, images, SVGs, or icons. This allows for full control over the port's appearance. - **Port Binding:** Ports have a [`type`](/docs/api/types/model/port/#type) property to set the connection type for each port. You can set it to `'both'`, `'target'`, or `'source'`. - **Port Positioning:** Ports have a [`side`](/docs/api/types/model/port/#side) property to set their placement. - **Origin Point Customization:** You can now use the `originPoint` input to precisely control the transform origin of each port. Supported values: `leftTop`, `leftMiddle`, `leftBottom`, `centerTop`, `centerMiddle`, `centerBottom`, `rightTop`, `rightMiddle`, `rightBottom`. This will apply the corresponding CSS transform for accurate port placement. For details, see the [`NgDiagramPortComponent`](/docs/api/components/ngdiagramportcomponent#originpoint) documentation. To further customize port placement, you can use CSS styling. **Learn more:** [Ports guide →](/docs/guides/nodes/ports/) --- ## Download Image Example > Example of how to download the flow as an image in ngDiagram URL: https://ngdiagram.dev/docs/examples/download-image/ This example demonstrates how to export the current flow as an image using Angular features and the `html-to-image` library.
## Additional Explanation ### Key Concepts - **Export:** Downloads the flow as a PNG image. - **Bounding Box Calculation:** Ensures the exported image includes all nodes with proper margins. ### Implementation Details - **Generate Image Service:** Handles the logic for exporting the flow as an image, using the `html-to-image` library and bounding box calculation. - **Helper Functions:** Manage the download process and calculate the bounding box for the flow. - **NavBar Component:** Provides a button to trigger the download action. Calculates the bounding box for the entire flow and passes the flow element reference to the service. ### Actions - **Download:** Exports the current flow as a PNG image using the bounding box and margin settings. **Learn more:** [Services overview →](/docs/intro/services/) --- ## Landing Page Diagram > Demonstrates the library's capabilities and integration with external libraries like charts in real scenarios URL: https://ngdiagram.dev/docs/examples/landing-page-diagram/ This example demonstrates the library's capabilities and the possibility to integrate with external libraries, such as presenting data on charts inside nodes. This is a real use case scenario.
**Learn more:** [Custom Nodes guide →](/docs/guides/nodes/custom-nodes/) --- ## Layout Integration Example > Example of how to integrate layout algorithms in ngDiagram URL: https://ngdiagram.dev/docs/examples/layout-integration/ This example demonstrates how to integrate external layout libraries and use built-in layout features in ngDiagram.
## Additional Explanation ### Key Concepts - **External Layout Libraries:** Integrate solutions like ELK.js for advanced layouts. ELK.js assigns [`position`](/docs/api/types/model/simplenode/#position) to nodes and generates edge paths automatically. - **User Interaction Detection:** Use the [`selectionMoved`](/docs/api/types/events/selectionmovedevent/) event to detect manual node movement. - **Edge Routing Modes:** - Set edges to [`manual`](/docs/api/types/routing/routingmode/) mode to preserve custom layout points from ELK. - Reset edges to [`auto`](/docs/api/types/routing/routingmode/) mode when connected nodes are moved manually. - **Batch Updates:** Use [`updateNodes`](/docs/api/types/model/modeladapter/#updatenodes) and [`updateEdges`](/docs/api/types/model/modeladapter/#updateedges) for efficient diagram updates. **Learn more:** [Edge Routing guide →](/docs/guides/edges/routing/) --- ## Hitting the limits in your own project? > Example of how to test performance in ngDiagram URL: https://ngdiagram.dev/docs/examples/performance-test/ This example demonstrates the performance capabilities of the ng-diagram library by rendering 500 nodes arranged in a 25x20 grid with almost 500 connections.
**Learn more:** [Virtualization guide →](/docs/guides/virtualization/) --- ## Properties Sidebar Example > Example of how to implement a sidebar with editing properties in ngDiagram URL: https://ngdiagram.dev/docs/examples/properties-sidebar/ This example demonstrates how to build an interactive properties panel that automatically updates when nodes are selected and allows real-time editing of node attributes in ngDiagram. ## Additional Explanation ### Key Concepts - **Selection Tracking:** Uses `NgDiagramSelectionService.selection()` to track selected nodes. - **Computed Properties:** Angular computed signals automatically update the UI when node properties change. - **Simple Update Methods:** Direct calls to `updateNodeData()` and `updateNode()` for property modifications. ### How It Works The sidebar component automatically: - Observes the current selection using the model service. - Displays the selected node's properties (label, resizable, rotatable). - Updates the node in real-time when properties are changed. - Disables controls when no node is selected. This pattern makes it easy to create property editors for any node attributes you need to expose to users. **Learn more:** [State Management guide →](/docs/guides/state-management/) --- ## Save Persistence Example > Example of how to save and restore state in ngDiagram URL: https://ngdiagram.dev/docs/examples/save-state/ This example demonstrates how to implement save and restore functionality for the diagram in ngDiagram using Angular features. ## Additional Explanation ### Key Concepts - **Persistence:** Saves the diagram state to local storage. - **Restoration:** Loads the saved state back into the diagram. - **Clear:** Removes the saved state from local storage. ### Implementation Details - **Save Persistence Service:** The `SaveStateService` manages saving, loading, and clearing the diagram state using Angular signals and effects. - **NavBar Component:** The navigation bar provides buttons for saving, loading, and clearing the diagram state. Button states are reactive. ### Actions - **Save:** Serializes and stores the current diagram state. - **Load:** Restores the diagram from the saved state. - **Clear:** Removes the saved state from local storage. ### When to Use This Approach This example keeps the default model and saves snapshots on demand with `toJSON()` — the simplest way to add save/load buttons to an app. If you want the model itself to live in your own storage layer (persist on every change, connect to a store or a backend), implement a custom `ModelAdapter` instead — see the [Custom Model example](/docs/examples/custom-model/). **Learn more:** [State Management guide →](/docs/guides/state-management/) --- ## Tailwind CSS Example > Example of how to use Tailwind CSS in ngDiagram URL: https://ngdiagram.dev/docs/examples/tailwind-styling/ This example demonstrates how to use Tailwind CSS in ngDiagram.
**Learn more:** [Styling guide →](/docs/intro/styling/) --- # API Reference ## Components ### NgDiagramBackgroundComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagrambackgroundcomponent/ The `NgDiagramBackgroundComponent` is responsible for rendering the background of the diagram. ## Example usage ```html ``` ## Implements - `AfterContentInit` ## Properties ### type > **type**: `InputSignal`\<`"grid"` \| `"dots"`\> The type of background pattern to display. #### Default ```ts 'dots' ``` --- ### NgDiagramBaseEdgeComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagrambaseedgecomponent/ Base edge component that handles edge rendering. It can be extended or used directly to render edges in the diagram. ## Properties ### edge > **edge**: `InputSignal`\<[`Edge`](/docs/api/types/model/edge/)\<`object`\>\> Edge data model *** ### routing > **routing**: `InputSignal`\<`undefined` \| `string`\> Edge routing mode *** ### sourceArrowhead > **sourceArrowhead**: `InputSignal`\<`undefined` \| `string`\> ID of a source element in the SVG document. Edge model data has precedence over this property. *** ### stroke > **stroke**: `InputSignal`\<`undefined` \| `string`\> Stroke color of the edge. Edge model data has precedence over this property. *** ### strokeDasharray > **strokeDasharray**: `InputSignal`\<`undefined` \| `string`\> Stroke dash array of the edge (e.g., '5 5' for dashed line, '10 5 2 5' for dash-dot pattern). *** ### strokeOpacity > **strokeOpacity**: `InputSignal`\<`undefined` \| `number`\> Stroke opacity of the edge *** ### strokeWidth > **strokeWidth**: `InputSignal`\<`undefined` \| `number`\> Stroke width of the edge *** ### targetArrowhead > **targetArrowhead**: `InputSignal`\<`undefined` \| `string`\> ID of a target element in the SVG document. Edge model data has precedence over this property. *** ### useInlineMarkers > `readonly` **useInlineMarkers**: `boolean` Whether to use inline markers (Safari fallback). Safari doesn't support context-stroke, so we render markers inline per edge. --- ### NgDiagramBaseEdgeLabelComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagrambaseedgelabelcomponent/ The `NgDiagramBaseEdgeLabelComponent` is responsible for displaying a label at a specific position along an edge. ## Example usage ```html ``` ## Implements - `OnInit` - `OnDestroy` ## Properties ### id > **id**: `InputSignal`\<`string`\> The unique identifier for the edge label. *** ### positionOnEdge > **positionOnEdge**: `InputSignal`\<[`EdgeLabelPosition`](/docs/api/types/model/edgelabelposition/)\> The relative position of the label along the edge (from 0 to 1). --- ### NgDiagramBaseNodeTemplateComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagrambasenodetemplatecomponent/ The `NgDiagramBaseNodeTemplateComponent` provides a base template for custom nodes with default node styling and features. This component wraps custom node content while providing the default node's visual appearance, selection states, resize and rotate adornments, and default ports. Use this as a convenient way to create custom nodes that maintain the default node's look and feel while adding custom content. ## Example ```html
{{ node().data.title }}
{{ node().data.description }}
``` ## Implements - [`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/) ## Properties ### node > **node**: `InputSignal`\<[`Node`](/docs/api/types/model/node/)\> Input signal containing the node data and properties. #### Implementation of [`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/).[`node`](/docs/api/types/templates/ngdiagramnodetemplate/#node) *** ### removeDefaultPorts > **removeDefaultPorts**: `InputSignal`\<`undefined` \| `boolean`\> When explicitly set to `true` this will remove the default ports in the template. When the ports are hidden through configuration, this can override the global config, i.e. set to `false` to show ports no matter the global setting. #### Since 1.3.0 --- ### NgDiagramComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagramcomponent/ Main diagram component for rendering flow diagrams with nodes and edges. ## Implements - `OnInit` - `OnDestroy` ## Properties ### clipboardPasted > **clipboardPasted**: `EventEmitter`\<[`ClipboardPastedEvent`](/docs/api/types/events/clipboardpastedevent/)\> Event emitted when clipboard content is pasted into the diagram. This event fires when nodes and edges are added via paste operations, either through keyboard shortcuts or programmatic paste commands. *** ### config > **config**: `InputSignal`\<`undefined` \| `DeepPartial`\<[`FlowConfig`](/docs/api/types/configuration/flowconfig/)\>\> Global configuration options for the diagram. *** ### diagramInit > **diagramInit**: `EventEmitter`\<[`DiagramInitEvent`](/docs/api/types/events/diagraminitevent/)\> Event emitted when the diagram initialization is complete. This event fires after all nodes and edges including their internal parts (ports, labels) have been measured and positioned. *** ### edgeDrawEnded > **edgeDrawEnded**: `EventEmitter`\<[`EdgeDrawEndedEvent`](/docs/api/types/events/edgedrawendedevent/)\> Event emitted when an edge draw gesture ends, regardless of outcome. Fires on every linking completion — both successful and cancelled. For successful draws, includes the created edge and target. For cancelled draws, includes the cancellation reason. *** ### ~~edgeDrawn~~ > **edgeDrawn**: `EventEmitter`\<[`EdgeDrawnEvent`](/docs/api/types/events/edgedrawnevent/)\> Event emitted when a user manually draws an edge between two nodes. This event only fires for user-initiated edge creation through the UI, but not for programmatically added edges. :::caution[Deprecated] Use `edgeDrawEnded` instead, which fires for both successful and cancelled draws. ::: *** ### edgeTemplateMap > **edgeTemplateMap**: `InputSignal`\<[`NgDiagramEdgeTemplateMap`](/docs/api/types/templates/ngdiagramedgetemplatemap/)\> The edge template map to use for the diagram. Optional - if not provided, default edge rendering will be used. *** ### groupMembershipChanged > **groupMembershipChanged**: `EventEmitter`\<[`GroupMembershipChangedEvent`](/docs/api/types/events/groupmembershipchangedevent/)\> Event emitted when nodes are grouped or ungrouped. This event fires when the user moves nodes in or out of a group node, changing their group membership status. *** ### middlewares > **middlewares**: `InputSignal`\<[`MiddlewareChain`](/docs/api/types/middleware/middlewarechain/)\> Optional — the initial middlewares to use. When provided, the middleware list can be modified to add new items, replace existing ones, or override the defaults. ⚠️ Use with caution — incorrectly implemented custom middlewares can degrade performance or completely break the data flow. *** ### model > **model**: `InputSignal`\<[`ModelAdapter`](/docs/api/types/model/modeladapter/)\> The model to use in the diagram. *** ### nodeDragEnded > **nodeDragEnded**: `EventEmitter`\<[`NodeDragEndedEvent`](/docs/api/types/events/nodedragendedevent/)\> Event emitted when a node drag operation ends. This event fires when the user releases the pointer after dragging nodes. Nodes will have their final positions when this event is received. *** ### nodeDragStarted > **nodeDragStarted**: `EventEmitter`\<[`NodeDragStartedEvent`](/docs/api/types/events/nodedragstartedevent/)\> Event emitted when a node drag operation begins. This event fires once when the drag threshold is crossed, signaling the start of a drag operation. *** ### nodeResized > **nodeResized**: `EventEmitter`\<[`NodeResizedEvent`](/docs/api/types/events/noderesizedevent/)\> Event emitted when a node or group size changes. This event fires when a node is resized manually by dragging resize handles or programmatically using resize methods. *** ### nodeResizeEnded > **nodeResizeEnded**: `EventEmitter`\<[`NodeResizeEndedEvent`](/docs/api/types/events/noderesizeendedevent/)\> Event emitted when a node resize operation ends. This event fires when the user releases the pointer after resizing a node. The node will have its final size when this event is received. *** ### nodeResizeStarted > **nodeResizeStarted**: `EventEmitter`\<[`NodeResizeStartedEvent`](/docs/api/types/events/noderesizestartedevent/)\> Event emitted when a node resize operation begins. This event fires once when the user starts resizing a node by dragging a resize handle. *** ### nodeRotateEnded > **nodeRotateEnded**: `EventEmitter`\<[`NodeRotateEndedEvent`](/docs/api/types/events/noderotateendedevent/)\> Event emitted when a node rotation operation ends. This event fires when the user releases the pointer after rotating a node. The node will have its final angle when this event is received. *** ### nodeRotateStarted > **nodeRotateStarted**: `EventEmitter`\<[`NodeRotateStartedEvent`](/docs/api/types/events/noderotatestartedevent/)\> Event emitted when a node rotation operation begins. This event fires once when the user starts rotating a node by dragging the rotation handle. *** ### nodeTemplateMap > **nodeTemplateMap**: `InputSignal`\<[`NgDiagramNodeTemplateMap`](/docs/api/types/templates/ngdiagramnodetemplatemap/)\> The node template map to use for the diagram. *** ### paletteItemDropped > **paletteItemDropped**: `EventEmitter`\<[`PaletteItemDroppedEvent`](/docs/api/types/events/paletteitemdroppedevent/)\> Event emitted when a palette item is dropped onto the diagram. This event fires when users drag items from the palette and drop them onto the canvas to create new nodes. *** ### selectionChanged > **selectionChanged**: `EventEmitter`\<[`SelectionChangedEvent`](/docs/api/types/events/selectionchangedevent/)\> Event emitted when the selection state changes in the diagram. This event fires when the user selects or deselects nodes and edges through clicking or programmatically using the `NgDiagramSelectionService`. *** ### selectionGestureEnded > **selectionGestureEnded**: `EventEmitter`\<[`SelectionGestureEndedEvent`](/docs/api/types/events/selectiongestureendedevent/)\> Event emitted when a selection gesture is complete. This event fires on pointerup after a selection operation completes — whether from clicking a node/edge, box selection, or select-all. *** ### selectionMoved > **selectionMoved**: `EventEmitter`\<[`SelectionMovedEvent`](/docs/api/types/events/selectionmovedevent/)\> Event emitted when selected nodes are moved within the diagram. This event fires when the user moves nodes manually by dragging or programmatically using the `NgDiagramNodeService.moveNodesBy()` method. *** ### selectionRemoved > **selectionRemoved**: `EventEmitter`\<[`SelectionRemovedEvent`](/docs/api/types/events/selectionremovedevent/)\> Event emitted when selected elements are deleted from the diagram. This event fires when the user deletes nodes and edges using the delete key, or programmatically through the diagram service. *** ### selectionRotated > **selectionRotated**: `EventEmitter`\<[`SelectionRotatedEvent`](/docs/api/types/events/selectionrotatedevent/)\> Event emitted when a node is rotated in the diagram. This event fires when the user rotates a node manually using the rotation handle or programmatically using the `NgDiagramNodeService` rotation methods. *** ### viewportChanged > **viewportChanged**: `EventEmitter`\<[`ViewportChangedEvent`](/docs/api/types/events/viewportchangedevent/)\> Event emitted when the viewport changes through panning or zooming. This event fires during pan and zoom operations, including mouse wheel zoom, and programmatic viewport changes. *** ### viewportPannable > `readonly` **viewportPannable**: `WritableSignal`\<`boolean`\> Whether panning is enabled in the diagram. ## Methods ### getNodeTemplate() > **getNodeTemplate**(`nodeType`): `null` \| `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\> Retrieves the custom Angular component template for rendering a specific node type. This method performs a lookup in the node template map to find a custom component for the given node type. If no custom template is registered, it returns null, which will cause the diagram to fall back to the default node template. #### Parameters ##### nodeType The type identifier of the node to get a template for. `undefined` | `string` #### Returns `null` \| `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\> The Angular component class registered for the node type, or null if no custom template is registered for this type #### Example Basic usage in template: ```typescript // In your component const nodeTemplates = new Map([ ['database', DatabaseNodeComponent], ['api', ApiNodeComponent] ]); // The method will return DatabaseNodeComponent for database nodes const dbTemplate = this.getNodeTemplate('database'); // Returns DatabaseNodeComponent ``` #### See - [nodeTemplateMap](/docs/api/components/ngdiagramcomponent/#nodetemplatemap) - The input property where templates are registered - [NgDiagramNodeTemplateMap](/docs/api/types/templates/ngdiagramnodetemplatemap/) - Type definition for the template map #### Throws This method does not throw exceptions - it handles all edge cases gracefully --- ### NgDiagramDefaultEdgeLabelComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagramdefaultedgelabelcomponent/ The `NgDiagramDefaultEdgeLabelComponent` wraps any projected content in the default edge label chip — theme-aware background, rounded border and a highlighted border while the edge is hovered or selected. Use it inside a [NgDiagramBaseEdgeLabelComponent](/docs/api/components/ngdiagrambaseedgelabelcomponent/) to give a custom edge template the same label look as the default edge without copying its styles. The selected state is read from the surrounding edge component, so the component must be used inside an edge template — instantiating it elsewhere fails with a dependency injection error. ## Example usage ```html {{ label() }} ``` --- ### NgDiagramMarkerComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagrammarkercomponent/ Component for defining SVG markers with cross-browser SVG2 support. This component enables the use of SVG2 properties like `context-stroke` and `context-fill` in marker definitions across all browsers. These properties allow markers to automatically inherit the stroke/fill color from the referencing edge, enabling dynamic color changes on hover, selection, and other states. Safari does not natively support `context-stroke`/`context-fill`, so this component registers the marker element for automatic inline rendering with `currentColor` fallback. ## Example ```html ``` ## Implements - `AfterViewInit` ## Methods ### ngAfterViewInit() > **ngAfterViewInit**(): `void` A callback method that is invoked immediately after Angular has completed initialization of a component's view. It is invoked only once when the view is instantiated. #### Returns `void` #### Implementation of `AfterViewInit.ngAfterViewInit` --- ### NgDiagramMinimapComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagramminimapcomponent/ A minimap component that displays a bird's-eye view of the diagram. Shows all nodes as small rectangles and a viewport rectangle indicating the currently visible area. The minimap updates reactively when the diagram viewport changes (pan/zoom) or when nodes are added/removed/updated. The minimap also supports navigation: click and drag on the minimap to pan the diagram viewport to different areas. ## Implements - `AfterViewInit` ## Properties ### deferNodeUpdates > **deferNodeUpdates**: `InputSignal`\<`boolean`\> When enabled, minimap node positions are frozen during drag, resize, and rotation operations — updated only when the operation ends. The viewport indicator rectangle always updates in real-time. #### Default ```ts false ``` #### Since 1.2.0 *** ### height > **height**: `InputSignal`\<`number`\> Height of the minimap in pixels. *** ### minimapNodeTemplateMap > **minimapNodeTemplateMap**: `InputSignal`\<[`NgDiagramMinimapNodeTemplateMap`](/docs/api/types/minimap/ngdiagramminimapnodetemplatemap/)\> Optional template map for complete control over node rendering per node type. Components registered in the map should render SVG elements. #### Example ```typescript const minimapTemplateMap = new NgDiagramMinimapNodeTemplateMap([ ['database', DatabaseMinimapNodeComponent], ['api', ApiMinimapNodeComponent], ]); // Usage: ``` *** ### nodeStyle > **nodeStyle**: `InputSignal`\<`undefined` \| [`MinimapNodeStyleFn`](/docs/api/types/minimap/minimapnodestylefn/)\> Optional callback function to customize node styling. Return style properties to override defaults, or null/undefined to use CSS defaults. #### Example ```typescript nodeStyle = (node: Node) => ({ fill: node.type === 'database' ? '#4CAF50' : '#9E9E9E', opacity: node.selected ? 1 : 0.6, }); ``` *** ### position > **position**: `InputSignal`\<[`NgDiagramPanelPosition`](/docs/api/types/ngdiagrampanelposition/)\> Position of the minimap panel within the diagram container. *** ### showZoomControls > **showZoomControls**: `InputSignal`\<`boolean`\> Whether to show zoom controls in the minimap footer. *** ### width > **width**: `InputSignal`\<`number`\> Width of the minimap in pixels. --- ### NgDiagramNodeResizeAdornmentComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagramnoderesizeadornmentcomponent/ The `NgDiagramNodeResizeAdornmentComponent` displays resize handles and lines around a selected, resizable node. ## Example usage ```html ``` ## Extends - `NodeContextGuardBase` ## Properties ### activeSides > **activeSides**: `InputSignal`\ Which sides of the node can be grabbed to resize it. All four lines always render, since they double as the node's selection frame, but the ones for sides left out here are inert: they do not start a resize and show no resize cursor. A corner handle renders only when both of its sides are listed, so `['right', 'bottom']` leaves only the bottom-right handle. Pass an empty array to keep the selection frame without allowing any interactive resize. #### Default ```ts ['top', 'right', 'bottom', 'left'] ``` #### Since 1.3.0 #### Example ```html ``` *** ### defaultResizable > **defaultResizable**: `InputSignal`\<`undefined` \| `boolean`\> Whether the node is resizable. #### Default ```ts undefined ``` --- ### NgDiagramNodeRotateAdornmentComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagramnoderotateadornmentcomponent/ The `NgDiagramNodeRotateAdornmentComponent` displays a rotation handle for a selected, rotatable node. ## Example usage ```html ``` ## Extends - `NodeContextGuardBase` ## Properties ### defaultRotatable > **defaultRotatable**: `InputSignal`\<`undefined` \| `boolean`\> Whether the node is rotatable. #### Default ```ts undefined ``` --- ### NgDiagramPaletteItemComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagrampaletteitemcomponent/ The `NgDiagramPaletteItemComponent` represents a single item in the diagram palette. ## Example usage ```html ``` ## Properties ### item > **item**: `InputSignal`\<[`NgDiagramPaletteItem`](/docs/api/types/palette/ngdiagrampaletteitem/)\> The palette item data to be rendered and managed. --- ### NgDiagramPaletteItemPreviewComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagrampaletteitempreviewcomponent/ The `NgDiagramPaletteItemPreviewComponent` is responsible for rendering a live preview of a palette item when it is being dragged or hovered in the palette. ## Example usage ```html ``` --- ### NgDiagramPortComponent URL: https://ngdiagram.dev/docs/api/components/ngdiagramportcomponent/ The `NgDiagramPortComponent` represents a single port on a node within the diagram. ## Example usage ```html ``` ## Extends - `NodeContextGuardBase` ## Implements - `OnInit` - `OnDestroy` - `AfterContentInit` ## Properties ### id > **id**: `InputSignal`\<`string`\> The unique identifier for the port. *** ### originPoint > **originPoint**: `InputSignal`\<[`OriginPoint`](/docs/api/types/model/originpoint/)\> The origin point for the port (e.g., topLeft, center, bottomRight). This value determines the transform origin of the port for precise positioning. By default, it is set to 'center'. *** ### side > **side**: `InputSignal`\<[`Side`](/docs/api/types/model/side/)\> The side of the node where the port is rendered (e.g., top, right, bottom, left). *** ### type > **type**: `InputSignal`\<`"source"` \| `"target"` \| `"both"`\> The type of the port (e.g., source, target, both). --- ## Directives ### NgDiagramGroupHighlightedDirective URL: https://ngdiagram.dev/docs/api/directives/ngdiagramgrouphighlighteddirective/ The `NgDiagramGroupHighlightedDirective` conditionally applies a highlight class to a group node in the diagram when it is highlighted. ## Example usage ```html
``` When the group's [GroupNode#highlighted](/docs/api/types/model/groupnode/#highlighted) property is `true`, the `ng-diagram-group-highlight` CSS class is applied. ## Properties ### node > **node**: `InputSignal`\<[`GroupNode`](/docs/api/types/model/groupnode/)\<`object`\>\> The group node instance to monitor for highlight state. --- ### NgDiagramMinimapNavigationDirective URL: https://ngdiagram.dev/docs/api/directives/ngdiagramminimapnavigationdirective/ Directive that enables drag navigation on the minimap. Users can drag on the minimap to move the diagram viewport. Supports both mouse and touch input. Uses pointer capture for reliable touch tracking on mobile devices. ## Implements - `OnDestroy` ## Methods ### ngOnDestroy() > **ngOnDestroy**(): `void` A callback method that performs custom clean-up, invoked immediately before a directive, pipe, or service instance is destroyed. #### Returns `void` #### Implementation of `OnDestroy.ngOnDestroy` --- ### NgDiagramNodeSelectedDirective URL: https://ngdiagram.dev/docs/api/directives/ngdiagramnodeselecteddirective/ The `NgDiagramNodeSelectedDirective` conditionally applies a selected class to a node in the diagram when it is selected. ## Example usage ```html
``` When the node's [SimpleNode#selected](/docs/api/types/model/simplenode/#selected) property is `true`, the `ng-diagram-node-selected` CSS class is applied. ## Properties ### node > **node**: `InputSignal`\<[`Node`](/docs/api/types/model/node/)\> The node instance to monitor for selection state. --- ## Services ### NgDiagramClipboardService URL: https://ngdiagram.dev/docs/api/services/ngdiagramclipboardservice/ The `NgDiagramClipboardService` provides clipboard operations for diagram. ## Example usage ```typescript private clipboardService = inject(NgDiagramClipboardService); // Copy selected elements this.clipboardService.copy(); ``` ## Extends - `NgDiagramBaseService` ## Methods ### copy() > **copy**(): `Promise`\<`void`\> Copies the current selection to the clipboard. #### Returns `Promise`\<`void`\> A promise that resolves once the selection has been copied. *** ### cut() > **cut**(): `Promise`\<`void`\> Cuts the current selection to the clipboard. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### paste() > **paste**(`position`, `options?`): `Promise`\<`void`\> Pastes the clipboard content at the specified position. #### Parameters ##### position [`Point`](/docs/api/types/geometry/point/) The position where to paste the content. ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after the pasted elements have been measured — useful before calling `zoomToFit()` or `centerOnNode()`. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. --- ### NgDiagramGroupsService URL: https://ngdiagram.dev/docs/api/services/ngdiagramgroupsservice/ The `NgDiagramGroupsService` provides methods for managing node groups in the diagram. ## Example usage ```typescript private groupsService = inject(NgDiagramGroupsService); // Add nodes to a group this.groupsService.addToGroup('groupId', ['nodeId1', 'nodeId2']); ``` ## Extends - `NgDiagramBaseService` ## Methods ### addToGroup() > **addToGroup**(`groupId`, `nodeIds`): `Promise`\<`void`\> Adds nodes to a group. #### Parameters ##### groupId `string` The ID of the group to add nodes to. ##### nodeIds `string`[] Array of node IDs to add to the group. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### highlightGroup() > **highlightGroup**(`groupId`, `nodes`): `Promise`\<`void`\> Highlights a group. #### Parameters ##### groupId `string` The ID of the group to highlight. ##### nodes [`Node`](/docs/api/types/model/node/)[] The nodes to highlight as part of the group. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied. *** ### highlightGroupClear() > **highlightGroupClear**(): `Promise`\<`void`\> Clears all group highlights. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied. *** ### removeFromGroup() > **removeFromGroup**(`groupId`, `nodeIds`): `Promise`\<`void`\> Removes nodes from a group. #### Parameters ##### groupId `string` The ID of the group to remove nodes from. ##### nodeIds `string`[] Array of node IDs to remove from the group. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. --- ### NgDiagramModelService URL: https://ngdiagram.dev/docs/api/services/ngdiagrammodelservice/ The `NgDiagramModelService` provides methods for accessing and manipulating the diagram's model. ## Example usage ```typescript private modelService = inject(NgDiagramModelService); // Add nodes this.modelService.addNodes([node1, node2]); ``` ## Extends - `NgDiagramBaseService` ## Implements - `OnDestroy` ## Properties ### edges > `readonly` **edges**: `Signal`\<[`Edge`](/docs/api/types/model/edge/)\<`object`\>[]\> Readonly signal of current edges in the diagram. *** ### metadata > `readonly` **metadata**: `Signal`\<[`Metadata`](/docs/api/types/model/metadata/)\<`object`\>\> Readonly signal of current diagram metadata. *** ### nodes > `readonly` **nodes**: `Signal`\<[`Node`](/docs/api/types/model/node/)[]\> Readonly signal of current nodes in the diagram. ## Methods ### addEdges() > **addEdges**(`edges`, `options?`): `Promise`\<`void`\> Adds new edges to the diagram. #### Parameters ##### edges [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Array of edges to add. ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after the added elements (e.g. edge labels) have been measured. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### addNodes() > **addNodes**(`nodes`, `options?`): `Promise`\<`void`\> Adds new nodes to the diagram. #### Parameters ##### nodes [`Node`](/docs/api/types/model/node/)[] Array of nodes to add. ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after the added nodes have been measured — useful before calling `zoomToFit()` or `centerOnNode()`. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### computePartsBounds() > **computePartsBounds**(`nodes`, `edges`): [`Rect`](/docs/api/types/geometry/rect/) #### Parameters ##### nodes [`Node`](/docs/api/types/model/node/)[] Array of nodes ##### edges [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Array of edges #### Returns [`Rect`](/docs/api/types/geometry/rect/) Bounding rectangle containing all nodes and edges #### Since 0.9.0 Computes the axis-aligned bounding rectangle that contains all specified nodes and edges. *** ### deleteEdges() > **deleteEdges**(`ids`): `Promise`\<`void`\> Deletes edges by their IDs. #### Parameters ##### ids `string`[] Array of edge IDs to delete. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### deleteNodes() > **deleteNodes**(`ids`): `Promise`\<`void`\> Deletes nodes by their IDs. #### Parameters ##### ids `string`[] Array of node IDs to delete. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### getChildren() > **getChildren**\<`T`\>(`groupId`): [`Node`](/docs/api/types/model/node/)\<`T`\>[] Gets all children nodes for a given group node id #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the nodes' `data` property. Defaults to `DataObject`. #### Parameters ##### groupId `string` group node id #### Returns [`Node`](/docs/api/types/model/node/)\<`T`\>[] Array of child nodes *** ### getChildrenNested() > **getChildrenNested**\<`T`\>(`groupId`): [`Node`](/docs/api/types/model/node/)\<`T`\>[] Gets all nested children (descendants) of a group node #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the nodes' `data` property. Defaults to `DataObject`. #### Parameters ##### groupId `string` Group node id #### Returns [`Node`](/docs/api/types/model/node/)\<`T`\>[] Array of all descendant nodes (children, grandchildren, etc.) *** ### getConnectedEdges() > **getConnectedEdges**\<`T`\>(`nodeId`): [`Edge`](/docs/api/types/model/edge/)\<`T`\>[] Gets all edges connected to a node #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the edges' `data` property. Defaults to `DataObject`. #### Parameters ##### nodeId `string` Node id #### Returns [`Edge`](/docs/api/types/model/edge/)\<`T`\>[] Array of edges where the node is either source or target *** ### getConnectedNodes() > **getConnectedNodes**\<`T`\>(`nodeId`): [`Node`](/docs/api/types/model/node/)\<`T`\>[] Gets all nodes connected to a node via edges #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the nodes' `data` property. Defaults to `DataObject`. #### Parameters ##### nodeId `string` Node id #### Returns [`Node`](/docs/api/types/model/node/)\<`T`\>[] Array of nodes connected to the given node *** ### getEdgeById() > **getEdgeById**\<`T`\>(`edgeId`): `null` \| [`Edge`](/docs/api/types/model/edge/)\<`T`\> Gets an edge by id. #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the edge's `data` property. Defaults to `DataObject`. #### Parameters ##### edgeId `string` Edge id. #### Returns `null` \| [`Edge`](/docs/api/types/model/edge/)\<`T`\> Edge or null if not found. *** ### getModel() > **getModel**(): [`ModelAdapter`](/docs/api/types/model/modeladapter/) Returns the current model that NgDiagram instance is using. Returns null if flowCore is not initialized. #### Returns [`ModelAdapter`](/docs/api/types/model/modeladapter/) *** ### getNearestNodeInRange() > **getNearestNodeInRange**\<`T`\>(`point`, `range`): `null` \| [`Node`](/docs/api/types/model/node/)\<`T`\> Gets the nearest node in a range from a point. #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the node's `data` property. Defaults to `DataObject`. #### Parameters ##### point [`Point`](/docs/api/types/geometry/point/) Point to check from. ##### range `number` Range to check in. #### Returns `null` \| [`Node`](/docs/api/types/model/node/)\<`T`\> Nearest node in range or null. *** ### getNearestPortInRange() > **getNearestPortInRange**(`point`, `range`): `null` \| [`Port`](/docs/api/types/model/port/) Gets the nearest port in a range from a point. #### Parameters ##### point [`Point`](/docs/api/types/geometry/point/) Point to check from. ##### range `number` Range to check in. #### Returns `null` \| [`Port`](/docs/api/types/model/port/) Nearest port in range or null. *** ### getNodeById() > **getNodeById**\<`T`\>(`nodeId`): `null` \| [`Node`](/docs/api/types/model/node/)\<`T`\> Gets a node by id. #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the node's `data` property. Defaults to `DataObject`. #### Parameters ##### nodeId `string` Node id. #### Returns `null` \| [`Node`](/docs/api/types/model/node/)\<`T`\> Node or null if not found. *** ### getNodeEnds() > **getNodeEnds**\<`S`, `T`\>(`edgeId`): `null` \| \{ `source`: [`Node`](/docs/api/types/model/node/)\<`S`\>; `target`: [`Node`](/docs/api/types/model/node/)\<`T`\>; \} Gets the source and target nodes of an edge #### Type Parameters ##### S `S` *extends* `object` = `object` The type of the source node's `data` property. Defaults to `DataObject`. ##### T `T` *extends* `object` = `object` The type of the target node's `data` property. Defaults to `DataObject`. #### Parameters ##### edgeId `string` Edge id #### Returns `null` \| \{ `source`: [`Node`](/docs/api/types/model/node/)\<`S`\>; `target`: [`Node`](/docs/api/types/model/node/)\<`T`\>; \} Object containing source and target nodes, or null if edge doesn't exist *** ### getNodesInRange() > **getNodesInRange**\<`T`\>(`point`, `range`): [`Node`](/docs/api/types/model/node/)\<`T`\>[] Gets all nodes in a range from a point. #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the nodes' `data` property. Defaults to `DataObject`. #### Parameters ##### point [`Point`](/docs/api/types/geometry/point/) Point to check from. ##### range `number` Range to check in. #### Returns [`Node`](/docs/api/types/model/node/)\<`T`\>[] Array of nodes in range. *** ### getOverlappingNodes() #### Call Signature > **getOverlappingNodes**\<`T`\>(`nodeId`): [`Node`](/docs/api/types/model/node/)\<`T`\>[] Detects collision with other nodes by finding all nodes whose rectangles intersect with the specified node's bounding rectangle. ##### Type Parameters ###### T `T` *extends* `object` = `object` The type of the nodes' `data` property. Defaults to `DataObject`. ##### Parameters ###### nodeId `string` The ID of the node to check for collisions ##### Returns [`Node`](/docs/api/types/model/node/)\<`T`\>[] An array of Nodes that overlap with the specified node #### Call Signature > **getOverlappingNodes**\<`T`\>(`node`): [`Node`](/docs/api/types/model/node/)\<`T`\>[] ##### Type Parameters ###### T `T` *extends* `object` = `object` The type of the nodes' `data` property. Defaults to `DataObject`. ##### Parameters ###### node [`Node`](/docs/api/types/model/node/)\<`T`\> The node to check for collisions ##### Returns [`Node`](/docs/api/types/model/node/)\<`T`\>[] An array of Nodes that overlap with the specified node ##### Since 0.9.0 Detects collision with other nodes by finding all nodes whose rectangles intersect with the specified node's bounding rectangle. *** ### getParentHierarchy() > **getParentHierarchy**\<`T`\>(`nodeId`): [`GroupNode`](/docs/api/types/model/groupnode/)\<`T`\>[] Gets the full chain of parent group Nodes for a given nodeId. #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the group nodes' `data` property. Defaults to `DataObject`. #### Parameters ##### nodeId `string` Node id #### Returns [`GroupNode`](/docs/api/types/model/groupnode/)\<`T`\>[] Array of parent group Node objects, from closest parent to farthest ancestor *** ### isNestedChild() > **isNestedChild**(`nodeId`, `groupId`): `boolean` Checks if a node is a nested child (descendant) of a group node #### Parameters ##### nodeId `string` Node id ##### groupId `string` Group node id #### Returns `boolean` True if the node is part of the group's nested subgraph *** ### toJSON() > **toJSON**(): `string` Serializes the current model to a JSON string. #### Returns `string` The model as a JSON string. *** ### updateEdge() > **updateEdge**(`edgeId`, `edge`, `options?`): `Promise`\<`void`\> Updates the properties of an edge. #### Parameters ##### edgeId `string` Edge id. ##### edge `Partial`\<[`Edge`](/docs/api/types/model/edge/)\> New edge properties. ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after measurements triggered by the update have completed. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### updateEdgeData() > **updateEdgeData**\<`T`\>(`edgeId`, `data`, `options?`): `Promise`\<`void`\> Updates the data of an edge. #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the edge's `data` property. Defaults to `DataObject`. #### Parameters ##### edgeId `string` Edge id. ##### data `T` New data to set for the edge. ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after measurements triggered by the update (e.g. re-rendered edge labels) have completed. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### updateEdges() > **updateEdges**(`edges`, `options?`): `Promise`\<`void`\> Updates multiple edges at once. #### Parameters ##### edges `Pick`\<[`Edge`](/docs/api/types/model/edge/)\<`object`\>, `"id"`\> & `Partial`\<[`Edge`](/docs/api/types/model/edge/)\<`object`\>\>[] Array of edge updates (must include id and any properties to update). ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after measurements triggered by the update have completed. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### updateNode() > **updateNode**(`nodeId`, `node`, `options?`): `Promise`\<`void`\> Updates the properties of a node. #### Parameters ##### nodeId `string` Node id. ##### node `Partial`\<[`Node`](/docs/api/types/model/node/)\> New node properties. ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after measurements triggered by the update have completed. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### updateNodeData() > **updateNodeData**\<`T`\>(`nodeId`, `data`, `options?`): `Promise`\<`void`\> Updates the data of a node. #### Type Parameters ##### T `T` *extends* `object` = `object` The type of the node's `data` property. Defaults to `DataObject`. #### Parameters ##### nodeId `string` Node id. ##### data `T` New data to set for the node. ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after measurements triggered by the update (e.g. a template resized by the new data) have completed. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### updateNodes() > **updateNodes**(`nodes`, `options?`): `Promise`\<`void`\> Updates multiple nodes at once. #### Parameters ##### nodes `Pick`\<[`Node`](/docs/api/types/model/node/), `"id"`\> & `Partial`\<[`Node`](/docs/api/types/model/node/)\>[] Array of node updates (must include id and any properties to update). ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after measurements triggered by the update have completed. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. --- ### NgDiagramNodeService URL: https://ngdiagram.dev/docs/api/services/ngdiagramnodeservice/ The `NgDiagramNodeService` provides methods for manipulating nodes in the diagram. ## Example usage ```typescript private nodeService = inject(NgDiagramNodeService); // Move nodes by a delta this.nodeService.moveNodesBy([node1, node2], { x: 10, y: 20 }); ``` ## Extends - `NgDiagramBaseService` ## Methods ### bringToFront() > **bringToFront**(`nodeIds?`, `edgeIds?`): `Promise`\<`void`\> Brings the specified nodes and edges to the front (highest z-index). #### Parameters ##### nodeIds? `string`[] Array of node IDs to bring to front. ##### edgeIds? `string`[] Array of edge IDs to bring to front. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### moveNodesBy() > **moveNodesBy**(`nodes`, `delta`): `Promise`\<`void`\> Moves nodes by the specified amounts. #### Parameters ##### nodes [`Node`](/docs/api/types/model/node/)[] Array of nodes to move. ##### delta [`Point`](/docs/api/types/geometry/point/) The amount to move the nodes by. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### resizeNode() > **resizeNode**(`id`, `size`, `position?`, `disableAutoSize?`, `options?`): `Promise`\<`void`\> Resizes a node to the specified dimensions. `Node.autoSize` must be set to false to resize a node. #### Parameters ##### id `string` The ID of the node to resize. ##### size [`Size`](/docs/api/types/geometry/size/) The new size of the node. ##### position? [`Point`](/docs/api/types/geometry/point/) Optional new position of the node. ##### disableAutoSize? `boolean` Optional flag to disable auto-sizing. ##### options? Optional settings. Set `waitForMeasurements: true` to resolve only after measurements triggered by the resize have completed. Available since 1.3.0. ###### waitForMeasurements? `boolean` #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### rotateNodeTo() > **rotateNodeTo**(`nodeId`, `angle`): `Promise`\<`void`\> Rotates a node to the specified angle. #### Parameters ##### nodeId `string` The ID of the node to rotate. ##### angle `number` The rotation angle in degrees. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### sendToBack() > **sendToBack**(`nodeIds?`, `edgeIds?`): `Promise`\<`void`\> Sends the specified nodes and edges to the back (lowest z-index). #### Parameters ##### nodeIds? `string`[] Array of node IDs to send to back. ##### edgeIds? `string`[] Array of edge IDs to send to back. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. --- ### NgDiagramSelectionService URL: https://ngdiagram.dev/docs/api/services/ngdiagramselectionservice/ The `NgDiagramSelectionService` provides methods for managing the selection state of nodes and edges in the diagram. ## Example usage ```typescript private selectionService = inject(NgDiagramSelectionService); // Select nodes and edges this.selectionService.select(['nodeId1'], ['edgeId1']); ``` ## Extends - `NgDiagramBaseService` ## Properties ### selection > **selection**: `Signal`\<\{ `edges`: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[]; `nodes`: [`Node`](/docs/api/types/model/node/)[]; \}\> Returns a computed signal for the current selection of nodes and edges. ## Methods ### deleteSelection() > **deleteSelection**(): `Promise`\<`void`\> Deletes the current selection of nodes and edges. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### deselect() > **deselect**(`nodeIds`, `edgeIds`): `Promise`\<`void`\> Deselects nodes and edges by their IDs. #### Parameters ##### nodeIds `string`[] = `[]` Array of node IDs to deselect. ##### edgeIds `string`[] = `[]` Array of edge IDs to deselect. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### deselectAll() > **deselectAll**(): `Promise`\<`void`\> Deselects all currently selected nodes and edges. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### select() > **select**(`nodeIds`, `edgeIds`): `Promise`\<`void`\> Selects nodes and edges by their IDs. #### Parameters ##### nodeIds `string`[] = `[]` Array of node IDs to select. ##### edgeIds `string`[] = `[]` Array of edge IDs to select. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. --- ### NgDiagramService URL: https://ngdiagram.dev/docs/api/services/ngdiagramservice/ The `NgDiagramService` provides advanced access to the diagram's core API, including configuration, layout, event management, routing, transactions, and more. ## Example usage ```typescript private ngDiagramService = inject(NgDiagramService); // Check if diagram is initialized (reactive signal) effect(() => { if (this.ngDiagramService.isInitialized()) { console.log('Diagram ready!'); } }); // Access reactive config const isDebugMode = this.ngDiagramService.config().debugMode; // Update configuration this.ngDiagramService.updateConfig({ debugMode: true }); ``` ## Extends - `NgDiagramBaseService` ## Properties ### actionState > `readonly` **actionState**: `Signal`\<`Readonly`\<[`ActionState`](/docs/api/internals/actionstate/)\>\> Reactive signal that tracks the current action state (readonly). This signal is managed internally by the diagram and updates automatically when actions like resizing, rotating, or linking start/end. - This property cannot be modified directly. *** ### config > `readonly` **config**: `Signal`\<`Readonly`\<`DeepPartial`\<[`FlowConfig`](/docs/api/types/configuration/flowconfig/)\>\>\> Reactive signal that tracks the current configuration (readonly). To update the configuration, use [updateConfig](/docs/api/services/ngdiagramservice/#updateconfig). *** ### isInitialized > **isInitialized**: `Signal`\<`boolean`\> Returns whether the diagram is fully initialized and all elements are measured. This signal is set to `true` when the `diagramInit` event fires. ## Methods ### addEventListener() > **addEventListener**\<`K`\>(`event`, `callback`): `UnsubscribeFn` Add an event listener for a diagram event. #### Type Parameters ##### K `K` *extends* keyof [`DiagramEventMap`](/docs/api/types/events/diagrameventmap/) #### Parameters ##### event `K` The event name. ##### callback `EventListener`\<[`DiagramEventMap`](/docs/api/types/events/diagrameventmap/)\[`K`\]\> The callback to invoke when the event is emitted. #### Returns `UnsubscribeFn` A function to unsubscribe. #### Example ```ts const unsubscribe = ngDiagramService.addEventListener('selectionChanged', (event) => { console.log('Selection changed', event.selectedNodes); }); ``` *** ### addEventListenerOnce() > **addEventListenerOnce**\<`K`\>(`event`, `callback`): `UnsubscribeFn` Add an event listener that will only fire once. #### Type Parameters ##### K `K` *extends* keyof [`DiagramEventMap`](/docs/api/types/events/diagrameventmap/) #### Parameters ##### event `K` The event name. ##### callback `EventListener`\<[`DiagramEventMap`](/docs/api/types/events/diagrameventmap/)\[`K`\]\> The callback to invoke when the event is emitted. #### Returns `UnsubscribeFn` A function to unsubscribe. #### Example ```ts ngDiagramService.addEventListenerOnce('diagramInit', (event) => { console.log('Diagram initialized', event); }); ``` *** ### areEventsEnabled() > **areEventsEnabled**(): `boolean` Check if event emissions are enabled. #### Returns `boolean` True if events are enabled. *** ### cancelActiveInteraction() > **cancelActiveInteraction**(): `Promise`\<`boolean`\> Aborts the in-progress gesture (linking, drag, resize, rotate or pan): removes its listeners immediately, restores the state it modified (positions, size, angle, temporary edge — the viewport is not rolled back) and fires the corresponding "ended" event with the `cancelled` reason. No-op when nothing is active, when the gesture is already completing, or while a transaction is active (refused with a console warning — cancel after it settles). Bound to Escape by default via the `cancelInteraction` shortcut action — see [configureShortcuts](/docs/api/utilities/configureshortcuts/). #### Returns `Promise`\<`boolean`\> Promise resolving to whether anything was torn down #### Example ```typescript ngDiagramService.cancelActiveInteraction(); ``` #### Since 1.3.0 *** ### getDefaultRouting() > **getDefaultRouting**(): `string` Gets the current default routing name. #### Returns `string` Name of the default routing. *** ### getEnvironment() > **getEnvironment**(): [`EnvironmentInfo`](/docs/api/internals/environmentinfo/) Gets the current environment information. #### Returns [`EnvironmentInfo`](/docs/api/internals/environmentinfo/) The environment info object. *** ### getRegisteredRoutings() > **getRegisteredRoutings**(): `string`[] Gets all registered routing names. #### Returns `string`[] Array of registered routing names. *** ### hasEventListeners() > **hasEventListeners**(`event`): `boolean` Check if there are any listeners for an event. #### Parameters ##### event keyof [`DiagramEventMap`](/docs/api/types/events/diagrameventmap/) The event name. #### Returns `boolean` True if there are listeners. #### Example ```ts if (ngDiagramService.hasEventListeners('selectionChanged')) { // There are listeners for selection changes } ``` *** ### invalidateMeasurements() > **invalidateMeasurements**(`options?`): `Promise`\<`void`\> Forces re-measurement of diagram elements via ResizeObserver. When called with no arguments, all nodes, ports, and edge labels are re-measured. When called with specific options, only the targeted elements are re-measured. Invalidating a node also re-measures all its ports. #### Parameters ##### options? [`InvalidateMeasurementsOptions`](/docs/api/other/invalidatemeasurementsoptions/) Optional. Specifies which elements to re-measure. #### Returns `Promise`\<`void`\> A promise that resolves once the triggered re-measurements have settled — the invalidated elements' `size`, `measuredPorts` and `measuredLabels` then read fresh (returned since 1.3.0; safe to ignore). #### Remarks Resolution is settle-based, like the transaction `waitForMeasurements` option: a discovery window opens and a rolling debounce waits for measurements to stop. - The promise never hangs: an element that delivers no new measurement (unmounted, zero-size, or unchanged) settles on window expiry; when nothing matching the request is observed, it resolves immediately. - Concurrent measurements settle together with these, and updates in flight at call time are waited out, so the promise may resolve slightly later. - Do not await this inside an active transaction (re-measurements apply only at commit, so the promise resolves before the fresh geometry lands) or inside a middleware (the update pipeline is not re-entrant — the await deadlocks). Fire-and-forget is safe in both. #### Example ```ts // Re-measure specific nodes (including their ports) and wait for fresh geometry await ngDiagramService.invalidateMeasurements({ nodes: [{ nodeId: 'node-1' }] }); // Re-measure labels on specific edges await ngDiagramService.invalidateMeasurements({ edges: [{ edgeId: 'edge-1' }] }); // Re-measure the entire diagram, fire-and-forget ngDiagramService.invalidateMeasurements(); ``` #### Since 1.2.3 *** ### registerMiddleware() > **registerMiddleware**(`middleware`): () => `void` Registers a new middleware in the chain. #### Parameters ##### middleware [`Middleware`](/docs/api/types/middleware/middleware/) Middleware to register. #### Returns Function to unregister the middleware. > (): `void` ##### Returns `void` *** ### registerRouting() > **registerRouting**(`routing`): `void` Registers a custom routing implementation. #### Parameters ##### routing [`EdgeRouting`](/docs/api/types/routing/edgerouting/) Routing implementation to register. #### Returns `void` #### Example ```ts const customRouting: Routing = { name: 'custom', computePoints: (source, target) => [...], computeSvgPath: (points) => '...' }; ngDiagramService.registerRouting(customRouting); ``` *** ### removeAllEventListeners() > **removeAllEventListeners**(): `void` Remove all event listeners. #### Returns `void` #### Example ```ts ngDiagramService.removeAllEventListeners(); ``` *** ### removeEventListener() > **removeEventListener**\<`K`\>(`event`, `callback?`): `void` Remove an event listener. #### Type Parameters ##### K `K` *extends* keyof [`DiagramEventMap`](/docs/api/types/events/diagrameventmap/) #### Parameters ##### event `K` The event name. ##### callback? `EventListener`\<[`DiagramEventMap`](/docs/api/types/events/diagrameventmap/)\[`K`\]\> Optional specific callback to remove. #### Returns `void` #### Example ```ts // Remove all listeners for an event ngDiagramService.removeEventListener('selectionChanged'); // Remove a specific listener ngDiagramService.removeEventListener('selectionChanged', myCallback); ``` *** ### setDefaultRouting() > **setDefaultRouting**(`name`): `void` Sets the default routing to use when not specified on edges. #### Parameters ##### name `string` Name of the routing to set as default. #### Returns `void` *** ### setEventsEnabled() > **setEventsEnabled**(`enabled`): `void` Enable or disable event emissions. #### Parameters ##### enabled `boolean` Whether events should be emitted. #### Returns `void` #### Example ```ts // Disable all events ngDiagramService.setEventsEnabled(false); // Re-enable events ngDiagramService.setEventsEnabled(true); ``` *** ### startLinking() > **startLinking**(`node`, `portId?`): `void` Call this method to start linking from your custom logic. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node from which the linking starts. ##### portId? `string` The port ID from which the linking starts. Creates a floating edge when undefined. #### Returns `void` *** ### transaction() #### Call Signature > **transaction**(`callback`): `Promise`\<[`TransactionResult`](/docs/api/types/middleware/transactionresult/)\> ##### Parameters ###### callback () => `Promise`\<`void`\> The async function to execute within the transaction. ##### Returns `Promise`\<[`TransactionResult`](/docs/api/types/middleware/transactionresult/)\> A promise that resolves with the transaction result. ##### Since 0.9.0 Executes an async function within a transaction context. All state updates within the callback are batched and applied atomically. ##### Example ```ts // Async transaction with data fetching await this.ngDiagramService.transaction(async () => { const nodes = await fetchNodesFromServer(); this.ngDiagramModelService.addNodes(node); }); ``` #### Call Signature > **transaction**(`callback`, `options`): `Promise`\<[`TransactionResult`](/docs/api/types/middleware/transactionresult/)\> ##### Parameters ###### callback () => `Promise`\<`void`\> The async function to execute within the transaction. ###### options [`TransactionOptions`](/docs/api/types/middleware/transactionoptions/) Transaction options. ##### Returns `Promise`\<[`TransactionResult`](/docs/api/types/middleware/transactionresult/)\> A promise that resolves with the transaction result. ##### Since 0.9.0 Executes an async function within a transaction context with options. All state updates within the callback are batched and applied atomically. ##### Example ```ts // Async transaction that waits for measurements await this.ngDiagramService.transaction(async () => { const nodes = await fetchNodesFromServer(); this.ngDiagramModelService.addNodes(nodes); }, { waitForMeasurements: true }); ``` #### Call Signature > **transaction**(`callback`): `Promise`\<[`TransactionResult`](/docs/api/types/middleware/transactionresult/)\> Executes a function within a transaction context. All state updates within the callback are batched and applied atomically. ##### Parameters ###### callback () => `void` The function to execute within the transaction. ##### Returns `Promise`\<[`TransactionResult`](/docs/api/types/middleware/transactionresult/)\> A promise that resolves with the transaction result once the transaction has been committed to the model (returned since 1.3.0; safe to ignore when not needed). ##### Example ```ts this.ngDiagramService.transaction(() => { this.ngDiagramModelService.addNodes([node1, node2]); this.ngDiagramModelService.addEdges([edge1]); }); ``` #### Call Signature > **transaction**(`callback`, `options`): `Promise`\<[`TransactionResult`](/docs/api/types/middleware/transactionresult/)\> ##### Parameters ###### callback () => `void` The function to execute within the transaction. ###### options [`TransactionOptions`](/docs/api/types/middleware/transactionoptions/) Transaction options. ##### Returns `Promise`\<[`TransactionResult`](/docs/api/types/middleware/transactionresult/)\> A promise that resolves with the transaction result. ##### Since 0.9.0 Executes a function within a transaction context with options. All state updates within the callback are batched and applied atomically. ##### Example ```ts // Transaction that waits for measurements to complete await this.ngDiagramService.transaction(() => { this.ngDiagramModelService.addNodes([node1, node2]); }, { waitForMeasurements: true }); ``` *** ### unregisterMiddleware() > **unregisterMiddleware**(`name`): `void` Unregister a middleware from the chain. #### Parameters ##### name `string` Name of the middleware to unregister. #### Returns `void` *** ### unregisterRouting() > **unregisterRouting**(`name`): `void` Unregisters a routing implementation. #### Parameters ##### name `string` Name of the routing to unregister. #### Returns `void` *** ### updateConfig() > **updateConfig**(`config`): `void` Updates the current configuration. #### Parameters ##### config `Partial`\<[`NgDiagramConfig`](/docs/api/types/configuration/ngdiagramconfig/)\> Partial configuration object containing properties to update. #### Returns `void` #### Example ```ts // Enable debug mode this.ngDiagramService.updateConfig({ debugMode: true }); ``` --- ### NgDiagramViewportService URL: https://ngdiagram.dev/docs/api/services/ngdiagramviewportservice/ The `NgDiagramViewportService` provides methods and signals for interacting with the diagram viewport. ## Example usage ```typescript private viewportService = inject(NgDiagramViewportService); // Move viewport to (100, 200) this.viewportService.moveViewport(100, 200); // Zoom in by a factor of 1.2 this.viewportService.zoom(1.2); ``` ## Extends - `NgDiagramBaseService` ## Properties ### canZoomIn > **canZoomIn**: `Signal`\<`boolean`\> Returns true if the current zoom level is below the maximum and can be increased. *** ### canZoomOut > **canZoomOut**: `Signal`\<`boolean`\> Returns true if the current zoom level is above the minimum and can be decreased. *** ### scale > **scale**: `Signal`\<`number`\> Returns a computed signal for the scale that safely handles uninitialized state. *** ### viewport > **viewport**: `Signal`\<[`Viewport`](/docs/api/types/model/viewport/)\> Returns a computed signal for the viewport that safely handles uninitialized state. ## Accessors ### maxZoom #### Get Signature > **get** **maxZoom**(): `number` Returns the maximum zoom scale from the diagram configuration. ##### Returns `number` *** ### minZoom #### Get Signature > **get** **minZoom**(): `number` Returns the minimum zoom scale from the diagram configuration. ##### Returns `number` ## Methods ### centerOnNode() > **centerOnNode**(`nodeOrId`): `Promise`\<`void`\> Centers the Node within the current viewport bounds. #### Parameters ##### nodeOrId The ID of the node or the node object to center on. `string` | [`Node`](/docs/api/types/model/node/) #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. #### Remarks When calling `centerOnNode()` immediately after adding or modifying a node, its dimensions may not be measured yet. Use the `waitForMeasurements` transaction option to ensure accurate centering: ```typescript await this.ngDiagramService.transaction(() => { this.modelService.addNodes([newNode]); }, { waitForMeasurements: true }); this.viewportService.centerOnNode(newNode.id); // Now centers correctly ``` *** ### centerOnRect() > **centerOnRect**(`rect`): `Promise`\<`void`\> Centers the rectangle within the current viewport bounds. #### Parameters ##### rect [`Rect`](/docs/api/types/geometry/rect/) The rectangle to center on. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### clientToFlowPosition() > **clientToFlowPosition**(`clientPosition`): [`Point`](/docs/api/types/geometry/point/) Converts a client position to a flow position. #### Parameters ##### clientPosition [`Point`](/docs/api/types/geometry/point/) Client position to convert. #### Returns [`Point`](/docs/api/types/geometry/point/) Flow position. *** ### clientToFlowViewportPosition() > **clientToFlowViewportPosition**(`clientPosition`): [`Point`](/docs/api/types/geometry/point/) Converts a client position to a position relative to the flow viewport. #### Parameters ##### clientPosition [`Point`](/docs/api/types/geometry/point/) Client position. #### Returns [`Point`](/docs/api/types/geometry/point/) Position on the flow viewport. *** ### flowToClientPosition() > **flowToClientPosition**(`flowPosition`): [`Point`](/docs/api/types/geometry/point/) Converts a flow position to a client position. #### Parameters ##### flowPosition [`Point`](/docs/api/types/geometry/point/) Flow position to convert. #### Returns [`Point`](/docs/api/types/geometry/point/) Client position. *** ### moveViewport() > **moveViewport**(`x`, `y`): `Promise`\<`void`\> Moves the viewport to the specified coordinates. #### Parameters ##### x `number` The x-coordinate to move the viewport to. ##### y `number` The y-coordinate to move the viewport to. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### moveViewportBy() > **moveViewportBy**(`dx`, `dy`): `Promise`\<`void`\> Moves the viewport by the specified amounts. #### Parameters ##### dx `number` The amount to move the viewport in the x-direction. ##### dy `number` The amount to move the viewport in the y-direction. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### setViewport() > **setViewport**(`x`, `y`, `scale`): `Promise`\<`void`\> Sets the viewport to an absolute position and scale. #### Parameters ##### x `number` The absolute x-coordinate for the viewport. ##### y `number` The absolute y-coordinate for the viewport. ##### scale `number` The absolute zoom scale (clamped to configured min/max). #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. #### Example ```typescript // Reset to origin at 50% zoom this.viewportService.setViewport(0, 0, 0.5); ``` #### Since 1.2.0 *** ### zoom() > **zoom**(`factor`, `center?`): `Promise`\<`void`\> Zooms the viewport by the specified factor. #### Parameters ##### factor `number` The factor to zoom by (e.g., 1.1 for 10% zoom in, 0.9 for 10% zoom out). ##### center? [`Point`](/docs/api/types/geometry/point/) The center point to zoom towards. #### Returns `Promise`\<`void`\> A promise that resolves once the change has been applied to the model. Inside a transaction, the promise resolves right away and the change is applied when the transaction commits. *** ### zoomToFit() > **zoomToFit**(`options?`): `Promise`\<`void`\> Automatically adjusts the viewport to fit all diagram content (or a specified subset) within the visible area. #### Parameters ##### options? Optional configuration object ###### edgeIds? `string`[] Array of edge IDs to fit. If not provided, all edges are included. ###### nodeIds? `string`[] Array of node IDs to fit. If not provided, all nodes are included. ###### padding? `number` \| \[`number`, `number`\] \| \[`number`, `number`, `number`\] \| \[`number`, `number`, `number`, `number`\] Padding around the content (default: 50). Supports CSS-like syntax: - Single number: uniform padding on all sides - [top/bottom, left/right]: vertical and horizontal padding - [top, left/right, bottom]: top, horizontal, bottom padding - [top, right, bottom, left]: individual padding for each side #### Returns `Promise`\<`void`\> #### Remarks Always `await` the preceding model mutation (e.g. `await modelService.deleteNodes(...)`) before calling `zoomToFit()` — an un-awaited mutation is not yet committed when `zoomToFit()` reads the model, so the viewport would fit the old content. When calling `zoomToFit()` immediately after adding or modifying nodes/edges, their dimensions may not be measured yet. Use the `waitForMeasurements` transaction option to ensure accurate results: ```typescript await this.ngDiagramService.transaction(() => { this.modelService.addNodes([newNode]); }, { waitForMeasurements: true }); this.viewportService.zoomToFit(); // Now includes new node dimensions ``` #### Example ```typescript // Fit all nodes and edges with default padding this.viewportService.zoomToFit(); // Fit with custom uniform padding this.viewportService.zoomToFit({ padding: 100 }); // Fit with different padding on each side [top, right, bottom, left] this.viewportService.zoomToFit({ padding: [50, 100, 50, 100] }); // Fit only specific nodes this.viewportService.zoomToFit({ nodeIds: ['node1', 'node2'] }); // Custom zoomToFit with anchor positioning using setViewport // anchor: (0,0) = top-left, (0.5,0.5) = center, (1,1) = bottom-right const anchor = { x: 0.5, y: 0.5 }; const { width, height } = this.modelService.metadata().viewport; const bounds = this.modelService.computePartsBounds(nodes, edges); const scale = Math.min(width / bounds.width, height / bounds.height); const x = width * anchor.x - (bounds.x + bounds.width * anchor.x) * scale; const y = height * anchor.y - (bounds.y + bounds.height * anchor.y) * scale; this.viewportService.setViewport(x, y, scale); ``` --- ## Utilities ### configureShortcuts URL: https://ngdiagram.dev/docs/api/utilities/configureshortcuts/ > **configureShortcuts**(`userShortcuts`, `baseShortcuts`): [`ShortcutDefinition`](/docs/api/types/configuration/shortcuts/shortcutdefinition/)[] Merges user shortcuts with base shortcuts, user shortcuts override by actionName ## Parameters ### userShortcuts [`ShortcutDefinition`](/docs/api/types/configuration/shortcuts/shortcutdefinition/)[] User-provided shortcuts that will override matching base shortcuts ### baseShortcuts [`ShortcutDefinition`](/docs/api/types/configuration/shortcuts/shortcutdefinition/)[] = `DEFAULT_SHORTCUTS` Base shortcuts to merge with. Optional parameter that defaults to built-in shortcuts ## Returns [`ShortcutDefinition`](/docs/api/types/configuration/shortcuts/shortcutdefinition/)[] Merged shortcut definitions ## Examples ```ts // Merge with default built-in shortcuts config = { shortcuts: configureShortcuts([ { actionName: 'keyboardMoveSelectionUp', bindings: [{ key: 'w' }], }, ]), } satisfies NgDiagramConfig; ``` ```ts // Merge with existing config shortcuts const currentShortcuts = ngDiagramService.config().shortcuts; const updatedShortcuts = configureShortcuts( [ { actionName: 'paste', bindings: [{ key: 'b', modifiers: { primary: true } }], }, ], currentShortcuts ); ``` --- ### createMiddlewares URL: https://ngdiagram.dev/docs/api/utilities/createmiddlewares/ > **createMiddlewares**\<`TMiddlewares`\>(`middlewares`): `TMiddlewares` Factory method to create a list of middlewares for ng-diagram. Allows modifying the default middleware chain by removing, replacing, or adding new middlewares. ## Type Parameters ### TMiddlewares `TMiddlewares` *extends* [`MiddlewareChain`](/docs/api/types/middleware/middlewarechain/) = \[[`Middleware`](/docs/api/types/middleware/middleware/)\<`string`\>, [`Middleware`](/docs/api/types/middleware/middleware/)\<`"z-index"`\>, [`Middleware`](/docs/api/types/middleware/middleware/)\<`string`\>\] The type of the resulting middleware chain ## Parameters ### middlewares (`defaults`) => `TMiddlewares` Function that receives default middlewares and returns modified middleware chain ## Returns `TMiddlewares` The modified middleware chain Use with extreme caution - incorrectly modifying required middlewares can break the library --- ### initializeModel URL: https://ngdiagram.dev/docs/api/utilities/initializemodel/ > **initializeModel**(`model`, `injector?`, `options?`): [`ModelAdapter`](/docs/api/types/model/modeladapter/) Creates a model adapter with initial nodes, edges, and metadata. This helper sets up a model instance ready for use in ng-diagram. It must be run in an Angular injection context unless the `injector` option is provided manually. ⚠️ This is only for creating the initial model. Any changes to the model or access to current data should be done via [NgDiagramModelService](/docs/api/services/ngdiagrammodelservice/). ## Parameters ### model `Partial`\<[`Model`](/docs/api/types/model/model/)\> = `{}` Initial model data (nodes, edges, metadata). ### injector? `Injector` Optional Angular `Injector` if not running inside an injection context. ### options? [`InitializeModelOptions`](/docs/api/types/model/initializemodeloptions/) Optional [InitializeModelOptions](/docs/api/types/model/initializemodeloptions/). ⚠️ Overriding the strip functions can and probably will break the diagram — use at your own risk. ## Returns [`ModelAdapter`](/docs/api/types/model/modeladapter/) ## Example ```typescript // Create an empty model model = initializeModel(); // Create a model with initial data model = initializeModel({ nodes: [{ id: '1', position: { x: 0, y: 0 }, data: { label: 'Node 1' } }], edges: [], }); // With an explicit injector (outside injection context) model = initializeModel({ nodes: [...], edges: [...] }, this.injector); // Safe to use inside reactive contexts (computed, effect, linkedSignal) model = computed(() => initializeModel(this.myModel(), this.injector)); // ⚠️ At your own risk: customize which runtime properties are stripped model = initializeModel({ nodes: [...], edges: [...] }, undefined, { stripNodeRuntimeProperties: (node) => ({ ...stripNodeRuntimeProperties(node), selected: node.selected, // keep selection state across reloads }), }); ``` ## Version History | Version | Changes | |---------|---------| | v0.8.0 | Introduced | | v1.2.0 | Can now be safely used inside reactive contexts (`computed`, `effect`, `linkedSignal`) | | v1.3.0 | Added `options` parameter for customizing runtime-property stripping | --- ### initializeModelAdapter URL: https://ngdiagram.dev/docs/api/utilities/initializemodeladapter/ > **initializeModelAdapter**(`adapter`, `model?`, `injector?`, `options?`): [`ModelAdapter`](/docs/api/types/model/modeladapter/) Initializes an existing model adapter for use in ng-diagram. Prepares all nodes and edges in the adapter so they are ready for rendering by ng-diagram. Use this when providing a custom [ModelAdapter](/docs/api/types/model/modeladapter/) implementation. ## Parameters ### adapter [`ModelAdapter`](/docs/api/types/model/modeladapter/) An existing ModelAdapter to initialize. ### model? `Partial`\<[`Model`](/docs/api/types/model/model/)\> Optional initial model data to seed the adapter with. ### injector? `Injector` Optional Angular `Injector` if not running inside an injection context. ### options? [`InitializeModelOptions`](/docs/api/types/model/initializemodeloptions/) Optional [InitializeModelOptions](/docs/api/types/model/initializemodeloptions/). ⚠️ Overriding the strip functions can and probably will break the diagram — use at your own risk. Note that for custom adapters these functions only affect initialization; keeping serialization consistent in your adapter's `toJSON()` is up to you. ## Returns [`ModelAdapter`](/docs/api/types/model/modeladapter/) ## Example ```typescript // Basic usage with a custom adapter model = initializeModelAdapter(new NgRxModelAdapter(this.store)); // With initial model data to seed the adapter model = initializeModelAdapter(new NgRxModelAdapter(this.store), { nodes: [{ id: '1', position: { x: 0, y: 0 }, data: { label: 'Node 1' } }], edges: [], }); // With an explicit injector (outside injection context) model = initializeModelAdapter(new NgRxModelAdapter(this.store), undefined, this.injector); ``` ## Version History | Version | Changes | |---------|---------| | v1.1.0 | Introduced | | v1.3.0 | Added `options` parameter for customizing runtime-property stripping | --- ### provideNgDiagram URL: https://ngdiagram.dev/docs/api/utilities/providengdiagram/ > **provideNgDiagram**(): `Provider`[] Provides all the services required for ng-diagram to function. ## Returns `Provider`[] Array of providers for all ng-diagram services ## Example ```typescript @Component({ imports: [NgDiagramComponent], providers: [provideNgDiagram()], template: `` }) export class Diagram { model = initializeModel({ nodes: [ { id: '1', position: { x: 0, y: 0 }, data: { label: 'Node 1' } } ] }); } ``` --- ### stripEdgeRuntimeProperties URL: https://ngdiagram.dev/docs/api/utilities/stripedgeruntimeproperties/ > **stripEdgeRuntimeProperties**(`edge`): [`Edge`](/docs/api/types/model/edge/) Strips runtime-computed properties from an edge (`sourcePosition`, `targetPosition`, `measuredLabels`, `computedZIndex`, `_internalId`). These properties are recomputed during initialization and stale values from persistence cause the measurement system to skip fresh DOM measurement. Free endpoints of dangling edges are the exception: when `source` or `target` is empty, the corresponding `sourcePosition`/`targetPosition` is authored data — the only source of truth for that endpoint — so it is preserved. This is the default edge strip function used by [initializeModel](/docs/api/utilities/initializemodel/) and [initializeModelAdapter](/docs/api/utilities/initializemodeladapter/). When providing a custom strip function, wrap this one instead of reimplementing it so future runtime properties stay covered. ## Parameters ### edge [`Edge`](/docs/api/types/model/edge/) ## Returns [`Edge`](/docs/api/types/model/edge/) --- ### stripNodeRuntimeProperties URL: https://ngdiagram.dev/docs/api/utilities/stripnoderuntimeproperties/ > **stripNodeRuntimeProperties**(`node`): [`Node`](/docs/api/types/model/node/) Strips runtime-computed properties from a node (`selected`, `measuredPorts`, `measuredBounds`, `computedZIndex`, `_internalId`). These properties are recomputed during initialization and stale values from persistence cause the measurement system to skip fresh DOM measurement. This is the default node strip function used by [initializeModel](/docs/api/utilities/initializemodel/) and [initializeModelAdapter](/docs/api/utilities/initializemodeladapter/). When providing a custom strip function, wrap this one instead of reimplementing it so future runtime properties stay covered. ## Parameters ### node [`Node`](/docs/api/types/model/node/) ## Returns [`Node`](/docs/api/types/model/node/) --- ## Types ### BackgroundConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/backgroundconfig/ Configuration for the diagram background. ## Properties ### cellSize? > `optional` **cellSize**: [`Size`](/docs/api/types/geometry/size/) The size of the smallest grid cell (minor grid spacing). Supports rectangular grids by specifying different width and height values. #### Default ```ts { width: 10, height: 10 } ``` *** ### dotSpacing? > `optional` **dotSpacing**: `number` Distance in pixels between consecutive dots in the background pattern. #### Default ```ts 30 ``` *** ### majorLinesFrequency? > `optional` **majorLinesFrequency**: `object` Specifies how often major grid lines occur, measured in counts of minor grid cells. E.g., { x: 5, y: 5 } draws a major vertical line every 5 minor columns and a major horizontal line every 5 minor rows. #### x > **x**: `number` #### y > **y**: `number` #### Default ```ts { x: 5, y: 5 } ``` --- ### BoxSelectionConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/boxselectionconfig/ Configuration for box selection behavior. ## Properties ### partialInclusion? > `optional` **partialInclusion**: `boolean` Whether to select nodes that are only partially within the selection box. #### Default ```ts true ``` *** ### realtime? > `optional` **realtime**: `boolean` Whether to select nodes in real-time as the selection box is being drawn. If false, nodes will only be selected when the box selection ends. #### Default ```ts true ``` --- ### DefaultNodeTemplateConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/defaultnodetemplateconfig/ Configuration for the default Node Templates ## Properties ### removePorts > **removePorts**: `boolean` When explicitly set to `true` this will remove the ports in the default Node Template #### Default ```ts undefined; ``` --- ### EdgeRoutingConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/edgeroutingconfig/ Configuration for edge routing behavior. ## Indexable \[`edgeRoutingName`: `string`\]: `undefined` \| `Record`\<`string`, `unknown`\> \| [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) Allow custom edge routing configurations. ## Properties ### bezier? > `optional` **bezier**: `object` configuration options for bezier routing #### bezierControlOffset? > `optional` **bezierControlOffset**: `number` bezier control point offset ##### Default ```ts 100 ``` *** ### defaultRouting > **defaultRouting**: [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) The default edge routing algorithm to use for edges. Can be one of the built-in routing names or a custom string for user-defined routing. #### See EdgeRoutingName #### Default ```ts 'orthogonal' ``` *** ### orthogonal? > `optional` **orthogonal**: `object` configuration options for orthogonal routing #### firstLastSegmentLength? > `optional` **firstLastSegmentLength**: `number` first/last segment length ##### Default ```ts 20 ``` #### maxCornerRadius? > `optional` **maxCornerRadius**: `number` maximum corner radius ##### Default ```ts 15 ``` --- ### GroupingConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/groupingconfig/ Configuration for node grouping behavior. ## Properties ### canGroup() > **canGroup**: (`node`, `group`) => `boolean` Determines if a node can be grouped into a group node. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node to group. ##### group [`Node`](/docs/api/types/model/node/) The group node. #### Returns `boolean` True if the node can be grouped, false otherwise. #### Default ```ts () => true ``` --- ### LinkingConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/linkingconfig/ Configuration for linking (edge creation) behavior. ## Properties ### edgePanningEnabled > **edgePanningEnabled**: `boolean` Enable edge panning when the routed edge is near the edge of the viewport. #### Default ```ts true ``` *** ### edgePanningForce > **edgePanningForce**: `number` Multiplier for edge panning speed while routing edge is near the edge of the viewport. #### Default ```ts 10 ``` *** ### edgePanningThreshold > **edgePanningThreshold**: `number` The threshold in pixels for edge panning to start. If the mouse pointer is within this distance from the edge of the viewport, panning will be triggered. #### Default ```ts 30 ``` *** ### finalEdgeDataBuilder() > **finalEdgeDataBuilder**: (`defaultFinalEdgeData`) => [`Edge`](/docs/api/types/model/edge/) Allows customization of the final edge object when the user completes edge creation. Receives the default finalized edge (with source/target node/port IDs) and should return a fully-formed Edge object to be added to the flow. #### Parameters ##### defaultFinalEdgeData [`Edge`](/docs/api/types/model/edge/) The default finalized edge data (may be incomplete). #### Returns [`Edge`](/docs/api/types/model/edge/) The Edge object to use for the finalized edge. #### Default ```ts (edge) => Edge ``` *** ### portSnapDistance > **portSnapDistance**: `number` The maximum distance (in pixels) at temporary edge will snap to target port. #### Default ```ts 10 ``` *** ### selectNodeOnPortPress > **selectNodeOnPortPress**: `boolean` Whether to select a node when the user presses a port to start linking. When true (default), pressing a port also triggers node selection events. When false, port press only initiates the linking gesture without selecting the node. #### Default ```ts true ``` #### Since 1.2.0 *** ### temporaryEdgeDataBuilder() > **temporaryEdgeDataBuilder**: (`defaultTemporaryEdgeData`) => [`Edge`](/docs/api/types/model/edge/) Allows customization of the temporary edge object shown while the user is dragging to create a new edge. Receives the default temporary edge (with source/target node/port IDs and positions) and should return a fully-formed Edge object for rendering the temporary edge. #### Parameters ##### defaultTemporaryEdgeData [`Edge`](/docs/api/types/model/edge/) The default temporary edge data (may be incomplete). #### Returns [`Edge`](/docs/api/types/model/edge/) The Edge object to use for the temporary edge. #### Default ```ts (edge) => Edge ``` *** ### validateConnection() > **validateConnection**: (`source`, `sourcePort`, `target`, `targetPort`) => `boolean` Validates whether a connection between two nodes and ports is allowed. #### Parameters ##### source The source node. `null` | [`Node`](/docs/api/types/model/node/) ##### sourcePort The source port. `null` | [`Port`](/docs/api/types/model/port/) ##### target The target node. `null` | [`Node`](/docs/api/types/model/node/) ##### targetPort The target port. `null` | [`Port`](/docs/api/types/model/port/) #### Returns `boolean` True if the connection is valid, false otherwise. #### Default ```ts () => true ``` --- ### NodeRotationConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/noderotationconfig/ Configuration for node rotation behavior. ## Properties ### computeSnapAngleForNode() > **computeSnapAngleForNode**: (`node`) => `null` \| `number` Computes the snap angle for a node's rotation. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node to compute the snap angle for. #### Returns `null` \| `number` The angle in degrees to snap to, or null if default snapping should be used. #### Default ```ts () => null ``` *** ### defaultRotatable > **defaultRotatable**: `boolean` The default rotatable state for nodes. #### Default ```ts true ``` *** ### defaultSnapAngle > **defaultSnapAngle**: `number` The default snap angle in degrees. Used if computeSnapAngleForNode returns null. #### Default ```ts 30 ``` *** ### shouldSnapForNode() > **shouldSnapForNode**: (`node`) => `boolean` Determines if rotation snapping should be enabled for a node. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node to check for rotation snapping. #### Returns `boolean` True if rotation should snap, false otherwise. #### Default ```ts () => false ``` --- ### ResizeConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/resizeconfig/ Configuration for node resizing behavior. ## Properties ### allowResizeBelowChildrenBounds > **allowResizeBelowChildrenBounds**: `boolean` Allows resizing a group node smaller than its children bounds. When set to false, a group node cannot be resized smaller than the bounding box of its children. By default a group can be resized below children size. #### Default ```ts true ``` *** ### defaultResizable > **defaultResizable**: `boolean` The default resizable state for nodes. #### Default ```ts true ``` *** ### getMinNodeSize() > **getMinNodeSize**: (`node`) => [`Size`](/docs/api/types/geometry/size/) Returns the minimum allowed size for a node. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node to compute the minimum size for. #### Returns [`Size`](/docs/api/types/geometry/size/) #### Default ```ts () => ({ width: 20, height: 20 }) ``` --- ### SelectionMovingConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/selectionmovingconfig/ Configuration for selection moving behavior. ## Properties ### edgePanningEnabled > **edgePanningEnabled**: `boolean` Enable edge panning when the moved node is near the edge of the viewport. #### Default ```ts true ``` *** ### edgePanningForce > **edgePanningForce**: `number` Multiplier for edge panning speed while dragging nodes near the edge of the viewport. #### Default ```ts 10 ``` *** ### edgePanningThreshold > **edgePanningThreshold**: `number` The threshold in pixels for edge panning to start. If the mouse pointer is within this distance from the edge of the viewport, panning will be triggered. #### Default ```ts 30 ``` --- ### SnappingConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/snappingconfig/ Configuration for node dragging behavior. ## Properties ### computeSnapForNodeDrag() > **computeSnapForNodeDrag**: (`node`) => `null` \| [`Size`](/docs/api/types/geometry/size/) Computes the snap size for a node while dragging. If null is returned, a default snap size will be used. If computeSnapForNodeDrag is used, it takes precedence over defaultDragSnap. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node to compute the snap size for dragging. #### Returns `null` \| [`Size`](/docs/api/types/geometry/size/) The snap size for the node while dragging, or null. #### Default ```ts () => null ``` *** ### computeSnapForNodeSize() > **computeSnapForNodeSize**: (`node`) => `null` \| [`Size`](/docs/api/types/geometry/size/) Computes the snap size for a node while resizing. If null is returned, a default snap size will be used. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node to compute the snap size for resizing. #### Returns `null` \| [`Size`](/docs/api/types/geometry/size/) The snap size for the node while resizing, or null. #### Default ```ts () => null ``` *** ### computeSnapOffsetForNodeSize() > **computeSnapOffsetForNodeSize**: (`node`) => `null` \| [`Size`](/docs/api/types/geometry/size/) Computes the snap offset for a node while resizing. The snapped size follows the sequence `offset + n * snap` per axis, so a node with a 60px header snapping every 50px can snap to 60, 110, 160, ... instead of 50, 100, 150, ... If null is returned, [defaultResizeSnapOffset](/docs/api/types/configuration/features/snappingconfig/#defaultresizesnapoffset) is used. If computeSnapOffsetForNodeSize is used, it takes precedence over defaultResizeSnapOffset. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node to compute the snap offset for resizing. #### Returns `null` \| [`Size`](/docs/api/types/geometry/size/) The snap offset for the node while resizing, or null. #### Default ```ts () => null ``` #### Since 1.3.0 *** ### defaultDragSnap > **defaultDragSnap**: [`Size`](/docs/api/types/geometry/size/) The default snap size for node dragging. If computeSnapForNodeDrag is used, it takes precedence over this value. #### Default ```ts { width: 10, height: 10 } ``` *** ### defaultResizeSnap > **defaultResizeSnap**: [`Size`](/docs/api/types/geometry/size/) The default snap size for node resizing. #### Default ```ts { width: 10, height: 10 } ``` *** ### defaultResizeSnapOffset > **defaultResizeSnapOffset**: [`Size`](/docs/api/types/geometry/size/) The default snap offset for node resizing. The snapped size follows the sequence `offset + n * snap` per axis (see [computeSnapOffsetForNodeSize](/docs/api/types/configuration/features/snappingconfig/#computesnapoffsetfornodesize)). If computeSnapOffsetForNodeSize is used, it takes precedence over this value. #### Default ```ts { width: 0, height: 0 } ``` #### Since 1.3.0 *** ### shouldSnapDragForNode() > **shouldSnapDragForNode**: (`node`) => `boolean` Determines if a node should snap to grid while dragging. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node being dragged. #### Returns `boolean` True if the node should snap to grid, false otherwise. #### Default ```ts () => false ``` *** ### shouldSnapResizeForNode() > **shouldSnapResizeForNode**: (`node`) => `boolean` Determines if a node should snap to grid while resizing. #### Parameters ##### node [`Node`](/docs/api/types/model/node/) The node being resized. #### Returns `boolean` True if the node should snap to grid, false otherwise. #### Default ```ts () => false ``` --- ### VirtualizationConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/virtualizationconfig/ Configuration for viewport virtualization behavior. When enabled, only nodes and edges visible in the viewport (plus padding) are rendered, significantly improving performance for large diagrams. ## Properties ### enabled > **enabled**: `boolean` Whether viewport virtualization is enabled. When disabled, all nodes/edges are rendered regardless of viewport. #### Default ```ts false ``` *** ### idleDelay? > `optional` **idleDelay**: `number` Delay in milliseconds after panning stops before re-rendering visible nodes. #### Default ```ts 100 ``` *** ### padding > **padding**: `number` Padding multiplier relative to viewport size. The actual padding is calculated as: max(viewportWidth, viewportHeight) * padding For example, 0.5 means 50% of the viewport size as padding in each direction. #### Default ```ts 0.5 ``` --- ### ZIndexConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/zindexconfig/ Configuration for z-index layering behavior. ## Properties ### edgesAboveConnectedNodes > **edgesAboveConnectedNodes**: `boolean` Whether edges should appear above their connected nodes. #### Default ```ts false ``` *** ### elevateOnSelection > **elevateOnSelection**: `boolean` Whether selected elements should be elevated by adding `selectedZIndex` to their computed z-index. #### Default ```ts true ``` *** ### enabled > **enabled**: `boolean` Whether z-index middleware is enabled. #### Default ```ts true ``` *** ### selectedZIndex > **selectedZIndex**: `number` The z-index value added to selected elements' computed z-index. Applied cumulatively — a selected child inside a selected parent receives this value twice (once from the parent's elevation, once from its own). #### Default ```ts 10000 ``` *** ### temporaryEdgeZIndex > **temporaryEdgeZIndex**: `number` The z-index value for temporary edge. #### Default ```ts 2147483647 ``` --- ### ZoomConfig URL: https://ngdiagram.dev/docs/api/types/configuration/features/zoomconfig/ Configuration for zooming behavior. ## Properties ### max > **max**: `number` The maximum allowed zoom level. #### Default ```ts 10.0 ``` *** ### min > **min**: `number` The minimum allowed zoom level. #### Default ```ts 0.01 ``` *** ### step > **step**: `number` The zoom step increment. #### Default ```ts 0.03 ``` *** ### zoomToFit > **zoomToFit**: `ZoomToFitConfig` Configuration for zoom-to-fit operations. --- ### FlowConfig URL: https://ngdiagram.dev/docs/api/types/configuration/flowconfig/ The main configuration interface for the flow system. This type defines all available configuration options for the diagram engine. For most use cases, you should use [NgDiagramConfig](/docs/api/types/configuration/ngdiagramconfig/), which allows you to override only the properties you need. ## Properties ### background > **background**: [`BackgroundConfig`](/docs/api/types/configuration/features/backgroundconfig/) Configuration for background behavior. *** ### boxSelection > **boxSelection**: [`BoxSelectionConfig`](/docs/api/types/configuration/features/boxselectionconfig/) Configuration for box selection behavior. *** ### computeEdgeId() > **computeEdgeId**: () => `string` Computes a unique ID for an edge. #### Returns `string` The edge's unique ID. *** ### computeNodeId() > **computeNodeId**: () => `string` Computes a unique ID for a node. #### Returns `string` The node's unique ID. *** ### debugMode > **debugMode**: `boolean` Enables or disables debug mode for the diagram. When enabled, additional console logs are printed. #### Default ```ts false ``` *** ### defaultNode? > `optional` **defaultNode**: [`DefaultNodeTemplateConfig`](/docs/api/types/configuration/features/defaultnodetemplateconfig/) #### Since 1.3.0 Configuration options for the default Node Templates *** ### edgeRouting > **edgeRouting**: [`EdgeRoutingConfig`](/docs/api/types/configuration/features/edgeroutingconfig/) Configuration for edge routing. *** ### grouping > **grouping**: [`GroupingConfig`](/docs/api/types/configuration/features/groupingconfig/) Configuration for node grouping. *** ### hideWatermark? > `optional` **hideWatermark**: `boolean` #### Since 0.9.0 Hides the ngDiagram watermark when set to true. #### Default ```ts undefined ``` *** ### linking > **linking**: [`LinkingConfig`](/docs/api/types/configuration/features/linkingconfig/) Configuration for linking (edge creation). *** ### nodeDraggingEnabled > **nodeDraggingEnabled**: `boolean` #### Since 1.0.0 Enables or disables node dragging on the diagram. When set to false, users cannot move nodes via mouse dragging or keyboard arrow keys. #### Default ```ts true ``` *** ### nodeRotation > **nodeRotation**: [`NodeRotationConfig`](/docs/api/types/configuration/features/noderotationconfig/) Configuration for node rotation behavior. *** ### resize > **resize**: [`ResizeConfig`](/docs/api/types/configuration/features/resizeconfig/) Configuration for node resizing. *** ### selectionMoving > **selectionMoving**: [`SelectionMovingConfig`](/docs/api/types/configuration/features/selectionmovingconfig/) Configuration for selection moving behavior. *** ### shortcuts > **shortcuts**: [`ShortcutDefinition`](/docs/api/types/configuration/shortcuts/shortcutdefinition/)[] Configuration for keyboard shortcuts. *** ### snapping > **snapping**: [`SnappingConfig`](/docs/api/types/configuration/features/snappingconfig/) Configuration for snapping behavior. *** ### viewportPanningEnabled > **viewportPanningEnabled**: `boolean` #### Since 0.9.0 Enables or disables panning on the diagram. When set to false, user is not able to move the viewport by panning. #### Default ```ts true ``` *** ### virtualization > **virtualization**: [`VirtualizationConfig`](/docs/api/types/configuration/features/virtualizationconfig/) Configuration for viewport virtualization. Improves performance for large diagrams by only rendering visible elements. *** ### watermarkPosition? > `optional` **watermarkPosition**: [`NgDiagramPanelPosition`](/docs/api/types/ngdiagrampanelposition/) #### Since 1.2.0 Sets the preferred position for the ngDiagram watermark. If the chosen position collides with a registered panel (e.g., minimap), the watermark shifts to the nearest available corner. #### Default ```ts 'bottom-right' ``` *** ### zIndex > **zIndex**: [`ZIndexConfig`](/docs/api/types/configuration/features/zindexconfig/) Configuration for z-index layering behavior. *** ### zoom > **zoom**: [`ZoomConfig`](/docs/api/types/configuration/features/zoomconfig/) Configuration for zooming. --- ### NgDiagramConfig URL: https://ngdiagram.dev/docs/api/types/configuration/ngdiagramconfig/ > **NgDiagramConfig** = `DeepPartial`\<[`FlowConfig`](/docs/api/types/configuration/flowconfig/)\> The recommended configuration type for ng-diagram. This type allows you to provide only the configuration options you want to override. All properties are optional and correspond to those in [FlowConfig](/docs/api/types/configuration/flowconfig/). ## See - [FlowConfig](/docs/api/types/configuration/flowconfig/) – for the full list of available configuration options - [NgDiagramComponent](/docs/api/components/ngdiagramcomponent/) - [NgDiagramService](/docs/api/services/ngdiagramservice/) ## Examples ```ts // define configuration in a component const config: NgDiagramConfig = { zoom: { max: 3 }, edgeRouting: { defaultRouting: 'orthogonal' }, }; ``` ```html ``` --- ### InputModifiers URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/inputmodifiers/ Interface representing keyboard and modifier keys state during an input event. ## Properties ### meta > **meta**: `boolean` Windows key OR Cmd key *** ### primary > **primary**: `boolean` Ctrl key (Windows/Linux) OR Cmd key (Mac) *** ### secondary > **secondary**: `boolean` Alt key *** ### shift > **shift**: `boolean` Shift key --- ### KeyboardActionName URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/keyboardactionname/ > **KeyboardActionName** = [`KeyboardMoveSelectionAction`](/docs/api/types/configuration/shortcuts/keyboardmoveselectionaction/) \| [`KeyboardPanAction`](/docs/api/types/configuration/shortcuts/keyboardpanaction/) \| [`KeyboardZoomAction`](/docs/api/types/configuration/shortcuts/keyboardzoomaction/) \| `Extract`\<`InputEventName`, `"cut"` \| `"paste"` \| `"copy"` \| `"deleteSelection"` \| `"undo"` \| `"redo"` \| `"selectAll"` \| `"cancelInteraction"`\> Keyboard action names that can be triggered by keyboard events --- ### KeyboardMoveSelectionAction URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/keyboardmoveselectionaction/ > **KeyboardMoveSelectionAction** = `"keyboardMoveSelectionUp"` \| `"keyboardMoveSelectionDown"` \| `"keyboardMoveSelectionLeft"` \| `"keyboardMoveSelectionRight"` Keyboard movement actions that map to directional events --- ### KeyboardPanAction URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/keyboardpanaction/ > **KeyboardPanAction** = `"keyboardPanUp"` \| `"keyboardPanDown"` \| `"keyboardPanLeft"` \| `"keyboardPanRight"` Keyboard panning actions that map to directional events --- ### KeyboardShortcutBinding URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/keyboardshortcutbinding/ Defines a keyboard shortcut binding with a key ## Properties ### key > **key**: `string` Key value (e.g., 'c', 'Delete', 'ArrowUp') #### See https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values - Complete list of valid key values *** ### modifiers? > `optional` **modifiers**: `Partial`\<[`InputModifiers`](/docs/api/types/configuration/shortcuts/inputmodifiers/)\> Required modifier keys (all are optional - omitted means no modifiers required) --- ### KeyboardShortcutDefinition URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/keyboardshortcutdefinition/ Keyboard shortcut definition with key-based bindings ## Properties ### actionName > **actionName**: [`KeyboardActionName`](/docs/api/types/configuration/shortcuts/keyboardactionname/) Action name for keyboard events *** ### bindings > **bindings**: ([`KeyboardShortcutBinding`](/docs/api/types/configuration/shortcuts/keyboardshortcutbinding/) \| [`ModifierOnlyShortcutBinding`](/docs/api/types/configuration/shortcuts/modifieronlyshortcutbinding/))[] Key-based bindings (at least one must have a key) --- ### KeyboardZoomAction URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/keyboardzoomaction/ > **KeyboardZoomAction** = `"keyboardZoomIn"` \| `"keyboardZoomOut"` Keyboard zooming actions --- ### ModifierOnlyShortcutBinding URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/modifieronlyshortcutbinding/ Defines a modifier-only shortcut binding (for pointer events) ## Properties ### key? > `optional` **key**: `undefined` Key must not be present for modifier-only bindings *** ### modifiers > **modifiers**: `Partial`\<[`InputModifiers`](/docs/api/types/configuration/shortcuts/inputmodifiers/)\> Required modifier keys - at least one modifier is typically required --- ### PointerOnlyActionName URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/pointeronlyactionname/ > **PointerOnlyActionName** = `"multiSelection"` \| `"boxSelection"` Pointer-only action names that can only be triggered by pointer events with modifiers (e.g., Shift+Click, Ctrl+Click) --- ### PointerOnlyShortcutDefinition URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/pointeronlyshortcutdefinition/ Pointer-only shortcut definition with modifier-only bindings ## Properties ### actionName > **actionName**: [`PointerOnlyActionName`](/docs/api/types/configuration/shortcuts/pointeronlyactionname/) Action name for pointer events *** ### bindings > **bindings**: [`ModifierOnlyShortcutBinding`](/docs/api/types/configuration/shortcuts/modifieronlyshortcutbinding/)[] Modifier-only bindings (keys are not allowed) --- ### ShortcutActionName URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/shortcutactionname/ > **ShortcutActionName** = [`KeyboardActionName`](/docs/api/types/configuration/shortcuts/keyboardactionname/) \| [`PointerOnlyActionName`](/docs/api/types/configuration/shortcuts/pointeronlyactionname/) \| [`WheelOnlyActionName`](/docs/api/types/configuration/shortcuts/wheelonlyactionname/) All valid action names for shortcuts Includes: - Keyboard actions (e.g., 'keyboardMoveSelectionUp', 'copy', 'selectAll') - Pointer-only actions (e.g., 'multiSelection', 'boxSelection') - Wheel-only actions (e.g. 'zoom') --- ### ShortcutDefinition URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/shortcutdefinition/ > **ShortcutDefinition** = [`KeyboardShortcutDefinition`](/docs/api/types/configuration/shortcuts/keyboardshortcutdefinition/) \| [`PointerOnlyShortcutDefinition`](/docs/api/types/configuration/shortcuts/pointeronlyshortcutdefinition/) \| [`WheelOnlyShortcutDefinition`](/docs/api/types/configuration/shortcuts/wheelonlyshortcutdefinition/) Shortcut definition for registering keyboard and pointer shortcuts This is a discriminated union that enforces: - Pointer-only actions (multiSelection, boxSelection) can only have modifier-only bindings - Wheel-only actions (zoom) can only have modifier-only bindings - Keyboard actions must have at least one key-based binding --- ### WheelOnlyActionName URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/wheelonlyactionname/ > **WheelOnlyActionName** = `"zoom"` Wheel-only action names that can only be triggered by wheel events with modifiers (e.g., Shift+Wheel, Ctrl+Wheel) --- ### WheelOnlyShortcutDefinition URL: https://ngdiagram.dev/docs/api/types/configuration/shortcuts/wheelonlyshortcutdefinition/ Wheel-only shortcut definition with modifier-only bindings ## Properties ### actionName > **actionName**: `"zoom"` Action name for wheel events *** ### bindings > **bindings**: [`ModifierOnlyShortcutBinding`](/docs/api/types/configuration/shortcuts/modifieronlyshortcutbinding/)[] Modifier-only bindings (keys are not allowed) --- ### ClipboardPastedEvent URL: https://ngdiagram.dev/docs/api/types/events/clipboardpastedevent/ Event payload emitted when clipboard content is pasted into the diagram. This event fires when nodes and edges are added via paste operations, either through keyboard shortcuts or programmatic paste commands. ## Properties ### edges > **edges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Edges that were pasted into the diagram *** ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] Nodes that were pasted into the diagram --- ### DiagramEventMap URL: https://ngdiagram.dev/docs/api/types/events/diagrameventmap/ Map of all available diagram events and their payload types ## Properties ### clipboardPasted > **clipboardPasted**: [`ClipboardPastedEvent`](/docs/api/types/events/clipboardpastedevent/) Event emitted when clipboard content is pasted into the diagram. This event fires when nodes and edges are added via paste operations, either through keyboard shortcuts or programmatic paste commands. *** ### diagramInit > **diagramInit**: [`DiagramInitEvent`](/docs/api/types/events/diagraminitevent/) Event emitted when the diagram initialization is complete. This event fires after all nodes and edges including their internal parts (ports, labels) have been measured and positioned. *** ### edgeDrawEnded > **edgeDrawEnded**: [`EdgeDrawEndedEvent`](/docs/api/types/events/edgedrawendedevent/) Event emitted when an edge draw gesture ends, regardless of outcome. Fires on every linking completion — both successful and cancelled. For successful draws, includes the created edge and target. For cancelled draws, includes the cancellation reason. #### Since 1.2.0 *** ### ~~edgeDrawn~~ > **edgeDrawn**: [`EdgeDrawnEvent`](/docs/api/types/events/edgedrawnevent/) Event emitted when a user manually draws an edge between two nodes. This event only fires for user-initiated edge creation through the UI, but not for programmatically added edges. :::caution[Deprecated] Use `edgeDrawEnded` instead, which fires for both successful and cancelled draws. ::: *** ### groupMembershipChanged > **groupMembershipChanged**: [`GroupMembershipChangedEvent`](/docs/api/types/events/groupmembershipchangedevent/) Event emitted when nodes are grouped or ungrouped. This event fires when the user moves nodes in or out of a group node, changing their group membership status. *** ### nodeDragEnded > **nodeDragEnded**: [`NodeDragEndedEvent`](/docs/api/types/events/nodedragendedevent/) Event emitted when a node drag operation ends. This event fires when the user releases the pointer after dragging nodes. Nodes will have their final positions when this event is received. *** ### nodeDragStarted > **nodeDragStarted**: [`NodeDragStartedEvent`](/docs/api/types/events/nodedragstartedevent/) Event emitted when a node drag operation begins. This event fires once when the drag threshold is crossed, signaling the start of a drag operation. *** ### nodeResized > **nodeResized**: [`NodeResizedEvent`](/docs/api/types/events/noderesizedevent/) Event emitted when a node or group size changes. This event fires when a node is resized manually by dragging resize handles or programmatically using resize methods. *** ### nodeResizeEnded > **nodeResizeEnded**: [`NodeResizeEndedEvent`](/docs/api/types/events/noderesizeendedevent/) Event emitted when a node resize operation ends. This event fires when the user releases the pointer after resizing a node. The node will have its final size when this event is received. *** ### nodeResizeStarted > **nodeResizeStarted**: [`NodeResizeStartedEvent`](/docs/api/types/events/noderesizestartedevent/) Event emitted when a node resize operation begins. This event fires once when the user starts resizing a node by dragging a resize handle. *** ### nodeRotateEnded > **nodeRotateEnded**: [`NodeRotateEndedEvent`](/docs/api/types/events/noderotateendedevent/) Event emitted when a node rotation operation ends. This event fires when the user releases the pointer after rotating a node. The node will have its final angle when this event is received. *** ### nodeRotateStarted > **nodeRotateStarted**: [`NodeRotateStartedEvent`](/docs/api/types/events/noderotatestartedevent/) Event emitted when a node rotation operation begins. This event fires once when the user starts rotating a node by dragging the rotation handle. *** ### paletteItemDropped > **paletteItemDropped**: [`PaletteItemDroppedEvent`](/docs/api/types/events/paletteitemdroppedevent/) Event emitted when a palette item is dropped onto the diagram. This event fires when users drag items from the palette and drop them onto the canvas to create new nodes. *** ### selectionChanged > **selectionChanged**: [`SelectionChangedEvent`](/docs/api/types/events/selectionchangedevent/) Event emitted when the selection state changes in the diagram. This event fires when the user selects or deselects nodes and edges through clicking or programmatically using the diagram selection service. *** ### selectionGestureEnded > **selectionGestureEnded**: [`SelectionGestureEndedEvent`](/docs/api/types/events/selectiongestureendedevent/) Event emitted when a selection gesture is complete. This event fires on pointerup after a selection operation completes - whether from clicking a node/edge, box selection, or select-all. *** ### selectionMoved > **selectionMoved**: [`SelectionMovedEvent`](/docs/api/types/events/selectionmovedevent/) Event emitted when selected nodes are moved within the diagram. This event fires when the user moves nodes manually by dragging or programmatically using the diagram node service. *** ### selectionRemoved > **selectionRemoved**: [`SelectionRemovedEvent`](/docs/api/types/events/selectionremovedevent/) Event emitted when selected elements are deleted from the diagram. This event fires when the user deletes nodes and edges using the delete key, or programmatically through the diagram service. *** ### selectionRotated > **selectionRotated**: [`SelectionRotatedEvent`](/docs/api/types/events/selectionrotatedevent/) Event emitted when a node is rotated in the diagram. This event fires when the user rotates a node manually using the rotation handle or programmatically using the diagram node service. *** ### viewportChanged > **viewportChanged**: [`ViewportChangedEvent`](/docs/api/types/events/viewportchangedevent/) Event emitted when the viewport changes through panning or zooming. This event fires during pan and zoom operations, including mouse wheel zoom, and programmatic viewport changes. --- ### DiagramInitEvent URL: https://ngdiagram.dev/docs/api/types/events/diagraminitevent/ Event payload emitted when the diagram initialization is complete. This event fires after all nodes and edges including their internal parts (ports, labels) have been measured and positioned. ## Properties ### edges > **edges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] All edges present in the diagram after initialization *** ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] All nodes present in the diagram after initialization *** ### viewport > **viewport**: [`Viewport`](/docs/api/types/model/viewport/) Current viewport configuration including position and scale --- ### EdgeDrawCancelReason URL: https://ngdiagram.dev/docs/api/types/events/edgedrawcancelreason/ > **EdgeDrawCancelReason** = `"noTarget"` \| `"invalidConnection"` \| `"invalidTarget"` \| `"cancelled"` Reason an edge draw gesture was cancelled. - `noTarget` — the user released on empty space (no target node/port snapped) - `invalidConnection` — `validateConnection()` returned false - `invalidTarget` — the target node doesn't exist or the target port has wrong type - `cancelled` — the gesture was aborted programmatically (e.g. Esc key, [NgDiagramService.cancelActiveInteraction](/docs/api/services/ngdiagramservice/#cancelactiveinteraction)) --- ### EdgeDrawEndedEvent URL: https://ngdiagram.dev/docs/api/types/events/edgedrawendedevent/ Event payload emitted when an edge draw gesture ends, regardless of outcome. Fires on every linking completion — both successful and cancelled. For successful completions, `edge`, `target`, and `targetPort` are populated. For cancellations, `reason` indicates why the gesture was cancelled. ## Properties ### dropPosition > **dropPosition**: [`Point`](/docs/api/types/geometry/point/) The position where the pointer was released *** ### edge? > `optional` **edge**: [`Edge`](/docs/api/types/model/edge/)\<`object`\> The created edge (only present on success) *** ### reason? > `optional` **reason**: [`EdgeDrawCancelReason`](/docs/api/types/events/edgedrawcancelreason/) The reason the draw was cancelled (only present on cancel) *** ### source > **source**: [`Node`](/docs/api/types/model/node/) The source node from which the edge was drawn *** ### sourcePort? > `optional` **sourcePort**: `string` Source port identifier if connected to a specific port *** ### success > **success**: `boolean` Whether the edge was successfully created *** ### target? > `optional` **target**: [`Node`](/docs/api/types/model/node/) The target node (only present on success) *** ### targetPort? > `optional` **targetPort**: `string` Target port identifier (only present on success) --- ### EdgeDrawnEvent URL: https://ngdiagram.dev/docs/api/types/events/edgedrawnevent/ Event payload emitted when a user manually draws an edge between two nodes. This event only fires for user-initiated edge creation through the UI, but not for programmatically added edges. :::caution[Deprecated] Use [EdgeDrawEndedEvent](/docs/api/types/events/edgedrawendedevent/) instead, which fires for both successful and cancelled draws. ::: ## Properties ### ~~edge~~ > **edge**: [`Edge`](/docs/api/types/model/edge/) The newly created edge object *** ### ~~source~~ > **source**: [`Node`](/docs/api/types/model/node/) The source node from which the edge originates *** ### ~~sourcePort?~~ > `optional` **sourcePort**: `string` Source port identifier if connected to a specific port *** ### ~~target~~ > **target**: [`Node`](/docs/api/types/model/node/) The target node to which the edge connects *** ### ~~targetPort?~~ > `optional` **targetPort**: `string` Target port identifier if connected to a specific port --- ### GestureCancelReason URL: https://ngdiagram.dev/docs/api/types/events/gesturecancelreason/ > **GestureCancelReason** = `"cancelled"` Reason an interactive gesture (drag, resize, rotation) ended without a normal pointer release. - `cancelled` — the gesture was aborted programmatically (e.g. Esc key, [NgDiagramService.cancelActiveInteraction](/docs/api/services/ngdiagramservice/#cancelactiveinteraction)) --- ### GroupMembershipChangedEvent URL: https://ngdiagram.dev/docs/api/types/events/groupmembershipchangedevent/ Event payload emitted when nodes are grouped or ungrouped. This event fires when the user moves nodes in or out of a group node, changing their group membership status. ## Properties ### grouped > **grouped**: `object`[] Nodes added to groups, organized by target group #### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] #### targetGroup > **targetGroup**: [`GroupNode`](/docs/api/types/model/groupnode/) *** ### ungrouped > **ungrouped**: [`Node`](/docs/api/types/model/node/)[] Nodes removed from groups --- ### NodeDragEndedEvent URL: https://ngdiagram.dev/docs/api/types/events/nodedragendedevent/ Event payload emitted when a node drag operation ends. This event fires when the user releases the pointer after dragging nodes. Nodes will have their final positions when this event is received. ## Properties ### cancelReason? > `optional` **cancelReason**: `"cancelled"` Present when the drag ended without a normal pointer release *** ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] Nodes that were dragged, with their final positions --- ### NodeDragStartedEvent URL: https://ngdiagram.dev/docs/api/types/events/nodedragstartedevent/ Event payload emitted when a node drag operation begins. This event fires once when the drag threshold is crossed, signaling the start of a drag operation. ## Properties ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] Nodes being dragged --- ### NodeResizeEndedEvent URL: https://ngdiagram.dev/docs/api/types/events/noderesizeendedevent/ Event payload emitted when a node resize operation ends. This event fires when the user releases the pointer after resizing a node. The node will have its final size when this event is received. ## Properties ### cancelReason? > `optional` **cancelReason**: `"cancelled"` Present when the resize ended without a normal pointer release *** ### node > **node**: [`Node`](/docs/api/types/model/node/) The node that was resized, with its final size --- ### NodeResizeStartedEvent URL: https://ngdiagram.dev/docs/api/types/events/noderesizestartedevent/ Event payload emitted when a node resize operation begins. This event fires once when the user starts resizing a node by dragging a resize handle. ## Properties ### node > **node**: [`Node`](/docs/api/types/model/node/) The node being resized --- ### NodeResizedEvent URL: https://ngdiagram.dev/docs/api/types/events/noderesizedevent/ Event payload emitted when a node or group size changes. This event fires when a node is resized manually by dragging resize handles or programmatically using resize methods. ## Properties ### node > **node**: [`Node`](/docs/api/types/model/node/) Node that was resized with its updated size *** ### previousSize > **previousSize**: [`Size`](/docs/api/types/geometry/size/) Previous size of the node before the change --- ### NodeRotateEndedEvent URL: https://ngdiagram.dev/docs/api/types/events/noderotateendedevent/ Event payload emitted when a node rotation operation ends. This event fires when the user releases the pointer after rotating a node. The node will have its final angle when this event is received. ## Properties ### cancelReason? > `optional` **cancelReason**: `"cancelled"` Present when the rotation ended without a normal pointer release *** ### node > **node**: [`Node`](/docs/api/types/model/node/) The node that was rotated, with its final angle --- ### NodeRotateStartedEvent URL: https://ngdiagram.dev/docs/api/types/events/noderotatestartedevent/ Event payload emitted when a node rotation operation begins. This event fires once when the user starts rotating a node by dragging the rotation handle. ## Properties ### node > **node**: [`Node`](/docs/api/types/model/node/) The node being rotated --- ### PaletteItemDroppedEvent URL: https://ngdiagram.dev/docs/api/types/events/paletteitemdroppedevent/ Event payload emitted when a palette item is dropped onto the diagram. This event fires when users drag items from the palette and drop them onto the canvas to create new nodes. ## Properties ### dropPosition > **dropPosition**: [`Point`](/docs/api/types/geometry/point/) The position where the item was dropped *** ### node > **node**: [`Node`](/docs/api/types/model/node/) The node that was created from the dropped palette item --- ### SelectionChangedEvent URL: https://ngdiagram.dev/docs/api/types/events/selectionchangedevent/ Event payload emitted when the selection state changes in the diagram. This event fires when the user selects or deselects nodes and edges through clicking or programmatically using the [NgDiagramSelectionService](/docs/api/services/ngdiagramselectionservice/). ## Properties ### previousEdges > **previousEdges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Previously selected edges before the change *** ### previousNodes > **previousNodes**: [`Node`](/docs/api/types/model/node/)[] Previously selected nodes before the change *** ### selectedEdges > **selectedEdges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Currently selected edges *** ### selectedNodes > **selectedNodes**: [`Node`](/docs/api/types/model/node/)[] Currently selected nodes --- ### SelectionGestureEndedEvent URL: https://ngdiagram.dev/docs/api/types/events/selectiongestureendedevent/ Event payload emitted when a selection gesture is complete. This event fires on pointerup after a selection operation completes — whether from clicking a node/edge, box selection, or select-all. ## Properties ### edges > **edges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Currently selected edges after the selection gesture *** ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] Currently selected nodes after the selection gesture --- ### SelectionMovedEvent URL: https://ngdiagram.dev/docs/api/types/events/selectionmovedevent/ Event payload emitted when selected nodes are moved within the diagram. This event fires when the user moves nodes manually by dragging or programmatically using the [NgDiagramNodeService.moveNodesBy](/docs/api/services/ngdiagramnodeservice/#movenodesby) method. ## Properties ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] Nodes that were moved with their updated positions --- ### SelectionRemovedEvent URL: https://ngdiagram.dev/docs/api/types/events/selectionremovedevent/ Event payload emitted when selected elements are deleted from the diagram. This event fires when the user deletes nodes and edges using the delete key, or programmatically through the diagram service. ## Properties ### deletedEdges > **deletedEdges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Edges that were deleted from the diagram *** ### deletedNodes > **deletedNodes**: [`Node`](/docs/api/types/model/node/)[] Nodes that were deleted from the diagram --- ### SelectionRotatedEvent URL: https://ngdiagram.dev/docs/api/types/events/selectionrotatedevent/ Event payload emitted when a node is rotated in the diagram. This event fires when the user rotates a node manually using the rotation handle or programmatically using the [NgDiagramNodeService](/docs/api/services/ngdiagramnodeservice/) rotation methods. ## Properties ### angle > **angle**: `number` The new angle of the node in degrees *** ### node > **node**: [`Node`](/docs/api/types/model/node/) The node that was rotated *** ### previousAngle > **previousAngle**: `number` The previous angle of the node in degrees --- ### ViewportChangedEvent URL: https://ngdiagram.dev/docs/api/types/events/viewportchangedevent/ Event payload emitted when the viewport changes through panning or zooming. This event fires during pan and zoom operations, including mouse wheel zoom, and programmatic viewport changes. ## Properties ### previousViewport > **previousViewport**: [`Viewport`](/docs/api/types/model/viewport/) Previous viewport state before the change *** ### viewport > **viewport**: [`Viewport`](/docs/api/types/model/viewport/) Current viewport state after the change --- ### Point URL: https://ngdiagram.dev/docs/api/types/geometry/point/ Interface representing a point in the flow diagram ## Properties ### x > **x**: `number` X coordinate of the point *** ### y > **y**: `number` Y coordinate of the point --- ### Rect URL: https://ngdiagram.dev/docs/api/types/geometry/rect/ Interface representing a rect in the flow diagram ## Properties ### height > **height**: `number` Height dimension *** ### width > **width**: `number` Width dimension *** ### x > **x**: `number` X coordinate of the rect's top-left corner *** ### y > **y**: `number` Y coordinate of the rect's top-left corner --- ### Size URL: https://ngdiagram.dev/docs/api/types/geometry/size/ Interface representing size in the flow diagram ## Properties ### height > **height**: `number` Height dimension *** ### width > **width**: `number` Width dimension --- ### FlowStateUpdate URL: https://ngdiagram.dev/docs/api/types/middleware/flowstateupdate/ Describes a set of changes to apply to the diagram state. Middlewares can modify state by passing a FlowStateUpdate to the `next()` function. ## Example ```typescript const middleware: Middleware = { name: 'auto-arranger', execute: (context, next) => { // Apply state changes next({ nodesToUpdate: [ { id: 'node1', position: { x: 100, y: 200 } }, { id: 'node2', position: { x: 300, y: 200 } } ], metadataUpdate: { viewport: { x: 0, y: 0, zoom: 1 } } }); } }; ``` ## Properties ### edgesToAdd? > `optional` **edgesToAdd**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Edges to add to the diagram *** ### edgesToRemove? > `optional` **edgesToRemove**: `string`[] IDs of edges to remove from the diagram *** ### edgesToUpdate? > `optional` **edgesToUpdate**: `Partial`\<[`Edge`](/docs/api/types/model/edge/)\<`object`\>\> & `object`[] Partial edge updates (only changed properties need to be specified) *** ### metadataUpdate? > `optional` **metadataUpdate**: `Partial`\<[`Metadata`](/docs/api/types/model/metadata/)\<`object`\>\> Partial metadata update (viewport, selection, etc.) *** ### nodesToAdd? > `optional` **nodesToAdd**: [`Node`](/docs/api/types/model/node/)[] Nodes to add to the diagram *** ### nodesToRemove? > `optional` **nodesToRemove**: `string`[] IDs of nodes to remove from the diagram *** ### nodesToUpdate? > `optional` **nodesToUpdate**: `Partial`\<[`Node`](/docs/api/types/model/node/)\> & `object`[] Partial node updates (only changed properties need to be specified) --- ### Middleware URL: https://ngdiagram.dev/docs/api/types/middleware/middleware/ Middleware interface for intercepting and modifying diagram state changes. Middlewares form a chain where each can: - Inspect the current state and action type - Modify the state by passing updates to `next()` - Block operations by calling `cancel()` - Perform side effects (logging, validation, etc.) ## Example ```typescript // Read-only middleware that blocks modifications const readOnlyMiddleware: Middleware<'read-only'> = { name: 'read-only', execute: (context, next, cancel) => { const blockedActions = ['addNodes', 'deleteNodes', 'updateNode']; if (context.modelActionTypes.some((action) => blockedActions.includes(action))) { console.warn('Action blocked in read-only mode'); cancel(); return; } next(); } }; // Auto-snap middleware that modifies positions const snapMiddleware: Middleware<'auto-snap'> = { name: 'auto-snap', execute: (context, next) => { const gridSize = 20; const nodesToSnap = context.helpers.getAffectedNodeIds(['position']); const updates = nodesToSnap.map(id => { const node = context.nodesMap.get(id)!; return { id, position: { x: Math.round(node.position.x / gridSize) * gridSize, y: Math.round(node.position.y / gridSize) * gridSize } }; }); next({ nodesToUpdate: updates }); } }; // Register middleware ngDiagramService.registerMiddleware(snapMiddleware); ``` ## Type Parameters ### TName `TName` *extends* `string` = `string` The middleware name type (string literal for type safety) ## Properties ### execute() > **execute**: (`context`, `next`, `cancel`) => `void` \| `Promise`\<`void`\> The middleware execution function. #### Parameters ##### context [`MiddlewareContext`](/docs/api/types/middleware/middlewarecontext/) Complete context including state, helpers, and configuration ##### next (`stateUpdate?`) => `Promise`\<[`FlowState`](/docs/api/types/model/flowstate/)\> Call this to continue to the next middleware (optionally with state updates) ##### cancel () => `void` Call this to abort the entire operation #### Returns `void` \| `Promise`\<`void`\> *** ### name > **name**: `TName` Unique identifier for the middleware --- ### MiddlewareChain URL: https://ngdiagram.dev/docs/api/types/middleware/middlewarechain/ > **MiddlewareChain** = [`Middleware`](/docs/api/types/middleware/middleware/)[] An array of middlewares that will be executed in sequence. --- ### MiddlewareContext URL: https://ngdiagram.dev/docs/api/types/middleware/middlewarecontext/ The context object passed to middleware execute functions. Provides access to the current state, helper functions, and configuration. ## Example ```typescript const middleware: Middleware = { name: 'validation', execute: (context, next, cancel) => { // Check if any nodes were added if (context.helpers.anyNodesAdded()) { console.log('Nodes added:', context.state.nodes); } // Access configuration console.log('Cell size:', context.config.background.cellSize); // Check what actions triggered this (supports transactions with multiple actions) if (context.modelActionTypes.includes('addNodes')) { // Validate new nodes const isValid = validateNodes(context.state.nodes); if (!isValid) { cancel(); // Block the operation return; } } next(); // Continue to next middleware } }; ``` ## Properties ### actionStateManager > **actionStateManager**: [`ActionStateManager`](/docs/api/internals/actionstatemanager/) Manager for action states (resizing, linking, etc.) *** ### config > **config**: [`FlowConfig`](/docs/api/types/configuration/flowconfig/) The current diagram configuration *** ### edgeRoutingManager > **edgeRoutingManager**: [`EdgeRoutingManager`](/docs/api/internals/edgeroutingmanager/) Manager for edge routing algorithms *** ### edgesMap > **edgesMap**: `Map`\<`string`, [`Edge`](/docs/api/types/model/edge/)\<`object`\>\> Map for quick edge lookup by ID. Contains the current state after previous middleware processing. Use this to access edges by ID instead of iterating through `state.edges`. *** ### environment > **environment**: [`EnvironmentInfo`](/docs/api/internals/environmentinfo/) Environment information (browser, rendering engine, etc.) *** ### helpers > **helpers**: [`MiddlewareHelpers`](/docs/api/types/middleware/middlewarehelpers/) Helper functions to check what changed (tracks all cumulative changes from the initial action and all previous middlewares) *** ### history > **history**: [`MiddlewareHistoryUpdate`](/docs/api/types/middleware/middlewarehistoryupdate/)[] All state updates from previous middlewares in the chain *** ### initialConnectedEdgesMap > **initialConnectedEdgesMap**: `Map`\<`string`, `string`[]\> Map from node ID to connected edge IDs (edges where node is source or target) before any modifications (before the initial action and before any middleware modifications). Use this to find edges connected to specific nodes without scanning all edges. #### Since 1.2.3 *** ### initialEdgesMap > **initialEdgesMap**: `Map`\<`string`, [`Edge`](/docs/api/types/model/edge/)\<`object`\>\> The initial edges map before any modifications (before the initial action and before any middleware modifications). Use this to compare state before and after all modifications. Common usage: Access removed edge instances that no longer exist in `edgesMap`. *** ### initialNodesMap > **initialNodesMap**: `Map`\<`string`, [`Node`](/docs/api/types/model/node/)\> The initial nodes map before any modifications (before the initial action and before any middleware modifications). Use this to compare state before and after all modifications. Common usage: Access removed node instances that no longer exist in `nodesMap`. *** ### initialState > **initialState**: [`FlowState`](/docs/api/types/model/flowstate/) The state before any modifications (before the initial action and before any middleware modifications) *** ### initialUpdate > **initialUpdate**: [`FlowStateUpdate`](/docs/api/types/middleware/flowstateupdate/) The initial state update that triggered the middleware chain. Middlewares can add their own updates to the state, so this may not contain all modifications that will be applied. Use `helpers` to get actual knowledge about all changes. *** ### ~~modelActionType~~ > **modelActionType**: [`ModelActionType`](/docs/api/types/middleware/modelactiontype/) The action that triggered the middleware execution. :::caution[Deprecated] Use `modelActionTypes` instead, which supports multiple actions from transactions. For single actions, this returns the first (and only) action type. ::: *** ### modelActionTypes > **modelActionTypes**: [`ModelActionTypes`](/docs/api/types/middleware/modelactiontypes/) All action types that triggered the middleware execution. For transactions, this contains the transaction name followed by all action types from commands executed within the transaction. For single commands outside transactions, this is a single-element array. #### Example ```typescript // For a transaction named 'batchUpdate' with addNodes and moveViewport commands: // modelActionTypes = ['batchUpdate', 'addNodes', 'moveViewport'] // For a single command outside a transaction: // modelActionTypes = ['addNodes'] ``` #### Since 0.9.0 *** ### nodesMap > **nodesMap**: `Map`\<`string`, [`Node`](/docs/api/types/model/node/)\> Map for quick node lookup by ID. Contains the current state after previous middleware processing. Use this to access nodes by ID instead of iterating through `state.nodes`. *** ### state > **state**: [`FlowState`](/docs/api/types/model/flowstate/) The current state (includes the initial modification and all changes from previous middlewares) --- ### MiddlewareHelpers URL: https://ngdiagram.dev/docs/api/types/middleware/middlewarehelpers/ Helper functions for checking what changed during middleware execution. These helpers track all cumulative changes from the initial state update and all previous middlewares. ## Properties ### anyEdgesAdded() > **anyEdgesAdded**: () => `boolean` Checks if any edges were added. #### Returns `boolean` true if at least one edge was added by the initial state update or any previous middleware *** ### anyEdgesRemoved() > **anyEdgesRemoved**: () => `boolean` Checks if any edges were removed. #### Returns `boolean` true if at least one edge was removed by the initial state update or any previous middleware *** ### anyNodesAdded() > **anyNodesAdded**: () => `boolean` Checks if any nodes were added. #### Returns `boolean` true if at least one node was added by the initial state update or any previous middleware *** ### anyNodesRemoved() > **anyNodesRemoved**: () => `boolean` Checks if any nodes were removed. #### Returns `boolean` true if at least one node was removed by the initial state update or any previous middleware *** ### checkIfAnyEdgePropsChanged() > **checkIfAnyEdgePropsChanged**: (`props`) => `boolean` Checks if any edge has one or more of the specified properties changed. #### Parameters ##### props `string`[] Array of property names to check (e.g., ['sourcePosition', 'targetPosition']) #### Returns `boolean` true if any edge has any of these properties modified by the initial state update or any previous middleware *** ### checkIfAnyNodePropsChanged() > **checkIfAnyNodePropsChanged**: (`props`) => `boolean` Checks if any node has one or more of the specified properties changed. #### Parameters ##### props `string`[] Array of property names to check (e.g., ['position', 'size']) #### Returns `boolean` true if any node has any of these properties modified by the initial state update or any previous middleware *** ### checkIfEdgeAdded() > **checkIfEdgeAdded**: (`id`) => `boolean` Checks if a specific edge was added. #### Parameters ##### id `string` The edge ID to check #### Returns `boolean` true if the edge was added by the initial state update or any previous middleware *** ### checkIfEdgeChanged() > **checkIfEdgeChanged**: (`id`) => `boolean` Checks if a specific edge has been modified. #### Parameters ##### id `string` The edge ID to check #### Returns `boolean` true if the edge was modified (any property changed) by the initial state update or any previous middleware *** ### checkIfEdgeRemoved() > **checkIfEdgeRemoved**: (`id`) => `boolean` Checks if a specific edge was removed. #### Parameters ##### id `string` The edge ID to check #### Returns `boolean` true if the edge was removed by the initial state update or any previous middleware *** ### checkIfNodeAdded() > **checkIfNodeAdded**: (`id`) => `boolean` Checks if a specific node was added. #### Parameters ##### id `string` The node ID to check #### Returns `boolean` true if the node was added by the initial state update or any previous middleware *** ### checkIfNodeChanged() > **checkIfNodeChanged**: (`id`) => `boolean` Checks if a specific node has been modified. #### Parameters ##### id `string` The node ID to check #### Returns `boolean` true if the node was modified (any property changed) by the initial state update or any previous middleware *** ### checkIfNodeRemoved() > **checkIfNodeRemoved**: (`id`) => `boolean` Checks if a specific node was removed. #### Parameters ##### id `string` The node ID to check #### Returns `boolean` true if the node was removed by the initial state update or any previous middleware *** ### getAddedEdges() > **getAddedEdges**: () => [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Gets all edges that were added. #### Returns [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Array of edge instances that were added by the initial state update or any previous middleware *** ### getAddedNodes() > **getAddedNodes**: () => [`Node`](/docs/api/types/model/node/)[] Gets all nodes that were added. #### Returns [`Node`](/docs/api/types/model/node/)[] Array of node instances that were added by the initial state update or any previous middleware *** ### getAffectedEdgeIds() > **getAffectedEdgeIds**: (`props`) => `string`[] Gets all edge IDs that have one or more of the specified properties changed. #### Parameters ##### props `string`[] Array of property names to check (e.g., ['sourcePosition', 'targetPosition']) #### Returns `string`[] Array of edge IDs that have any of these properties modified by the initial state update or any previous middleware *** ### getAffectedNodeIds() > **getAffectedNodeIds**: (`props`) => `string`[] Gets all node IDs that have one or more of the specified properties changed. #### Parameters ##### props `string`[] Array of property names to check (e.g., ['position', 'size']) #### Returns `string`[] Array of node IDs that have any of these properties modified by the initial state update or any previous middleware *** ### getChangedEdgeIds() > **getChangedEdgeIds**: () => `string`[] Gets all edge IDs that have any property changed, regardless of which property. #### Returns `string`[] Array of edge IDs that were modified by the initial state update or any previous middleware #### Since 1.2.2 *** ### getChangedNodeIds() > **getChangedNodeIds**: () => `string`[] Gets all node IDs that have any property changed, regardless of which property. #### Returns `string`[] Array of node IDs that were modified by the initial state update or any previous middleware #### Since 1.2.2 *** ### getRemovedEdges() > **getRemovedEdges**: () => [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Gets all edges that were removed. Uses `initialEdgesMap` to access the removed instances. #### Returns [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Array of edge instances that were removed by the initial state update or any previous middleware *** ### getRemovedNodes() > **getRemovedNodes**: () => [`Node`](/docs/api/types/model/node/)[] Gets all nodes that were removed. Uses `initialNodesMap` to access the removed instances. #### Returns [`Node`](/docs/api/types/model/node/)[] Array of node instances that were removed by the initial state update or any previous middleware --- ### MiddlewareHistoryUpdate URL: https://ngdiagram.dev/docs/api/types/middleware/middlewarehistoryupdate/ Records a state update made by a specific middleware. Used to track the history of state transformations through the middleware chain. ## Example ```typescript const middleware: Middleware = { name: 'audit-logger', execute: (context, next) => { // Check what previous middlewares did context.history.forEach(update => { console.log(`${update.name} modified:`, update.stateUpdate); }); next(); } }; ``` ## Properties ### name > **name**: `string` The name of the middleware that made the update *** ### stateUpdate > **stateUpdate**: [`FlowStateUpdate`](/docs/api/types/middleware/flowstateupdate/) The state update that was applied --- ### ModelActionType URL: https://ngdiagram.dev/docs/api/types/middleware/modelactiontype/ > **ModelActionType** = `"init"` \| `"changeSelection"` \| `"moveNodesBy"` \| `"deleteSelection"` \| `"addNodes"` \| `"updateNode"` \| `"updateNodes"` \| `"deleteNodes"` \| `"clearModel"` \| `"paletteDropNode"` \| `"addEdges"` \| `"updateEdge"` \| `"deleteEdges"` \| `"deleteElements"` \| `"addEdgeLabelsBulk"` \| `"updateEdgeLabelsBulk"` \| `"deleteEdgeLabelsBulk"` \| `"addPortsBulk"` \| `"updatePortsBulk"` \| `"deletePortsBulk"` \| `"paste"` \| `"moveViewport"` \| `"resizeNode"` \| `"resizeNodeStart"` \| `"resizeNodeStop"` \| `"cancelResize"` \| `"startLinking"` \| `"moveTemporaryEdge"` \| `"finishLinking"` \| `"zoom"` \| `"changeZOrder"` \| `"rotateNodeTo"` \| `"rotateNodeStart"` \| `"rotateNodeStop"` \| `"cancelRotate"` \| `"highlightGroup"` \| `"highlightGroupClear"` \| `"moveNodes"` \| `"moveNodesStart"` \| `"moveNodesStop"` \| `"cancelDrag"` \| `"selectEnd"` Individual model action type that can trigger middleware execution. These represent all possible operations that modify the diagram state. ## Example ```typescript const blockedActions: ModelActionType[] = ['addNodes', 'deleteNodes', 'updateNode']; ``` --- ### ModelActionTypes URL: https://ngdiagram.dev/docs/api/types/middleware/modelactiontypes/ > **ModelActionTypes** = `LooseAutocomplete`\<[`ModelActionType`](/docs/api/types/middleware/modelactiontype/)\>[] Array of model action types, used to track all actions in a transaction or a single action. Supports both known action types with autocomplete and custom string action types. ## Example ```typescript const middleware: Middleware = { name: 'logger', execute: (context, next) => { console.log('Action types:', context.modelActionTypes.join(', ')); next(); } }; ``` --- ### TransactionOptions URL: https://ngdiagram.dev/docs/api/types/middleware/transactionoptions/ Options for configuring transaction behavior. ## Properties ### waitForMeasurements? > `optional` **waitForMeasurements**: `boolean` When true, the transaction promise will not resolve until all measurements (node sizes, port positions, etc.) triggered by the transaction are complete. This is useful when you need to perform operations that depend on measured values, such as `zoomToFit()` after adding nodes or edges. #### Default ```ts false ``` #### Example ```typescript // Without waitForMeasurements - zoomToFit might not include new nodes await diagramService.transaction(() => { modelService.addNodes([newNode]); }); viewportService.zoomToFit(); // May not account for new node dimensions // With waitForMeasurements - zoomToFit will include new nodes await diagramService.transaction(() => { modelService.addNodes([newNode]); }, { waitForMeasurements: true }); viewportService.zoomToFit(); // Correctly includes new node dimensions ``` --- ### TransactionResult URL: https://ngdiagram.dev/docs/api/types/middleware/transactionresult/ Result of a transaction execution. ## Properties ### actionTypes > **actionTypes**: [`ModelActionTypes`](/docs/api/types/middleware/modelactiontypes/) All action types that were executed within the transaction. #### Since 0.9.0 *** ### commandsCount > **commandsCount**: `number` Number of commands emitted during the transaction *** ### results > **results**: [`FlowStateUpdate`](/docs/api/types/middleware/flowstateupdate/) Results of the transaction as a state update --- ### MinimapNodeShape URL: https://ngdiagram.dev/docs/api/types/minimap/minimapnodeshape/ > **MinimapNodeShape** = `"rect"` \| `"circle"` \| `"ellipse"` Available shapes for minimap node rendering. --- ### MinimapNodeStyle URL: https://ngdiagram.dev/docs/api/types/minimap/minimapnodestyle/ Style properties that can be applied to minimap nodes. All properties are optional - unset properties use CSS defaults. ## Properties ### cssClass? > `optional` **cssClass**: `string` CSS class to apply to the node *** ### fill? > `optional` **fill**: `string` Fill color for the node *** ### opacity? > `optional` **opacity**: `number` Opacity from 0 to 1 *** ### shape? > `optional` **shape**: [`MinimapNodeShape`](/docs/api/types/minimap/minimapnodeshape/) Shape of the node in the minimap. Defaults to 'rect'. *** ### stroke? > `optional` **stroke**: `string` Stroke color for the node *** ### strokeWidth? > `optional` **strokeWidth**: `number` Stroke width in pixels --- ### MinimapNodeStyleFn URL: https://ngdiagram.dev/docs/api/types/minimap/minimapnodestylefn/ > **MinimapNodeStyleFn** = (`node`) => [`MinimapNodeStyle`](/docs/api/types/minimap/minimapnodestyle/) \| `null` \| `undefined` Function signature for the nodeStyle callback. Return style properties to override defaults, or null/undefined to use defaults. ## Parameters ### node [`Node`](/docs/api/types/model/node/) ## Returns [`MinimapNodeStyle`](/docs/api/types/minimap/minimapnodestyle/) \| `null` \| `undefined` ## Example ```typescript const nodeStyle: MinimapNodeStyleFn = (node) => ({ fill: node.type === 'database' ? '#4CAF50' : '#9E9E9E', opacity: node.selected ? 1 : 0.6, }); ``` --- ### NgDiagramMinimapNodeTemplate URL: https://ngdiagram.dev/docs/api/types/minimap/ngdiagramminimapnodetemplate/ Interface for custom minimap node components. Components implementing this interface can be registered in NgDiagramMinimapNodeTemplateMap to customize how specific node types are rendered in the minimap. Custom templates are rendered inside a foreignObject that handles positioning and sizing, so the component only needs to render content that fills its container. ## Example ```typescript @Component({ selector: 'my-minimap-node', standalone: true, template: `
{{ node().type }}
`, styles: [`.minimap-icon { width: 100%; height: 100%; }`] }) export class MyMinimapNodeComponent implements NgDiagramMinimapNodeTemplate { node = input.required(); nodeStyle = input(); // Required by interface, can be ignored if not needed } ``` ## Properties ### node > **node**: `InputSignal`\<[`Node`](/docs/api/types/model/node/)\> Input signal containing the original Node object for accessing node data, type, etc. *** ### nodeStyle > **nodeStyle**: `InputSignal`\<`undefined` \| [`MinimapNodeStyle`](/docs/api/types/minimap/minimapnodestyle/)\> Input signal for style overrides computed by nodeStyle callback. Can be ignored if not needed. --- ### NgDiagramMinimapNodeTemplateMap URL: https://ngdiagram.dev/docs/api/types/minimap/ngdiagramminimapnodetemplatemap/ Map that associates node type names with their corresponding minimap Angular component classes. Used by ng-diagram-minimap to determine which custom component to render based on node type. ## Example ```typescript const minimapTemplateMap = new NgDiagramMinimapNodeTemplateMap([ ['database', DatabaseMinimapNodeComponent], ['api', ApiMinimapNodeComponent], ]); // Usage in template: ``` ## Extends - `Map`\<`string`, `Type`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\>\> ## Properties ### size > `readonly` **size**: `number` #### Returns the number of elements in the Map. #### Inherited from `Map.size` ## Methods ### \[iterator\]() > **\[iterator\]**(): `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\>\]\> Returns an iterable of entries in the map. #### Returns `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\>\]\> #### Inherited from `Map.[iterator]` *** ### delete() > **delete**(`key`): `boolean` #### Parameters ##### key `string` #### Returns `boolean` true if an element in the Map existed and has been removed, or false if the element does not exist. #### Inherited from `Map.delete` *** ### entries() > **entries**(): `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\>\]\> Returns an iterable of key, value pairs for every entry in the map. #### Returns `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\>\]\> #### Inherited from `Map.entries` *** ### forEach() > **forEach**(`callbackfn`, `thisArg?`): `void` Executes a provided function once per each key/value pair in the Map, in insertion order. #### Parameters ##### callbackfn (`value`, `key`, `map`) => `void` ##### thisArg? `any` #### Returns `void` #### Inherited from `Map.forEach` *** ### get() > **get**(`key`): `undefined` \| `Type$1`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\> Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map. #### Parameters ##### key `string` #### Returns `undefined` \| `Type$1`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\> Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned. #### Inherited from `Map.get` *** ### has() > **has**(`key`): `boolean` #### Parameters ##### key `string` #### Returns `boolean` boolean indicating whether an element with the specified key exists or not. #### Inherited from `Map.has` *** ### keys() > **keys**(): `MapIterator`\<`string`\> Returns an iterable of keys in the map #### Returns `MapIterator`\<`string`\> #### Inherited from `Map.keys` *** ### set() > **set**(`key`, `value`): `this` Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated. #### Parameters ##### key `string` ##### value `Type$1` #### Returns `this` #### Inherited from `Map.set` *** ### values() > **values**(): `MapIterator`\<`Type$1`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\>\> Returns an iterable of values in the map #### Returns `MapIterator`\<`Type$1`\<[`NgDiagramMinimapNodeTemplate`](/docs/api/types/minimap/ngdiagramminimapnodetemplate/)\>\> #### Inherited from `Map.values` --- ### AbsoluteEdgeLabelPosition URL: https://ngdiagram.dev/docs/api/types/model/absoluteedgelabelposition/ > **AbsoluteEdgeLabelPosition** = `` `${number}px` `` Type representing an absolute edge label position in pixels. Positive values measure from the source, negative from the target. ## Example ```ts `'30px'` — 30px from source, `'-20px'` — 20px from target @public ``` --- ### Edge URL: https://ngdiagram.dev/docs/api/types/model/edge/ Interface representing an edge (connection) between nodes in the flow diagram ## Type Parameters ### T `T` *extends* `DataObject` = `DataObject` ## Properties ### computedZIndex? > `readonly` `optional` **computedZIndex**: `number` #### Remarks ComputedZIndex is computed by the system and should not be set manually. The final z-index applied to the DOM element for rendering order. Without `zOrder`: derived from `max(source, target)` connected node z-indices. With `zOrder`: uses the explicit value plus connected node elevation. *** ### data > **data**: `T` The data associated with the edge. *** ### id > **id**: `string` The unique identifier for the edge. *** ### measuredLabels? > `readonly` `optional` **measuredLabels**: [`EdgeLabel`](/docs/api/types/model/edgelabel/)[] #### Remarks MeasuredLabels are computed by the system and should not be set manually. The labels of the edge with computed position and size. *** ### points? > `optional` **points**: [`Point`](/docs/api/types/geometry/point/)[] The points of the edge defining the path. *** ### routing? > `optional` **routing**: [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) The routing of the edge. *** ### routingMode? > `optional` **routingMode**: [`RoutingMode`](/docs/api/types/routing/routingmode/) The routing mode of the edge. 'auto' (default): Points are computed automatically based on routing algorithm 'manual': Points are provided by the user and routing algorithm is used to render the path *** ### selected? > `optional` **selected**: `boolean` Whether the edge is selected *** ### source > **source**: `string` The source node of the edge. If empty string it will use sourcePosition. *** ### sourceArrowhead? > `optional` **sourceArrowhead**: `string` The id of the source arrowhead of the edge. *** ### sourcePort? > `optional` **sourcePort**: `string` The port of the source node. *** ### sourcePosition? > `optional` **sourcePosition**: [`Point`](/docs/api/types/geometry/point/) The position of the edge start. *** ### target > **target**: `string` The target node of the edge. If empty string it will use targetPosition. *** ### targetArrowhead? > `optional` **targetArrowhead**: `string` The id of the target arrowhead of the edge. *** ### targetPort? > `optional` **targetPort**: `string` The port of the target node. *** ### targetPosition? > `optional` **targetPosition**: [`Point`](/docs/api/types/geometry/point/) The position of the edge end. *** ### temporary? > `optional` **temporary**: `boolean` Whether the edge is temporary. *** ### type? > `optional` **type**: `string` The type of the edge declared in edgeTemplateMap. *** ### zOrder? > `optional` **zOrder**: `number` The z-order of the edge. When set, overrides the default edge z-index (which is derived from connected nodes). When a connected node is selected, the node's elevation is added so the edge stays visible above elevated nodes. Set by `bringToFront` / `sendToBack` commands, or manually. #### See [computedZIndex](/docs/api/types/model/edge/#computedzindex) for the final rendered z-index. --- ### EdgeLabel URL: https://ngdiagram.dev/docs/api/types/model/edgelabel/ Interface representing a label of an edge. ## Properties ### id > **id**: `string` The id of the label. *** ### position? > `optional` **position**: [`Point`](/docs/api/types/geometry/point/) The position of the label on flow. *** ### positionOnEdge > **positionOnEdge**: [`EdgeLabelPosition`](/docs/api/types/model/edgelabelposition/) The position of the label on the edge. - **Relative** (`number`, 0-1): 0 is the source, 1 is the target, 0.5 is the midpoint. - **Absolute** (`'Npx'`): pixel distance from source (positive) or target (negative). #### Example ```ts positionOnEdge: 0.5 // midpoint (relative) positionOnEdge: '30px' // 30px from source (absolute) positionOnEdge: '-20px' // 20px from target (absolute) ``` *** ### size? > `optional` **size**: [`Size`](/docs/api/types/geometry/size/) The size of the label. --- ### EdgeLabelPosition URL: https://ngdiagram.dev/docs/api/types/model/edgelabelposition/ > **EdgeLabelPosition** = `number` \| [`AbsoluteEdgeLabelPosition`](/docs/api/types/model/absoluteedgelabelposition/) Type representing edge label position — either relative (0-1) or absolute (`'Npx'`). - **Relative** (`number`, 0-1): percentage along the path. Clamped to [0, 1]. - **Absolute** (`string`, `'Npx'`): pixel distance from source (positive) or target (negative). Clamped to path length. --- ### FlowState URL: https://ngdiagram.dev/docs/api/types/model/flowstate/ The complete state of the flow diagram. Represents the current state of all nodes, edges, and metadata. ## Properties ### edges > **edges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] All edges currently in the diagram *** ### metadata > **metadata**: [`Metadata`](/docs/api/types/model/metadata/) Diagram metadata (selection, viewport, etc.) *** ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] All nodes currently in the diagram --- ### GroupNode URL: https://ngdiagram.dev/docs/api/types/model/groupnode/ Interface representing a group node in the diagram ## Extends - [`SimpleNode`](/docs/api/types/model/simplenode/)\<`T`\> ## Type Parameters ### T `T` *extends* `DataObject` = `DataObject` ## Properties ### angle? > `optional` **angle**: `number` The angle of the node from 0 to 360. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`angle`](/docs/api/types/model/simplenode/#angle) *** ### autoSize? > `optional` **autoSize**: `boolean` Whether the size of the node is automatically resized based on the content. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`autoSize`](/docs/api/types/model/simplenode/#autosize) *** ### computedZIndex? > `readonly` `optional` **computedZIndex**: `number` #### Remarks ComputedZIndex is computed by the system and should not be set manually. The final z-index applied to the DOM element for rendering order. Computed from `zOrder`, group hierarchy, and selection elevation. Children are always above their parent group. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`computedZIndex`](/docs/api/types/model/simplenode/#computedzindex) *** ### data > **data**: `T` The data associated with the node. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`data`](/docs/api/types/model/simplenode/#data) *** ### draggable? > `optional` **draggable**: `boolean` Whether the node is draggable. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`draggable`](/docs/api/types/model/simplenode/#draggable) *** ### groupId? > `optional` **groupId**: `string` The id of the parent node. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`groupId`](/docs/api/types/model/simplenode/#groupid) *** ### highlighted > **highlighted**: `boolean` Whether the group is highlighted. For example, when a node is being dragged over it. *** ### id > **id**: `string` The unique identifier for the node. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`id`](/docs/api/types/model/simplenode/#id) *** ### isGroup > **isGroup**: `true` Flag indicating the node is a group *** ### measuredBounds? > `readonly` `optional` **measuredBounds**: [`Rect`](/docs/api/types/geometry/rect/) #### Remarks MeasuredBounds are computed by the system and should not be set manually. Bounding box that encompasses the node including its ports, accounting for rotation. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`measuredBounds`](/docs/api/types/model/simplenode/#measuredbounds) *** ### measuredPorts? > `readonly` `optional` **measuredPorts**: [`Port`](/docs/api/types/model/port/)[] #### Remarks MeasuredPorts are computed by the system and should not be set manually. The ports of the node with computed position and size. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`measuredPorts`](/docs/api/types/model/simplenode/#measuredports) *** ### position > **position**: [`Point`](/docs/api/types/geometry/point/) The position of the node in the diagram. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`position`](/docs/api/types/model/simplenode/#position) *** ### resizable? > `optional` **resizable**: `boolean` Whether the node is resizable. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`resizable`](/docs/api/types/model/simplenode/#resizable) *** ### rotatable? > `optional` **rotatable**: `boolean` Whether the node is rotatable. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`rotatable`](/docs/api/types/model/simplenode/#rotatable) *** ### selected? > `optional` **selected**: `boolean` Whether the node is selected. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`selected`](/docs/api/types/model/simplenode/#selected) *** ### size? > `optional` **size**: [`Size`](/docs/api/types/geometry/size/) The size of the node. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`size`](/docs/api/types/model/simplenode/#size) *** ### type? > `optional` **type**: `string` The type of the node declared in nodeTemplateMap. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`type`](/docs/api/types/model/simplenode/#type) *** ### zOrder? > `optional` **zOrder**: `number` The z-order of the node. Controls relative ordering among nodes on the same hierarchy level. With proper values, it can also influence ordering across different hierarchy levels, since each nesting level adds +1 to the computed z-index per child. - Root nodes: used directly as the base z-index (negative values allowed). - Grouped nodes: acts as a minimum floor — cannot go below the parent's z-index. Set by `bringToFront` / `sendToBack` commands, or manually. #### See [computedZIndex](/docs/api/types/model/simplenode/#computedzindex) for the final rendered z-index. #### Inherited from [`SimpleNode`](/docs/api/types/model/simplenode/).[`zOrder`](/docs/api/types/model/simplenode/#zorder) --- ### InitializeModelOptions URL: https://ngdiagram.dev/docs/api/types/model/initializemodeloptions/ Options for [initializeModel](/docs/api/utilities/initializemodel/) and [initializeModelAdapter](/docs/api/utilities/initializemodeladapter/). ## Properties ### stripEdgeRuntimeProperties? > `optional` **stripEdgeRuntimeProperties**: [`StripEdgeRuntimePropertiesFn`](/docs/api/types/model/stripedgeruntimepropertiesfn/) Replaces the function that strips runtime-computed properties from edges during initialization (and, for the default model created by [initializeModel](/docs/api/utilities/initializemodel/), during `toJSON()` serialization). ⚠️ **Use at your own risk.** The default ([stripEdgeRuntimeProperties](/docs/api/utilities/stripedgeruntimeproperties/)) exists because stale runtime values (`sourcePosition`, `targetPosition`, `measuredLabels`, `computedZIndex`, `_internalId`) loaded from persistence can and probably will break the diagram — e.g. edges rendered at outdated positions or duplicated internal ids. The default already preserves the authored free-endpoint position of a dangling edge (empty `source`/`target`), so keeping `sourcePosition`/`targetPosition` yourself is not needed for that. Overriding this function and keeping such properties is unsupported territory; prefer wrapping the default and re-adding only the properties you know you need. *** ### stripNodeRuntimeProperties? > `optional` **stripNodeRuntimeProperties**: [`StripNodeRuntimePropertiesFn`](/docs/api/types/model/stripnoderuntimepropertiesfn/) Replaces the function that strips runtime-computed properties from nodes during initialization (and, for the default model created by [initializeModel](/docs/api/utilities/initializemodel/), during `toJSON()` serialization). ⚠️ **Use at your own risk.** The default ([stripNodeRuntimeProperties](/docs/api/utilities/stripnoderuntimeproperties/)) exists because stale runtime values (`selected`, `measuredPorts`, `measuredBounds`, `computedZIndex`, `_internalId`) loaded from persistence can and probably will break the diagram — e.g. skipped DOM measurements, wrong z-ordering, or duplicated internal ids. Overriding this function and keeping such properties is unsupported territory; prefer wrapping the default and re-adding only the properties you know you need. --- ### Metadata URL: https://ngdiagram.dev/docs/api/types/model/metadata/ Interface representing the metadata of the diagram. ## Type Parameters ### T `T` *extends* `DataObject` = `DataObject` ## Properties ### data? > `optional` **data**: `T` Custom user data associated with the diagram *** ### viewport > **viewport**: [`Viewport`](/docs/api/types/model/viewport/) Viewport of the diagram --- ### Model URL: https://ngdiagram.dev/docs/api/types/model/model/ Interface representing the entire model of the flow diagram ## Properties ### edges > **edges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Array of edges connecting the nodes *** ### metadata > **metadata**: `Partial`\<[`Metadata`](/docs/api/types/model/metadata/)\> Metadata associated with the diagram *** ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] Array of nodes in the diagram --- ### ModelAdapter URL: https://ngdiagram.dev/docs/api/types/model/modeladapter/ Interface for model adapters that handle the data management of a flow diagram ## Methods ### destroy() > **destroy**(): `void` Destroy the model adapter and clean up resources This should be called when the model is no longer needed to prevent memory leaks #### Returns `void` *** ### getEdges() > **getEdges**(): [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Get all edges in the model #### Returns [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] *** ### getMetadata() > **getMetadata**(): [`Metadata`](/docs/api/types/model/metadata/) Get metadata associated with the model #### Returns [`Metadata`](/docs/api/types/model/metadata/) *** ### getNodes() > **getNodes**(): [`Node`](/docs/api/types/model/node/)[] Get all nodes in the model #### Returns [`Node`](/docs/api/types/model/node/)[] *** ### onChange() > **onChange**(`callback`): `void` Register a callback to be called when the model changes #### Parameters ##### callback (`__namedParameters`) => `void` Function to be called on changes #### Returns `void` *** ### redo() > **redo**(): `void` Redo the last undone change #### Returns `void` *** ### toJSON() > **toJSON**(): `string` Convert the model to a JSON string #### Returns `string` *** ### undo() > **undo**(): `void` Undo the last change #### Returns `void` *** ### unregisterOnChange() > **unregisterOnChange**(`callback`): `void` Unregister a callback from being called when the model changes #### Parameters ##### callback (`__namedParameters`) => `void` Function to unregister from changes #### Returns `void` *** ### updateEdges() > **updateEdges**(`edges`): `void` Update edges in the model #### Parameters ##### edges [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Array of edges to set #### Returns `void` *** ### updateMetadata() > **updateMetadata**(`metadata`): `void` Set metadata for the model #### Parameters ##### metadata [`Metadata`](/docs/api/types/model/metadata/) Metadata to set #### Returns `void` *** ### updateNodes() > **updateNodes**(`nodes`): `void` Update nodes in the model #### Parameters ##### nodes [`Node`](/docs/api/types/model/node/)[] Array of nodes to set #### Returns `void` --- ### ModelChanges URL: https://ngdiagram.dev/docs/api/types/model/modelchanges/ Interface representing a snapshot of the diagram model state. This read-only interface is provided by the library when the model changes. It contains the complete current state of nodes, edges, and metadata. Typically received in `onChange` callbacks to observe model updates. ## Properties ### edges > **edges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Current array of all edges in the diagram. *** ### metadata > **metadata**: [`Metadata`](/docs/api/types/model/metadata/) Current metadata associated with the diagram. *** ### nodes > **nodes**: [`Node`](/docs/api/types/model/node/)[] Current array of all nodes in the diagram. --- ### Node URL: https://ngdiagram.dev/docs/api/types/model/node/ > **Node**\<`T`\> = [`SimpleNode`](/docs/api/types/model/simplenode/)\<`T`\> \| [`GroupNode`](/docs/api/types/model/groupnode/)\<`T`\> Interface representing all possible node types in the diagram ## Type Parameters ### T `T` *extends* `DataObject` = `DataObject` --- ### OriginPoint URL: https://ngdiagram.dev/docs/api/types/model/originpoint/ > **OriginPoint** = `"topLeft"` \| `"topCenter"` \| `"topRight"` \| `"centerLeft"` \| `"center"` \| `"centerRight"` \| `"bottomLeft"` \| `"bottomCenter"` \| `"bottomRight"` The origin point options for port placement. --- ### Port URL: https://ngdiagram.dev/docs/api/types/model/port/ Interface representing a port in the node. ## Properties ### id > **id**: `string` The unique identifier for the port. *** ### nodeId > **nodeId**: `string` The id of the node that the port belongs to. *** ### position? > `optional` **position**: [`Point`](/docs/api/types/geometry/point/) The position of the port in the node. *** ### side > **side**: [`Side`](/docs/api/types/model/side/) The side of the node that the port is on. *** ### size? > `optional` **size**: [`Size`](/docs/api/types/geometry/size/) The size of the port. *** ### type > **type**: `"source"` \| `"target"` \| `"both"` The type of the port. --- ### PortLocation URL: https://ngdiagram.dev/docs/api/types/model/portlocation/ > **PortLocation** = `object` & [`Point`](/docs/api/types/geometry/point/) Interface representing the location of a port on a node ## Type Declaration ### side > **side**: [`PortSide`](/docs/api/types/model/portside/) --- ### PortSide URL: https://ngdiagram.dev/docs/api/types/model/portside/ > **PortSide** = [`Side`](/docs/api/types/model/side/) Interface representing a port side on a node in the diagram --- ### Side URL: https://ngdiagram.dev/docs/api/types/model/side/ > **Side** = `"top"` \| `"right"` \| `"bottom"` \| `"left"` One of the four sides of a rectangular area. --- ### SimpleNode URL: https://ngdiagram.dev/docs/api/types/model/simplenode/ Interface representing the most basic node in the diagram ## Extended by - [`GroupNode`](/docs/api/types/model/groupnode/) ## Type Parameters ### T `T` *extends* `DataObject` = `DataObject` ## Properties ### angle? > `optional` **angle**: `number` The angle of the node from 0 to 360. *** ### autoSize? > `optional` **autoSize**: `boolean` Whether the size of the node is automatically resized based on the content. *** ### computedZIndex? > `readonly` `optional` **computedZIndex**: `number` #### Remarks ComputedZIndex is computed by the system and should not be set manually. The final z-index applied to the DOM element for rendering order. Computed from `zOrder`, group hierarchy, and selection elevation. Children are always above their parent group. *** ### data > **data**: `T` The data associated with the node. *** ### draggable? > `optional` **draggable**: `boolean` Whether the node is draggable. *** ### groupId? > `optional` **groupId**: `string` The id of the parent node. *** ### id > **id**: `string` The unique identifier for the node. *** ### measuredBounds? > `readonly` `optional` **measuredBounds**: [`Rect`](/docs/api/types/geometry/rect/) #### Remarks MeasuredBounds are computed by the system and should not be set manually. Bounding box that encompasses the node including its ports, accounting for rotation. *** ### measuredPorts? > `readonly` `optional` **measuredPorts**: [`Port`](/docs/api/types/model/port/)[] #### Remarks MeasuredPorts are computed by the system and should not be set manually. The ports of the node with computed position and size. *** ### position > **position**: [`Point`](/docs/api/types/geometry/point/) The position of the node in the diagram. *** ### resizable? > `optional` **resizable**: `boolean` Whether the node is resizable. *** ### rotatable? > `optional` **rotatable**: `boolean` Whether the node is rotatable. *** ### selected? > `optional` **selected**: `boolean` Whether the node is selected. *** ### size? > `optional` **size**: [`Size`](/docs/api/types/geometry/size/) The size of the node. *** ### type? > `optional` **type**: `string` The type of the node declared in nodeTemplateMap. *** ### zOrder? > `optional` **zOrder**: `number` The z-order of the node. Controls relative ordering among nodes on the same hierarchy level. With proper values, it can also influence ordering across different hierarchy levels, since each nesting level adds +1 to the computed z-index per child. - Root nodes: used directly as the base z-index (negative values allowed). - Grouped nodes: acts as a minimum floor — cannot go below the parent's z-index. Set by `bringToFront` / `sendToBack` commands, or manually. #### See [computedZIndex](/docs/api/types/model/simplenode/#computedzindex) for the final rendered z-index. --- ### StripEdgeRuntimePropertiesFn URL: https://ngdiagram.dev/docs/api/types/model/stripedgeruntimepropertiesfn/ > **StripEdgeRuntimePropertiesFn** = (`edge`) => [`Edge`](/docs/api/types/model/edge/) A function that removes runtime-computed properties from an edge before initialization or serialization. ## Parameters ### edge [`Edge`](/docs/api/types/model/edge/) ## Returns [`Edge`](/docs/api/types/model/edge/) --- ### StripNodeRuntimePropertiesFn URL: https://ngdiagram.dev/docs/api/types/model/stripnoderuntimepropertiesfn/ > **StripNodeRuntimePropertiesFn** = (`node`) => [`Node`](/docs/api/types/model/node/) A function that removes runtime-computed properties from a node before initialization or serialization. ## Parameters ### node [`Node`](/docs/api/types/model/node/) ## Returns [`Node`](/docs/api/types/model/node/) --- ### Viewport URL: https://ngdiagram.dev/docs/api/types/model/viewport/ Interface representing the viewport of the diagram. ## Properties ### height? > `optional` **height**: `number` Height of the viewport *** ### scale > **scale**: `number` Scale factor of the viewport *** ### width? > `optional` **width**: `number` Width of the viewport *** ### x > **x**: `number` X coordinate of the viewport center *** ### y > **y**: `number` Y coordinate of the viewport center --- ### NgDiagramPanelPosition URL: https://ngdiagram.dev/docs/api/types/ngdiagrampanelposition/ > **NgDiagramPanelPosition** = `"top-left"` \| `"top-right"` \| `"bottom-left"` \| `"bottom-right"` Position for diagram overlay panels (minimap, watermark, etc.). --- ### BasePaletteItemData URL: https://ngdiagram.dev/docs/api/types/palette/basepaletteitemdata/ Base data interface for palette items. All palette item data should extend this interface and include at minimum a `label` property. ## Properties ### label > **label**: `string` The display label for the palette item. --- ### GroupNodeData URL: https://ngdiagram.dev/docs/api/types/palette/groupnodedata/ > **GroupNodeData**\<`Data`\> = [`SimpleNodeData`](/docs/api/types/palette/simplenodedata/)\<`Data`\> & `Pick`\<[`GroupNode`](/docs/api/types/model/groupnode/), `"isGroup"`\> Data structure for group node palette items. Extends [SimpleNodeData](/docs/api/types/palette/simplenodedata/) with the [GroupNode#isGroup](/docs/api/types/model/groupnode/#isgroup) property to identify it as a group. ## Type Parameters ### Data `Data` *extends* `object` = [`BasePaletteItemData`](/docs/api/types/palette/basepaletteitemdata/) --- ### NgDiagramPaletteItem URL: https://ngdiagram.dev/docs/api/types/palette/ngdiagrampaletteitem/ > **NgDiagramPaletteItem**\<`Data`\> = [`SimpleNodeData`](/docs/api/types/palette/simplenodedata/)\<`Data`\> \| [`GroupNodeData`](/docs/api/types/palette/groupnodedata/)\<`Data`\> The [NgDiagramPaletteItem](/docs/api/types/palette/ngdiagrampaletteitem/) represents the data structure for items that can be shown in the diagram palette and dragged onto the canvas to create nodes or groups. It supports both simple nodes and group nodes, allowing you to specify properties such as type, data, size, rotation, and grouping. Example usage: ```typescript const paletteItem: NgDiagramPaletteItem = { type: 'customNode', data: { label: 'My Node' }, resizable: true, rotatable: false, }; ``` ## Type Parameters ### Data `Data` *extends* `object` = [`BasePaletteItemData`](/docs/api/types/palette/basepaletteitemdata/) --- ### SimpleNodeData URL: https://ngdiagram.dev/docs/api/types/palette/simplenodedata/ > **SimpleNodeData**\<`Data`\> = `Pick`\<[`SimpleNode`](/docs/api/types/model/simplenode/)\<`Data`\>, `"type"` \| `"data"` \| `"resizable"` \| `"rotatable"` \| `"size"` \| `"angle"` \| `"autoSize"` \| `"zOrder"`\> Data structure for node palette items. Contains the essential properties needed to create a fully configured node from the palette. ## Type Parameters ### Data `Data` *extends* `object` = [`BasePaletteItemData`](/docs/api/types/palette/basepaletteitemdata/) --- ### EdgeRouting URL: https://ngdiagram.dev/docs/api/types/routing/edgerouting/ Interface for routing implementations ## Properties ### name > **name**: `string` Name identifier for the routing. ## Methods ### computePointAtDistance()? > `optional` **computePointAtDistance**(`points`, `distancePx`): [`Point`](/docs/api/types/geometry/point/) Gets a point on the path at a given pixel distance from the start. Negative values measure from the end of the path. #### Parameters ##### points [`Point`](/docs/api/types/geometry/point/)[] The points defining the path. ##### distancePx `number` Distance in pixels (positive = from start, negative = from end). #### Returns [`Point`](/docs/api/types/geometry/point/) The point at the given distance along the path. *** ### computePointOnPath()? > `optional` **computePointOnPath**(`points`, `percentage`): [`Point`](/docs/api/types/geometry/point/) Gets a point on the path at a given percentage (0-1). Useful for positioning labels, decorations, or interaction handles. #### Parameters ##### points [`Point`](/docs/api/types/geometry/point/)[] The points defining the path. ##### percentage `number` Position along the path (0 = start, 1 = end). #### Returns [`Point`](/docs/api/types/geometry/point/) The point at the given percentage along the path. *** ### computePoints() > **computePoints**(`context`, `config?`): [`Point`](/docs/api/types/geometry/point/)[] Computes the points for the edge path. This is the core routing logic that determines how an edge is drawn between source and target. #### Parameters ##### context [`EdgeRoutingContext`](/docs/api/types/routing/edgeroutingcontext/) The routing context containing source/target info and layout state. ##### config? [`EdgeRoutingConfig`](/docs/api/types/configuration/features/edgeroutingconfig/) Optional configuration parameters for routing behavior. #### Returns [`Point`](/docs/api/types/geometry/point/)[] An array of points representing the routed edge path. *** ### computeSvgPath() > **computeSvgPath**(`points`, `config?`): `string` Generates an SVG path string from points. Converts the routed points into a valid `d` attribute for an `` SVG element. #### Parameters ##### points [`Point`](/docs/api/types/geometry/point/)[] The points defining the edge path. ##### config? [`EdgeRoutingConfig`](/docs/api/types/configuration/features/edgeroutingconfig/) Optional configuration parameters for path generation. #### Returns `string` An SVG path string. --- ### EdgeRoutingContext URL: https://ngdiagram.dev/docs/api/types/routing/edgeroutingcontext/ Context object containing all information needed for routing computation ## Properties ### edge > **edge**: [`Edge`](/docs/api/types/model/edge/) The edge being routed *** ### sourceNode? > `optional` **sourceNode**: [`Node`](/docs/api/types/model/node/) Source node *** ### sourcePoint > **sourcePoint**: [`PortLocation`](/docs/api/types/model/portlocation/) Source port location *** ### sourcePort? > `optional` **sourcePort**: [`Port`](/docs/api/types/model/port/) Source port (if edge is connected to a specific port) *** ### targetNode? > `optional` **targetNode**: [`Node`](/docs/api/types/model/node/) Target node *** ### targetPoint > **targetPoint**: [`PortLocation`](/docs/api/types/model/portlocation/) Target port location *** ### targetPort? > `optional` **targetPort**: [`Port`](/docs/api/types/model/port/) Target port (if edge is connected to a specific port) --- ### EdgeRoutingName URL: https://ngdiagram.dev/docs/api/types/routing/edgeroutingname/ > **EdgeRoutingName** = `LooseAutocomplete`\<`BuiltInEdgeRoutingName`\> Type representing edge routing name - can be built-in or custom **Allowed values:** `'orthogonal' | 'bezier' | 'polyline'` --- ### RoutingMode URL: https://ngdiagram.dev/docs/api/types/routing/routingmode/ > **RoutingMode** = `"manual"` \| `"auto"` Type representing edge routing mode --- ### NgDiagramEdgeTemplate URL: https://ngdiagram.dev/docs/api/types/templates/ngdiagramedgetemplate/ `NgDiagramEdgeTemplate` is an interface for custom edge components in ng-diagram. It describes the required input signal for edge data and properties. This interface is used when creating custom edge components to ensure they receive the correct edge input. ## Example usage ```typescript @Component({...}) export class MyCustomEdgeComponent implements NgDiagramEdgeTemplate { edge!: InputSignal>; } ``` ## Type Parameters ### Data `Data` *extends* `DataObject` = `DataObject` The type of data associated with the edge ## Properties ### edge > **edge**: `InputSignal`\<[`Edge`](/docs/api/types/model/edge/)\<`Data`\>\> Input signal containing the edge data and properties. --- ### NgDiagramEdgeTemplateMap URL: https://ngdiagram.dev/docs/api/types/templates/ngdiagramedgetemplatemap/ `NgDiagramEdgeTemplateMap` is a map that associates edge type names with their corresponding Angular component classes. ## Example usage ```typescript // Define a map of edge types to their components const edgeTemplateMap = new NgDiagramEdgeTemplateMap([['someEdge', SomeEdgeComponent]]); ``` ```html ``` ## Extends - `Map`\<`string`, `Type`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\>\> ## Properties ### size > `readonly` **size**: `number` #### Returns the number of elements in the Map. #### Inherited from `Map.size` ## Methods ### \[iterator\]() > **\[iterator\]**(): `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\>\]\> Returns an iterable of entries in the map. #### Returns `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\>\]\> #### Inherited from `Map.[iterator]` *** ### delete() > **delete**(`key`): `boolean` #### Parameters ##### key `string` #### Returns `boolean` true if an element in the Map existed and has been removed, or false if the element does not exist. #### Inherited from `Map.delete` *** ### entries() > **entries**(): `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\>\]\> Returns an iterable of key, value pairs for every entry in the map. #### Returns `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\>\]\> #### Inherited from `Map.entries` *** ### forEach() > **forEach**(`callbackfn`, `thisArg?`): `void` Executes a provided function once per each key/value pair in the Map, in insertion order. #### Parameters ##### callbackfn (`value`, `key`, `map`) => `void` ##### thisArg? `any` #### Returns `void` #### Inherited from `Map.forEach` *** ### get() > **get**(`key`): `undefined` \| `Type$1`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\> Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map. #### Parameters ##### key `string` #### Returns `undefined` \| `Type$1`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\> Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned. #### Inherited from `Map.get` *** ### has() > **has**(`key`): `boolean` #### Parameters ##### key `string` #### Returns `boolean` boolean indicating whether an element with the specified key exists or not. #### Inherited from `Map.has` *** ### keys() > **keys**(): `MapIterator`\<`string`\> Returns an iterable of keys in the map #### Returns `MapIterator`\<`string`\> #### Inherited from `Map.keys` *** ### set() > **set**(`key`, `value`): `this` Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated. #### Parameters ##### key `string` ##### value `Type$1` #### Returns `this` #### Inherited from `Map.set` *** ### values() > **values**(): `MapIterator`\<`Type$1`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\>\> Returns an iterable of values in the map #### Returns `MapIterator`\<`Type$1`\<[`NgDiagramEdgeTemplate`](/docs/api/types/templates/ngdiagramedgetemplate/)\<`any`\>\>\> #### Inherited from `Map.values` --- ### NgDiagramGroupNodeTemplate URL: https://ngdiagram.dev/docs/api/types/templates/ngdiagramgroupnodetemplate/ Interface for custom group node components. ## Extends - [`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`Data`, [`GroupNode`](/docs/api/types/model/groupnode/)\<`Data`\>\> ## Type Parameters ### Data `Data` *extends* `DataObject` = `DataObject` The type of data associated with the group node ## Properties ### node > **node**: `InputSignal`\<[`GroupNode`](/docs/api/types/model/groupnode/)\<`Data`\>\> Input signal containing the node data and properties. #### Inherited from [`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/).[`node`](/docs/api/types/templates/ngdiagramnodetemplate/#node) --- ### NgDiagramNodeTemplate URL: https://ngdiagram.dev/docs/api/types/templates/ngdiagramnodetemplate/ Interface for custom node components. ## Extended by - [`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/) ## Type Parameters ### Data `Data` *extends* `DataObject` = `DataObject` The type of data associated with the node ### NodeType `NodeType` *extends* [`Node`](/docs/api/types/model/node/)\<`Data`\> = [`SimpleNode`](/docs/api/types/model/simplenode/)\<`Data`\> The type of node (SimpleNode or GroupNode) ## Properties ### node > **node**: `InputSignal`\<`NodeType`\> Input signal containing the node data and properties. --- ### NgDiagramNodeTemplateMap URL: https://ngdiagram.dev/docs/api/types/templates/ngdiagramnodetemplatemap/ Map that associates node type names with their corresponding Angular component classes. Used by ng-diagram to determine which custom node component to render based on node type. ## Extends - `Map`\<`string`, `Type`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`\>\> \| `Type`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\>\> ## Properties ### size > `readonly` **size**: `number` #### Returns the number of elements in the Map. #### Inherited from `Map.size` ## Methods ### \[iterator\]() > **\[iterator\]**(): `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\>\]\> Returns an iterable of entries in the map. #### Returns `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\>\]\> #### Inherited from `Map.[iterator]` *** ### delete() > **delete**(`key`): `boolean` #### Parameters ##### key `string` #### Returns `boolean` true if an element in the Map existed and has been removed, or false if the element does not exist. #### Inherited from `Map.delete` *** ### entries() > **entries**(): `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\>\]\> Returns an iterable of key, value pairs for every entry in the map. #### Returns `MapIterator`\<\[`string`, `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\>\]\> #### Inherited from `Map.entries` *** ### forEach() > **forEach**(`callbackfn`, `thisArg?`): `void` Executes a provided function once per each key/value pair in the Map, in insertion order. #### Parameters ##### callbackfn (`value`, `key`, `map`) => `void` ##### thisArg? `any` #### Returns `void` #### Inherited from `Map.forEach` *** ### get() > **get**(`key`): `undefined` \| `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\> Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map. #### Parameters ##### key `string` #### Returns `undefined` \| `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\> Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned. #### Inherited from `Map.get` *** ### has() > **has**(`key`): `boolean` #### Parameters ##### key `string` #### Returns `boolean` boolean indicating whether an element with the specified key exists or not. #### Inherited from `Map.has` *** ### keys() > **keys**(): `MapIterator`\<`string`\> Returns an iterable of keys in the map #### Returns `MapIterator`\<`string`\> #### Inherited from `Map.keys` *** ### set() > **set**(`key`, `value`): `this` Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated. #### Parameters ##### key `string` ##### value `Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> | `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\> #### Returns `this` #### Inherited from `Map.set` *** ### values() > **values**(): `MapIterator`\<`Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\>\> Returns an iterable of values in the map #### Returns `MapIterator`\<`Type$1`\<[`NgDiagramNodeTemplate`](/docs/api/types/templates/ngdiagramnodetemplate/)\<`any`, [`SimpleNode`](/docs/api/types/model/simplenode/)\<`any`\>\>\> \| `Type$1`\<[`NgDiagramGroupNodeTemplate`](/docs/api/types/templates/ngdiagramgroupnodetemplate/)\<`any`\>\>\> #### Inherited from `Map.values` --- ## Internals ### ActionState URL: https://ngdiagram.dev/docs/api/internals/actionstate/ Interface representing the current state of various user interactions in the diagram. This state is read-only and automatically managed by the library. It provides information about active operations such as resizing, linking, dragging, and other user interactions. Use this to observe the current state, not to modify it. ## Properties ### copyPaste? > `optional` **copyPaste**: [`CopyPasteActionState`](/docs/api/internals/copypasteactionstate/) State related to copy-paste actions *** ### dragging? > `optional` **dragging**: [`DraggingActionState`](/docs/api/internals/draggingactionstate/) State related to dragging elements *** ### highlightGroup? > `optional` **highlightGroup**: [`HighlightGroupActionState`](/docs/api/internals/highlightgroupactionstate/) State related to highlighting groups *** ### linking? > `optional` **linking**: [`LinkingActionState`](/docs/api/internals/linkingactionstate/) State related to linking nodes *** ### panning? > `optional` **panning**: [`PanningActionState`](/docs/api/internals/panningactionstate/) State related to panning the viewport *** ### resize? > `optional` **resize**: [`ResizeActionState`](/docs/api/internals/resizeactionstate/) State related to node resizing action *** ### rotation? > `optional` **rotation**: [`RotationActionState`](/docs/api/internals/rotationactionstate/) State related to node rotation *** ### selection? > `optional` **selection**: [`SelectionActionState`](/docs/api/internals/selectionactionstate/) State related to selection gestures --- ### ActionStateManager URL: https://ngdiagram.dev/docs/api/internals/actionstatemanager/ **Internal manager** for temporary state during ongoing user actions. Tracks the state of interactive operations like resizing, linking, rotating, and dragging until the action completes. ## Remarks **For application code, use [NgDiagramService.actionState](/docs/api/services/ngdiagramservice/#actionstate) signal instead.** This class is exposed primarily for middleware development where you can access it via `context.actionStateManager`. ## Example ```typescript const middleware: Middleware = { name: 'resize-validator', execute: (context, next, cancel) => { const resizeState = context.actionStateManager.resize; if (resizeState) { console.log('Currently resizing node:', resizeState.nodeId); } next(); } }; ``` ## Accessors ### copyPaste #### Get Signature > **get** **copyPaste**(): `undefined` \| [`CopyPasteActionState`](/docs/api/internals/copypasteactionstate/) Gets the current copy/paste action state. ##### Returns `undefined` \| [`CopyPasteActionState`](/docs/api/internals/copypasteactionstate/) The copy/paste state if a copy/paste operation is in progress, undefined otherwise #### Set Signature > **set** **copyPaste**(`value`): `void` Sets the copy/paste action state. ##### Parameters ###### value The copy/paste state to set, or undefined to clear `undefined` | [`CopyPasteActionState`](/docs/api/internals/copypasteactionstate/) ##### Returns `void` *** ### dragging #### Get Signature > **get** **dragging**(): `undefined` \| [`DraggingActionState`](/docs/api/internals/draggingactionstate/) Gets the current dragging action state. ##### Returns `undefined` \| [`DraggingActionState`](/docs/api/internals/draggingactionstate/) The dragging state if nodes are being dragged, undefined otherwise #### Set Signature > **set** **dragging**(`value`): `void` Sets the dragging action state. ##### Parameters ###### value The dragging state to set, or undefined to clear `undefined` | [`DraggingActionState`](/docs/api/internals/draggingactionstate/) ##### Returns `void` *** ### highlightGroup #### Get Signature > **get** **highlightGroup**(): `undefined` \| [`HighlightGroupActionState`](/docs/api/internals/highlightgroupactionstate/) Gets the current highlight group action state. ##### Returns `undefined` \| [`HighlightGroupActionState`](/docs/api/internals/highlightgroupactionstate/) The highlight group state if a group is being highlighted, undefined otherwise #### Set Signature > **set** **highlightGroup**(`value`): `void` Sets the highlight group action state. ##### Parameters ###### value The highlight group state to set, or undefined to clear `undefined` | [`HighlightGroupActionState`](/docs/api/internals/highlightgroupactionstate/) ##### Returns `void` *** ### linking #### Get Signature > **get** **linking**(): `undefined` \| [`LinkingActionState`](/docs/api/internals/linkingactionstate/) Gets the current linking action state. ##### Returns `undefined` \| [`LinkingActionState`](/docs/api/internals/linkingactionstate/) The linking state if a link is being created, undefined otherwise #### Set Signature > **set** **linking**(`value`): `void` Sets the linking action state. ##### Parameters ###### value The linking state to set, or undefined to clear `undefined` | [`LinkingActionState`](/docs/api/internals/linkingactionstate/) ##### Returns `void` *** ### panning #### Get Signature > **get** **panning**(): `undefined` \| [`PanningActionState`](/docs/api/internals/panningactionstate/) Gets the current panning action state. ##### Returns `undefined` \| [`PanningActionState`](/docs/api/internals/panningactionstate/) The panning state if viewport is being panned, undefined otherwise #### Set Signature > **set** **panning**(`value`): `void` Sets the panning action state. ##### Parameters ###### value The panning state to set, or undefined to clear `undefined` | [`PanningActionState`](/docs/api/internals/panningactionstate/) ##### Returns `void` *** ### resize #### Get Signature > **get** **resize**(): `undefined` \| [`ResizeActionState`](/docs/api/internals/resizeactionstate/) Gets the current resize action state. ##### Returns `undefined` \| [`ResizeActionState`](/docs/api/internals/resizeactionstate/) The resize state if a resize is in progress, undefined otherwise #### Set Signature > **set** **resize**(`value`): `void` Sets the resize action state. ##### Parameters ###### value The resize state to set, or undefined to clear `undefined` | [`ResizeActionState`](/docs/api/internals/resizeactionstate/) ##### Returns `void` *** ### rotation #### Get Signature > **get** **rotation**(): `undefined` \| [`RotationActionState`](/docs/api/internals/rotationactionstate/) Gets the current rotation action state. ##### Returns `undefined` \| [`RotationActionState`](/docs/api/internals/rotationactionstate/) The rotation state if a rotation is in progress, undefined otherwise #### Set Signature > **set** **rotation**(`value`): `void` Sets the rotation action state. ##### Parameters ###### value The rotation state to set, or undefined to clear `undefined` | [`RotationActionState`](/docs/api/internals/rotationactionstate/) ##### Returns `void` *** ### selection #### Get Signature > **get** **selection**(): `undefined` \| [`SelectionActionState`](/docs/api/internals/selectionactionstate/) Gets the current selection action state. ##### Returns `undefined` \| [`SelectionActionState`](/docs/api/internals/selectionactionstate/) The selection state if set, undefined otherwise #### Set Signature > **set** **selection**(`value`): `void` Sets the selection action state. ##### Parameters ###### value The selection state to set, or undefined to clear `undefined` | [`SelectionActionState`](/docs/api/internals/selectionactionstate/) ##### Returns `void` ## Methods ### clearCopyPaste() > **clearCopyPaste**(): `void` Clears the copy/paste action state. #### Returns `void` *** ### clearDragging() > **clearDragging**(): `void` Clears the dragging action state. #### Returns `void` *** ### clearHighlightGroup() > **clearHighlightGroup**(): `void` Clears the highlight group action state. #### Returns `void` *** ### clearLinking() > **clearLinking**(): `void` Clears the linking action state. #### Returns `void` *** ### clearPanning() > **clearPanning**(): `void` Clears the panning action state. #### Returns `void` *** ### clearResize() > **clearResize**(): `void` Clears the resize action state. #### Returns `void` *** ### clearRotation() > **clearRotation**(): `void` Clears the rotation action state. #### Returns `void` *** ### clearSelection() > **clearSelection**(): `void` Clears the selection action state. #### Returns `void` *** ### getState() > **getState**(): `Readonly`\<[`ActionState`](/docs/api/internals/actionstate/)\> Gets the current action state (readonly). #### Returns `Readonly`\<[`ActionState`](/docs/api/internals/actionstate/)\> The complete action state object *** ### isDragging() > **isDragging**(): `boolean` Checks if a dragging operation is currently in progress. #### Returns `boolean` *** ### isLinking() > **isLinking**(): `boolean` Checks if a linking operation is currently in progress. #### Returns `boolean` *** ### isPanning() > **isPanning**(): `boolean` Checks if a panning operation is currently in progress. #### Returns `boolean` *** ### isResizing() > **isResizing**(): `boolean` Checks if a resize operation is currently in progress. #### Returns `boolean` *** ### isRotating() > **isRotating**(): `boolean` Checks if a rotation operation is currently in progress. #### Returns `boolean` --- ### CopyPasteActionState URL: https://ngdiagram.dev/docs/api/internals/copypasteactionstate/ State containing copied nodes and edges for paste operations. ## Properties ### copiedEdges > **copiedEdges**: [`Edge`](/docs/api/types/model/edge/)\<`object`\>[] Array of edges that were copied. *** ### copiedNodes > **copiedNodes**: [`Node`](/docs/api/types/model/node/)[] Array of nodes that were copied. --- ### DraggingActionState URL: https://ngdiagram.dev/docs/api/internals/draggingactionstate/ State tracking a drag operation in progress. ## Properties ### accumulatedDeltas > **accumulatedDeltas**: `Map`\<`string`, [`Point`](/docs/api/types/geometry/point/)\> Accumulated deltas per node that haven't yet resulted in a snap movement. Key is node ID, value is the accumulated delta that hasn't been applied due to snapping. *** ### cancelReason? > `optional` **cancelReason**: `"cancelled"` Set when the drag is aborted; carried into `nodeDragEnded`. *** ### modifiers > **modifiers**: [`InputModifiers`](/docs/api/types/configuration/shortcuts/inputmodifiers/) Input modifiers (e.g., Ctrl, Shift) active during the drag. *** ### movementStarted > **movementStarted**: `boolean` Whether the pointer has moved beyond the move threshold, indicating an actual drag. `false` when the drag state is first created (on pointer down), `true` once movement exceeds the threshold. *** ### nodeIds > **nodeIds**: `string`[] IDs of all nodes participating in the drag (selected + children, filtered by draggable). --- ### EdgeRoutingManager URL: https://ngdiagram.dev/docs/api/internals/edgeroutingmanager/ **Internal manager** for registration, selection, and execution of edge routing implementations. ## Remarks **For application code, use [NgDiagramService](/docs/api/services/ngdiagramservice/) routing methods instead.** This class is exposed primarily for middleware development where you can access it via `context.edgeRoutingManager`. The manager comes pre-populated with built-in routings (`orthogonal`, `bezier`, `polyline`). You can register custom routings at runtime. ## Example ```typescript const middleware: Middleware = { name: 'routing-optimizer', execute: (context, next) => { const routingManager = context.edgeRoutingManager; const defaultRouting = routingManager.getDefaultRouting(); console.log('Using routing:', defaultRouting); next(); } }; ``` ## Methods ### computePath() > **computePath**(`routingName`, `points`): `string` Computes an SVG path string for the given points using the specified routing. #### Parameters ##### routingName The routing to use. If omitted or undefined, the default routing is used. `undefined` | [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) ##### points [`Point`](/docs/api/types/geometry/point/)[] The points to convert into an SVG path string #### Returns `string` An SVG path string suitable for the `d` attribute of an SVG `` element #### Example ```typescript const points = [{ x: 0, y: 0 }, { x: 100, y: 100 }, { x: 200, y: 100 }]; const path = routingManager.computePath('polyline', points); // Returns: "M 0 0 L 100 100 L 200 100" ``` *** ### computePointAtDistance() > **computePointAtDistance**(`routingName`, `points`, `distancePx`): [`Point`](/docs/api/types/geometry/point/) Computes a point along the path at a given pixel distance from the start. #### Parameters ##### routingName The routing to use. If omitted, the default routing is used. `undefined` | [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) ##### points [`Point`](/docs/api/types/geometry/point/)[] The path points ##### distancePx `number` Distance in pixels (positive = from start, negative = from end) #### Returns [`Point`](/docs/api/types/geometry/point/) The point on the path at the given distance #### Remarks If the selected routing implements `computePointAtDistance`, it will be used. Otherwise, falls back to segment-based distance traversal along the points array. Negative values measure from the end of the path. *** ### computePointOnPath() > **computePointOnPath**(`routingName`, `points`, `percentage`): [`Point`](/docs/api/types/geometry/point/) Computes a point along the path at a given percentage. #### Parameters ##### routingName The routing to use. If omitted or undefined, the default routing is used. `undefined` | [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) ##### points [`Point`](/docs/api/types/geometry/point/)[] The path points ##### percentage `number` Position along the path in range [0, 1] where 0 = start, 1 = end #### Returns [`Point`](/docs/api/types/geometry/point/) The interpolated point on the path #### Remarks If the selected routing implements `computePointOnPath`, it will be used. Otherwise, falls back to linear interpolation between the first and last points. #### Example ```typescript const points = [{ x: 0, y: 0 }, { x: 100, y: 100 }]; const midpoint = routingManager.computePointOnPath('polyline', points, 0.5); // Returns: { x: 50, y: 50 } const quarterPoint = routingManager.computePointOnPath('polyline', points, 0.25); // Returns: { x: 25, y: 25 } ``` *** ### computePoints() > **computePoints**(`routingName`, `context`): [`Point`](/docs/api/types/geometry/point/)[] Computes the routed points for an edge using the specified routing algorithm. #### Parameters ##### routingName The routing to use. If omitted or undefined, the default routing is used. `undefined` | [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) ##### context [`EdgeRoutingContext`](/docs/api/types/routing/edgeroutingcontext/) The routing context containing source/target nodes, ports, edge data, etc. #### Returns [`Point`](/docs/api/types/geometry/point/)[] The computed polyline as an array of points #### Example ```typescript const points = routingManager.computePoints('orthogonal', { sourceNode: node1, targetNode: node2, sourcePosition: { x: 100, y: 50 }, targetPosition: { x: 300, y: 200 }, edge: edge }); ``` *** ### getDefaultRouting() > **getDefaultRouting**(): [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) Gets the current default routing name. #### Returns [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) The name of the current default routing *** ### getRegisteredRoutings() > **getRegisteredRoutings**(): [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/)[] Gets all registered routing names. #### Returns [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/)[] An array of registered routing names (built-in and custom) *** ### getRouting() > **getRouting**(`name`): `undefined` \| [`EdgeRouting`](/docs/api/types/routing/edgerouting/) Gets a routing implementation by name. #### Parameters ##### name [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) The routing name to look up #### Returns `undefined` \| [`EdgeRouting`](/docs/api/types/routing/edgerouting/) The routing implementation or `undefined` if not registered *** ### hasRouting() > **hasRouting**(`name`): `boolean` Checks whether a routing is registered. #### Parameters ##### name [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) The routing name to check #### Returns `boolean` `true` if registered; otherwise `false` *** ### registerRouting() > **registerRouting**(`routing`): `void` Registers (or replaces) a routing implementation. #### Parameters ##### routing [`EdgeRouting`](/docs/api/types/routing/edgerouting/) The routing instance to register. Its name must be non-empty. #### Returns `void` *** ### setDefaultRouting() > **setDefaultRouting**(`name`): `void` Sets the default routing to use for all edges when no specific routing is specified. #### Parameters ##### name [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) The routing name to set as default #### Returns `void` *** ### unregisterRouting() > **unregisterRouting**(`name`): `void` Unregisters a routing by name. #### Parameters ##### name [`EdgeRoutingName`](/docs/api/types/routing/edgeroutingname/) The routing name to remove #### Returns `void` --- ### EnvironmentInfo URL: https://ngdiagram.dev/docs/api/internals/environmentinfo/ Interface representing environment information ## Properties ### browser > **browser**: `null` \| `LooseAutocomplete`\<`"Chrome"` \| `"Firefox"` \| `"Safari"` \| `"Edge"` \| `"Opera"` \| `"IE"` \| `"Other"`\> User Browser name (when applicable) *** ### generateId() > **generateId**: () => `string` Generates a unique ID #### Returns `string` *** ### now() > **now**: () => `number` Current timestamp in ms #### Returns `number` *** ### os > **os**: `null` \| `LooseAutocomplete`\<`"MacOS"` \| `"Windows"` \| `"Linux"` \| `"iOS"` \| `"Android"` \| `"Unknown"`\> User Operating system name *** ### runtime > **runtime**: `null` \| `LooseAutocomplete`\<`"node"` \| `"web"` \| `"other"`\> Platform identity for high-level adapter routing --- ### HighlightGroupActionState URL: https://ngdiagram.dev/docs/api/internals/highlightgroupactionstate/ State tracking which group is currently highlighted. ## Properties ### highlightedGroupId > **highlightedGroupId**: `null` \| `string` ID of the highlighted group, or null if no group is highlighted. --- ### LinkingActionState URL: https://ngdiagram.dev/docs/api/internals/linkingactionstate/ State tracking an edge creation operation in progress. ## Properties ### cancelReason? > `optional` **cancelReason**: [`EdgeDrawCancelReason`](/docs/api/types/events/edgedrawcancelreason/) Reason the linking gesture was cancelled (set by finishLinking on failure paths). *** ### dropPosition? > `optional` **dropPosition**: [`Point`](/docs/api/types/geometry/point/) Position where the pointer was released. *** ### sourceNodeId > **sourceNodeId**: `string` ID of the node where the edge starts. *** ### sourcePortId > **sourcePortId**: `string` ID of the port where the edge starts. *** ### temporaryEdge > **temporaryEdge**: `null` \| [`Edge`](/docs/api/types/model/edge/)\<`object`\> Temporary edge displayed while creating the connection. --- ### PanningActionState URL: https://ngdiagram.dev/docs/api/internals/panningactionstate/ State tracking a panning operation in progress. ## Properties ### active > **active**: `boolean` Whether panning is currently active. --- ### ResizeActionState URL: https://ngdiagram.dev/docs/api/internals/resizeactionstate/ State tracking a node resize operation in progress. ## Properties ### cancelReason? > `optional` **cancelReason**: `"cancelled"` Set when the resize is aborted; carried into `nodeResizeEnded`. *** ### resizingNode > **resizingNode**: [`Node`](/docs/api/types/model/node/) Reference to the node being resized. *** ### startHeight > **startHeight**: `number` Initial height of the node before resize. *** ### startNodePositionX > **startNodePositionX**: `number` Initial X position of the node in diagram space. *** ### startNodePositionY > **startNodePositionY**: `number` Initial Y position of the node in diagram space. *** ### startWidth > **startWidth**: `number` Initial width of the node before resize. *** ### startX > **startX**: `number` Initial X coordinate in screen space where the resize started. *** ### startY > **startY**: `number` Initial Y coordinate in screen space where the resize started. --- ### RotationActionState URL: https://ngdiagram.dev/docs/api/internals/rotationactionstate/ State tracking a node rotation operation in progress. ## Properties ### cancelReason? > `optional` **cancelReason**: `"cancelled"` Set when the rotation is aborted; carried into `nodeRotateEnded`. *** ### initialNodeAngle > **initialNodeAngle**: `number` Initial angle of the node before rotation. *** ### nodeId > **nodeId**: `string` ID of the node being rotated. *** ### startAngle > **startAngle**: `number` Angle in degrees at the start of the rotation operation. --- ### SelectionActionState URL: https://ngdiagram.dev/docs/api/internals/selectionactionstate/ State tracking whether a selection gesture has changed the selection. Set by selection commands when they apply changes, cleared when the `selectionGestureEnded` event is emitted on `selectEnd`. ## Properties ### selectionChanged > **selectionChanged**: `boolean` Whether selection has changed since the gesture started. --- ## Other ### BaseEdgeLabelComponent URL: https://ngdiagram.dev/docs/api/other/baseedgelabelcomponent/ > `const` **BaseEdgeLabelComponent**: *typeof* [`NgDiagramBaseEdgeLabelComponent`](/docs/api/components/ngdiagrambaseedgelabelcomponent/) = `NgDiagramBaseEdgeLabelComponent` :::caution[Deprecated] Use [NgDiagramBaseEdgeLabelComponent](/docs/api/components/ngdiagrambaseedgelabelcomponent/) instead. This alias will be removed in a future version. ::: --- ### InvalidateMeasurementsOptions URL: https://ngdiagram.dev/docs/api/other/invalidatemeasurementsoptions/ Options for selective invalidation of diagram element measurements. When provided to `invalidateMeasurements()`, only the specified elements are re-measured. When omitted, all elements are re-measured. ## Properties ### edges? > `optional` **edges**: `object`[] Edges whose labels should be re-measured. #### edgeId > **edgeId**: `string` *** ### nodes? > `optional` **nodes**: `object`[] Nodes to re-measure. Invalidating a node also re-measures all its ports. #### nodeId > **nodeId**: `string` --- # Policies ## API Stability > API stability levels and Angular version support for ngDiagram URL: https://ngdiagram.dev/docs/policies/api-stability/ This document outlines ngDiagram's API stability levels and version support policy. Understanding these stability levels helps you make informed decisions about which APIs to use in production and plan for future upgrades. ## API Stability Levels ngDiagram uses TSDoc tags to indicate API stability: | Tag | Level | Breaking Changes | Migration Support | Production Use | | --------------- | -------- | -------------------------------- | ----------------- | ------------------- | | `@public` | Stable | Only in major versions | Yes, guaranteed | ✅ Safe | | `@beta` | Preview | Possible in minor versions | Yes, provided | ⚠️ Use with caution | | `@experimental` | Unstable | May change or be removed anytime | Not guaranteed | ❌ Testing only | | `@internal` | Private | May change without notice | No | ❌ Do not use | **Note**: APIs without tags are treated as `@beta` before v1.0, and `@public` after v1.0. ## Angular Version Support ngDiagram follows Angular's official support policy: **Supported Versions**: Current Angular version + 2 previous major versions (3 versions total) ### Current Support | Angular Version | ngDiagram Support | Angular EOL | | --------------- | ----------------- | ----------- | | Angular 21 | ✅ Supported | May 2027 | | Angular 20 | ✅ Supported | Nov 2026 | | Angular 19 | ✅ Supported | May 2026 | | Angular 18 | ✅ Supported | Nov 2025 | | Angular 17 | ⚠️ Not tested | May 2025 | **Current Requirement**: Angular 18.0.0+ ### Support Timeline When a new Angular version releases: - Added to ngDiagram within 2 months - Oldest supported version deprecated - Deprecated version support ends after 6 months ## Version Support | ngDiagram Version | Support Status | Updates | | ----------------- | -------------- | ---------------------------------- | | Latest (1.x) | Active | Features, bugs, security | | Previous major | Maintenance | Critical bugs, security (6 months) | | Older versions | Unsupported | No updates | ## Semantic Versioning ngDiagram follows [semver](https://semver.org/): - **Major (X.0.0)**: Breaking changes - **Minor (X.Y.0)**: New features, backward-compatible - **Patch (X.Y.Z)**: Bug fixes only See [Deprecation Policy](/docs/policies/deprecation-policy/) for breaking change process. --- ## Deprecation Policy > ngDiagram's policy for deprecating and removing APIs URL: https://ngdiagram.dev/docs/policies/deprecation-policy/ This document outlines ngDiagram's approach to deprecating and removing APIs, features, and functionality. Following a clear deprecation policy ensures you have time to migrate your code and understand when breaking changes will occur. ## Deprecation Timeline When an API, feature, or functionality is marked as deprecated: 1. **Deprecation Notice**: The item is marked with `@deprecated` in the code and announced in the release notes 2. **Deprecation Period**: The deprecated item remains functional for a minimum of: - **1 major version**, OR - **6 months** (whichever comes first) 3. **Removal**: The deprecated item is removed only in a major version release (X.0.0) ### Example Timeline If a feature is deprecated in version 1.2.0: - **Deprecated in**: v1.2.0 (December 2025) - **Still available in**: v1.x.x - **Can be removed in**: v2.0.0 (earliest removal - after 1 major version or 6 months) ## Exceptions Deprecation timeline may be shortened or skipped for: 1. **Security Issues**: Security vulnerabilities require immediate fixes 2. **Critical Bugs**: Bugs that cause data loss or severe functionality issues 3. **Beta/Experimental APIs**: APIs marked with `@beta` or `@experimental` (see [API Stability Policy](/docs/policies/api-stability/)) 4. **Pre-1.0 Releases**: During 0.x.x versions, breaking changes may occur more frequently In these cases, the reason will be clearly communicated in release notes. ## Communication Channels Deprecations are announced through: 1. **Changelog**: All deprecations listed under "Deprecated" section 2. **Release Notes**: Highlighted in GitHub releases 3. **Documentation**: Updated API reference and guides 4. **Console Warnings**: Runtime warnings in development mode 5. **TypeScript**: Type deprecation hints in IDEs ## Migration Support For each deprecated API, we provide: - Clear documentation of the replacement - Migration guide for complex changes - Timeline for removal ## Questions? If you have questions about a specific deprecation: 1. Check the [Changelog](/docs/changelog/) for details 2. Open a [GitHub Discussion](https://github.com/synergycodes/ng-diagram/discussions) --- # Changelog # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Changed ### Added ### Fixed ## [1.3.0] - 2026-08-10 ### Changed - **`NgDiagramService.invalidateMeasurements` is awaitable** — it returns a `Promise` that resolves once the triggered re-measurements have settled, so the invalidated elements' `size`, `measuredPorts` and `measuredLabels` read fresh on the next line. An element that delivers no new measurement (unmounted, zero-size, or unchanged) does not stall the promise. Existing call sites keep working (`void` → `Promise`); ignoring the promise is fine ([#778](https://github.com/synergycodes/ng-diagram/pull/778)) - **Awaitable service methods** — every mutating method on the public services (`NgDiagramModelService`, `NgDiagramNodeService`, `NgDiagramSelectionService`, `NgDiagramClipboardService`, `NgDiagramGroupsService`, `NgDiagramViewportService`) now returns a `Promise` that resolves once the change has been applied to the model, so the next line of code reads the updated state. Read it through `getModel()` or the getter methods (`getNodeById`, `getEdgeById`, `getConnectedEdges`, …) — these are synchronous with the model. The `nodes()`, `edges()` and `metadata()` signals refresh with Angular's change detection, so right after the `await` (and inside diagram event handlers) they can still show the previous state. Existing call sites keep working (`void` → `Promise`). **Do not await these promises from inside a middleware** — the update pipeline is not re-entrant and the await would deadlock; fire-and-forget calls are safe there ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) ### Added - **`NgDiagramDefaultEdgeLabelComponent` is now public** — the component rendering the default edge label chip (`ng-diagram-default-edge-label`) is exported from the package, so custom edge templates can compose it inside `ng-diagram-base-edge-label` and get the default label look (theme-aware chip, hover and selected border highlights) without copying its styles. The hover and selected border highlights now work in any edge template, and the new `--edge-label-border-color-hover` and `--edge-label-border-color-selected` variables override their colors (each falling back to `--edge-label-border-color`, then the matching `--ngd-default-edge-stroke-hover`/`-selected` token). ([#777](https://github.com/synergycodes/ng-diagram/pull/777)) - **Configurable resize sides** — `ng-diagram-node-resize-adornment` accepts an `activeSides` input that limits which sides of the node can be grabbed, for example `[activeSides]="['right', 'bottom']"` for a node anchored at its top-left corner. All four lines keep rendering (they double as the selection frame), but the ones left out are inert and show no resize cursor, and a corner handle renders only when both of its sides are listed. Omitting the input keeps all four sides and corners active, so existing templates are unaffected. The new `Side` type names one of the four sides of a rectangular area; `PortSide` is now an alias of it ([#775](https://github.com/synergycodes/ng-diagram/pull/775)) - **Remove ports from default nodes** – this is now possible to remove ports from default nodes ([#759](https://github.com/synergycodes/ng-diagram/pull/759)) - `waitForMeasurements` option on service methods — `addNodes`, `addEdges`, `updateNode`, `updateNodes`, `updateNodeData`, `updateEdge`, `updateEdges`, `updateEdgeData` on `NgDiagramModelService`, `resizeNode` on `NgDiagramNodeService` and `paste` on `NgDiagramClipboardService` accept `options?: { waitForMeasurements?: boolean }`; when set, the returned promise resolves only after the elements affected by the change have been measured — useful whenever the next step depends on real dimensions (for example `zoomToFit()` or `centerOnNode()`). The option exists only on methods whose changes can trigger measurements; deletions and other model-only operations have nothing to measure, so awaiting the method itself is already enough there. Inside an already active transaction the option is ignored with a console warning — pass `{ waitForMeasurements: true }` to the transaction itself instead ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) - **Customizable runtime-property stripping** – `initializeModel` and `initializeModelAdapter` accept an optional `InitializeModelOptions` parameter to control which properties are stripped on initialization and `toJSON()`. Overriding the defaults can break the diagram — use at your own risk ([#760](https://github.com/synergycodes/ng-diagram/pull/760)) - **Resize snap offset** — new `computeSnapOffsetForNodeSize` and `defaultResizeSnapOffset` options on `SnappingConfig`. Snapped node sizes now follow the sequence `offset + n * snap` per axis, so a node with a 60px header and a 50px vertical resize snap can snap to 60, 110, 160, … instead of 50, 100, 150, …. Defaults to `{ width: 0, height: 0 }` ([#765](https://github.com/synergycodes/ng-diagram/issues/765), [#770](https://github.com/synergycodes/ng-diagram/pull/770)) — thanks [@logan-brd](https://github.com/logan-brd) for the suggestion! 🙏 - **`NgDiagramService.transaction` always returns the commit promise** — the synchronous-callback overload used to return `void`, and for some async callbacks the commit promise was silently discarded; all overloads now return `Promise`, so awaiting a transaction reliably waits for its commit ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) - **Cancel in-progress gestures** – new `NgDiagramService.cancelActiveInteraction()` aborts the active linking, drag, resize, rotate or pan gesture immediately and restores the pre-gesture state: dragged nodes snap back to their initial positions, resized/rotated nodes regain their original geometry, and the temporary edge is discarded (state cleared, document listeners removed, no need to wait for pointer release). Bound to Escape by default via the new `cancelInteraction` shortcut action. The `edgeDrawEnded` event gains a `cancelled` reason, and `nodeDragEnded`/`nodeResizeEnded`/`nodeRotateEnded` gain an optional `cancelReason` field ([#747](https://github.com/synergycodes/ng-diagram/issues/747), [#766](https://github.com/synergycodes/ng-diagram/pull/766)) ### Fixed - **Gesture reliability** — drag, resize, rotate and linking now behave correctly with slow (asynchronous) middlewares and throwing user callbacks: `nodeDragStarted`/`nodeDragEnded`, `nodeResizeStarted`/`nodeResizeEnded` and `nodeRotateStarted`/`nodeRotateEnded` always come in pairs and report the node(s) of their own gesture; a throwing user callback (e.g. connection validation or a grouping check) no longer leaves a gesture stuck — linking cannot become permanently blocked and node measurements are not suppressed afterwards; and deleting a node mid-gesture (while resizing, rotating or linking it) cleans up correctly ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) - **A throwing middleware no longer freezes the diagram** — an uncaught error (or unhandled rejection) inside a middleware used to silently freeze every subsequent update; it now rejects the promise returned by the mutating call and the diagram keeps working ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) - **`waitForMeasurements` no longer resolves early when measurement rounds overlap** — a leftover debounce timer from a previous round could settle a newly started round before its measurements arrived ([#778](https://github.com/synergycodes/ng-diagram/pull/778)) - **Initialization resilience** — an error thrown during initialization (e.g. by a custom `ModelAdapter`) no longer leaves the diagram in a state where nothing gets measured; initialization completes and the error is logged ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) - **`waitForMeasurements` accuracy** — a concurrent unrelated update can no longer make `waitForMeasurements` resolve too early or wait for the wrong elements; the option passed to a nested transaction now logs a warning instead of silently resolving before the updates are applied. As a consequence, a transaction now waits only for measurements caused by its own changes: a transaction with an empty callback resolves immediately, so it no longer works as a barrier that waits for unrelated measurement activity (a pattern some apps used after `invalidateMeasurements`) — `await invalidateMeasurements()` itself instead ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) - **Overlapping transactions no longer lose updates** — a transaction (or a plain service call) issued while a previous un-awaited transaction was still committing used to be silently dropped; every transaction now applies its own updates, and the overlap logs a console warning recommending to await transactions ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) - **Port and edge-label measurements no longer get lost during rapid re-rendering** — fast mount/unmount cycles (e.g. virtualization while panning) could apply port and label updates out of order or drop them entirely when one update failed, leaving stale port positions or labels; a failed batch no longer blocks all future ones either ([#769](https://github.com/synergycodes/ng-diagram/pull/769)) - **`NgDiagramNodeService.resizeNode` now resizes an unselected group** — a programmatic `resizeNode` call targeting a group node used to silently do nothing unless the group was selected; it now applies regardless of selection state, still enforcing the group resize constraints (children containment, minimum node size and resize snapping). Interactive resize behavior is unchanged. Calls that used to silently no-op now apply ([#772](https://github.com/synergycodes/ng-diagram/pull/772)) - **Dangling edges survive persistence** — `initializeModel` and `initializeModelAdapter` no longer strip the authored `sourcePosition`/`targetPosition` of an edge's free endpoint (empty `source`/`target`), and `toJSON()` now includes them in the serialized output, so dangling edges load from a persisted model the same way they work when added at runtime; no more "Invalid edge coordinates detected" for valid dangling edges on init ([#751](https://github.com/synergycodes/ng-diagram/issues/751), [#760](https://github.com/synergycodes/ng-diagram/pull/760)) - **Port `side`/`type` no longer stay stale after a port moves** — recreating a port with the same id in a different place (e.g. toggling a port between a `side: 'left'` and a `side: 'right'` block) now updates `measuredPorts` with the new `side`/`type`, so edges anchor to the correct side; measured `size`/`position` keep coming from the DOM as before. The same applies to edge labels re-registered with a changed `positionOnEdge` ([#750](https://github.com/synergycodes/ng-diagram/issues/750), [#763](https://github.com/synergycodes/ng-diagram/pull/763)) - **Group with children jumping on resize snap** — resizing a group that contains child nodes from the bottom/right edge no longer moves the group when a resize snap is configured ([#765](https://github.com/synergycodes/ng-diagram/issues/765), [#770](https://github.com/synergycodes/ng-diagram/pull/770)) — thanks [@logan-brd](https://github.com/logan-brd) for the issue submission! 🙏 - **Keyboard shortcuts work when a gesture starts with focus outside the diagram** — the resize/rotate handles stop the pointerdown propagation, which used to skip the diagram's focus grab; starting a resize right after clicking an external control (e.g. a toolbar button) left every shortcut dead — in particular Escape could not cancel the gesture. The diagram now takes focus on any pointerdown inside it ([#766](https://github.com/synergycodes/ng-diagram/pull/766)) - **Touch gestures stay exclusive under virtualization** — on touch devices with virtualization enabled, nodes and ports leaving the rendered area during a pan or pinch-zoom no longer reset the internal gesture-exclusivity state, so a stray touch can no longer start a second gesture (drag, resize, linking) in the middle of an active one ([#766](https://github.com/synergycodes/ng-diagram/pull/766)) - **Resize snapping no longer cuts group children** — with `allowResizeBelowChildrenBounds: false`, a snapped group size that would land inside the children bounds now rounds up to the next snap value that still contains the children ([#770](https://github.com/synergycodes/ng-diagram/pull/770)) - **Size changes made right after a resize gesture are no longer overwritten by a stale measurement** — a middleware reverting an invalid resize on `resizeNodeStop`, or a `nodeResizeEnded` handler correcting the size, used to lose when the mouse button was released while still moving; the corrected size now always wins. The resized node is also re-measured once after the gesture, so when CSS (e.g. `min-width`) keeps the element larger than the resized size, the model picks up the element's real size ([#771](https://github.com/synergycodes/ng-diagram/discussions/771), [#776](https://github.com/synergycodes/ng-diagram/pull/776)) — thanks [@logan-brd](https://github.com/logan-brd) for the report and the reproduction! 🙏 - **Releasing the mouse while still moving no longer loses the end of a resize, drag or rotation** — the node used to stop short of where the pointer was released (the faster the release, the bigger the miss; with resize snapping the difference could reach a whole grid step). The release position is now applied as the final update of the gesture, before `nodeDragEnded`/`nodeResizeEnded`/`nodeRotateEnded` fires, so the reported geometry always matches where the pointer stopped ([#771](https://github.com/synergycodes/ng-diagram/discussions/771), [#779](https://github.com/synergycodes/ng-diagram/pull/779)) - **Drawing an edge is cancelled when another touch gesture takes over** — on touch devices, a two-finger pan or pinch started in the middle of drawing an edge used to finish the edge at the other finger's position, sometimes connecting it to a target the user never pointed at; the drawing is now cancelled and `edgeDrawEnded` reports the `cancelled` reason ([#779](https://github.com/synergycodes/ng-diagram/pull/779)) ## [1.2.4] - 2026-06-02 ### Changed - **Improved trackpad gestures support** - panning with a trackpad now smoothly pans the diagram. Pinching defaults to zooming in/out on the diagram ([#717](https://github.com/synergycodes/ng-diagram/pull/717)) ### Fixed - **Panning direction change with Shift** - On MacOS devices pressing the Shift and using the wheel on a mouse didn't change the panning axis ([#717](https://github.com/synergycodes/ng-diagram/pull/717)) ## [1.2.3] - 2026-05-07 ### Changed - **Updated z-index defaults** — `selectedZIndex` changed from `1000` to `10000` to provide more headroom for explicit `zOrder` values; `temporaryEdgeZIndex` changed from `1000` to `2147483647` (max 32-bit int) so the edge being drawn always renders on top ([#697](https://github.com/synergycodes/ng-diagram/pull/697)) ### Added - `invalidateMeasurements(options?)` method on `NgDiagramService` — forces re-measurement of nodes, ports, and edge labels via `ResizeObserver`. Call with no arguments to re-measure the entire diagram, or pass `{ nodes: [...], edges: [...] }` to target specific elements. Invalidating a node also re-measures all its ports. Use this when CSS-only repositioning (class toggles, style bindings) changes port positions without changing sizes, which `ResizeObserver` cannot detect ([#698](https://github.com/synergycodes/ng-diagram/pull/698)) - `initialConnectedEdgesMap` on `MiddlewareContext` — a `Map` from node ID to connected edge IDs (source or target) captured before any modifications. Allows middleware to find edges connected to specific nodes without scanning all edges ([#697](https://github.com/synergycodes/ng-diagram/pull/697)) - **MCP server: inline code snippets** — `search_docs` and `get_doc` now resolve `` and `` tags in documentation pages, inlining the referenced source files directly into tool results. AI assistants see complete, runnable examples without needing access to the source repository ([#699](https://github.com/synergycodes/ng-diagram/pull/699)) ### Fixed - **Z-ordering reworked** — rewrote the z-index assignment middleware and `bringToFront`/`sendToBack` commands, fixing multiple issues: children are now always rendered above their parent group regardless of `zOrder` values, and siblings within a group are correctly re-sorted when `zOrder`, selection, or group membership changes.([#697](https://github.com/synergycodes/ng-diagram/pull/697)) - Fixed ports and edge labels not being measured when a node or edge is removed and re-added with the same ID in the same tick ([#701](https://github.com/synergycodes/ng-diagram/pull/701)) ## [1.2.2] - 2026-04-30 ### Changed - Reworked port and label measurement pipeline to batch DOM reads and writes, reducing layout thrashing during bulk operations ([#671](https://github.com/synergycodes/ng-diagram/pull/671)) ### Added - `getChangedNodeIds()` and `getChangedEdgeIds()` helpers on `MiddlewareHelpers` — return IDs of all nodes/edges with property changes in the current update ([#671](https://github.com/synergycodes/ng-diagram/pull/671)) ### Fixed - Fixed `waitForMeasurements` transaction not tracking port measurements, causing the transaction to resolve before ports were measured ([#685](https://github.com/synergycodes/ng-diagram/pull/685)) - Fixed race condition when applying multiple port changes in a single transaction ([#671](https://github.com/synergycodes/ng-diagram/pull/671)) - Fixed touch input (text fields, dropdowns) inside custom nodes not responding on iOS/iPadOS due to `preventDefault` in the box selection touch handler ([#686](https://github.com/synergycodes/ng-diagram/pull/686)) ## [1.2.1] - 2026-04-21 ### Added - New [Templates](https://www.ngdiagram.dev/docs/templates/) section — we're excited to introduce a dedicated space for production-grade starter kits curated and built by the ngDiagram team. Kicking it off with an interactive [Org Chart](https://github.com/synergycodes/ng-diagram-orgchart) starter kit featuring drag-and-drop reordering, expand/collapse subtrees, sidebar node editing, dynamic layouts, dark/light theme, minimap, and automatic tree layout powered by ELK.js. Clone it, explore the code, and use it as a launchpad for your own app! 🚀 ([#667](https://github.com/synergycodes/ng-diagram/pull/667)) ### Fixed - Fixed linking state not being cleared when edge drawing fails before creating a temporary edge (e.g., starting from a target port), which permanently blocked all subsequent edge drawing ([#666](https://github.com/synergycodes/ng-diagram/pull/666)) ## [1.2.0] - 2026-04-20 ### Added - `deferNodeUpdates` input on `NgDiagramMinimapComponent` — freezes minimap node positions during drag, resize, and rotation operations, updating only when the interaction ends. Use this to eliminate minimap overhead in large diagrams ([#638](https://github.com/synergycodes/ng-diagram/pull/638)) - `watermarkPosition` property on `FlowConfig` — allows configuring the watermark corner position via `NgDiagramPanelPosition`, with automatic collision avoidance when a panel occupies the same corner ([#621](https://github.com/synergycodes/ng-diagram/issues/621), [#652](https://github.com/synergycodes/ng-diagram/pull/652)) — thanks [@jimmeryn](https://github.com/jimmeryn) for the issue submission! 🙏 - `setViewport(x, y, scale)` method on `NgDiagramViewportService` — sets absolute viewport position and scale in a single call, enabling custom-anchor `zoomToFit` implementations ([#591](https://github.com/synergycodes/ng-diagram/discussions/591), [#653](https://github.com/synergycodes/ng-diagram/pull/653)) — thanks [@MeMeMax](https://github.com/MeMeMax) for the discussion that led to this! 🙏 - Generic type parameters on `NgDiagramModelService` getter methods (`getNodeById`, `getEdgeById`, `getConnectedNodes`, `getConnectedEdges`, `getChildren`, `getChildrenNested`, `getParentHierarchy`, `getOverlappingNodes`, `getNodesInRange`, `getNearestNodeInRange`, `getNodeEnds`) — eliminates the need for `as` casts when accessing typed `node.data` or `edge.data` ([#654](https://github.com/synergycodes/ng-diagram/pull/654)) - Exported `DataObject` type from public API ([#654](https://github.com/synergycodes/ng-diagram/pull/654)) - `edgeDrawEnded` event — fires on every linking gesture completion (success and cancel), with source, drop position, and cancel reason (`noTarget`, `invalidConnection`, `invalidTarget`) ([#637](https://github.com/synergycodes/ng-diagram/issues/637), [#655](https://github.com/synergycodes/ng-diagram/pull/655)) — thanks [@ninjapiratica](https://github.com/ninjapiratica) for the inspiration! 🙏 - `selectNodeOnPortPress` option on `LinkingConfig` — when `false`, port press only initiates linking without selecting the parent node. Default `true` preserves existing behavior ([#637](https://github.com/synergycodes/ng-diagram/issues/637), [#655](https://github.com/synergycodes/ng-diagram/pull/655)) — thanks [@ninjapiratica](https://github.com/ninjapiratica) for the issue submission! 🙏 ### Changed - Minimap now caches `MinimapNodeData` by `Node` object reference, reusing cached data for unchanged nodes and reducing per-frame computation during interactions ([#638](https://github.com/synergycodes/ng-diagram/pull/638)) ### Fixed - `initializeModel` can now be safely called inside reactive contexts (`computed`, `effect`, `linkedSignal`) without throwing NG0602 ([#608](https://github.com/synergycodes/ng-diagram/issues/608), [#622](https://github.com/synergycodes/ng-diagram/pull/622)) - Fixed palette drag preview not rendering when an ancestor element has `overflow: hidden` ([#624](https://github.com/synergycodes/ng-diagram/pull/624)) - Fixed port position not updating when `side` or `originPoint` input changes at runtime ([#647](https://github.com/synergycodes/ng-diagram/pull/647)) — thanks [@ninjapiratica](https://github.com/ninjapiratica) for the issue submission! 🙏 - Fixed `waitForMeasurements` incurring a 2-second timeout when a transaction includes no-op updates ([#648](https://github.com/synergycodes/ng-diagram/pull/648)) - Fixed node position not being snapped when node snapping is enabled and node is dropped from palette or pasted onto the canvas ([#649](https://github.com/synergycodes/ng-diagram/pull/649)) - Fixed port hitbox (`::before` pseudo-element) not being centered on the port ([#650](https://github.com/synergycodes/ng-diagram/pull/650)) - `updateNodeData` and `updateEdgeData` now accept interfaces and union types — relaxed generic constraint from `Record | undefined` to `DataObject` ([#654](https://github.com/synergycodes/ng-diagram/pull/654)) ### Deprecated - `edgeDrawn` event — use `edgeDrawEnded` instead, which fires for both successful and cancelled draws. `edgeDrawn` continues to fire for backward compatibility ([#655](https://github.com/synergycodes/ng-diagram/pull/655)) ## [1.1.2] - 2026-03-17 ### Changed - Updated MCP server README with ASCII diagrams, Windows setup instructions, and streamlined documentation ([#610](https://github.com/synergycodes/ng-diagram/pull/610)) - Added MCP Server documentation page and updated roadmap status ([#610](https://github.com/synergycodes/ng-diagram/pull/610)) ### Fixed - Fixed broken internal documentation URLs in Configuration, Edges, Changelog, and Policies pages ([#610](https://github.com/synergycodes/ng-diagram/pull/610)) - Exported missing `PanningActionState` and `SelectionActionState` types from public API ([#610](https://github.com/synergycodes/ng-diagram/pull/610)) ## [1.1.1] - 2026-03-12 ### Added - New MCP server for enhanced AI-assisted development with MiniSearch indexing and API symbol search ([#590](https://github.com/synergycodes/ng-diagram/pull/590)) ### Fixed - Fixed documentation pages being difficult to read on mobile devices due to excessive margins ([#605](https://github.com/synergycodes/ng-diagram/pull/605) - thanks [@martinboue](https://github.com/martinboue) for reporting this 💪) ## [1.1.0] - 2026-02-27 ### Added - Zoom support in [Shortcut Manager](https://www.ngdiagram.dev/docs/guides/shortcut-manager/) - configurable keyboard shortcuts (`keyboardZoomIn`, `keyboardZoomOut`) and wheel-based zoom with modifier keys (`zoom`) via new `WheelOnlyShortcutDefinition` ([#571](https://github.com/synergycodes/ng-diagram/pull/571)) - Start and end lifecycle events for node interactions: [`nodeDragStarted`](https://www.ngdiagram.dev/docs/api/components/ngdiagramcomponent/#nodedragstarted)/[`nodeDragEnded`](https://www.ngdiagram.dev/docs/api/components/ngdiagramcomponent/#nodedragended), [`nodeResizeStarted`](https://www.ngdiagram.dev/docs/api/components/ngdiagramcomponent/#noderesizestarted)/[`nodeResizeEnded`](https://www.ngdiagram.dev/docs/api/components/ngdiagramcomponent/#noderesizeended), [`nodeRotateStarted`](https://www.ngdiagram.dev/docs/api/components/ngdiagramcomponent/#noderotatestarted)/[`nodeRotateEnded`](https://www.ngdiagram.dev/docs/api/components/ngdiagramcomponent/#noderotateended) ([#572](https://github.com/synergycodes/ng-diagram/pull/572)) - [`selectionGestureEnded`](https://www.ngdiagram.dev/docs/api/types/events/selectiongestureendedevent) event - fires on pointerup after a selection gesture completes (object click, box selection, or select-all), providing the currently selected nodes and edges. Use this for actions that should run after selection is done, such as showing toolbars or updating panels ([#582](https://github.com/synergycodes/ng-diagram/pull/582)) - [Absolute edge label positioning](https://www.ngdiagram.dev/docs/guides/edges/labels/#absolute-positioning) - `positionOnEdge` now accepts pixel-based strings (`'30px'`, `'-20px'`) in addition to relative numbers (0–1). Negative pixel values measure from the target end ([#580](https://github.com/synergycodes/ng-diagram/pull/580)) - Default edge now supports `positionOnEdge` data property to control [label positioning](https://www.ngdiagram.dev/docs/guides/edges/labels/#using-labels-in-default-edges) (defaults to `0.5`) ([#581](https://github.com/synergycodes/ng-diagram/pull/581)) - [`nodeIds`](https://www.ngdiagram.dev/docs/api/internals/draggingactionstate/#nodeids) property on `DraggingActionState` containing IDs of all nodes participating in the drag operation ([#572](https://github.com/synergycodes/ng-diagram/pull/572)) - [`movementStarted`](https://www.ngdiagram.dev/docs/api/internals/draggingactionstate/#movementstarted) property on `DraggingActionState` that indicates whether pointer movement exceeded the drag threshold before entering the dragging state ([#569](https://github.com/synergycodes/ng-diagram/pull/569)) - [`initializeModelAdapter`](https://www.ngdiagram.dev/docs/api/utilities/initializemodeladapter) function for initializing custom [`ModelAdapter`](https://www.ngdiagram.dev/docs/api/types/model/modeladapter/) implementations. Use this when providing a custom adapter (e.g., backed by localStorage, NgRx, or an external store). The function prepares the adapter for use with ng-diagram. `initializeModel` continues to create the default `SignalModelAdapter` from `Partial` data. ([#586](https://github.com/synergycodes/ng-diagram/pull/586)) ### Changed - [Custom Model example](https://www.ngdiagram.dev/docs/examples/custom-model) now uses `initializeModelAdapter` and improved `LocalStorageModelAdapter` with `Partial` and `ModelChanges` types ([#586](https://github.com/synergycodes/ng-diagram/pull/586)) ### Fixed - Added explicit `ModelAdapter` return type to `initializeModel()` to prevent TypeScript errors when building with `declaration: true` ([#573](https://github.com/synergycodes/ng-diagram/pull/573)) (thanks [@MeMeMax](https://github.com/MeMeMax) for reporting this 💪) - Edge labels vanishing permanently after model reinitialization ([#585](https://github.com/synergycodes/ng-diagram/pull/585)) - Edge labels not being measured when loading a model with pre-existing edge points (e.g., from localStorage) ([#586](https://github.com/synergycodes/ng-diagram/pull/586)) - `selectionChanged` event now fires after paste action, ensuring selection state stays in sync ([#584](https://github.com/synergycodes/ng-diagram/pull/584)) - Fixed compatibility issue with Angular 18 in default edge and minimap components ([#587](https://github.com/synergycodes/ng-diagram/pull/587)) ## [1.0.0] - 2026-02-06 🎉 **We've reached v1.0!** This milestone marks a stable, feature-complete library for building interactive diagrams in Angular. We'd love to hear your feedback — share your thoughts in our [GitHub Discussions](https://github.com/synergycodes/ng-diagram/discussions) or join us on [Discord](https://discord.gg/FDMjRuarFb)! ### Added - [Virtualization](https://www.ngdiagram.dev/docs/guides/virtualization/) for performance optimization on large diagrams - renders only visible elements within the viewport ([#513](https://github.com/synergycodes/ng-diagram/pull/513)) - [Minimap component](https://www.ngdiagram.dev/docs/guides/minimap/) for bird's-eye view navigation of diagrams ([#537](https://github.com/synergycodes/ng-diagram/pull/537)) - [Touch Gestures](https://www.ngdiagram.dev/docs/guides/touch-gestures/) documentation article explaining touch device support ([#530](https://github.com/synergycodes/ng-diagram/pull/530)) - [`nodeDraggingEnabled`](https://www.ngdiagram.dev/docs/api/types/configuration/flowconfig/#nodedraggingenabled) config option and per-node [`draggable`](https://www.ngdiagram.dev/docs/api/types/model/simplenode/#draggable) property to disable node dragging via mouse and keyboard ([#539](https://github.com/synergycodes/ng-diagram/pull/539) - thanks for raising this [@advayumare](https://github.com/advayumare) 💪) - [`stopLinking`](https://www.ngdiagram.dev/docs/api/services/ngdiagramservice/#stoplinking) method to cancel programmatic linking action on touch devices ([#524](https://github.com/synergycodes/ng-diagram/pull/524)) ### Changed - Improved diagram panning on Mac with Figma-like trackpad experience ([#498](https://github.com/synergycodes/ng-diagram/pull/498)) ### Fixed - Fixed keyboard shortcuts not working when CapsLock is enabled. Letter key shortcuts (e.g., Ctrl+C, Ctrl+V, Ctrl+A) now match case-insensitively ([#546](https://github.com/synergycodes/ng-diagram/pull/546)) - Fixed model reinitialization issues: viewport dimensions being undefined (causing `zoomToFit` and linking failures) and missing `_internalId` for nodes (causing Angular tracking issues) ([#523](https://github.com/synergycodes/ng-diagram/pull/523)) - `toJSON()` now strips readonly computed fields (`measuredPorts`, `measuredBounds`, `computedZIndex`) from serialized nodes and (`measuredLabels`, `computedZIndex`) from serialized edges. These are system-computed values that should be re-derived from the DOM on load, not persisted ([#545](https://github.com/synergycodes/ng-diagram/pull/545)) ## [0.9.1] - 2026-01-08 ### Fixed - Fixed resizing group with rotated child nodes ([#504](https://github.com/synergycodes/ng-diagram/pull/504)) - Fixed error on drag&drop HTML object (not palette node) to the diagram ([#510](https://github.com/synergycodes/ng-diagram/pull/510)) ## [0.9.0] - 2025-12-12 ### Added - API stability and deprecation policy documentation with defined stability levels and Angular version support matrix ([#462](https://github.com/synergycodes/ng-diagram/pull/462)) - API Extractor integration for automated breaking change detection with CI validation ([#462](https://github.com/synergycodes/ng-diagram/pull/462)) - Landing page diagram example in documentation ([#464](https://github.com/synergycodes/ng-diagram/pull/464)) - [Floating edges](https://www.ngdiagram.dev/docs/guides/edges/floating-edges/) for edges with no ports specified ([#465](https://github.com/synergycodes/ng-diagram/pull/465)) - [Ports with custom content](https://www.ngdiagram.dev/docs/guides/nodes/ports/#custom-content) - ports can now render custom Angular components instead of simple circles ([#468](https://github.com/synergycodes/ng-diagram/pull/468)) - [`hideWatermark`](https://www.ngdiagram.dev/docs/api/types/configuration/flowconfig/#hidewatermark) config option to hide the ngDiagram watermark via diagram configuration ([#469](https://github.com/synergycodes/ng-diagram/pull/469)) - Expose [`computePartsBounds`](https://www.ngdiagram.dev/docs/api/services/ngdiagrammodelservice/#computepartsbounds) method in API ([#477](https://github.com/synergycodes/ng-diagram/pull/477)) - Added overload to [`getOverlappingNodes`](https://www.ngdiagram.dev/docs/api/services/ngdiagrammodelservice/#getoverlappingnodes) to accept `Node` object in addition to node ID, supporting cases when the node object has newer data than the node in state (e.g., within middlewares) ([#486](https://github.com/synergycodes/ng-diagram/pull/486)) - [`modelActionTypes`](https://www.ngdiagram.dev/docs/api/types/middleware/middlewarecontext/#modelactiontypes) property on `MiddlewareContext` - an array containing all action types that triggered the middleware execution. For transactions, this includes the transaction name followed by all action types from commands executed within the transaction. For single commands, this is a single-element array ([#489](https://github.com/synergycodes/ng-diagram/pull/489)) - Add grab cursor on background when panning ([#479](https://github.com/synergycodes/ng-diagram/pull/479)) - Disable diagram panning by config [`viewportPanningEnabled`](https://www.ngdiagram.dev/docs/api/types/configuration/flowconfig/#viewportpanningenabled) ([#480](https://github.com/synergycodes/ng-diagram/pull/480)) - [Async transaction](https://www.ngdiagram.dev/docs/guides/transactions/#async-transactions) support - transactions now accept async callbacks, allowing asynchronous operations like data fetching before adding or modifying the diagram ([#493](https://github.com/synergycodes/ng-diagram/pull/493)) - [`waitForMeasurements`](https://www.ngdiagram.dev/docs/guides/transactions/#waitformeasurements) transaction option - ensures the transaction promise resolves only after all DOM measurements (node sizes, port positions, edge labels) are complete. Useful when performing viewport operations like `zoomToFit()` after adding or modifying elements ([#493](https://github.com/synergycodes/ng-diagram/pull/493)) ### Changed - Standardized error messages across the ng-diagram library ([#463](https://github.com/synergycodes/ng-diagram/pull/463)) ### Fixed - Fixed misleading error when destroying `NgDiagramModelService` after engine is already destroyed. The error incorrectly reported "Library engine not initialized yet". Now the service checks if engine is available and skips listener cleanup if already destroyed. ([#466](https://github.com/synergycodes/ng-diagram/issues/466) - thanks for finding this [@Filipstrozik](https://github.com/Filipstrozik) 💪) - Fixed keyboard movement of nodes with arrow keys when using large snap step values ([#461](https://github.com/synergycodes/ng-diagram/pull/461)) - Fixed drag-snapping issues with different snapping configurations. The issue still occurred when dragging multiple nodes at the same hierarchy level (i.e., nodes without groups) ([#470](https://github.com/synergycodes/ng-diagram/pull/470)) - Fixed incorrectly computed measuredBounds for nodes ([#486](https://github.com/synergycodes/ng-diagram/pull/486)) - Fixed missing edge arrowheads in Safari. Safari doesn't support `context-stroke` in SVG markers, so a fallback using inline markers with `currentColor` substitution is now used for Safari compatibility ([#487](https://github.com/synergycodes/ng-diagram/pull/487)) - Fixed copy-paste retaining `groupId` when pasting nodes outside their group. Now `groupId` is only preserved when the group is also copied, with the reference updated to the new group's ID ([#491](https://github.com/synergycodes/ng-diagram/pull/491)) - Fixed zoom to fit not working correctly on diagram initialization ([#492](https://github.com/synergycodes/ng-diagram/pull/492)) - Fixed bullet points styles in the documentation ([#494](https://github.com/synergycodes/ng-diagram/pull/494)) ### Deprecated - `modelActionType` property on `MiddlewareContext` is now deprecated. Use `modelActionTypes` instead, which supports multiple actions from transactions. ([#489](https://github.com/synergycodes/ng-diagram/pull/489)) ## [0.8.1] - 2025-11-20 ### Added - Tailwind CSS example in documentation ([#436](https://github.com/synergycodes/ng-diagram/pull/436)) ### Fixed - Fixed drag snapping with different snapping config issue ([#451](https://github.com/synergycodes/ng-diagram/pull/451)) - Fixed ungrouping when dragging node selected with group ([#446](https://github.com/synergycodes/ng-diagram/pull/446)) - Fixed shortcut capture, events, and collision with inputs ([#447](https://github.com/synergycodes/ng-diagram/pull/447)) - Fixed zIndex assignment ([#449](https://github.com/synergycodes/ng-diagram/pull/449)) - Fixed Layout in documentation ([#438](https://github.com/synergycodes/ng-diagram/pull/438)) - Fixed Reactive config in background ([#445](https://github.com/synergycodes/ng-diagram/pull/445)) - Fixed Example zomming in documentation ([#448](https://github.com/synergycodes/ng-diagram/pull/448)) ## [0.8.0] - 2025-11-07 🎉 **This is our first stable release!** We've graduated from beta and are proud to present a production-ready version. ### Added - Zoom to fit feature with configurable padding and option to automatically apply on model initialization ([#386](https://github.com/synergycodes/ng-diagram/pull/386)) - Environment layer for unified environment - related functionalities ([#350](https://github.com/synergycodes/ng-diagram/pull/350)) - Helpers for node relationships and traversal ([#395](https://github.com/synergycodes/ng-diagram/pull/395)) - Box selection for selecting multiple nodes at once ([#374](https://github.com/synergycodes/ng-diagram/pull/374)) - Implemented multiple event hooks for ng-diagram ([#387](https://github.com/synergycodes/ng-diagram/pull/387)) - Configurable built-in grid background ([#397](https://github.com/synergycodes/ng-diagram/pull/397)) - Configurable Shortcut Manager ([#398](https://github.com/synergycodes/ng-diagram/pull/398)) - Improved collision detection for rotated nodes and introduced `measuredBounds` property to Node interface ([#407](https://github.com/synergycodes/ng-diagram/pull/407)) - Improved diagram navigation experience - smooth panning ([#417](https://github.com/synergycodes/ng-diagram/pull/417)) - Snapping documentation article explaining node snapping functionality ([#414](https://github.com/synergycodes/ng-diagram/pull/414)) - Diagram configuration documentation article ([#419](https://github.com/synergycodes/ng-diagram/pull/419)) - Microsnapping for angle adjustments ([#404](https://github.com/synergycodes/ng-diagram/pull/404)) - Background guide documentation article ([#400](https://github.com/synergycodes/ng-diagram/pull/400)) - Label support for default edges ([#376](https://github.com/synergycodes/ng-diagram/pull/376)) - Default node exported for public use ([#377](https://github.com/synergycodes/ng-diagram/pull/377)) - Center on node and center on rect command handlers for programmatic viewport control ([#371](https://github.com/synergycodes/ng-diagram/pull/371)) ### Changed - Renamed 'internal' folder to 'guides' in documentation and updated all related links ([#358](https://github.com/synergycodes/ng-diagram/pull/358)) - Improved documentation examples structure for consistency ([#360](https://github.com/synergycodes/ng-diagram/pull/360)) - Unified documentation styles ([#357](https://github.com/synergycodes/ng-diagram/pull/357)) - Redirected documentation root to quick-start page and reordered Intro articles ([#370](https://github.com/synergycodes/ng-diagram/pull/370)) - Changed default behavior for resizable and rotatable properties on diagram nodes ([#374](https://github.com/synergycodes/ng-diagram/pull/374)) - Complete API documentation reorganization and improvements ([#421](https://github.com/synergycodes/ng-diagram/pull/421)) - Better configuration for resizable and rotatable properties on diagram nodes ([#374](https://github.com/synergycodes/ng-diagram/pull/374)) ### Fixed - Fixed `NgDiagramModelService.addEdges` not redrawing diagram ([#369](https://github.com/synergycodes/ng-diagram/pull/369)) - Fixed download image example not working in Angular 18 ([#375](https://github.com/synergycodes/ng-diagram/pull/375)) - Fixed model synchronization issues ([#372](https://github.com/synergycodes/ng-diagram/pull/372)) - Fixed base edge label component name and maintained backward compatibility with deprecated `BaseEdgeLabelComponent` alias ([#368](https://github.com/synergycodes/ng-diagram/pull/368)) - Fixed ESLint errors in Angular templates ([#367](https://github.com/synergycodes/ng-diagram/pull/367)) - Fixed multiple documentation issues and broken API links ([#356](https://github.com/synergycodes/ng-diagram/pull/356)) - Fixed post-release Angular 18 issues ([#355](https://github.com/synergycodes/ng-diagram/pull/355)) - Resolved context menu example to enable copying multiple nodes - Fixed diagram capturing all keyboard events on page ([#444](https://github.com/synergycodes/ng-diagram/pull/444)) - Fixed zIndex assignment for added nodes and multiple selection of group and children ([#449](https://github.com/synergycodes/ng-diagram/pull/449)) ## [0.4.0-beta.5] - 2025-10-14 Initial tagged release. [unreleased]: https://github.com/synergycodes/ng-diagram/compare/v1.3.0...HEAD [1.3.0]: https://github.com/synergycodes/ng-diagram/compare/v1.2.4...v1.3.0 [1.2.4]: https://github.com/synergycodes/ng-diagram/compare/v1.2.3...v1.2.4 [1.2.3]: https://github.com/synergycodes/ng-diagram/compare/v1.2.2...v1.2.3 [1.2.2]: https://github.com/synergycodes/ng-diagram/compare/v1.2.1...v1.2.2 [1.2.1]: https://github.com/synergycodes/ng-diagram/compare/v1.2.0...v1.2.1 [1.2.0]: https://github.com/synergycodes/ng-diagram/compare/v1.1.2...v1.2.0 [1.1.2]: https://github.com/synergycodes/ng-diagram/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/synergycodes/ng-diagram/compare/v1.1.0...v1.1.1 [1.1.0]: https://github.com/synergycodes/ng-diagram/compare/v1.0.0...v1.1.0 [1.0.0]: https://github.com/synergycodes/ng-diagram/compare/v0.9.1...v1.0.0 [0.9.1]: https://github.com/synergycodes/ng-diagram/compare/v0.9.0...v0.9.1 [0.9.0]: https://github.com/synergycodes/ng-diagram/releases/tag/v0.9.0 [0.8.1]: https://github.com/synergycodes/ng-diagram/releases/tag/v0.8.1 [0.8.0]: https://github.com/synergycodes/ng-diagram/releases/tag/v0.8.0 [0.4.0-beta.5]: https://github.com/synergycodes/ng-diagram/releases/tag/v0.4.0-beta.5