Semi circle progress

v0.0.10

v0.0.10StableMobStatelessApache-2.0
Installation mix mishka.ui.gen.mob semi_circle_progress
Source View Source

The Mishka Chelekom Mob Semi Circle Progress is a half circle gauge for iOS and Android apps built with Mob. It draws a real arc on a canvas and reads out the value, and it is the native port of the headless Semi Circle Progress.

Overview of the Mob Semi Circle Progress component for iOS and Android

The gauge is a true half circle. The component draws two arcs on Mob.UI.canvas/1 with Mob.Canvas.arc/6, a track and an indicator, from 180° to 360°. Angles start at 0° on the right and sweep clockwise, so the arc bulges up and the flat side sits at the bottom.

The proportions come from the web component, which draws its arcs in a viewBox of 0 0 200 108. The height is 0.54 times size, the default thickness is 0.06 times size, and the radius is inset by one stroke width, which leaves half a stroke of clearance at the edge. The gauge keeps the same shape at any size.

The track has a flat butt cap and the indicator has a round cap, as on the web. At a zero sweep the component leaves the indicator out, because a round cap with nothing to stroke would paint a small dot.

The readout is a real Text stacked over the canvas. Text drawn inside a canvas is only a drawing, so the platform has nothing to announce and a device test has nothing to find. The readout is the rounded percentage unless you set value_text.

size is the width of the gauge in dp, 140 by default. A canvas has a fixed size, so the gauge is exactly size wide and centered. A label appears as a centered caption under the gauge.

The value goes through the same range math as Mob Progress, so it is clamped into [min, max]. Semi Circle Progress has no events. It is a display, so the screen owns the value and any buttons that change it.

Generate the semi circle progress component

Run this from your Mob app's root to add the component to lib/<app>/components/:

bash
mix mishka.ui.gen.mob semi_circle_progress

The generator registers the <SemiCircleProgress> tag so you can use it in ~MOB markup. It also generates the Mob Progress component, because the gauge uses its range math. The examples on this page use the mishka_ prefix of the showcase app (--module-prefix mishka_), so the tag is <MishkaSemiCircleProgress>. Without a prefix the tag is <SemiCircleProgress>.

Semi circle progress gauge

Pass value and a label to draw the arc at the proportions of the web gauge. The gauge only displays the value, so the two buttons that change it by 15 belong to the screen. Clamp the value where you change it. The arc clamps what it draws, but an assign that keeps growing past 100 makes several taps do nothing before the arc moves again. The code below uses the showcase app's handle/2 callback. In your own screen, write those clauses as handle_info/2.

Semi circle progress gauge

A gauge card with a half circle arc filled to 72%, the readout 72%, the caption BATTERY and white minus 15 and dark plus 15 buttons
A half circle gauge labelled BATTERY filled to 87 percent with minus and plus buttons below.

Left: the example as it loads. Right: after a tap. The arc follows the value the screen holds.

elixir
<MishkaSemiCircleProgress value={@value} label="Battery" />

# the gauge is a display, so the buttons are the screen's
def handle(:up, socket), do: nudge(socket, +15)
def handle(:down, socket), do: nudge(socket, -15)

# clamp at the call site — the arc clamps, but a runaway assign means
# several taps do nothing before the needle moves again
defp nudge(socket, delta) do
  value = min(max(socket.assigns.value + delta, 0), 100)
  Mob.Socket.assign(socket, :value, value)
end

Semi circle progress with a custom readout

value_text replaces the percentage in the gauge. Here the range is 0 to 5, the value is 3 and the readout is 3 / 5. The screenshot also sets a STEPS caption and a green indicator with color.

Semi circle progress with a custom readout

Custom readout card with a green half circle arc filled to 60%, the readout 3 / 5 and the caption STEPS, in the MishkaMob showcase app on Android
heex
<MishkaSemiCircleProgress value={3} max={5} value_text="3 / 5" />

Props

PropTypeDefaultDescription
valuenumber or numeric stringminThe measurement. A numeric string such as "72" reads as 72, like the web attribute.
minnumber0Lower bound of the range.
maxnumber100Upper bound of the range.
labelstringnilCaption under the gauge. It is the web component's aria-label, shown as visible text.
value_textstringnilReplaces the readout. The default readout is a rounded percentage.
colorcolor token or ARGB integer:primaryIndicator color.
sizenumber140Gauge width in dp. The height follows at 0.54 times the width, as the web viewBox does.
thicknessnumber0.06 times sizeArc stroke width. It matches the web component's stroke-width of 12 in a w-48 box.

Differences from the web component

  • The svg_class, track_class, indicator_class, label_class and id attributes are not ported.
  • The web inner_block slot, which holds an arbitrary centered readout, is a string here: value_text.
  • label is the web component's aria-label. Mob has no accessibility layer to announce it into, so the component renders it as a visible caption instead of dropping it.