npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ng-draw-flow/layouts

v1.2.3

Published

Strict-tree automatic layouts for @ng-draw-flow/core

Readme

@ng-draw-flow/layouts

Dynamic strict-tree positioning for graphs rendered by @ng-draw-flow/core.

Features

  • Left-to-right, right-to-left, top-to-bottom and bottom-to-top trees
  • Fixed or measured node dimensions
  • Configurable level and sibling gaps
  • Stable branch ordering for nodes with multiple outputs
  • Anchored updates that keep the activated parent under the pointer
  • Position animation through the core configuration
  • Signal-based running, result and error state

The package uses d3-hierarchy internally. Applications configure the supported tree behavior and inject DfAutoLayoutService; they do not instantiate or manage a D3 engine.

Installation

npm install @ng-draw-flow/layouts

A compatible @ng-draw-flow/core installation is required as a peer dependency.

Basic Setup

Register layouts next to the core editor configuration. The following setup creates a non-draggable strict tree with measured node dimensions and animated position updates.

import {DfArrowhead, DfConnectionType, provideNgDrawFlowConfigs} from '@ng-draw-flow/core';
import {DfNodeSizingStrategy, DfTreeLayoutDirection, provideNgDrawFlowLayouts} from '@ng-draw-flow/layouts';

providers: [
  provideNgDrawFlowConfigs({
    nodes: {
      treeNode: TreeNodeComponent,
    },
    connection: {
      type: DfConnectionType.SmoothStep,
      arrowhead: {type: DfArrowhead.ArrowClosed},
    },
    options: {
      nodesDraggable: false,
      connectionsCreatable: false,
      connectionsDeletable: false,
    },
    positionAnimation: {
      duration: 280,
      easing: 'ease-in-out',
    },
  }),
  provideNgDrawFlowLayouts({
    tree: {
      direction: DfTreeLayoutDirection.LeftToRight,
      nodeSizing: {
        strategy: DfNodeSizingStrategy.Measured,
        fallback: {width: 180, height: 64},
      },
      levelGap: 96,
      siblingGap: 32,
    },
  }),
];

Call apply() after the editor is attached. The service reads the current model from core, calculates positions and writes the resulting model back through the editor and its form control.

import {type AfterViewInit, inject} from '@angular/core';
import {DfAutoLayoutService} from '@ng-draw-flow/layouts';

export class TreeEditorComponent implements AfterViewInit {
  private readonly autoLayout = inject(DfAutoLayoutService);

  readonly layoutRunning = this.autoLayout.running;
  readonly layoutResult = this.autoLayout.result;
  readonly layoutError = this.autoLayout.error;

  ngAfterViewInit(): void {
    this.autoLayout.apply();
  }
}

Dynamic Children

An action output is a click-only df-output that requests an application action instead of starting a draggable draft connection. It does not create a node automatically. The (activated) handler must update the model with both the new node and its connection.

<ng-template #addChildIcon>
  <tui-icon icon="@tui.plus" />
</ng-template>

<df-output
  title="Add child"
  [content]="addChildIcon"
  [layoutOrder]="0"
  [connectorData]="{
    nodeId: nodeIdSignal(),
    connectorId: nodeIdSignal() + '-output-1',
    single: false,
    data: {childType: 'treeNode'},
  }"
  [mode]="outputMode.Action"
  (activated)="addChild($event)"
/>

Pass the changed model directly to apply(). anchorNodeId translates the complete result so the activated parent keeps its current canvas position while the rest of the tree is rearranged.

import {
  DfConnectionPoint,
  type DfDataConnectorConfig,
  type DfDataNode,
} from '@ng-draw-flow/core';

private addChild({nodeId, connectorId}: DfDataConnectorConfig): void {
  const model = this.form.getRawValue();
  const parent = model.nodes.find(({id}) => id === nodeId);

  if (!parent) {
    return;
  }

  const childId = crypto.randomUUID();
  const position = 'position' in parent ? parent.position : {x: 0, y: 0};
  const child: DfDataNode = {
    id: childId,
    data: {type: 'treeNode', title: 'New node'},
    position: {...position},
  };

  this.autoLayout.apply({
    anchorNodeId: nodeId,
    model: {
      nodes: [...model.nodes, child],
      connections: [
        ...model.connections,
        {
          source: {
            nodeId,
            connectorId,
            connectorType: DfConnectionPoint.Output,
          },
          target: {
            nodeId: childId,
            connectorId: childId + '-input-1',
            connectorType: DfConnectionPoint.Input,
          },
        },
      ],
    },
  });
}

The child component must render the target df-input with the same connector id. Connection paths continue to use the real connector elements from core; layouts only calculate node positions.

Node Sizing

Fixed

Fixed sizing is the default and assumes 180 x 64px nodes. Provide an explicit size when every node follows another known dimension.

provideNgDrawFlowLayouts({
  tree: {
    nodeSizing: {
      strategy: DfNodeSizingStrategy.Fixed,
      size: {width: 240, height: 80},
    },
  },
});

Measured

Use measured sizing when node dimensions depend on text, forms or expandable content. The fallback is used before every current node has reported its DOM size.

provideNgDrawFlowLayouts({
  tree: {
    nodeSizing: {
      strategy: DfNodeSizingStrategy.Measured,
      fallback: {width: 180, height: 64},
    },
  },
});

Measured sizing opts into core's node ResizeObserver, coalesces size changes per animation frame and reapplies the layout after all current nodes have measurements. DOM dimensions remain runtime view state and are not stored in DfDataModel.

Branch Order

When one parent has children connected through multiple outputs, assign every used output a unique zero-based layoutOrder.

  • Horizontal trees interpret output order from top to bottom.
  • Vertical trees interpret output order from left to right.
  • Children connected through the same output retain their order from DfDataModel.connections.
  • A parent with only one connected output does not need layoutOrder.

Tree Options

| Option | Behavior | | ---------------------- | --------------------------------------------------------------------------- | | direction | Tree orientation. Defaults to LeftToRight. | | nodeSizing | Fixed or measured node dimensions. | | levelGap | Space between parent and child levels. Defaults to 80. | | siblingGap | Space between sibling nodes. Defaults to 32. | | preserveRootPosition | Keeps the model's root position by default. Set to false to use origin. | | origin | Root position when the existing root position is not preserved. | | rootId | Verifies the expected root id. The model must still have exactly one root. |

Strict-tree Constraints

The current package supports strict trees only. A valid model must have:

  • exactly one root with no incoming connection;
  • no cycles;
  • at most one parent for every non-root node;
  • no disconnected nodes;
  • connections that reference existing nodes.

Invalid models are exposed through DfAutoLayoutService.error as DfTreeLayoutError. General DAG layouts and custom layout engines are not supported.