Custom Ports
This example demonstrates how to create custom ports in ngDiagram by customizing their appearance and behavior.
Key Concepts
Section titled “Key Concepts”-
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
<ng-diagram-port>
component, which supports various attributes. -
Node Template Customization: The
NodeComponent
template defines the arrangement and styling of ports within each node. Ports are stored in themeasuredPorts
property, which is read-only and cannot be modified in the node definition. -
Port Binding: Ports have a
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
property to set their placement. To further customize port placement, you can use CSS styling.
Example Overview
Section titled “Example Overview”Two nodes are rendered, each with four ports (left, top, right, bottom).
- The right port of the second node uses a data property to apply red background.
- The top port has a changed inline position in both nodes.
- The left port is customized with styles based on class property.
Example Code
Section titled “Example Code”Node Template HTML
Section titled “Node Template HTML”<div class="node"> <div class="node-header"> <span>{{ node().data.name }}</span> </div> <div class="node-body"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. </div></div><ng-diagram-port id="port-left" type="target" side="left" [style.backgroundColor]="node().data.leftPortColor"/><ng-diagram-port id="port-top" type="source" side="top" style="top: 15px; left: 200px"/><ng-diagram-port id="port-right" class="some-custom-class" type="both" side="right"/>
Custom Port CSS
Section titled “Custom Port CSS”20 collapsed lines
:host { display: flex; width: 100%; height: 100%; background-color: white; border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
.node { display: flex; flex-direction: column; padding: 4px 8px; border: 1px solid var(--ngd-node-stroke-primary-default); border-radius: 4px; background-color: var(--ngd-node-bg-primary-default);
&-body { font-size: 12px; } }
.some-custom-class { // Override default styles using port CSS custom properties --ngd-port-border-size: 0px;
// Custom styles and adding SVG background width: 15px; height: 16px; background: url('data:image/svg+xml;utf8,<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><polygon points="7.5,0 9,6 15,6 10.5,9 12,15 7.5,12 3,15 4.5,9 0,6 6,6" fill="%239140ff"/></svg>'); background-repeat: no-repeat; }}
- Assign a custom CSS class to a node’s port via node data.
- Style the port using CSS for unique shapes or hover effects.
- Override CSS variables used in
NgDiagramPortComponent
. - Use inline styles for quick adjustments.
import '@angular/compiler';import { Component } from '@angular/core';import { initializeModel, NgDiagramComponent, NgDiagramModelService, type NgDiagramConfig, type NgDiagramNodeTemplateMap,} from 'ng-diagram';import { NodeComponent } from './node/node.component';
@Component({ selector: 'custom-ports-example', imports: [NgDiagramComponent], template: ` <div class="not-content diagram"> <ng-diagram [model]="model" [config]="config" [nodeTemplateMap]="nodeTemplateMap" /> </div> `, styleUrl: './custom-ports-example.component.scss', providers: [NgDiagramModelService],})export class CustomPortsExampleComponent { nodeTemplateMap: NgDiagramNodeTemplateMap = new Map([ ['myType', NodeComponent], ]);
config = { edgeRouting: { defaultRouting: 'orthogonal' }, zoom: { max: 3, }, zIndex: { edgesAboveConnectedNodes: true, }, } satisfies NgDiagramConfig;
model = initializeModel({ nodes: [ { id: '1', position: { x: 100, y: 100 }, type: 'myType', data: { name: 'Custom Node', }, }, { id: '2', position: { x: 300, y: 200 }, type: 'myType', data: { name: 'Custom Node 2', leftPortColor: 'red', }, }, ], edges: [ { id: '1', source: '1', target: '2', data: {}, sourcePort: 'port-bottom', targetPort: 'port-left', sourceArrowhead: 'ng-diagram-arrow', }, { id: '2', source: '2', target: '1', data: {}, sourcePort: 'port-top', targetPort: 'port-right', sourceArrowhead: 'ng-diagram-arrow', }, { id: '3', source: '2', target: '1', data: {}, sourcePort: 'port-right', targetPort: 'port-left', sourceArrowhead: 'ng-diagram-arrow', }, ], metadata: { viewport: { x: 0, y: 0, scale: 1 } }, });}
import '@angular/compiler';import { Component } from '@angular/core';import { NgDiagramModelService, provideNgDiagram } from 'ng-diagram';import { CustomPortsExampleComponent } from './custom-ports-example.component';
@Component({ selector: 'custom-ports-wrapper', imports: [CustomPortsExampleComponent], template: ` <custom-ports-example></custom-ports-example> `, styles: [ ` :host { flex: 1; display: flex; position: relative; } `, ], providers: [NgDiagramModelService, provideNgDiagram()],})export class CustomPortsWrapperComponent {}
import { Component, input, model } from '@angular/core';import { NgDiagramPortComponent, type NgDiagramNodeTemplate, type Node,} from 'ng-diagram';
@Component({ selector: 'node', imports: [NgDiagramPortComponent], templateUrl: './node.component.html', styleUrls: ['./node.component.scss'],})export class NodeComponent implements NgDiagramNodeTemplate<Data> { text = model<string>(''); node = input.required<Node<Data>>();}
type Data = { name: string; leftPortColor: string;};
<div class="node"> <div class="node-header"> <span>{{ node().data.name }}</span> </div> <div class="node-body"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. </div></div><ng-diagram-port id="port-left" type="target" side="left" [style.backgroundColor]="node().data.leftPortColor"/><ng-diagram-port id="port-top" type="source" side="top" style="top: 15px; left: 200px"/><ng-diagram-port id="port-right" class="some-custom-class" type="both" side="right"/>
:host { width: 100%; height: 100%;}
.diagram { flex: 1; display: flex; height: 20rem; font-family: 'Poppins', sans-serif;}
:host { display: flex; width: 100%; height: 100%; background-color: white; border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
.node { display: flex; flex-direction: column; padding: 4px 8px; border: 1px solid var(--ngd-node-stroke-primary-default); border-radius: 4px; background-color: var(--ngd-node-bg-primary-default);
&-body { font-size: 12px; } }
.some-custom-class { // Override default styles using port CSS custom properties --ngd-port-border-size: 0px;
// Custom styles and adding SVG background width: 15px; height: 16px; background: url('data:image/svg+xml;utf8,<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><polygon points="7.5,0 9,6 15,6 10.5,9 12,15 7.5,12 3,15 4.5,9 0,6 6,6" fill="%239140ff"/></svg>'); background-repeat: no-repeat; }}