UNPKG

nevera

Version:

Minimal 3kb charts as web components

109 lines (95 loc) 2.32 kB
import { html, svg, render } from "lit-html"; import { attachEvents } from "../utils.js"; type Slices = { value: number; deg: number; fill?: string; }[]; type Options = { total: number }; const getSvgTemplate = (slices: Slices) => html`<svg width="100%" height="100%" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" style="transform: rotate(-0.25turn)" > <circle r="10" cx="10" cy="10" class="bg" shape-rendering="geometricPrecision" style="fill: var(--nev-bg);" /> ${slices.map( (slice) => svg`<circle r="5" cx="10" cy="10" fill="transparent" stroke="${slice.fill}" stroke-width="10" stroke-dasharray="${(slice.value * 31.42) / 100} 31.42" style="transform-origin: 10px;transform: rotate(${slice.deg}deg)" />` )} </svg>`; type Data = Array<{ key: string; value: number; fill?: string; }>; const getChartData = (data: Data, options: Options) => { const dataTotal = data.reduce((acc, d) => acc + d.value, 0); const total = options.total || dataTotal; let progress = 0; const slices = data.map((d) => { const step = (d.value / total) * 100; const res = { value: step, deg: progress * 3.6, fill: d.fill, }; progress += step; return res; }); return slices; }; class NeveraPieChart extends HTMLElement { static observedAttributes = ["total"]; constructor() { super(); } _data?: Data = undefined; set data(val: Data | undefined) { this._data = val; this.renderSvg(); } get data() { return this._data; } codeEl: HTMLElement | null = null; styleEl: HTMLStyleElement | null = null; connectedCallback() { this.renderSvg(); setTimeout( () => attachEvents(this.querySelector("svg")!, "circle:not(.bg)", this.data!, this), 10 ); } renderSvg() { if (this.data) { const options = { total: Number(this.getAttribute("total")), }; const slices = getChartData(this.data, options); render(getSvgTemplate(slices), this); } } attributeChangedCallback(oldValue: string | null, newValue: string | null) { if (oldValue !== newValue) { this.renderSvg(); } } } if (!customElements.get("nev-piechart")) customElements.define("nev-piechart", NeveraPieChart);