Skip to content

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.

  • Nodes can be rotated by dragging the rotation handle.
  • The rotation angle is stored in the node’s angle property.
  • Rotation can be enabled per node and configured globally via diagram config.

Adding Rotation Adornment to a Custom Node

Section titled “Adding Rotation Adornment to a Custom Node”

To make a custom node rotatable, include <ng-diagram-node-rotate-adornment /> in your node template and import the NgDiagramNodeRotateAdornmentComponent reference.

import { Component, input } from '@angular/core';
import {
NgDiagramNodeRotateAdornmentComponent,
NgDiagramNodeSelectedDirective,
type NgDiagramNodeTemplate,
type Node,
} from 'ng-diagram';
@Component({
selector: 'node',
imports: [NgDiagramNodeRotateAdornmentComponent],
template: `
<ng-diagram-node-rotate-adornment />
<div class="node">
<div class="node-header">Header</div>
<div class="node-content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
11 collapsed lines
</div>
</div>
`,
hostDirectives: [
{ directive: NgDiagramNodeSelectedDirective, inputs: ['node'] },
],
styleUrl: './node.component.scss',
})
export class CustomNodeComponent implements NgDiagramNodeTemplate {
node = input.required<Node>();
}

Enable rotation by setting the rotatable property to true in your node definition:

42 collapsed lines
import '@angular/compiler';
import { Component } from '@angular/core';
import {
initializeModel,
NgDiagramComponent,
provideNgDiagram,
type NgDiagramConfig,
type NgDiagramNodeTemplateMap,
} from 'ng-diagram';
import { CustomNodeComponent } from './node.component';
@Component({
selector: 'rotation',
imports: [NgDiagramComponent],
providers: [provideNgDiagram()],
template: `
<div class="not-content diagram">
<ng-diagram
[model]="model"
[config]="config"
[nodeTemplateMap]="nodeTemplateMap"
/>
</div>
`,
styleUrl: './rotation-wrapper.component.scss',
})
export class RotationWrapperComponent {
nodeTemplateMap: NgDiagramNodeTemplateMap = new Map([
['myType', CustomNodeComponent],
]);
config = {
zoom: {
max: 3,
},
nodeRotation: {
computeSnapAngleForNode: () => 45,
defaultSnapAngle: 25,
shouldSnapForNode: () => true,
},
} satisfies NgDiagramConfig;
model = initializeModel({
nodes: [
{
id: '1',
position: { x: 100, y: 100 },
type: 'myType',
data: {},
rotatable: true,
},
],
edges: [],
metadata: { viewport: { x: 0, y: 0, scale: 1 } },
});
}

When rotatable is set, the rotation handle will appear, and the node can be rotated by the user.

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.

If you want to use a custom icon as a handle, simply place your SVG or Angular component inside <ng-diagram-node-rotate-adornment>. The content you provide will be rendered inside the handle.

<ng-diagram-node-rotate-adornment>
<!-- Your custom SVG icon or component here -->
<svg width="24" height="24" ...>...</svg>
</ng-diagram-node-rotate-adornment>

If you do not provide any content inside <ng-diagram-node-rotate-adornment>, the component will automatically display its built-in default rotation icon.

You can further customize rotation behavior using the nodeRotation configuration in NgDiagramConfig. This configuration allows you to control snapping and snap angles for node rotation:

  • computeSnapAngleForNode - Computes the snap angle for a node’s rotation.
  • defaultSnapAngle - The default snap angle in degrees, used if computeSnapAngleForNode returns null.
  • shouldSnapForNode - Determines whether rotation snapping should be enabled for a node.

You can set these options in your diagram configuration:

34 collapsed lines
import '@angular/compiler';
import { Component } from '@angular/core';
import {
initializeModel,
NgDiagramComponent,
provideNgDiagram,
type NgDiagramConfig,
type NgDiagramNodeTemplateMap,
} from 'ng-diagram';
import { CustomNodeComponent } from './node.component';
@Component({
selector: 'rotation',
imports: [NgDiagramComponent],
providers: [provideNgDiagram()],
template: `
<div class="not-content diagram">
<ng-diagram
[model]="model"
[config]="config"
[nodeTemplateMap]="nodeTemplateMap"
/>
</div>
`,
styleUrl: './rotation-wrapper.component.scss',
})
export class RotationWrapperComponent {
nodeTemplateMap: NgDiagramNodeTemplateMap = new Map([
['myType', CustomNodeComponent],
]);
config = {
zoom: {
max: 3,
},
nodeRotation: {
computeSnapAngleForNode: () => 45,
defaultSnapAngle: 25,
shouldSnapForNode: () => true,
},
} satisfies NgDiagramConfig;
model = initializeModel({
nodes: [
{
id: '1',
position: { x: 100, y: 100 },
type: 'myType',
data: {},
rotatable: true,
},
],
edges: [],
metadata: { viewport: { x: 0, y: 0, scale: 1 } },
});
}

Pass this configuration to the ng-diagram component:

16 collapsed lines
import '@angular/compiler';
import { Component } from '@angular/core';
import {
initializeModel,
NgDiagramComponent,
provideNgDiagram,
type NgDiagramConfig,
type NgDiagramNodeTemplateMap,
} from 'ng-diagram';
import { CustomNodeComponent } from './node.component';
@Component({
selector: 'rotation',
imports: [NgDiagramComponent],
providers: [provideNgDiagram()],
template: `
<div class="not-content diagram">
<ng-diagram
[model]="model"
[config]="config"
[nodeTemplateMap]="nodeTemplateMap"
/>
</div>
`,
32 collapsed lines
styleUrl: './rotation-wrapper.component.scss',
})
export class RotationWrapperComponent {
nodeTemplateMap: NgDiagramNodeTemplateMap = new Map([
['myType', CustomNodeComponent],
]);
config = {
zoom: {
max: 3,
},
nodeRotation: {
computeSnapAngleForNode: () => 45,
defaultSnapAngle: 25,
shouldSnapForNode: () => true,
},
} satisfies NgDiagramConfig;
model = initializeModel({
nodes: [
{
id: '1',
position: { x: 100, y: 100 },
type: 'myType',
data: {},
rotatable: true,
},
],
edges: [],
metadata: { viewport: { x: 0, y: 0, scale: 1 } },
});
}