Drafter.Widget.Meter (drafter v0.3.1)

Copy Markdown View Source

Renders a horizontal or vertical meter with threshold-based color zones.

Uses Unicode eighth-block characters for sub-character precision on horizontal meters and vertical block characters for vertical meters. Color zones are defined via configurable thresholds.

Component tag

Tag :meter, built by Drafter.App as {:meter, opts}:

meter(opts)

There is no positional argument; every prop comes from opts.

Options

  • :value - float/0 fill fraction, clamped into 0.0..1.0 when rendering. Default 0.0.
  • :label - String.t/0 title, or nil. Default nil. Truncated to the rect width.
  • :orientation - :horizontal | :vertical. Default :horizontal; any value other than :vertical renders horizontally.

  • :thresholds - [{float(), {r, g, b}}] upper bounds sorted ascending before use; the first bound the value is <= supplies the colour, and the last entry covers everything above it. Default [{0.6, {80, 200, 100}}, {0.8, {255, 200, 0}}, {1.0, {255, 60, 60}}].
  • :show_value - boolean/0, draw the rounded percentage. Default true.
  • :show_label - boolean/0, draw :label. Default true; a nil label draws nothing either way.
  • :style - map/0. Default %{}. Held on the state and never read by render/2, which uses fixed track and text colours.
  • :class - theme class atom or list of them, normalised by Drafter.Style.normalize_classes/1 and reaching mount/1 as :classes. Default []. Held on the state and never read by render/2.

update/2 accepts every key above plus :app_module. Through the component tree only :value, :label, :orientation, :thresholds, :show_value and :show_label are live-updatable — update_props_from_mount/3 drops :style, :classes and :app_module, making them mount-only.

Usage

meter(value: 0.72)
meter(value: 0.45, label: "CPU", orientation: :vertical)
meter(value: 0.95, thresholds: [{0.5, {0, 200, 0}}, {0.75, {255, 200, 0}}, {1.0, {255, 0, 0}}])

Summary

Functions

Sets :value from the newest entry of a Drafter.RingBuffer.

The component tag this widget registers under.

Builds the props map for a {:meter, opts} element.

Ignores every event and returns {:noreply, state}. The meter is not focusable.

Builds the widget state from props.

The number of rows the element asks for.

Draws the meter into rect.

Callback implementation for Drafter.Widget.unmount/1.

Replaces the state fields named in props, keeping the current value for any key that is absent.

Narrows a re-render to the props that may change after mount.

Types

rgb()

@type rgb() :: {0..255, 0..255, 0..255}

t()

@type t() :: %Drafter.Widget.Meter{
  app_module: module() | nil,
  classes: [atom()],
  label: String.t() | nil,
  orientation: :horizontal | :vertical,
  show_label: boolean(),
  show_value: boolean(),
  style: map(),
  thresholds: [threshold()],
  value: float()
}

threshold()

@type threshold() :: {float(), rgb()}

Functions

apply_data_buffer(state, buffer, rect)

@spec apply_data_buffer(t(), Drafter.RingBuffer.t(), Drafter.Widget.rect()) :: t()

Sets :value from the newest entry of a Drafter.RingBuffer.

Returns state unchanged when the buffer is empty. The rect is ignored.

component_tag()

@spec component_tag() :: :meter

The component tag this widget registers under.

iex> Drafter.Widget.Meter.component_tag()
:meter

focused(state)

from_component_opts(args, opts)

@spec from_component_opts(
  term(),
  keyword()
) :: Drafter.Widget.props()

Builds the props map for a {:meter, opts} element.

The positional argument is ignored. :class is normalised into the :classes key and :__app_module__ into :app_module; every other option keeps its name and the default stated in the module doc.

iex> props = Drafter.Widget.Meter.from_component_opts(nil, value: 0.5, class: :danger)
iex> {props.value, props.classes, props.orientation}
{0.5, [:danger], :horizontal}

handle_event(event, state)

@spec handle_event(Drafter.Event.t(), t()) :: {:noreply, t()}

Ignores every event and returns {:noreply, state}. The meter is not focusable.

mount(props)

@spec mount(Drafter.Widget.props()) :: t()

Builds the widget state from props.

Every option listed in the module doc is read here with the default stated there.

iex> Drafter.Widget.Meter.mount(%{}).value
0.0

iex> state = Drafter.Widget.Meter.mount(%{value: 0.4, label: "CPU"})
iex> {state.label, state.orientation, state.show_value, state.show_label}
{"CPU", :horizontal, true, true}

iex> Drafter.Widget.Meter.mount(%{}).thresholds
[{0.6, {80, 200, 100}}, {0.8, {255, 200, 0}}, {1.0, {255, 60, 60}}]

preferred_height(args, opts)

@spec preferred_height(
  term(),
  keyword()
) :: pos_integer()

The number of rows the element asks for.

A vertical meter asks for opts[:height], default 8. A horizontal meter asks for 2 when a non-nil :label is given and :show_label is not false, and 1 otherwise. :height is ignored for a horizontal meter.

iex> Drafter.Widget.Meter.preferred_height(nil, [])
1

iex> Drafter.Widget.Meter.preferred_height(nil, label: "CPU")
2

iex> Drafter.Widget.Meter.preferred_height(nil, label: "CPU", show_label: false)
1

iex> Drafter.Widget.Meter.preferred_height(nil, orientation: :vertical)
8

render(state, rect)

Draws the meter into rect.

state may be a plain props map, in which case it is passed through mount/1 first. A horizontal meter returns one strip, or two when a label is drawn. A vertical meter returns an optional label row, rect.height minus the label and value rows of bar rows, and an optional percentage row.

unmount(state)

Callback implementation for Drafter.Widget.unmount/1.

update(props, state)

@spec update(Drafter.Widget.props(), t()) :: t()

Replaces the state fields named in props, keeping the current value for any key that is absent.

Accepts :value, :label, :orientation, :thresholds, :show_value, :show_label, :style, :classes and :app_module.

iex> state = Drafter.Widget.Meter.mount(%{value: 0.2, label: "CPU"})
iex> updated = Drafter.Widget.Meter.update(%{value: 0.9}, state)
iex> {updated.value, updated.label}
{0.9, "CPU"}

update_props_from_mount(mount_props, existing_state, opts)

@spec update_props_from_mount(Drafter.Widget.props(), term(), keyword()) ::
  Drafter.Widget.props()

Narrows a re-render to the props that may change after mount.

Returns :value, :label, :orientation, :thresholds, :show_value and :show_label. :style, :classes and :app_module are dropped, so they are mount-only through the component tree.

iex> props = Drafter.Widget.Meter.from_component_opts(nil, value: 0.5, class: :danger)
iex> Drafter.Widget.Meter.update_props_from_mount(props, %{}, []) |> Map.keys() |> Enum.sort()
[:label, :orientation, :show_label, :show_value, :thresholds, :value]