Import these from @grafloria/angular.
On their own pages
AngularAnimationService: Angular-injectable Animation ServiceBreakpointManagerService: BreakpointManager ServiceComponentRendererService: Service for rendering Angular components inside SVG foreignObject elements. Manages component lifecycle, inputs/outputs, and container management.ExecutionTrackerService: ExecutionTracker ServiceModeManagerService: Angular service wrapper for engine ModeManager. Provides reactive API using RxJS observables.PropertyPanelService: Core service for managing property schemas and property values. Acts as bridge between property panel UI and diagram engine.
Classes
HandleRegistryService
Service to track HTML handles and query their DOM positions Similar to React Flow's handle detection system
Hybrid HTML+SVG Rendering
This service:
- Tracks all HTML handles registered via GrafloriaHandleDirective
- Queries DOM positions using getBoundingClientRect() like React Flow
- Provides handle bounds for connection drawing
- Enables hit testing for connection drag operations
SHAPE AWARENESS: This service queries actual DOM positions, so it automatically supports all shape types (rect, circle, ellipse, diamond, hexagon) as long as the handles are positioned correctly in the template. Handle positioning is done by diagram-canvas.component.ts using getPortPositionForShape() which provides shape-aware positioning.
ts@Injectable({ providedIn: 'root' })
export class HandleRegistryService
Methods
registerHandle(nodeId: string, handle: HTMLHandle): void— Register a handle for a node Called by GrafloriaHandleDirective on initunregisterHandle(nodeId: string, handleId: string): void— Unregister a handle Called by GrafloriaHandleDirective on destroygetHandles(nodeId: string): HTMLHandle[]— Get all handles for a nodegetHandleBounds( nodeId: string, handleId: string, zoom: number = 1 ): HandleBounds | null— Get bounds for a specific handle (React Flow style) Queries DOM using getBoundingClientRect()getAllHandleBounds(zoom: number = 1): Map<string, HandleBounds[]>— Get bounds for all handles in the diagram Used for connection drag operationsgetHandleAtPoint( screenX: number, screenY: number, zoom: number = 1 ): { nodeId: string; handleId: string; handle: HTMLHandle } | null— Find handle at screen coordinates (for hit testing)getStats(): { nodeCount: number; handleCount: number }— Get count of registered nodes and handles Useful for debuggingclear(): void— Clear all registered handles Useful for cleanup/reset
InteractionHandlerService
Also has every member of InteractionController, listed on its own entry.
InteractionHandlerService
Angular binding for {@link InteractionController} — and nothing else.
ALL of the interaction logic (port hover, connection dragging, link
reconnection, inline label repositioning, waypoint and control-point editing)
now lives in the framework-agnostic {@link InteractionController} in
@grafloria/renderer, so React / Vue / web-component wrappers get it for free. This class exists purely to make that controller injectable; it adds no
behaviour and overrides no methods.
The separation this encodes
- WHAT changed → the controller. Its handlers are pure w.r.t. Angular and return a boolean meaning "a re-render is warranted".
- TELL THE FRAMEWORK TO RENDER → the caller.
DiagramCanvasComponentturns those booleans intocdr.markForCheck()/scheduleRender().
The controller therefore never imports Angular, never holds a
ChangeDetectorRef, and is instantiated with a plain new in the e2e
harness. Do not add Angular-aware behaviour here: put logic in the controller
and change detection in the component.
ts@Injectable({
providedIn: 'root',
})
export class InteractionHandlerService extends InteractionController
Methods
constructor()
See also: InteractionController — the real implementation (and its full API).
PropertyEditorRegistryService
Registry service for property editor components.
This service manages all property editor components (both built-in and custom). It provides a centralized way to register and retrieve editor components by type.
Built-in editors are automatically registered on service initialization:
- string, number, boolean, select, multiselect, color, slider, textarea, date, datetime, file, json
Custom editors can be registered using the registerEditor method.
ts@Injectable({
providedIn: 'root',
})
export class PropertyEditorRegistryService
Methods
constructor()registerEditor(type: string, component: Type<any>): void— Register a custom editor component.
This method allows you to register custom property editor components or override built-in editors. If an editor with the same type already exists, it will be overwritten.
getEditor(type: string): Type<any> | null— Get the editor component class for a given type.hasEditor(type: string): boolean— Check if an editor is registered for a given type.getEditorTypes(): string[]— Get all registered editor types.
Example
typescript// Register a custom editor
### `SimulationEngineService`
SimulationEngine Service
High-performance animation engine for diagram simulations. Runs at 60 FPS using requestAnimationFrame.
Features:
- 60 FPS animation loop
- Frame rate monitoring
- Delta time tracking
- Multiple animation callbacks
- Pause/resume support
- Performance stats
```ts
@Injectable({ providedIn: 'root' })
export class SimulationEngineService implements OnDestroy
Properties
| Name | Type | Default | Description |
|---|---|---|---|
state$ | Observable of simulation state. | ||
stats$ | Observable of animation stats (updated every second). |
Methods
constructor(private ngZone: NgZone)ngOnDestroy(): voidconfigure(config: AnimationConfig): void— Configure simulation engine.start(): void— Start simulation.stop(): void— Stop simulation.pause(): void— Pause simulation.resume(): void— Resume simulation.isRunning(): boolean— Check if simulation is running.isPaused(): boolean— Check if simulation is paused.reset(): void— Reset simulation timing.registerAnimation(callback: AnimationCallback): () => void— Register animation callback. Callback is called every frame with delta time.clearAnimations(): void— Clear all animation callbacks.getAnimationCount(): number— Get number of registered animations.getStats(): AnimationStats— Get current animation stats.
Example
typescriptconstructor(
private simulationEngine: SimulationEngineService
) {}
ngOnInit() {
// Register animation callback
const unsubscribe = this.simulationEngine.registerAnimation((deltaTime, elapsedTime) => {
// Update node positions, animations, etc.
this.updateNodePositions(deltaTime);
});
// Start simulation
this.simulationEngine.start();
}
ngOnDestroy() {
this.simulationEngine.stop();
}
VNodeRendererService
VNodeRendererService
Angular-facing wrapper around the framework-agnostic VNode → DOM patcher
(VNodePatcher in @grafloria/renderer). This service holds NO rendering logic
of its own: the diff/patch rules live in one place so the Angular canvas, the
e2e harness and any headless consumer all materialize VNodes identically.
render() used to wipe the container (innerHTML = '') and rebuild the whole
DOM on every frame, which destroyed focus, text selection, running CSS
animations and anything mounted inside a <foreignObject>. It now reconciles:
existing DOM elements are reused, reordered by key, and only genuinely-changed
attributes are written.
ts@Injectable({
providedIn: 'root',
})
export class VNodeRendererService
Methods
render(vnode: VNode, container: HTMLElement): void— Render (or re-render) a VNode tree into a container, reusing the DOM that is already there. This is the hot path — it runs once per frame.reconcile(container: HTMLElement, vnode: VNode): Element— Reconcile a VNode tree into a container and hand back the root element. Same as {@link render}, for callers that want the element.renderVNode(vnode: VNode): Element— Build a fresh, detached DOM element for a VNode (deep). Used for one-shot materialization;render()is what you want for a canvas.updateVNode(element: Element, oldVNode: VNode, newVNode: VNode): void— Diff two VNodes onto an existing element: props AND children. (The old implementation only diffed props and left a "TODO: handle children" behind — children are now reconciled by key.)unmount(container: HTMLElement): void— Remove the tree this service mounted incontainerand forget it.getLastPatchStats(): Readonly<PatchStats>— Work done by the lastrender()— created / reused / moved / removed / skipped node counts. A steady-state frame should create ~nothing.
Interfaces
AnimationConfig
Animation configuration
tsinterface AnimationConfig
Properties
| Name | Type | Default | Description |
|---|---|---|---|
fps? | number | Target FPS (default: 60) | |
maxDeltaTime? | number | Max delta time cap in ms (prevents spiral of death) | |
autoStart? | boolean | Whether to auto-start (default: false) |
AnimationStats
Animation frame stats
tsinterface AnimationStats
Properties
| Name | Type | Default | Description |
|---|---|---|---|
fps | number | Current FPS | |
avgFps | number | Average FPS | |
frameCount | number | Frame count | |
elapsedTime | number | Total elapsed time in ms | |
deltaTime | number | Last frame delta time in ms |
Breakpoint
Breakpoint definition
tsinterface Breakpoint
Properties
| Name | Type | Default | Description |
|---|---|---|---|
id | string | Unique breakpoint ID | |
nodeId | string | Node ID where breakpoint is set | |
type | BreakpointType | Breakpoint type | |
enabled | boolean | Whether breakpoint is enabled | |
condition? | BreakpointCondition | Condition for conditional breakpoints | |
conditionExpression? | string | Condition expression (for display) | |
hitCount | number | Hit count (how many times breakpoint was hit) | |
createdAt | number | Creation timestamp | |
metadata? | Record<string, any> | Metadata |
BreakpointHitEvent
Breakpoint hit event
tsinterface BreakpointHitEvent
Properties
| Name | Type | Default | Description |
|---|---|---|---|
breakpoint | Breakpoint | Breakpoint that was hit | |
nodeId | string | Node ID | |
context | any | Execution context at breakpoint | |
timestamp | number | Timestamp |
ComponentBounds
Component bounds for foreignObject.
tsinterface ComponentBounds
Properties
| Name | Type | Default | Description |
|---|---|---|---|
x | number | ||
y | number | ||
width | number | ||
height | number |
ComponentUpdate
Component update for batch operations.
tsinterface ComponentUpdate
Properties
| Name | Type | Default | Description |
|---|---|---|---|
nodeId | string | ||
inputs | Record<string, any> |
DiagramNode
Mock DiagramNode interface (temporary - should come from
tsinterface DiagramNode
Properties
| Name | Type | Default | Description |
|---|---|---|---|
id | string | ||
type | string | ||
getMetadata? | () => Record<string, any> |
ExecutionSession
Execution session record
tsinterface ExecutionSession
Properties
| Name | Type | Default | Description |
|---|---|---|---|
id | string | Session ID | |
startTime | number | Session start timestamp | |
endTime | number | null | Session end timestamp (null if still running) | |
duration | number | null | Session duration in ms (null if still running) | |
state | ExecutionState | Session state | |
steps | ExecutionStep[] | Execution steps | |
currentStepIndex | number | Current step index | |
metadata? | Record<string, any> | Session metadata |
ExecutionStep
Execution step record
tsinterface ExecutionStep
Properties
| Name | Type | Default | Description |
|---|---|---|---|
id | string | Step ID | |
nodeId | string | Node ID being executed | |
nodeType | string | Node type | |
startTime | number | Step start timestamp | |
endTime | number | null | Step end timestamp (null if still running) | |
duration | number | null | Step duration in ms (null if still running) | |
status | 'pending' | 'running' | 'completed' | 'error' | 'skipped' | Step status | |
input? | any | Input data | |
output? | any | Output data | |
error? | { message: string; code?: string; stack?: string; } | Error details (if status is error) | |
metadata? | Record<string, any> | Step metadata |
HandleBounds
Handle bounds (calculated from DOM) Used for connection drawing and hit testing
tsinterface HandleBounds
Properties
| Name | Type | Default | Description |
|---|---|---|---|
id | string | ||
type | 'source' | 'target' | ||
nodeId | string | ||
position | 'top' | 'right' | 'bottom' | 'left' | ||
x | number | ||
y | number | ||
width | number | ||
height | number | ||
absoluteX? | number | ||
absoluteY? | number |
HTMLHandle
HTML Handle metadata (stored in registry)
tsinterface HTMLHandle
Properties
| Name | Type | Default | Description |
|---|---|---|---|
id | string | ||
type | 'source' | 'target' | ||
position | 'top' | 'right' | 'bottom' | 'left' | ||
element | HTMLElement |
ModeAnalytics
Mode analytics data
tsinterface ModeAnalytics
ModeChangeEvent
Mode change event
tsinterface ModeChangeEvent
Properties
| Name | Type | Default | Description |
|---|---|---|---|
previousMode | DiagramMode | ||
currentMode | DiagramMode |
ModeGuardResult
Mode guard function result
tsinterface ModeGuardResult
Properties
| Name | Type | Default | Description |
|---|---|---|---|
allowed | boolean | ||
reason? | string |
ModeHistoryEntry
Mode history entry
tsinterface ModeHistoryEntry
Properties
| Name | Type | Default | Description |
|---|---|---|---|
mode | DiagramMode | ||
timestamp | number | ||
duration | number | null |
ModeViewportSettings
Viewport settings for a specific mode
tsinterface ModeViewportSettings
Properties
| Name | Type | Default | Description |
|---|---|---|---|
allowZoom? | boolean | ||
allowPan? | boolean | ||
minZoom? | number | ||
maxZoom? | number | ||
centerOnLoad? | boolean | ||
fitToScreen? | boolean | ||
followNode? | string | ||
autoCenter? | boolean | ||
resetOnEnter? | boolean |
PropertyChangeEvent
Property change event
tsinterface PropertyChangeEvent
Properties
| Name | Type | Default | Description |
|---|---|---|---|
nodeId? | string | Node ID (single node change) | |
nodeIds? | string[] | Node IDs (bulk change) | |
propertyKey | string | Property key that changed | |
oldValue? | any | Old value (single node change) | |
newValue | any | New value | |
timestamp | number | Timestamp of change |
PropertyDiagramNode
Diagram node interface for property management Simplified interface to work with any node type that has data storage
tsinterface PropertyDiagramNode
Properties
| Name | Type | Default | Description |
|---|---|---|---|
id | string | ||
type | string | ||
label? | string | Optional human-readable label shown in the panel header (falls back to id) | |
data | Record<string, any> |
RenderComponentOptions
Options for rendering a component.
tsinterface RenderComponentOptions
Properties
| Name | Type | Default | Description |
|---|---|---|---|
inputs? | Record<string, any> | Initial input values | |
outputHandlers? | Record<string, (event: any) => void> | Output event handlers |
Types
AnimationCallback
Animation callback function
tstype AnimationCallback = (deltaTime: number, elapsedTime: number) => void;
BreakpointCondition
Breakpoint condition function
tstype BreakpointCondition = (context: any) => boolean;
ModeChangeHook
Mode change hook function
tstype ModeChangeHook = (
previousMode: DiagramMode,
nextMode: DiagramMode,
context?: any
) => void | false;
ModeGuardFunction
Mode transition guard function
tstype ModeGuardFunction = (
previousMode: DiagramMode,
nextMode: DiagramMode
) => ModeGuardResult;
Enums
BreakpointType
Breakpoint type
tsenum BreakpointType
Members
BEFORE = 'before'— Break before node executionAFTER = 'after'— Break after node executionCONDITIONAL = 'conditional'— Break on condition
ExecutionState
Execution state for workflow/process execution
tsenum ExecutionState
Members
IDLE = 'idle'RUNNING = 'running'PAUSED = 'paused'COMPLETED = 'completed'ERROR = 'error'
SimulationState
Simulation state
tsenum SimulationState
Members
IDLE = 'idle'RUNNING = 'running'PAUSED = 'paused'
Was this page helpful?