Hakushi.Components (Hakushi v0.6.0)

Copy Markdown View Source

Function components for the canvas.

import Hakushi.Components

<.canvas id="schema" graph={@graph} on_change={&Schema.change/2}>
  <:node type="table" :let={node}>
    <div class="table">
      <h3>{node.data.name}</h3>
      <div :for={column <- node.data.columns} class="relative">
        <.handle id={column.name} kind={:target} side={:left} />
        {column.name}
        <.handle id={column.name} kind={:source} side={:right} />
      </div>
    </div>
  </:node>
</.canvas>

canvas/1 needs the Hakushi hook in the LiveSocket and the Hakushi CSS (see the README).

Summary

Functions

Renders a canvas: an endless sheet that people pan and zoom, with the nodes of graph on it, drawn by the :node slots, and its edges.

Renders a canvas in a frame of its own, for a page that has other things than the canvas: a document (a Kotoba embed), a card, a panel. The frame has a bar with the canvas's icon and title, the items of its kits (kit_items/1), the app's own actions, and a button that takes it full screen and back.

Renders an item that people drag onto a canvas, outside it: a palette of the things the canvas makes. Dropped on the canvas, it becomes the node that the canvas's new_node gives for item. Enter or a click puts it in the middle of the canvas, for the keyboard and for a touch screen.

Renders a handle: a point of a node where edges start (:source), end (:target), or both.

Renders the items of kits, outside a canvas: one for each element of each kit (a table, a step, a note), which people drag onto the canvas, or click (or Enter) to put one in its middle. See canvas_item/1.

Functions

canvas(assigns)

Renders a canvas: an endless sheet that people pan and zoom, with the nodes of graph on it, drawn by the :node slots, and its edges.

People move nodes by dragging them (or with the arrow keys), select them with a click, Shift and a box, connect them by dragging from a handle to a handle (or with C, see the Navigation guide), delete them with Delete, and copy, paste, duplicate, undo and redo with the usual keys. Each change goes to the server, which checks it (rules, then on_change) before anyone sees it, and takes it back in the browser when it refuses it.

Nodes

A :node slot draws the nodes of its type; a :node slot without a type draws the others. The slot gets the Hakushi.Node, and draws it from its data, with the handles where edges start and end (handle/1). A canvas with no :node slot draws each node as a box with its label.

A node is drawn once, and again when it changes: a change of its data (a change :update, or a new graph) draws it again; a change of the LiveView's own assigns does not.

The graph

Without live, the canvas keeps its own copy of graph, which its changes change. Give it a new graph (after the app's own change, say) and it shows what changed. With live, the graph is the room's (see Hakushi.Issho): make the app's changes with Hakushi.Live.change/2 or Hakushi.Issho.change/3.

Attributes

  • id (:string) (required) - the id of the canvas.
  • graph (Hakushi.Graph) (required) - the nodes and edges, a Hakushi.Graph.
  • on_change (:any) - fn change, context -> :ok | {:error, reason} end: the app's own check of each change, and where it saves it. context has the graph before the change and the result after it, by, who made it (on a shared canvas an Issho.Identity: a person, an agent and whom it acts for, or the server; alone, the canvas's user), and the canvas. See the Changes guide. Defaults to nil.

  • new_node (:any) - fn item, {x, y} -> node | nil end: the node for an item dropped on the canvas (canvas_item/1), or for a double click on the sheet (item is nil). A node with no id gets one. Defaults to nil.

  • rules (:any) - the rules of the edges, see Hakushi.Rules; they win over the rules of the kits. Defaults to [].
  • kits (:list) - kits (Hakushi.Kit) whose nodes the canvas draws, makes and edits by itself: [Hakushi.Kits.Schema]; see the Kits guide. Defaults to [].
  • issho (:any) - a canvas that everyone in its Issho room shares: [instance: MyApp.Issho, document: id], with the keys of every component (Issho.Join: :can, :people, :follow, :on_behalf_of, :claims); see Hakushi.Issho. Defaults to nil.
  • live (:any) - removed in 0.3: issho; see the Upgrading guide. Defaults to nil.
  • user (:map) - the person, on a shared canvas: the app's user, as its Issho.Actor says them (or a map with an :id, and a :name, :color and :avatar). Defaults to nil.
  • background (:any) - the paper: :dots, :lines (graph paper), :cross, :none, or the name of a paper of the app's own (see Hakushi.Paper); the default is the first kit's (Hakushi.Kit.canvas/0), else dots. A paper people chose (papers) wins. Defaults to nil.
  • grid (:integer) - the size of a square of the paper, in pixels at 100%; the default is a kit's, else 20. Defaults to nil.
  • snap (:boolean) - when true, nodes snap to the paper's grid; the default is a kit's, else false. Defaults to nil.
  • papers (:any) - the papers people choose from, in a picker of the controls: true for Hakushi's (dots, graph paper, crosses, none), or a list of them (:dots) and of the app's own (%{name: "iso", label: "Isometric"}); none by default. The paper chosen is the graph's (a change, which undoes and which everyone sees); see Hakushi.Paper. Defaults to nil.
  • wheel (:atom) - what the mouse wheel does: pan (and zoom with ⌘ or Ctrl), zoom, or scroll the page (and zoom with ⌘, Ctrl or a pinch), for a canvas in a page that scrolls, as an embed. Defaults to :pan. Must be one of :pan, :zoom, or :scroll.
  • fit (:any) - when true, the canvas opens on all of its nodes; when :readable, on all of them if they are large enough to read (60% or more), else on its most joined node and its neighbours, at a zoom people read: for a large graph (a schema of hundreds of tables), whose whole would show no detail. Defaults to true. Must be one of true, false, or :readable.
  • refit (:boolean) - when true, the canvas shows all of its nodes again when its box changes size, as an embed that goes full screen and back. Defaults to false.
  • min_zoom (:float) - the smallest zoom. Defaults to 0.1.
  • max_zoom (:float) - the largest zoom. Defaults to 4.0.
  • minimap (:boolean) - when true, an overview of the canvas in a corner. Defaults to true.
  • controls (:boolean) - when true, buttons to zoom, fit, tidy up, undo and redo, and to download the canvas. Defaults to true.
  • layout (:any) - the way the tidy up (⇧L, the controls) lays the nodes out: in layers from left to right (:right) or from top to bottom (:down), by forces (:force), or in a grid (:grid); :layered is :right, and {:layered, :down} is :down. The default is a kit's, else :right. People choose another in the menu by the tidy up button; see Layout and export. Defaults to nil.
  • tidy (:boolean) - when true, the canvas lays its nodes out (its layout) as it opens, before people see them, for a graph whose nodes have no places of their own (a schema read from a database); not on a shared canvas, whose places are the room's. See Layout and export. Defaults to false.
  • export (:boolean) - when true, a button of the controls downloads the canvas as an image. Defaults to true.
  • readonly (:any) - when true, people pan, zoom and select, and change nothing; when :arrange, they also move the nodes and tidy them up (and undo that), and change nothing else, as a diagram made from data; see Layout and export. Defaults to false. Must be one of true, false, or :arrange.
  • follow (:any) - removed in 0.3: issho's :follow. Defaults to nil.
  • label (:string) - the name of the canvas, for screen readers. Defaults to nil.
  • node_label (:any) - fn node -> text end: the name of a node for screen readers; the default is its data's label or name, or its id. Defaults to &Hakushi.Canvas.label/1.
  • locale (:string) - the locale of the canvas's own words; the default is config :hakushi, locale:, else "en". Defaults to nil.
  • messages (:map) - words that replace the built-in ones, see Hakushi.Messages. Defaults to nil.
  • class (:any) - classes for the canvas element. Defaults to nil.
  • Global attributes are accepted. attributes for the canvas element.

Slots

  • node - draws the nodes of a type (:let gets the Hakushi.Node). Accepts attributes:
    • type (:string) - the type of the nodes it draws; none for every other type.
    • resizable (:boolean) - when true, people resize these nodes by their corners.
    • group (:boolean) - when true, these nodes hold others: a node dropped on one goes in it, see Groups.
  • person - draws a person on a shared canvas (:let gets a map with "id", "name", "color", "avatar").
  • empty - shows on a canvas without nodes.

canvas_embed(assigns)

Renders a canvas in a frame of its own, for a page that has other things than the canvas: a document (a Kotoba embed), a card, a panel. The frame has a bar with the canvas's icon and title, the items of its kits (kit_items/1), the app's own actions, and a button that takes it full screen and back.

<.canvas_embed title={@diagram.title} for="diagram" kits={@kits} full={@full} on_full={JS.push("full")}>
  <.canvas id="diagram" graph={@diagram.graph} kits={@kits} wheel={:scroll} refit />
</.canvas_embed>

The frame takes the height of its parent (--hakushi-embed-height when the parent has none). Give its canvas wheel={:scroll}, so that the wheel scrolls the page around it, and refit, so that it shows all of its nodes when it goes full screen and back.

The frame does not go full screen by itself: on_full is the app's (a Phoenix.LiveView.JS command or an event name), and full says which way the button goes. A Kotoba embed gives both (see the Kits guide).

Attributes

  • title (:string) (required) - the canvas's title.
  • icon (:string) - a name of Hakushi.Icons. Defaults to "shapes".
  • subtitle (:string) - words after the title, as the kind of canvas. Defaults to nil.
  • for (:string) - the id of the canvas, for the items of kits. Defaults to nil.
  • kits (:list) - the kits whose items the bar has. Defaults to [].
  • readonly (:boolean) - when true, the bar has no items. Defaults to false.
  • full (:boolean) - whether the frame is full screen now. Defaults to false.
  • on_full (:any) - the phx-click of the full screen button; none without it. Defaults to nil.
  • locale (:string) - the locale of the words, as the canvas's. Defaults to nil.
  • messages (:map) - words that replace the built-in ones. Defaults to nil.
  • class (:any) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • heading - the app's own heading in place of the title, as a field to rename the canvas.
  • actions - the app's own buttons, before the full screen button.
  • inner_block (required) - the canvas.

canvas_item(assigns)

Renders an item that people drag onto a canvas, outside it: a palette of the things the canvas makes. Dropped on the canvas, it becomes the node that the canvas's new_node gives for item. Enter or a click puts it in the middle of the canvas, for the keyboard and for a touch screen.

<.canvas_item for="schema" item="table">New table</.canvas_item>

Attributes

  • for (:string) (required) - the id of the canvas.
  • item (:string) (required) - what it makes, for new_node.
  • class (:any) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • inner_block (required)

handle(assigns)

Renders a handle: a point of a node where edges start (:source), end (:target), or both.

A handle sits on a side of its nearest positioned ancestor: the node, or an element of it with position: relative, as a row of a table whose edges start at the row.

<div :for={column <- node.data.columns} class="relative">
  {column.name}
  <.handle id={column.name} side={:right} type={column.type} />
</div>

A node may have several handles with one id, on different sides (a row with a handle at each end): an edge meets the one nearest its other end, so the line takes the short way whichever side the other node is on.

type and accepts say what connects to what: a handle connects to a handle that accepts its type (any, when accepts is nil). While a person draws an edge, the handles it may end on show, and no others.

Attributes

  • id (:string) - the id of the handle in its node, the edges' source_handle or target_handle. Defaults to nil.
  • kind (:atom) - where edges start (:source), end (:target), or both. Defaults to :both. Must be one of :source, :target, or :both.
  • side (:atom) - the side it sits on. Defaults to :right. Must be one of :left, :right, :top, or :bottom.
  • type (:string) - what its edges carry, for accepts. Defaults to nil.
  • accepts (:list) - the types it takes; nil for any. Defaults to nil.
  • max (:integer) - the most edges it has; nil for any number. Defaults to nil.
  • label (:string) - its name, for screen readers. Defaults to nil.
  • class (:any) - Defaults to nil.
  • Global attributes are accepted.

kit_items(assigns)

Renders the items of kits, outside a canvas: one for each element of each kit (a table, a step, a note), which people drag onto the canvas, or click (or Enter) to put one in its middle. See canvas_item/1.

<.kit_items for="model" kits={[Hakushi.Kits.Schema]} />

Attributes

  • for (:string) (required) - the id of the canvas.
  • kits (:list) (required) - the canvas's kits.
  • locale (:string) - the locale of the words, as the canvas's. Defaults to nil.
  • messages (:map) - words that replace the built-in ones. Defaults to nil.
  • class (:any) - Defaults to nil.
  • Global attributes are accepted.