Skip to content
D
Documentation

Resize and size nodes

how-to
3 min readUpdated

Set a node's starting dimensions, constrain a user's resize gesture, or let the renderer fit a node to its label. This page focuses on node sizing; for mounting patterns and framework-specific data bindings, see Build runnable workflows. These steps cover JavaScript, Angular, React, and Vue; the Qwik binding is outside this page's scope.

Mount nodes with sizes and sizing rules

The example renders four nodes: one with a declared starting size, one whose resize gesture has minimums and maximums, one with a locked aspect ratio, and one that opts into content-aware sizing. Give the canvas a real height so the rendered diagram has room to appear.

js
import { render } from '@grafloria/element';

const host = document.createElement('div');
host.style.height = '700px';
document.body.append(host);

const diagram = render({
  nodes: [
    {
      id: 'sized',
      position: { x: 120, y: 80 },
      size: { width: 180, height: 90 },
      label: 'Declared size: 180 × 90',
    },
    {
      id: 'resizable',
      position: { x: 120, y: 220 },
      size: { width: 160, height: 100 },
      label: 'Resize me: 80–260 wide',
      metadata: {
        sizing: {
          minWidth: 80,
          minHeight: 60,
          maxWidth: 260,
          maxHeight: 200,
        },
      },
    },
    {
      id: 'ratio',
      position: { x: 420, y: 220 },
      size: { width: 160, height: 100 },
      label: 'Aspect ratio stays at 1.6',
      metadata: { sizing: { aspectLock: true } },
    },
    {
      id: 'auto',
      position: { x: 120, y: 360 },
      size: { width: 60, height: 36 },
      label: 'This long label grows beyond the declared sixty-pixel width',
      metadata: { sizing: { auto: true, padding: 10 } },
    },
  ],
  edges: [],
}, host);

The first box starts at its declared 180 × 90 size. Select the constrained box to show the renderer's corner and edge resize handles, then drag a handle: its dimensions stay within the declared limits. The adjacent node holds its initial 1.6 width-to-height ratio while you resize it. The bottom node opts into content-aware sizing, so its long label expands it beyond its declared 60-pixel width. The non-auto node remains at its declared dimensions until a user resizes it.

Choose the sizing fields

Put per-node constraints in metadata.sizing. The renderer applies the same constraints to the interactive resize and content-aware sizing paths.

OptionTypeDefaultWhat it does
size{ width: number; height: number }No default statedDeclares a node's width and height in its NodeSpec.
metadata.sizing.autobooleanOff unless trueOpts that node into content-aware sizing to fit its label.
metadata.sizing.minWidth, minHeightnumberNo per-node constraint; the resizer's global floor still appliesSets the node's minimum width or height during resizing and auto-sizing.
metadata.sizing.maxWidth, maxHeightnumberNo per-node limitSets the node's maximum width or height during resizing and auto-sizing.
metadata.sizing.aspectLockboolean | numberUnlockedtrue locks to the node's current width-to-height ratio; a positive number locks to that explicit ratio.
metadata.sizing.paddingnumber8 pxReserves space around the label when auto-sizing.

The selected-node handles appear for one selected, resizable, unlocked node. A multi-node selection does not provide proportional resize handles. For automatic fitting, only nodes with metadata.sizing.auto: true grow; padding defaults to 8 pixels unless you set it, as the example does. The auto-sized node's measured dimensions update on the renderer's frame, and the sizing pass uses the same min/max limits and aspect lock as dragging.

Watch the demos

  • Auto-sizing nodes shows an opted-in node fitting its label and growing again when the label changes.
  • Node resize gesture shows the built-in handles, per-handle cursors, and live min/max/aspect constraints.
  • Node resizer contrasts the selected-node resizer with a custom resize control.

Pitfalls

  • Register a custom node renderer before mounting the diagram. If a node's type has no renderer when its host mounts, that host stays empty; registering later does not back-fill it. A custom renderer runs at mount, not as a data binding, so update the DOM you own or use a component with its own reactive source when its content must change.
  • Give the canvas a parent with a resolved height. A canvas inside a zero-height wrapper has no visible area to draw into.

Was this page helpful?