Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
0f6a428
Virtualization PoC
piotrblaszczyk Dec 1, 2025
53713fb
Merge branch 'main' of https://github.com/synergycodes/angularflow in…
piotrblaszczyk Dec 11, 2025
78f94a3
fix logs
piotrblaszczyk Dec 11, 2025
680e790
performance improvements
piotrblaszczyk Dec 12, 2025
3c66bb4
Merge branch 'main' of https://github.com/synergycodes/angularflow in…
piotrblaszczyk Dec 12, 2025
f81b9bc
Fix linking
piotrblaszczyk Dec 16, 2025
79a22ba
Fix padding for virtual viewport
piotrblaszczyk Dec 16, 2025
e054ad2
Add zoom tracking to the render strategy with debounced updates
piotrblaszczyk Dec 16, 2025
e166a4a
Fix unit-tests
piotrblaszczyk Dec 16, 2025
1660d6e
fix panning
piotrblaszczyk Dec 16, 2025
c94f907
Increase viewport padding and support quick panning
piotrblaszczyk Dec 16, 2025
757b62f
Fix performance issue during selection
piotrblaszczyk Dec 16, 2025
2a1ddf8
Improve implementation
piotrblaszczyk Dec 18, 2025
a5006e2
Optimize algorithm to find nearest nodes to eliminate lag during linking
piotrblaszczyk Dec 18, 2025
40f8806
Move render method to the dedicated base class
piotrblaszczyk Dec 18, 2025
57f6a60
Refactor internal updater
piotrblaszczyk Dec 19, 2025
7202ed9
Refactor
piotrblaszczyk Jan 7, 2026
36d8f88
Refactor
piotrblaszczyk Jan 7, 2026
3bab8e8
Improve init
piotrblaszczyk Jan 7, 2026
341c006
disable zoomToFit when virtualization is enabled
piotrblaszczyk Jan 8, 2026
5affd97
Improve implementation - remove buffer Filling and introduce zoomTrac…
piotrblaszczyk Jan 8, 2026
71d8e32
optimization
piotrblaszczyk Jan 9, 2026
553f082
Fix viewport calculation
piotrblaszczyk Jan 12, 2026
dce3856
Refactor
piotrblaszczyk Jan 12, 2026
9cd0308
Merge pull request #517 from synergycodes/virtualization-optimization
piotrblaszczyk Jan 12, 2026
820f501
improvements
piotrblaszczyk Jan 13, 2026
1315bff
Merge branch 'main' of https://github.com/synergycodes/angularflow in…
piotrblaszczyk Jan 13, 2026
e8dc139
Fix unit-tests
piotrblaszczyk Jan 14, 2026
2207de8
Update public API
piotrblaszczyk Jan 15, 2026
956bf12
update public API file
piotrblaszczyk Jan 15, 2026
7fa51cf
Add the article about virtualization to the docs
piotrblaszczyk Jan 15, 2026
1d09228
Fix doc
piotrblaszczyk Jan 15, 2026
75d11a7
add missing docs
piotrblaszczyk Jan 15, 2026
e883309
Merge branch 'main' of https://github.com/synergycodes/angularflow in…
piotrblaszczyk Jan 15, 2026
e7ca06d
fix style
piotrblaszczyk Jan 15, 2026
5071aa1
Merge branch 'main' of https://github.com/synergycodes/angularflow in…
piotrblaszczyk Jan 15, 2026
c35d3db
update public api
piotrblaszczyk Jan 15, 2026
0bd4ad1
port deletion cleanup
piotrblaszczyk Jan 15, 2026
d1976c8
cleanup
piotrblaszczyk Jan 16, 2026
af80f09
fix the article style
piotrblaszczyk Jan 16, 2026
88d1196
Support port only deletion (node exists)
piotrblaszczyk Jan 19, 2026
26c342f
FIx comments
piotrblaszczyk Jan 30, 2026
2b9b321
Fix routing during node dragging
piotrblaszczyk Jan 30, 2026
b854fe3
Fix unit-test
piotrblaszczyk Feb 2, 2026
5c17164
Merge branch 'main' of https://github.com/synergycodes/angularflow in…
piotrblaszczyk Feb 4, 2026
028a889
adjust minimap to support virtuazliation
piotrblaszczyk Feb 5, 2026
b99e501
Update api report and support Angular 18
piotrblaszczyk Feb 5, 2026
5f53d0b
Fix custom model example
piotrblaszczyk Feb 5, 2026
585e9e2
update api report
piotrblaszczyk Feb 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions apps/angular-demo/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
[config]="config"
(diagramInit)="onDiagramInit($event)"
(selectionChanged)="onSelectionChanged($event)"
(selectionMoved)="onSelectionMoved($event)"
(groupMembershipChanged)="onGroupMembershipChanged($event)"
(selectionRotated)="onSelectionRotated($event)"
(viewportChanged)="onViewportChanged($event)"
(edgeDrawn)="onEdgeDrawn($event)"
(clipboardPasted)="onClipboardPasted($event)"
(nodeResized)="onNodeResized($event)"
Expand All @@ -19,6 +17,9 @@
<ng-diagram-background type="grid"></ng-diagram-background>
</ng-diagram>
<ng-diagram-minimap [nodeStyle]="nodeStyle" [minimapNodeTemplateMap]="minimapNodeTemplateMap" />
<app-toolbar (reinitializeModelClick)="onReinitializeModel()" />
<app-toolbar
(testVirtualizationClick)="enableVirtualizationTest()"
(reinitializeModelClick)="onReinitializeModel()"
/>
<app-palette [model]="paletteModel" />
</div>
39 changes: 20 additions & 19 deletions apps/angular-demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ import {
PaletteItemDroppedEvent,
provideNgDiagram,
SelectionChangedEvent,
SelectionMovedEvent,
SelectionRemovedEvent,
SelectionRotatedEvent,
ViewportChangedEvent,
type Edge,
type EdgeLabel,
type Node,
type Port,
} from 'ng-diagram';
import { defaultModel } from './data/default-model';
import { generateModel } from './data/generate-model';
import { nodeTemplateMap } from './data/node-template';
import { paletteModel } from './data/palette-model';
import { virtualizationConfigOverrides, virtualizationTestConfig } from './data/virtualization-test.config';
import { ButtonEdgeComponent } from './edge-template/button-edge/button-edge.component';
import { CustomPolylineEdgeComponent } from './edge-template/custom-polyline-edge/custom-polyline-edge.component';
import { DashedEdgeComponent } from './edge-template/dashed-edge/dashed-edge.component';
Expand Down Expand Up @@ -67,7 +67,7 @@ export class AppComponent {

minimapNodeTemplateMap = new NgDiagramMinimapNodeTemplateMap([['image', ImageMinimapNodeComponent]]);

config = {
config: NgDiagramConfig = {
zoom: {
max: 2,
zoomToFit: {
Expand Down Expand Up @@ -102,7 +102,17 @@ export class AppComponent {
bindings: [{ key: 'd' }, { key: 'ArrowRight' }],
},
]),
} satisfies NgDiagramConfig;
};

model = initializeModel(defaultModel);

enableVirtualizationTest(): void {
this.config = {
...this.config,
...virtualizationConfigOverrides,
};
this.model = initializeModel(generateModel(virtualizationTestConfig.nodeCount), this.injector);
}

onDiagramInit(event: DiagramInitEvent): void {
console.log('INIT');
Expand Down Expand Up @@ -133,19 +143,6 @@ export class AppComponent {
});
}

onSelectionMoved(event: SelectionMovedEvent): void {
console.log('Selection Moved:', {
nodes: event.nodes.map((n: Node) => n.id),
});
}

onViewportChanged(event: ViewportChangedEvent): void {
console.log('Viewport Changed:', {
current: event.viewport,
previous: event.previousViewport,
});
}

onEdgeDrawn(event: EdgeDrawnEvent): void {
console.log('Edge Drawn:', {
edge: event.edge.id,
Expand Down Expand Up @@ -213,11 +210,15 @@ export class AppComponent {
}

onReinitializeModel(): void {
this.config = {
...this.config,
virtualization: {
enabled: false,
},
};
this.model = initializeModel(defaultModel, this.injector);
}

model = initializeModel(defaultModel);

nodeStyle(node: Node): MinimapNodeStyle {
const style: MinimapNodeStyle = {};

Expand Down
6 changes: 6 additions & 0 deletions apps/angular-demo/src/app/data/default-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ export const defaultModel: DiagramModel = {
data: { label: 'not draggable' },
draggable: false,
},
{
id: '17',
type: 'port-toggle',
position: { x: 100, y: 850 },
data: { text: 'Port Toggle Test' },
},
],
edges: [
{
Expand Down
51 changes: 51 additions & 0 deletions apps/angular-demo/src/app/data/generate-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { type Edge, type Node } from 'ng-diagram';

export function generateModel(nodeCount: number): { nodes: Node[]; edges: Edge[] } {
const nodes: Node[] = [];
const edges: Edge[] = [];

const cols = Math.ceil(Math.sqrt(nodeCount));
const rows = Math.ceil(nodeCount / cols);

const spacingX = 200;
const spacingY = 150;

for (let i = 0; i < nodeCount; i++) {
const row = Math.floor(i / cols);
const col = i % cols;

nodes.push({
id: `node-${i}`,
position: {
x: col * spacingX,
y: row * spacingY,
},
data: { label: `Node ${i}` },
});

if (col < cols - 1 && i + 1 < nodeCount) {
edges.push({
id: `edge-h-${i}`,
source: `node-${i}`,
target: `node-${i + 1}`,
sourcePort: 'port-right',
targetPort: 'port-left',
data: {},
});
}

if (row < rows - 1 && i + cols < nodeCount && col % 5 === 0) {
edges.push({
id: `edge-v-${i}`,
source: `node-${i}`,
target: `node-${i + cols}`,
sourcePort: 'port-right',
targetPort: 'port-left',
data: {},
});
}
}

console.log(`Generated ${nodes.length} nodes and ${edges.length} edges`);
return { nodes, edges };
}
3 changes: 3 additions & 0 deletions apps/angular-demo/src/app/data/node-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CustomizedDefaultNodeComponent } from '../node-template/customized-defa
import { GroupNodeComponent } from '../node-template/group-node/group-node.component';
import { ImageNodeComponent } from '../node-template/image-node/image-node.component';
import { InputFieldNodeComponent } from '../node-template/input-field-node/input-field-node.component';
import { PortToggleNodeComponent } from '../node-template/port-toggle-node/port-toggle-node.component';
import { ResizableNodeComponent } from '../node-template/resizable-node/resizable-node.component';

export enum NodeTemplateType {
Expand All @@ -13,6 +14,7 @@ export enum NodeTemplateType {
CustomizedDefault = 'customized-default',
Group = 'custom-group',
Chip = 'chip',
PortToggle = 'port-toggle',
}

export const nodeTemplateMap = new NgDiagramNodeTemplateMap([
Expand All @@ -22,4 +24,5 @@ export const nodeTemplateMap = new NgDiagramNodeTemplateMap([
[NodeTemplateType.Group, GroupNodeComponent],
[NodeTemplateType.CustomizedDefault, CustomizedDefaultNodeComponent],
[NodeTemplateType.Chip, ChipNodeComponent],
[NodeTemplateType.PortToggle, PortToggleNodeComponent],
]);
12 changes: 12 additions & 0 deletions apps/angular-demo/src/app/data/virtualization-test.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type NgDiagramConfig } from 'ng-diagram';

export const virtualizationTestConfig = {
/** Number of nodes to generate for virtualization test */
nodeCount: 5000,
} as const;

export const virtualizationConfigOverrides: Partial<NgDiagramConfig> = {
virtualization: {
enabled: true,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<label class="port-toggle-label">
<input
class="port-toggle-checkbox"
type="checkbox"
[checked]="showPorts()"
(change)="togglePorts()"
(keydown)="$event.stopPropagation()"
(keypress)="$event.stopPropagation()"
(keyup)="$event.stopPropagation()"
/>
Render Ports
</label>
<div>
@if (showPorts()) {
<ng-diagram-port id="port-left" type="both" side="left" />
<ng-diagram-port id="port-right" type="both" side="right" />
}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
:host {
display: flex;
width: 100%;
height: 100%;
padding: 0.5rem;
background-color: var(--ngd-node-bg-primary-default);
border: var(--ngd-node-border-size) solid var(--ngd-node-border-color);
color: var(--ngd-txt-primary-default);
border-radius: var(--ngd-node-border-radius);
min-width: 150px;

.port-toggle-label {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;

.port-toggle-checkbox {
cursor: pointer;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ChangeDetectionStrategy, Component, input, signal } from '@angular/core';
import { NgDiagramNodeSelectedDirective, NgDiagramNodeTemplate, NgDiagramPortComponent, Node } from 'ng-diagram';

@Component({
selector: 'app-port-toggle-node',
imports: [NgDiagramPortComponent],
templateUrl: './port-toggle-node.component.html',
styleUrls: ['./port-toggle-node.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [{ directive: NgDiagramNodeSelectedDirective, inputs: ['node'] }],
host: {
'[class.ng-diagram-port-hoverable]': 'true',
},
})
export class PortToggleNodeComponent implements NgDiagramNodeTemplate<{ text: string }> {
node = input.required<Node<{ text: string }>>();

showPorts = signal(true);

togglePorts(): void {
this.showPorts.update((v) => !v);
}
}
1 change: 1 addition & 0 deletions apps/angular-demo/src/app/toolbar/toolbar.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
<button [disabled]="!isNodeSelected()" (click)="onChangeNodeTypeClick()">Change Node Type</button>
<button (click)="onZoomToFitClick()">Zoom to fit</button>
<button (click)="onAsyncTransactionWithMeasurementsDemo()">Async + Measurements + Zoom</button>
<button (click)="testVirtualizationClick.emit()">Test Virtualization</button>
<button (click)="reinitializeModelClick.emit()">Reinitialize Model</button>
</div>
1 change: 1 addition & 0 deletions apps/angular-demo/src/app/toolbar/toolbar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class ToolbarComponent {
private readonly nodeTypes = Array.from(nodeTemplateMap.keys()) as NodeTemplateType[];

reinitializeModelClick = output<void>();
testVirtualizationClick = output<void>();

isNodeSelected = computed(() => this.ngDiagramSelectionService.selection().nodes.length > 0);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ export class DiagramComponent {
id: 'edge-1',
source: '1',
target: '2',
sourcePort: 'port-right',
targetPort: 'port-left',
sourcePort: 'port-bottom',
targetPort: 'port-top',
data: {},
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
@Component({
imports: [NgDiagramBaseNodeTemplateComponent],
template: `
<ng-diagram-base-node-template [node]="node">
<ng-diagram-base-node-template [node]="node()">
<input
type="text"
[placeholder]="'Enter text'"
Expand Down
8 changes: 8 additions & 0 deletions apps/docs/src/content/docs/api/Internals/ActionState.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ State related to linking nodes

***

### panning?

> `optional` **panning**: `PanningActionState`

State related to panning the viewport

***

### resize?

> `optional` **resize**: [`ResizeActionState`](/docs/api/internals/resizeactionstate/)
Expand Down
Loading