# `Hakushi.Change`
[🔗](https://github.com/hattoriai/hakushi/blob/v0.1.0/lib/hakushi/change.ex#L1)

A change to a canvas: what a person did, or what the app does.

Every change goes the same way, whoever makes it: the canvas applies it
to its graph (`Hakushi.Graph.apply/2`), checks its rules
(`Hakushi.Rules`), asks the app (`on_change`), and only then shows it,
to the person and to everyone else on the canvas. A change the server
refuses goes back in the browser, with the reason.

`op` is one of:

  * `:add` - `nodes` is a list of `Hakushi.Node`s, `edges` a list of
    `Hakushi.Edge`s between them or others: a node dropped on the canvas,
    a paste, a duplicate, an undone delete.
  * `:connect` - `edges` is a list of `Hakushi.Edge`s, drawn by a person
    from a handle to a handle.
  * `:move` - `nodes` is a list of maps with `:id`, `:x` and `:y`,
    `:width` and `:height` for a node that was resized, and `:parent`
    for a node dropped into a group (an id) or out of one (`nil`). The
    nodes in a moved node move with it: `Hakushi.Graph.apply/2` lists
    them.
  * `:reconnect` - `edges` is a list of maps with `:id` and the new
    ends (`:source`, `:source_handle`, `:target`, `:target_handle`): an
    edge's end dragged to another handle.
  * `:update` - `nodes` is a list of maps with `:id` and the keys that
    change (`:data`, `:type`, `:locked`), `edges` a list of maps with
    `:id` and the keys that change (`:label`, `:path`, `:marker`,
    `:animated`, `:data`).
  * `:delete` - `nodes` and `edges` are lists of ids. Deleting a node
    deletes the nodes in it and the edges of all of them: the change
    that `Hakushi.Graph.apply/2` gives back lists them.

`by` is the `user` of the canvas that made it (a map with an `:id`), or
`nil` for the app's own.

# `op`

```elixir
@type op() :: :add | :connect | :move | :reconnect | :update | :delete
```

# `t`

```elixir
@type t() :: %Hakushi.Change{
  by: map() | nil,
  edges: [Hakushi.Edge.t() | map() | Hakushi.Edge.id()],
  nodes: [Hakushi.Node.t() | map() | Hakushi.Node.id()],
  op: op()
}
```

# `add`

```elixir
@spec add([Hakushi.Node.t() | map()], [Hakushi.Edge.t() | map()]) :: t()
```

Adds nodes, and edges.

# `connect`

```elixir
@spec connect(Hakushi.Edge.t() | map() | [Hakushi.Edge.t() | map()]) :: t()
```

Connects two nodes: an edge, or a list of them.

# `delete`

```elixir
@spec delete(keyword()) :: t()
```

Deletes nodes (with their edges) and edges, by id.

# `ids`

```elixir
@spec ids(t()) :: {[Hakushi.Node.id()], [Hakushi.Edge.id()]}
```

The ids of the nodes a change touches, and of its edges, as two lists.

# `move`

```elixir
@spec move([{Hakushi.Node.id(), number(), number()} | map()]) :: t()
```

Moves nodes: `[{id, x, y}]` or maps with `:id`, `:x` and `:y`.

# `reconnect`

```elixir
@spec reconnect([map()]) :: t()
```

Moves the ends of edges: maps with the edge's `:id` and its new
`:source`, `:source_handle`, `:target` or `:target_handle`.

# `update`

```elixir
@spec update(keyword()) :: t()
```

Changes nodes and edges: maps with an `:id` and the keys that change.

    Hakushi.Change.update(nodes: [%{id: "users", data: %{name: "people"}}])

---

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