Visualize.Components.Board (Visualize v0.8.0)

Copy Markdown View Source

A live board in LiveView (spec/15 §9, D-146): the grid, its cells, and the hooks that make them interactive, over a running Visualize.Board.Server.

A Phoenix.LiveComponent. It subscribes the page's process to the board when the page connects, lays the cells on the board's 12-column grid at the arrangement for the container's width (spec/15 §1.6), and renders each cell as its own Visualize.Components.Board.Cell component, so a frame updates one cell's component and the diff the page sends is that cell's alone.

<.live_component module={Visualize.Components.Board} id="ops"
                 server={@board} board={@board_value} />

def handle_info({:visualize_board, _board, _message} = message, socket) do
  Visualize.Components.Board.forward("ops", message)
  {:noreply, socket}
end

The board process sends its messages to the page's process, which hands them on with forward/2: a cell's view goes to that cell's component, and the board's window, zone and width to the board's. The hooks' pushes come back to this component — BoardHook's width (pushEventTo) and each cell's brushed window (BrushHook with data-brush-target) — and become calls on the board process, so the page handles no event of the board's.

Interaction across cells (spec/15 §13, D-151)

A brush sets the board's window once rapid brushes settle, and the header's Reset window restores the window the board was started with. A click on a chart, or Enter on a point the keyboard reached, picks the point: in a cell with a drill target it opens that target, and in any other it selects the datum's {field, value} across the board. The header shows the selection and Clear selection; Escape clears it too.

Events (spec/15 §9.2, D-170)

Everything the page is sent is one Visualize.Event, as {:visualize_event, id, %Visualize.Event{}}, id this component's:

  • a mark's declared event — a click on a datum whose mark's tooltip names an event (spec/14 §5.7) — with the cell, and the row as the mark drew it, typed, resolved by the cell's process against the drawing it holds;
  • :drill, value: %{board: ref, vars: vars}, when a pick in a cell with a drill resolves its target, with the picked row;
  • :brush, value: %{domain: [from, to] | nil}, under brush: :host;

  • :select, value: %{identity: identity | nil}, whenever the board's selection changes.

The component does not navigate. The page, which knows its routes, follows a drill:

def handle_info({:visualize_event, "ops", %Visualize.Event{event: :drill, value: %{board: :detail, vars: vars}}}, socket) do
  {:noreply, push_navigate(socket, to: "/detail?" <> URI.encode_query(vars))}
end

A host-owned window (brush: :host, D-161)

A page that keeps the window in its URL takes the brush itself. A brush, pushed once when its drag ends, is sent to the page as the :brush event with value: %{domain: [from, to]}, the ends UTC DateTimes, and the header's Reset window with value: %{domain: nil}; the component calls no window function. The page updates its URL and applies the window with Visualize.Board.Server.window/2 — %{from: from, to: to}, or its own default for nil — which is never debounced; Visualize.Board.Server.brush/2 takes the same window and debounces rapid re-brushes, if the page would rather.

Assigns

  • id - the component's id, the board's DOM id and the prefix of its cells' (required)
  • server - the board process: a pid or a registered name (required)
  • board - the %Visualize.Board{} it runs (required): its cells, titles and layout
  • theme - the theme a cell is drawn in before its first view (default Visualize.Theme.default/0)
  • title - the board's heading (default the board's meta.name)
  • width - the width the grid is arranged at until BoardHook pushes one (default 1200)
  • brush - who sets a brushed window: :server, the board process, or :host, the page (default :server)

Summary

Functions

The DOM and component id of a board's cell.

A board process's message handed to its component (spec/15 §9.2): a cell's view to the cell's component, the board's state to the board's. :ignore for any other message.

Functions

cell_id(board_id, cell)

@spec cell_id(String.t(), atom()) :: String.t()

The DOM and component id of a board's cell.

forward(id, arg2)

@spec forward(String.t(), term()) :: :ok | :ignore

A board process's message handed to its component (spec/15 §9.2): a cell's view to the cell's component, the board's state to the board's. :ignore for any other message.