# `Mob.Canvas`
[🔗](https://github.com/genericjam/mob/blob/main/lib/mob/canvas.ex#L1)

Drawing-op constructors for `Mob.UI.canvas/1`.

Each function returns a plain map describing one draw operation. The
canvas widget takes a `:draw` list of these and renders them in order.
Color values can be theme tokens (e.g. `:primary`, `:on_surface`) or
raw strings ("#ff0000") — they are resolved by `Mob.Renderer` against
the active theme before serialisation to the native side.

All coordinates are canvas-local in points/dp, top-left origin
(matches SwiftUI `Canvas` and Jetpack Compose `Canvas` natively, no
translation cost).

## Op map equivalence

Helpers and raw maps produce identical output. These are the same:

    Mob.Canvas.line(0, 0, 100, 100, color: :primary, width: 4)
    %{op: :line, x1: 0, y1: 0, x2: 100, y2: 100, color: :primary, width: 4}

Use whichever you prefer; the renderer doesn't care.

## Available ops

  * `line/5`     — straight stroke between two points
  * `circle/4`   — circle (outline or filled)
  * `ellipse/5`  — ellipse with separate rx, ry
  * `arc/6`      — circular arc between two angles in degrees
  * `rect/5`     — rectangle (outline or filled, optional corner radius)
  * `path/2`     — sequence of points (open or closed; outline or filled)
  * `text/4`     — text at a point with anchor
  * `image/5`    — image from an asset name into a rect

## Common modifiers (accepted on every op where they make sense)

  * `:opacity`   — float 0.0–1.0
  * `:width`     — stroke width in points/dp (ignored on filled-only ops)
  * `:dash`      — list of [on, off] floats for dashed strokes, e.g. `[4, 4]`
  * `:cap`       — `:butt` | `:round` | `:square` (line/arc/path)
  * `:join`      — `:miter` | `:round` | `:bevel` (path/rect outline)
  * `:fill`      — boolean (circle/ellipse/rect/path); default false (stroke)

## Text-specific

  * `:weight`    — `:thin` | `:light` | `:regular` | `:medium` | `:semibold` | `:bold`
  * `:family`    — string font family name; platform default if omitted
  * `:anchor`    — `:start` | `:center` | `:end` (horizontal); default `:start`

# `arc`

```elixir
@spec arc(number(), number(), number(), number(), number(), keyword() | map()) ::
  map()
```

Draw a circular arc centered at (x, y), radius r, from `start_deg`
sweeping clockwise to `end_deg`. 0° points to the right, 90° points
down (matching SwiftUI / Compose conventions).

    Mob.Canvas.arc(100, 100, 50, 0, 90, color: :primary, width: 2)

# `circle`

```elixir
@spec circle(number(), number(), number(), keyword() | map()) :: map()
```

Draw a circle. Defaults to stroke; pass `fill: true` for a filled disc.

    Mob.Canvas.circle(120, 120, 60, color: :primary)
    Mob.Canvas.circle(120, 120, 60, color: :primary, fill: true)

# `ellipse`

```elixir
@spec ellipse(number(), number(), number(), number(), keyword() | map()) :: map()
```

Draw an ellipse with separate horizontal and vertical radii.

    Mob.Canvas.ellipse(100, 80, 60, 30, color: :primary, fill: true)

# `image`

```elixir
@spec image(number(), number(), number(), number(), String.t(), keyword() | map()) ::
  map()
```

Draw an image into the rect at (x, y, w, h). `source` is an asset
name resolved by the platform (e.g. an iOS asset catalog name or
Android drawable name).

    Mob.Canvas.image(0, 0, 100, 100, "logo")

# `line`

```elixir
@spec line(number(), number(), number(), number(), keyword() | map()) :: map()
```

Stroke a line from (x1, y1) to (x2, y2).

    Mob.Canvas.line(0, 0, 100, 100, color: :primary, width: 4, cap: :round)

# `path`

```elixir
@spec path([{number(), number()} | [number()]], keyword() | map()) :: map()
```

Draw a path through a list of points. Points are 2-element lists or
2-tuples; tuples are normalised to lists for JSON serialisation.

Closed paths (`closed: true`) are wrapped back to the first point.
Filled paths (`fill: true`) are filled regardless of `:closed`.

    Mob.Canvas.path([{0, 0}, {100, 0}, {50, 80}], color: :primary, closed: true)

# `rect`

```elixir
@spec rect(number(), number(), number(), number(), keyword() | map()) :: map()
```

Draw a rectangle. Defaults to stroke; pass `fill: true` for filled.
`radius:` rounds the corners (single value, all four corners).

    Mob.Canvas.rect(10, 10, 100, 50, color: :primary, fill: true, radius: 8)

# `text`

```elixir
@spec text(number(), number(), String.t(), keyword() | map()) :: map()
```

Draw text at (x, y). The anchor controls horizontal alignment of the
text relative to x; vertical baseline is ascender (text grows downward
from y, matching SwiftUI/Compose Canvas defaults).

    Mob.Canvas.text(120, 50, "Hello", color: :on_surface, size: 18, anchor: :center)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
