PhoenixKitWeb.Components.Core.Chart (phoenix_kit v2.17.0)

Copy Markdown View Source

Server-rendered SVG chart primitives — no JavaScript, no external libraries. Charts re-render whenever LiveView assigns change, so they are live by construction. (They snap rather than tween: SVG geometry attributes are not CSS-transitionable.)

All charts draw in currentColor: set a text colour on the component (class="text-primary") and stroke, fill and gradient all follow it in light and dark themes.

Sizing

Each chart fills its container. The SVG uses preserveAspectRatio="none", so it stretches to whatever box you give it while strokes stay crisp via vector-effect="non-scaling-stroke". Give the wrapper a height — otherwise you inherit the viewBox's intrinsic ratio, which is rarely what you want:

<div class="h-48 w-full">
  <.line_chart id="p" data={@points} class="text-primary" />
</div>

Heavy stretching still distorts anything measured in user space: dash patterns and the bars' rounded corners. Strokes are protected; those are not.

Data

Values are plain numbers — callers map their domain (time, money, watts) to x/y first, which is what keeps these primitives generic: a price curve, a CPU graph and a signup funnel are all just {x, y} pairs.

Points may be {x, y} tuples or %{x: x, y: y} maps, and Decimal values are converted automatically (money and metrics arrive that way from Ecto). Points that aren't numeric are dropped rather than crashing the page; if nothing usable is left, the :empty slot renders.

Series are sorted by x, so out-of-order data plots correctly instead of zigzagging.

Origin: extracted from NordSwitch's live price charts; also intended as the drawing layer for phoenix_kit_dashboards widgets.

Summary

Functions

A vertical bar chart, measured from a zero baseline.

A line chart for a numeric series, optionally filled.

A minimal inline sparkline for a list of values.

Functions

bar_chart(assigns)

A vertical bar chart, measured from a zero baseline.

Examples

<.bar_chart
  id="daily-kwh"
  data={Enum.map(@days, &%{label: &1.date, value: &1.kwh})}
  aria_label="Daily consumption"
  class="text-secondary"
/>

Bars carry a native <title>, so hovering one shows its label and value with no JS. Negative values hang below the baseline instead of disappearing. A datum may set class: to colour one bar differently (%{label: "Fri", value: 22, class: "text-error"}).

Attributes

  • id (:string) (required) - Unique id (applied to the SVG element).
  • data (:list) (required) - List of %{label: term, value: number, class: optional_string}.
  • width (:integer) - Defaults to 960.
  • height (:integer) - Defaults to 200.
  • show_labels (:boolean) - Render labels beneath the bars. Defaults to false.
  • baseline (:boolean) - Draw the zero line when any value is negative (its position is not otherwise implied). Defaults to true.
  • class (:any) - Classes for the wrapper (set text-* for colour). Defaults to nil.
  • aria_label (:string) - Accessible name for the chart. Defaults to nil.
  • value_format (:any) - 1-arity fun formatting a value for its tooltip. No generic chart can infer units or locale, so pass your own. It receives the NUMBER, not your original struct — non-numeric values are dropped before this runs — so write &"$#{&1}", not &Money.to_string/1. Defaults to a compact numeric rendering. Defaults to nil.
  • Global attributes are accepted. Extra attributes for the wrapper.

Slots

  • empty - Rendered instead of the SVG when there is no usable data.

line_chart(assigns)

A line chart for a numeric series, optionally filled.

Examples

<%!-- a day of prices: x = minute of day, y = EUR/MWh --%>
<.line_chart
  id="price-day"
  data={Enum.map(@slots, &{minute_of_day(&1.starts_at), &1.eur_mwh})}
  x_domain={{0, 1440}}
  step
  marker_x={minute_of_day(@now)}
  aria_label="Electricity price today"
  class="text-primary"
/>

<%!-- a bare line, auto domains --%>
<.line_chart id="signups" data={@signups} area={false} />

With step each point holds its y until the next x (right-open steps — the correct reading for slot/interval data like prices). marker_x draws a dashed vertical "now" line. Domains default to the data's min/max, y padded by 10%; a reversed domain is normalised.

Attributes

  • id (:string) (required) - Unique id (namespaces the SVG gradient defs).
  • data (:list) (required) - Points as {x, y} tuples or %{x: , y: } maps. Non-numeric points are dropped.
  • step (:boolean) - Step interpolation (interval data). Defaults to false.
  • area (:boolean) - Fill a gradient area under the line. Defaults to true.
  • x_domain (:any) - {min, max} for x, or nil to fit data. Defaults to nil.
  • y_domain (:any) - {min, max} for y, or nil to fit data (10% padded). Defaults to nil.
  • marker_x (:any) - x position for a dashed vertical marker, or nil. Defaults to nil.
  • y_invert (:boolean) - Flip the y axis so SMALLER values plot higher. For rank-like data (search position, race place, leaderboard) where 1 is the best result and belongs at the top. Without it callers had to negate their own values, which flips the sign of every domain and marker they pass too. Defaults to false.
  • width (:integer) - viewBox width (the SVG scales to its container). Defaults to 960.
  • height (:integer) - viewBox height. Defaults to 240.
  • gridlines (:integer) - Number of horizontal gridlines (0 disables). Defaults to 3.
  • class (:any) - Classes for the wrapper (set text-* for colour). Defaults to nil.
  • aria_label (:string) - Accessible name. role="img" without one is an unlabelled graphic to a screen reader; pass what the chart shows. Unlabelled charts are marked decorative. Defaults to nil.
  • Global attributes are accepted. Extra attributes for the wrapper.

Slots

  • empty - Rendered instead of the SVG when there is no usable data.

sparkline(assigns)

A minimal inline sparkline for a list of values.

Examples

<.sparkline values={Enum.map(@upcoming, & &1.eur_mwh)} class="w-full h-12 text-info" />

A single value draws a flat line rather than nothing — one sample is a real state, and an empty box reads as a rendering bug.

Attributes

  • values (:list) (required) - Numbers, in order. Non-numeric values are dropped.
  • width (:integer) - viewBox width. Defaults to 200.
  • height (:integer) - viewBox height. Defaults to 48.
  • y_invert (:boolean) - Flip the y axis so SMALLER values plot higher — rank-like data. Defaults to false.
  • class (:any) - Classes for the wrapper (set text-* for colour). Defaults to nil.
  • aria_label (:string) - Accessible name. Left unset the sparkline is marked decorative. Defaults to nil.
  • Global attributes are accepted. Extra attributes for the wrapper.

Slots

  • empty - Rendered instead of the SVG when there is no usable data.