# `Expresso.Element.Diagram`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/element/diagram.ex#L1)

An element that shows an SVG file as a diagram

The `src` option gives the path of the SVG file, and the path is relative to
the working directory of the command or to the `root` option of the deck, as
for an image. The render function
puts the SVG into the document as an element, and not as a data URI as
`Expresso.Element.Image` does. Therefore the rules of the theme reach the
parts of the diagram, and a part can show at a step.

A `part` entity names an element of the file by its `id`, and the `at`
option and the `on` entities of the part give the steps. The parts are the
children of the diagram, so the transformer gives each part its steps, and
the verifier checks each part against the diagram. The render function
writes the overlay attributes of a part on the element of the file that has
its `id`. A file without that `id` stops the render with a message that
names the id and the path.

A part with an `on` entity, or with an effect that moves or grows it, goes
into a wrapper, a `g` element with the class `diagram-part`, and the wrapper
gets the overlay attributes. The theme moves,
turns and outlines the wrapper, so the part keeps its own `transform`
attribute, and a turn goes around the center of the part. A `g` element is
valid only in an `svg`, a `g` or an `a` element. A part in a different
parent, such as a `tspan`, gets the attributes itself, and it can then only
fade, dim and change its color.

The `width` option gives the width of the diagram, as the option of an image
does, and a percentage is a part of the width of the slide. A diagram
without the option takes the width that the file gives.

The file goes into the document as it is, with one change. The document
holds one copy of the file for the present view, one for each page of the
handout view and one in the menu. A browser resolves a reference such as
`url(#fill)` to the first element of the document with that `id`, and a
`<style>` element applies to the whole document. Therefore
`Expresso.SvgCopy.number/2` gives each copy its own ids, its own references
and its own style rules. `Expresso.Copies` gives the number.

A part with a `class` in a `text` element keeps its class next to the
class `diagram-part`. The render function finds a part by its `id`
attribute, so an id such as `step.1` or `a:b` works.

A `.dot` or a `.gv` file is the source of a graph in the language of
Graphviz, and a `.d2` file is the source of a graph in the language of D2.
`draw/1` runs the tool before the render, and it keeps the SVG and the
names of the graph in the struct. `Expresso.Element.Diagram.Graphviz` and
`Expresso.Element.Diagram.D2` give each element of the graph a name from the
source, so a part names it in the words of the source. The `layout` option
gives the layout engine of the tool. With the `edges` option `:follow`, the
default, `draw/1` gives each edge without its own part the steps where both
of its ends show. `docs/graph-diagrams.md` gives the plan.

A `.mmd` file is the source of a diagram in the language of Mermaid, and
`Expresso.Element.Diagram.Pele` draws it with Pele in Node. The `source`
option gives the text of a diagram in the deck in place of a file, and the
`lang` option names its language, such as `:mermaid`. A diagram takes `src`
or `source`, and not both. `docs/mermaid-diagrams.md` gives the plan.

`Expresso.Deck.render/1` writes the document with Floki, which writes each
name of the SVG in lowercase. A browser reads `viewbox` as `viewBox` and
`lineargradient` as `linearGradient` inside an `svg` element, so the
diagram keeps its meaning.

# `t`

```elixir
@type t() :: %Expresso.Element.Diagram{
  __spark_metadata__: term(),
  alt: term(),
  at: term(),
  class: term(),
  colors: term(),
  easing: term(),
  edges: term(),
  effect: term(),
  el: term(),
  elements: term(),
  font: term(),
  lang: term(),
  layout: term(),
  morph: term(),
  names: term(),
  on: term(),
  signature: term(),
  source: term(),
  speed: term(),
  src: term(),
  steps: term(),
  svg: term(),
  width: term()
}
```

The struct of a diagram

# `check`

```elixir
@spec check(t()) :: {:ok, t()} | {:error, String.t()}
```

Refuse a diagram without one source, the options of a graph for an SVG file,
and a layout of a different tool

A diagram takes the `src` argument or the `source` option, and not both. The
`source` option needs the `lang` option, and a file takes no `lang` option,
because its extension gives its language. The entity of the DSL and
`Expresso.Builder` call this function.

# `draw`

```elixir
@spec draw(Expresso.Deck.t()) :: Expresso.Deck.t()
```

Run the tool of each graph of a deck, and keep the SVG and the names

`Expresso.Renderer` calls this function before `place/1`, so a render runs
each tool one time. A diagram of an SVG file does not change.

# `get_assigns`

```elixir
@spec get_assigns(t()) :: map()
```

Make the assigns of the render function from the struct

The key `overlay` holds the attributes of the overlay contract, from
`Expresso.Overlay.Render.attributes/1`, and, with the `alt` option, the
role `img` and the name of the diagram. The key `svg` holds the SVG with
the attributes of each part on its element. The function raises for a file
that it cannot read, and for an `id` that the file does not hold.

# `place`

```elixir
@spec place(Expresso.Deck.t()) :: Expresso.Deck.t()
```

Replace each `move_to` of the parts of a deck with a move

An `on` entity of a part can take `move_to`, the id of an element of the
SVG file. This function reads the file of each diagram with such an entity,
and `Expresso.Element.Diagram.Geometry.distance/3` gives the distance from
the center of the part to the center of that element. The function puts the
distance into `set` as `x` and `y`, in the units of the file, and the render
writes it as for each other `set`. A change of the file then changes the
move at the next render.

`Expresso.Renderer` calls this function before the render. It raises for
an id that the file does not have, and for an element with no shape.

# `render`

```elixir
@spec render(map()) :: Phoenix.HTML.safe()
```

Make the HTML of a diagram

# `text`

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

Return the SVG of a diagram

The SVG of a graph comes from `draw/1`, and the SVG of a file comes from the
file. `Expresso.Morph` reads the SVG with this function too.

---

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