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/0fill fraction, clamped into0.0..1.0when rendering. Default0.0.:label-String.t/0title, ornil. Defaultnil. Truncated to the rect width.:orientation-:horizontal | :vertical. Default:horizontal; any value other than:verticalrenders 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. Defaulttrue.:show_label-boolean/0, draw:label. Defaulttrue; anillabel draws nothing either way.:style-map/0. Default%{}. Held on the state and never read byrender/2, which uses fixed track and text colours.:class- theme class atom or list of them, normalised byDrafter.Style.normalize_classes/1and reachingmount/1as:classes. Default[]. Held on the state and never read byrender/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
@type rgb() :: {0..255, 0..255, 0..255}
Functions
@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.
@spec component_tag() :: :meter
The component tag this widget registers under.
iex> Drafter.Widget.Meter.component_tag()
:meter
@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}
@spec handle_event(Drafter.Event.t(), t()) :: {:noreply, t()}
Ignores every event and returns {:noreply, state}. The meter is not focusable.
@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}}]
@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
@spec render(t() | Drafter.Widget.props(), Drafter.Widget.rect()) :: [ Drafter.Draw.Strip.t() ]
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.
Callback implementation for Drafter.Widget.unmount/1.
@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"}
@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]