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
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, aHakushi.Graph.on_change(:any) -fn change, context -> :ok | {:error, reason} end: the app's own check of each change, and where it saves it.contexthas thegraphbefore the change and theresultafter it,by, who made it (on a shared canvas anIssho.Identity: a person, an agent and whom it acts for, or the server; alone, the canvas'suser), and thecanvas. See the Changes guide. Defaults tonil.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 (itemisnil). A node with noidgets one. Defaults tonil.rules(:any) - the rules of the edges, seeHakushi.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); seeHakushi.Issho. Defaults tonil.live(:any) - removed in 0.3:issho; see the Upgrading guide. Defaults tonil.user(:map) - the person, on a shared canvas: the app's user, as itsIssho.Actorsays them (or a map with an:id, and a:name,:colorand:avatar). Defaults tonil.background(:any) - the paper::dots,:lines(graph paper),:cross,:none, or the name of a paper of the app's own (seeHakushi.Paper); the default is the first kit's (Hakushi.Kit.canvas/0), else dots. A paper people chose (papers) wins. Defaults tonil.grid(:integer) - the size of a square of the paper, in pixels at 100%; the default is a kit's, else 20. Defaults tonil.snap(:boolean) - whentrue, nodes snap to the paper's grid; the default is a kit's, elsefalse. Defaults tonil.papers(:any) - the papers people choose from, in a picker of the controls:truefor 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); seeHakushi.Paper. Defaults tonil.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) - whentrue, 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 totrue. Must be one oftrue,false, or:readable.refit(:boolean) - whentrue, the canvas shows all of its nodes again when its box changes size, as an embed that goes full screen and back. Defaults tofalse.min_zoom(:float) - the smallest zoom. Defaults to0.1.max_zoom(:float) - the largest zoom. Defaults to4.0.minimap(:boolean) - whentrue, an overview of the canvas in a corner. Defaults totrue.controls(:boolean) - whentrue, buttons to zoom, fit, tidy up, undo and redo, and to download the canvas. Defaults totrue.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);:layeredis: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 tonil.tidy(:boolean) - whentrue, the canvas lays its nodes out (itslayout) 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 tofalse.export(:boolean) - whentrue, a button of the controls downloads the canvas as an image. Defaults totrue.readonly(:any) - whentrue, 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 tofalse. Must be one oftrue,false, or:arrange.follow(:any) - removed in 0.3:issho's:follow. Defaults tonil.label(:string) - the name of the canvas, for screen readers. Defaults tonil.node_label(:any) -fn node -> text end: the name of a node for screen readers; the default is its data'slabelorname, or its id. Defaults to&Hakushi.Canvas.label/1.locale(:string) - the locale of the canvas's own words; the default isconfig :hakushi, locale:, else "en". Defaults tonil.messages(:map) - words that replace the built-in ones, seeHakushi.Messages. Defaults tonil.class(:any) - classes for the canvas element. Defaults tonil.- Global attributes are accepted. attributes for the canvas element.
Slots
node- draws the nodes of a type (:letgets theHakushi.Node). Accepts attributes:type(:string) - the type of the nodes it draws; none for every other type.resizable(:boolean) - whentrue, people resize these nodes by their corners.group(:boolean) - whentrue, these nodes hold others: a node dropped on one goes in it, see Groups.
person- draws a person on a shared canvas (:letgets a map with "id", "name", "color", "avatar").empty- shows on a canvas without nodes.
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 ofHakushi.Icons. Defaults to"shapes".subtitle(:string) - words after the title, as the kind of canvas. Defaults tonil.for(:string) - the id of the canvas, for the items ofkits. Defaults tonil.kits(:list) - the kits whose items the bar has. Defaults to[].readonly(:boolean) - whentrue, the bar has no items. Defaults tofalse.full(:boolean) - whether the frame is full screen now. Defaults tofalse.on_full(:any) - thephx-clickof the full screen button; none without it. Defaults tonil.locale(:string) - the locale of the words, as the canvas's. Defaults tonil.messages(:map) - words that replace the built-in ones. Defaults tonil.class(:any) - Defaults tonil.- 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.
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, fornew_node.class(:any) - Defaults tonil.- Global attributes are accepted.
Slots
inner_block(required)
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_handleortarget_handle. Defaults tonil.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, foraccepts. Defaults tonil.accepts(:list) - the types it takes;nilfor any. Defaults tonil.max(:integer) - the most edges it has;nilfor any number. Defaults tonil.label(:string) - its name, for screen readers. Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted.
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 tonil.messages(:map) - words that replace the built-in ones. Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted.