Skip to content
D
Documentation

Services

reference
3 min readUpdated

Import these from @grafloria/angular.

On their own pages

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 init
  • unregisterHandle(nodeId: string, handleId: string): void — Unregister a handle Called by GrafloriaHandleDirective on destroy
  • getHandles(nodeId: string): HTMLHandle[] — Get all handles for a node
  • getHandleBounds( 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 operations
  • getHandleAtPoint( 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 debugging
  • clear(): 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. DiagramCanvasComponent turns those booleans into cdr.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

NameTypeDefaultDescription
state$Observable of simulation state.
stats$Observable of animation stats (updated every second).

Methods

  • constructor(private ngZone: NgZone)
  • ngOnDestroy(): void
  • configure(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

typescript
constructor(
  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 in container and forget it.
  • getLastPatchStats(): Readonly<PatchStats> — Work done by the last render() — created / reused / moved / removed / skipped node counts. A steady-state frame should create ~nothing.

Interfaces

AnimationConfig

Animation configuration

ts
interface AnimationConfig

Properties

NameTypeDefaultDescription
fps?numberTarget FPS (default: 60)
maxDeltaTime?numberMax delta time cap in ms (prevents spiral of death)
autoStart?booleanWhether to auto-start (default: false)

AnimationStats

Animation frame stats

ts
interface AnimationStats

Properties

NameTypeDefaultDescription
fpsnumberCurrent FPS
avgFpsnumberAverage FPS
frameCountnumberFrame count
elapsedTimenumberTotal elapsed time in ms
deltaTimenumberLast frame delta time in ms

Breakpoint

Breakpoint definition

ts
interface Breakpoint

Properties

NameTypeDefaultDescription
idstringUnique breakpoint ID
nodeIdstringNode ID where breakpoint is set
typeBreakpointTypeBreakpoint type
enabledbooleanWhether breakpoint is enabled
condition?BreakpointConditionCondition for conditional breakpoints
conditionExpression?stringCondition expression (for display)
hitCountnumberHit count (how many times breakpoint was hit)
createdAtnumberCreation timestamp
metadata?Record<string, any>Metadata

BreakpointHitEvent

Breakpoint hit event

ts
interface BreakpointHitEvent

Properties

NameTypeDefaultDescription
breakpointBreakpointBreakpoint that was hit
nodeIdstringNode ID
contextanyExecution context at breakpoint
timestampnumberTimestamp

ComponentBounds

Component bounds for foreignObject.

ts
interface ComponentBounds

Properties

NameTypeDefaultDescription
xnumber
ynumber
widthnumber
heightnumber

ComponentUpdate

Component update for batch operations.

ts
interface ComponentUpdate

Properties

NameTypeDefaultDescription
nodeIdstring
inputsRecord<string, any>

DiagramNode

Mock DiagramNode interface (temporary - should come from

ts
interface DiagramNode

Properties

NameTypeDefaultDescription
idstring
typestring
getMetadata?() => Record<string, any>

ExecutionSession

Execution session record

ts
interface ExecutionSession

Properties

NameTypeDefaultDescription
idstringSession ID
startTimenumberSession start timestamp
endTimenumber | nullSession end timestamp (null if still running)
durationnumber | nullSession duration in ms (null if still running)
stateExecutionStateSession state
stepsExecutionStep[]Execution steps
currentStepIndexnumberCurrent step index
metadata?Record<string, any>Session metadata

ExecutionStep

Execution step record

ts
interface ExecutionStep

Properties

NameTypeDefaultDescription
idstringStep ID
nodeIdstringNode ID being executed
nodeTypestringNode type
startTimenumberStep start timestamp
endTimenumber | nullStep end timestamp (null if still running)
durationnumber | nullStep duration in ms (null if still running)
status'pending' | 'running' | 'completed' | 'error' | 'skipped'Step status
input?anyInput data
output?anyOutput 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

ts
interface HandleBounds

Properties

NameTypeDefaultDescription
idstring
type'source' | 'target'
nodeIdstring
position'top' | 'right' | 'bottom' | 'left'
xnumber
ynumber
widthnumber
heightnumber
absoluteX?number
absoluteY?number

HTMLHandle

HTML Handle metadata (stored in registry)

ts
interface HTMLHandle

Properties

NameTypeDefaultDescription
idstring
type'source' | 'target'
position'top' | 'right' | 'bottom' | 'left'
elementHTMLElement

ModeAnalytics

Mode analytics data

ts
interface ModeAnalytics

ModeChangeEvent

Mode change event

ts
interface ModeChangeEvent

Properties

NameTypeDefaultDescription
previousModeDiagramMode
currentModeDiagramMode

ModeGuardResult

Mode guard function result

ts
interface ModeGuardResult

Properties

NameTypeDefaultDescription
allowedboolean
reason?string

ModeHistoryEntry

Mode history entry

ts
interface ModeHistoryEntry

Properties

NameTypeDefaultDescription
modeDiagramMode
timestampnumber
durationnumber | null

ModeViewportSettings

Viewport settings for a specific mode

ts
interface ModeViewportSettings

Properties

NameTypeDefaultDescription
allowZoom?boolean
allowPan?boolean
minZoom?number
maxZoom?number
centerOnLoad?boolean
fitToScreen?boolean
followNode?string
autoCenter?boolean
resetOnEnter?boolean

PropertyChangeEvent

Property change event

ts
interface PropertyChangeEvent

Properties

NameTypeDefaultDescription
nodeId?stringNode ID (single node change)
nodeIds?string[]Node IDs (bulk change)
propertyKeystringProperty key that changed
oldValue?anyOld value (single node change)
newValueanyNew value
timestampnumberTimestamp of change

PropertyDiagramNode

Diagram node interface for property management Simplified interface to work with any node type that has data storage

ts
interface PropertyDiagramNode

Properties

NameTypeDefaultDescription
idstring
typestring
label?stringOptional human-readable label shown in the panel header (falls back to id)
dataRecord<string, any>

RenderComponentOptions

Options for rendering a component.

ts
interface RenderComponentOptions

Properties

NameTypeDefaultDescription
inputs?Record<string, any>Initial input values
outputHandlers?Record<string, (event: any) => void>Output event handlers

Types

AnimationCallback

Animation callback function

ts
type AnimationCallback = (deltaTime: number, elapsedTime: number) => void;

BreakpointCondition

Breakpoint condition function

ts
type BreakpointCondition = (context: any) => boolean;

ModeChangeHook

Mode change hook function

ts
type ModeChangeHook = (
  previousMode: DiagramMode,
  nextMode: DiagramMode,
  context?: any
) => void | false;

ModeGuardFunction

Mode transition guard function

ts
type ModeGuardFunction = (
  previousMode: DiagramMode,
  nextMode: DiagramMode
) => ModeGuardResult;

Enums

BreakpointType

Breakpoint type

ts
enum BreakpointType

Members

  • BEFORE = 'before' — Break before node execution
  • AFTER = 'after' — Break after node execution
  • CONDITIONAL = 'conditional' — Break on condition

ExecutionState

Execution state for workflow/process execution

ts
enum ExecutionState

Members

  • IDLE = 'idle'
  • RUNNING = 'running'
  • PAUSED = 'paused'
  • COMPLETED = 'completed'
  • ERROR = 'error'

SimulationState

Simulation state

ts
enum SimulationState

Members

  • IDLE = 'idle'
  • RUNNING = 'running'
  • PAUSED = 'paused'

Was this page helpful?

Services — Grafloria