# ArrowRenderer

Import it from `@grafloria/renderer`.

ArrowRenderer generates SVG VNodes for different arrow types.

Supports:
- Basic arrows (arrow, circle, square, diamond)
- ERD arrows (crow-foot, one, zero-or-one, zero-or-many, one-or-many)
- UML arrows (hollow-diamond, filled-diamond, generalization, open-arrow, double-arrow)
- Additional arrows (cross, bar, dot, oval)
- Half-arrowheads (Mermaid 11.13) — `half-arrow-left` / `half-arrow-right`
- AUTHOR-DEFINED markers: a raw SVG `path`, or anything
  registered with `registerMarker` — the catalogue is no longer a closed enum.

```ts
class ArrowRenderer
```

**Methods**

- `getTipOffset(style: ArrowStyle): number` — Distance from the marker's local origin to its forward-most point (its
visual tip), in the +x direction the marker is rotated toward.

The renderer positions markers by pulling the transform origin back from
the path endpoint by exactly this amount so every tip lands ON the port —
a uniform offset only fits the triangle family and left circles/diamonds
floating off the node.

A custom marker declares its own. Precedence is
`style.tipOffset` (explicit) > the registered marker's > 0 (a raw `path`
marker is assumed to be drawn with its tip at the origin).
- `renderArrow( style: ArrowStyle, transform: string, backgroundColor: string = 'white', end: 'source' | 'target' = 'target' ): VNode | null` — Render an arrow based on the provided style and transform

**Example**

```typescript
const renderer = new ArrowRenderer();
const arrowVNode = renderer.renderArrow({
  type: 'crow-foot',
  size: 10,
  filled: false,
  color: '#000'
}, 'translate(100, 50) rotate(45)');
```

**Example**

 A custom marker
```typescript
registerMarker('feather', {
  tipOffset: style => style.size,
  render: ctx => ({ type: 'path', props: { d: `M0,0 L${ctx.size},0`, stroke: ctx.color, transform: ctx.transform } }),
});
link.updateStyle({ arrowHead: { type: 'feather', size: 12, filled: true } });
```
