UNPKG

nevera

Version:

Minimal 3kb charts as web components

90 lines (78 loc) 2.21 kB
import { html, svg, render } from "lit-html"; import { scaleBand, scaleLinear, attachEvents } from "../utils.js"; type Bars = { x: number; y: number; width: number; height: number; fill?: string; }[]; type Options = { width: number; height: number }; const getSvgTemplate = (bars: Bars, options: Options) => html`<svg width="100%" height="100%" viewBox="0 0 ${options.width} ${options.height}" xmlns="http://www.w3.org/2000/svg" > ${bars.map( (bar) => svg`<rect class="bar" x="${bar.x}" y="${bar.y}" width="${bar.width}" height="${bar.height}" style="fill: var(--nev-fill); stroke: var(--nev-stroke); stroke-width: var(--nev-stroke-width); fill: ${bar.fill}"> </rect>` )} </svg>`; type Data = Array<{ key: string; value: number; fill?: string; }>; const getChartData = (data: Data, options: Options) => { const x = scaleBand( data.map((d) => d.key), [0, options.width], 0.1 ); const y = scaleLinear([0, Math.max(...data.map((d) => d.value))], [options.height, 0]); const bars = data.map((d) => ({ x: x(d.key) || 0, y: y(d.value), fill: d.fill, width: x?.bandWidth ?? 1, height: options.height - y(d.value), })); return bars; }; class NeveraBarchart extends HTMLElement { static observedAttributes = ["height", "width"]; constructor() { super(); } _data?: Data = undefined; set data(val: Data | undefined) { this._data = val; this.renderSvg(); } get data() { return this._data; } connectedCallback() { this.renderSvg(); setTimeout(() => attachEvents(this.querySelector("svg")!, "rect", this.data!, this), 10); } renderSvg() { if (this.data) { const options = { width: Number(this.getAttribute("width")) || 400, height: Number(this.getAttribute("height")) || 200, }; const bars = getChartData(this.data, options); render(getSvgTemplate(bars, options), this); } } attributeChangedCallback(oldValue: string | null, newValue: string | null) { if (oldValue !== newValue) { this.renderSvg(); } } } if (!customElements.get("nev-barchart")) customElements.define("nev-barchart", NeveraBarchart);