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 extending NgDiagramNodeTemplate
and implementing CustomNodeComponent
.
7 collapsed lines
import { Component, input } from '@angular/core';import { NgDiagramNodeSelectedDirective, type NgDiagramNodeTemplate, NgDiagramPortComponent, type Node,} from 'ng-diagram';
@Component({ selector: 'node', imports: [NgDiagramPortComponent], // Add selection directive to automatically apply selection styles. // Note: The host element must have display: block or flex for selection box-shadow to render properly hostDirectives: [ { directive: NgDiagramNodeSelectedDirective, inputs: ['node'] }, ], template: ` <div class="node"> <div class="node-header">Header</div> <div class="node-content"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. </div>
<!-- Left port for connections --> <ng-diagram-port [side]="'left'" [type]="'both'" [id]="'port-left'" />
<!-- Right port for connections --> <ng-diagram-port [side]="'right'" [type]="'both'" [id]="'port-right'" /> </div> `, styleUrl: './node.component.scss',})export class CustomNodeComponent implements NgDiagramNodeTemplate { node = input.required<Node>();}
Registering Custom Node Types
Section titled “Registering Custom Node Types”To register a custom node, you need to add it to the nodeTemplateMap
.
The map associates a string key, such as myType
, with a value like CustomNodeComponent
, which is a reference to an Angular component class.
export class CustomNodeWrapperComponent { nodeTemplateMap: NgDiagramNodeTemplateMap = new Map([ ['myType', CustomNodeComponent], ]);
After registering, you need to pass the map to the ngDiagram
component.
<ng-diagram [model]="model" [config]="config" [nodeTemplateMap]="nodeTemplateMap" />
Setting the Proper Type for the Node
Section titled “Setting the Proper Type for the Node”Assigning the 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.
model = initializeModel({ nodes: [ { id: '1', position: { x: 100, y: 100 }, type: 'myType', data: {}, }, ],
Custom Appearance
Section titled “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.
Using Node Definition Properties
Section titled “Using Node Definition Properties”By using this approach—creating custom node components that implement 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:
interface SimpleNode<T = any> { 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<T>['id']; // The id of the parent node.}
Handling Interactive Elements
Section titled “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 inputdata-no-drag="true"
- Prevents the node itself from being dragged when the user clicks and drags on the input
<!-- Input that prevents both diagram panning and node dragging --><input type="text" data-no-pan="true" data-no-drag="true" placeholder="Type here" />
Extending with NgDiagram Functionalities
Section titled “Extending with NgDiagram Functionalities”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.