Skip to content

arrow ​

Draws a curved, arrowheaded connector from the first child to the second. Like line, arrow links elements that have already been placed by another layer or constraint — but it renders a directed, gently bowed arrow (powered by perfect-arrows) instead of a plain line. Reach for it in diagrams: callouts, pointer/heap edges, and labeled annotations.

js
gf.layer([
  gf.rect({ w: 70, h: 40, fill: gf.color.blue[2] }).name("a"),
  gf.rect({ w: 70, h: 40, fill: gf.color.red[2] }).name("b"),
])
  .relate(({ a, b }) => [
    gf.Constraint.distribute({ dir: "x", spacing: 120 }, [a, b]),
    gf.Constraint.align({ y: "middle" }, [a, b]),
    gf.arrow({ stroke: "#333", strokeWidth: 3 }, [a, b]),
  ])
  .render(root, { w: 320, h: 100 });

Signature ​

ts
arrow({
  // visual
  stroke?, strokeWidth?, start?,
  // curve shape (perfect-arrows)
  bow?, stretch?, stretchMin?, stretchMax?,
  padStart?, padEnd?, flip?, straights?,
}, [from, to])

The children are usually two named elements: operands of a .relate() callback, or ref(...) calls (or datum-level sub-refs of a createName token). The arrow runs from the first child to the second. Fewer than two children renders nothing.

Parameters ​

A perfect-arrows box-to-box arrow between exactly two children.

OptionTypeDefaultDescription
bownumber0.2Baseline curvature. 0 is a straight line; higher values bow the arc further from center.
stretchnumber0.5How much the bow grows as the endpoints get closer, and shrinks as they get farther apart.
stretchMinnumber40Distance in pixels below which stretch has its full effect.
stretchMaxnumber420Distance in pixels above which stretch has no effect.
padStartnumber5Gap in pixels between the source box and the start of the line.
padEndnumber20Gap in pixels between the end of the line and the target box, leaving room for the arrowhead.
flipbooleanfalseFlip which side the arrow bows toward.
straightsbooleantrueAllow a perfectly straight line when the endpoints are axis-aligned, instead of forcing a slight bow.
strokestring"black"Color of the arrow's line and head, and of the start dot when shown.
strokeWidthnumber3Line width; also scales the arrowhead and the start dot.
startbooleanfalseDraw a dot at the start endpoint.

Curve shape ​

The arrow's path is a quadratic bezier whose bow and routing come straight from perfect-arrows' getBoxToBoxArrow. The bow, stretch, stretchMin, stretchMax, padStart, padEnd, flip, and straights options above are passed through to it unchanged.

Examples ​

ts
// Labeled callout: a text label pointing at a named shape (gently bowed default)
layer([planets, label]).relate(({ label, Mercury }) => [
  arrow({}, [label, Mercury]),
]);

// Pointer edge: straight, with a dot at the source (e.g. a heap/stack reference)
layer([stack, heap]).relate(({ stackSlot, heapCell }) => [
  arrow({ bow: 0, stretch: 0, padStart: 0, stroke: "#1A5683", start: true }, [
    stackSlot,
    heapCell,
  ]),
]);

// Datum-level endpoints: arrow into a specific selected sub-element of a
// createName token (a token reaches across component boundaries)
arrow({ bow: 0, padEnd: 25, padStart: 0, stroke: "#1A5683", start: true }, [
  ref(heap).path(0, 1).val,
  ref(heap).path(0, 2).elmTuples[0],
]);

Notes ​

  • The arrow's bbox is the union of the resolved endpoints' boxes — like line, it does not contribute its own space.
  • An arrow over string names is a .relate() clause: it is laid out after the layer's constraints, so it runs between the final positions of its endpoints. A string ref("name") outside a .relate() clause is an error. With createName() tokens, the name is global and ref(token) works anywhere.
  • Use line or ribbon instead when you want an undirected line (or a multi-stop polyline) with explicit bbox-anchor control; use arrow when you want a directed arrowhead and automatic curved routing.
  • Pair the operator with z-order constraints (Constraint.zAbove / zBelow) when an arrow needs to sit between two elements in paint order.