Sparkline
A small inline chart of a list of numbers: a line, an area or bars, safe with no data or flat data.
Demo
Revenue this week up 50%.
Get it
It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.
$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/sparkline.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/sparkline.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/sparkline.qwe
view SparklineDemo() = <div.demo-stack> <div.demo-row> <Sparkline values={[12, 18, 14, 22, 19, 26, 30]} label="Signups"/> <Sparkline values={[40, 38, 41, 35, 30, 32, 28, 24]} variant="area" tone="danger" label="Stock"/> <Sparkline values={[3, 7, 4, 9, 6, 11, 8, 12, 10, 14]} variant="area" tone="success" width={160}/> <Sparkline values={[4, 0, 7, 3, 5, 8, 2]} variant="bar" width={80} tone="info" label="Orders"/> </div> <p.demo-note>Revenue this week <Sparkline values={[5, 9, 7, 12, 10, 15]} width={64} height={18} dot={false}/> up 50%.</p> <div.demo-row> <Sparkline values={[]} label="Empty"/> <Sparkline values={[7]} label="One value"/> <Sparkline values={[5, 5, 5, 5]} tone="neutral" label="Flat"/> <Sparkline values={[-4, 2, -1, 5, -3]} variant="bar" tone="warning" width={80} label="Net"/> </div> </div>Source
ui/sparkline.qwe
// Sparkline: a small chart in the line of text, of a list of numbers.//// <Sparkline values={[12, 18, 14, 22, 30]}/>// <Sparkline values={daily_signups} variant="area" tone="success" label="Signups"/>// <Sparkline values={[4, 0, 7, 3]} variant="bar" width={80}/>//// values: the numbers, oldest first; it spans their lowest to their highest (a bar// chart starts at 0). No values draws a dashed line, one or all equal a flat one.// variant: "line" (default), "area" (the line, filled under) or "bar".// width and height: its size in pixels (120 by 32). tone: "accent" (default),// "neutral", "success", "warning", "danger" or "info". dot: the last point marked// (true by default). label: what it shows; screen readers hear "Signups: 12 to 30"// ("Trend" by default).import ui/theme.qwe use ui_clslet sparkline_css = css`.ui-spark { display: inline-block; vertical-align: middle; overflow: visible; color: var(--ui-accent); }.ui-spark-neutral { color: var(--ui-muted); }.ui-spark-success { color: var(--ui-success); }.ui-spark-warning { color: var(--ui-warning); }.ui-spark-danger { color: var(--ui-danger); }.ui-spark-info { color: var(--ui-info); }.ui-spark-line { fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }.ui-spark-fill { fill: currentColor; opacity: .14; stroke: none; }.ui-spark-none { fill: none; stroke: var(--ui-border); stroke-width: 1.5; stroke-dasharray: 3 3; }.ui-spark-dot { fill: currentColor; stroke: var(--ui-bg); stroke-width: 1.5; }.ui-spark-bar { fill: currentColor; opacity: .85; }.ui-spark-bar:last-child { opacity: 1; }`// A coordinate to one decimal, written the same on the server and in the browser.fn sparkline_num(n: num) -> str { let r = round(n * 10) / 10 r == floor(r) ? str(floor(r)) : str(r)}view Sparkline(values: list = [], width: int = 120, height: int = 32, variant: str = "line", tone: str = "accent", dot: bool = true, label: str = "Trend", class: str? = null) { style global sparkline_css let n = len(values) let pad = 3 let bars = variant == "bar" let lo = n == 0 ? 0 : (bars ? min([0, min(values)]) : min(values)) let hi = n == 0 ? 0 : (bars ? max([0, max(values)]) : max(values)) let span = hi - lo let y = (v) => span == 0 ? (bars ? height : height / 2) : pad + (hi - v) * (height - 2 * pad) / span let pts = n == 1 ? [values[0], values[0]] : values let m = len(pts) let xs = for i in range(m) => pad + i * (width - 2 * pad) / (m - 1) let line = "M" + join(for i in range(m) => `${sparkline_num(xs[i])},${sparkline_num(y(pts[i]))}`, " L") let bottom = sparkline_num(height - pad) let slot = n == 0 ? 0 : width / n let base = y(0) let said = n == 0 ? `${label}: no data` : `${label}: ${sparkline_num(values[0])}${n > 1 ? ` to ${sparkline_num(values[-1])}` : ""}` <svg class={ui_cls(["ui-spark", tone != "accent" && `ui-spark-${tone}`, class])} width={width} height={height} viewBox={`0 0 ${width} ${height}`} role="img" aria-label={said}> {n == 0 ? <path.ui-spark-none d={`M${pad},${sparkline_num(height / 2)} H${width - pad}`}/> : bars ? (for [i, v] in enumerate(values) => { let top = y(v) let tall = abs(base - top) <rect.ui-spark-bar x={sparkline_num(i * slot + slot * 0.15)} width={sparkline_num(slot * 0.7)} y={sparkline_num(tall < 1 ? base - 1 : (top < base ? top : base))} height={sparkline_num(tall < 1 ? 1 : tall)} rx="1"/> }) : [variant == "area" && <path.ui-spark-fill d={`${line} L${sparkline_num(xs[m - 1])},${bottom} L${sparkline_num(xs[0])},${bottom} Z`}/>, <path.ui-spark-line d={line}/>, dot && <circle.ui-spark-dot cx={sparkline_num(xs[m - 1])} cy={sparkline_num(y(pts[m - 1]))} r="2.5"/>]} </svg>}Related
AreaChartFilled areas for one or more series, overlapping or stacked into a total, with a hover crosshair listing every value.6 views · 8 downloadsBarChartBars up or across, one series or several grouped or stacked, on round ticks, with values on hover and a table for screen readers.7 views · 7 downloadsBollingerChartPrices with Bollinger bands of a period and a number of deviations, closes outside them marked, as a line or candles.7 views · 5 downloadsBoxPlotQuartiles, median, whiskers and outliers for each group, worked out from the raw values, with the five numbers on hover.5 views · 8 downloadsBrushChartA large chart of a range with an overview below, where a window dragged or moved by keys picks the range shown.6 views · 5 downloadsBubbleChartPoints placed by two numbers and sized by a third, in coloured groups, labelled when big enough, with all three numbers on hover.7 views · 9 downloads
Thread
Thread 0 posts
On Sparkline: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.