# `Toddy.Canvas.Shape`
[🔗](https://github.com/toddy-ui/toddy-elixir/blob/v0.3.0/lib/toddy/canvas/shape.ex#L1)

Convenience builders for canvas shape descriptors.

Every function produces a plain map with string keys, ready for the wire
protocol. These are optional helpers -- raw maps work identically.

## Basic shapes

    rect(10, 20, 100, 50, fill: "#ff0000")
    circle(50, 50, 25, stroke: stroke("#000", 2))
    line(0, 0, 100, 100, stroke: stroke("#333", 1, cap: "round"))
    text(10, 10, "Hello", fill: "#000", size: 16)

## Paths

    path([move_to(0, 0), line_to(100, 0), line_to(50, 80), close()],
      fill: "#0088ff",
      stroke: stroke("#000", 2)
    )

## Transforms

Transform commands are interleaved with shapes in a layer's shape list:

    [
      push_transform(),
      translate(100, 100),
      rotate(:math.pi() / 4),
      rect(0, 0, 50, 50, fill: "#f00"),
      pop_transform()
    ]

## Clipping

Clip regions restrict drawing to a rectangular area:

    [
      push_clip(10, 10, 100, 80),
      rect(0, 0, 200, 200, fill: "#ff0000"),
      pop_clip()
    ]

Clip regions nest -- inner clips are intersected with outer clips.

## Per-shape opacity

All shapes accept an `:opacity` option (0.0-1.0) that multiplies into
the fill and stroke color alpha channels:

    rect(0, 0, 100, 100, fill: "#ff0000", opacity: 0.5)
    circle(50, 50, 25, stroke: stroke("#000", 2), opacity: 0.3)

## Text alignment

The `text/4` builder accepts `:align_x` and `:align_y` options:

    text(100, 50, "Centered", fill: "#000", align_x: "center", align_y: "center")

Valid values for `:align_x`: `"left"`, `"center"`, `"right"`.
Valid values for `:align_y`: `"top"`, `"center"`, `"bottom"`.

## Gradients

Use `linear_gradient/3` as a `fill` value:

    rect(0, 0, 200, 100,
      fill: linear_gradient({0, 0}, {200, 0}, [{0.0, "#ff0000"}, {1.0, "#0000ff"}])
    )

# `arc`

```elixir
@spec arc(
  cx :: number(),
  cy :: number(),
  r :: number(),
  start_angle :: number(),
  end_angle :: number()
) :: list()
```

Arc path command (center, radius, start and end angles in radians).

# `arc_to`

```elixir
@spec arc_to(
  x1 :: number(),
  y1 :: number(),
  x2 :: number(),
  y2 :: number(),
  radius :: number()
) :: list()
```

Tangent arc path command.

# `bezier_to`

```elixir
@spec bezier_to(
  cp1x :: number(),
  cp1y :: number(),
  cp2x :: number(),
  cp2y :: number(),
  x :: number(),
  y :: number()
) :: list()
```

Cubic bezier curve path command.

# `circle`

```elixir
@spec circle(x :: number(), y :: number(), r :: number(), opts :: keyword()) :: map()
```

Builds a circle shape descriptor.

# `close`

```elixir
@spec close() :: String.t()
```

Close path command.

# `ellipse`

```elixir
@spec ellipse(
  cx :: number(),
  cy :: number(),
  rx :: number(),
  ry :: number(),
  rotation :: number(),
  start_angle :: number(),
  end_angle :: number()
) :: list()
```

Ellipse path command.

# `image`

```elixir
@spec image(
  source :: String.t(),
  x :: number(),
  y :: number(),
  w :: number(),
  h :: number(),
  opts :: keyword()
) :: map()
```

Draws a raster image on the canvas at the given position and size.

## Options

- `:rotation` -- rotation angle in radians.
- `:opacity` -- opacity multiplier (0.0-1.0).

# `line`

```elixir
@spec line(
  x1 :: number(),
  y1 :: number(),
  x2 :: number(),
  y2 :: number(),
  opts :: keyword()
) :: map()
```

Builds a line shape descriptor.

# `line_to`

```elixir
@spec line_to(x :: number(), y :: number()) :: list()
```

Line-to path command.

# `linear_gradient`

```elixir
@spec linear_gradient(
  from :: {number(), number()},
  to :: {number(), number()},
  stops :: [{number(), String.t()}]
) :: map()
```

Builds a linear gradient descriptor, usable as a `fill` value.

Stops are `{offset, color}` tuples where offset is 0.0..1.0.

# `move_to`

```elixir
@spec move_to(x :: number(), y :: number()) :: list()
```

Move-to path command.

# `path`

```elixir
@spec path(commands :: [map() | list() | String.t()], opts :: keyword()) :: map()
```

Builds an arbitrary path shape descriptor.

Commands are produced by `move_to/2`, `line_to/2`, `bezier_to/6`,
`quadratic_to/4`, `arc/5`, `arc_to/5`, `ellipse/7`, `rounded_rect/5`,
and `close/0`.

# `pop_clip`

```elixir
@spec pop_clip() :: map()
```

Pops the most recent clipping rectangle.

# `pop_transform`

```elixir
@spec pop_transform() :: map()
```

Pop (restore) the previously saved transform state from the stack.

# `push_clip`

```elixir
@spec push_clip(x :: number(), y :: number(), w :: number(), h :: number()) :: map()
```

Pushes a clipping rectangle. All shapes until the matching pop_clip are clipped to this region.

# `push_transform`

```elixir
@spec push_transform() :: map()
```

Push (save) the current transform state onto the stack.

# `quadratic_to`

```elixir
@spec quadratic_to(cpx :: number(), cpy :: number(), x :: number(), y :: number()) ::
  list()
```

Quadratic bezier curve path command.

# `rect`

```elixir
@spec rect(
  x :: number(),
  y :: number(),
  w :: number(),
  h :: number(),
  opts :: keyword()
) :: map()
```

Builds a rectangle shape descriptor.

# `rotate`

```elixir
@spec rotate(angle :: number()) :: map()
```

Rotate the coordinate system (angle in radians).

# `rounded_rect`

```elixir
@spec rounded_rect(
  x :: number(),
  y :: number(),
  w :: number(),
  h :: number(),
  radius :: number()
) :: list()
```

Rounded rectangle path command.

# `scale`

```elixir
@spec scale(x :: number(), y :: number()) :: map()
```

Scale the coordinate system.

# `stroke`

```elixir
@spec stroke(color :: String.t(), width :: number(), opts :: keyword()) :: map()
```

Builds a stroke descriptor.

## Options

- `:cap` -- line cap: `"butt"`, `"round"`, or `"square"`. Default: `"butt"`.
- `:join` -- line join: `"miter"`, `"round"`, or `"bevel"`. Default: `"miter"`.
- `:dash` -- dash pattern as `{segments, offset}` where segments is a list
  of numbers and offset is the starting offset.

# `svg`

```elixir
@spec svg(
  source :: String.t(),
  x :: number(),
  y :: number(),
  w :: number(),
  h :: number()
) :: map()
```

Draws an SVG on the canvas at the given position and size.

# `text`

```elixir
@spec text(x :: number(), y :: number(), content :: String.t(), opts :: keyword()) ::
  map()
```

Builds a text shape descriptor.

# `translate`

```elixir
@spec translate(x :: number(), y :: number()) :: map()
```

Translate the coordinate origin.

---

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