// DataDashboard ~~ MIT License // Utilities // Imports import { ChartConfiguration, ChartDataset } from 'chart.js'; import { libX } from 'web-ignition'; // Modules import { WebAppChartColor } from './config'; import { webAppLookup } from './lookup'; // Types export type WebAppSettingsNarrowScreenSaver = { maxPoints: number, screenWidth: number, }; export type EventItem = (string | number | boolean)[]; const webAppUtil = { lookupChartColor(i: number): string { return (webAppLookup.chartColors[i % webAppLookup.chartColors.length]).value; }, addChartColors(datasets: ChartDataset[], startIndex = 0): ChartDataset[] { type ChartDataset$ = ChartDataset & { fill: boolean }; //patch library type const colorize = (dataset: ChartDataset, i: number) => { (dataset).fill = false; dataset.borderColor = webAppUtil.lookupChartColor(startIndex + i); dataset.backgroundColor = webAppUtil.lookupChartColor(startIndex + i); }; datasets.forEach(colorize); return datasets; }, narrowScreenSaver(chartInfo: ChartConfiguration, options?: Partial): ChartConfiguration { const defaults: WebAppSettingsNarrowScreenSaver = { maxPoints: 200, screenWidth: 700 }; const settings = { ...defaults, ...options }; const shrinkRatio = Math.ceil(chartInfo.data.labels!.length / settings.maxPoints); const shrinkNow = () => { const shrink = (points: number[]) => points.filter((_point, i) => i % shrinkRatio === 0); chartInfo.data.labels = shrink(chartInfo.data.labels); const setData = (dataset: ChartDataset) => dataset.data = shrink(dataset.data); chartInfo.data.datasets.forEach(setData); }; if (shrinkRatio > 1 && globalThis.window.innerWidth < settings.screenWidth) shrinkNow(); return chartInfo; }, secsToStr(epocSeconds: number): string { //example: "2019-01-02 05:34:15" return new Date(epocSeconds * 1000).toISOString().replace('T', '+').substring(0, 19); }, spinnerStart(widgetElem: Element): Element { // //

Title

// ... // //
const elem = widgetElem.closest('web-app-widget')!; const create = () => { const options = { html: '' }; const spinner = dna.dom.create('web-app-widget-spinner', options); spinner.style.paddingTop = String(elem.clientHeight / 2 - 50) + 'px'; elem.appendChild(libX.ui.makeIcons(spinner)); return spinner; }; const spinnerElem = elem.querySelector('web-app-widget-spinner') || create(); elem.classList.add('waiting'); dna.ui.fadeIn(dna.ui.hide(spinnerElem)); return widgetElem; }, spinnerStop(widgetElem: Element): Element { const elem = widgetElem.closest('web-app-widget')!; const spinner = elem.querySelector('web-app-widget-spinner')!; elem.classList.remove('waiting'); // dna.ui.fadeOut(spinner, { duration: 1500 }).then(dna.ui.hide); dna.ui.fadeOut(spinner).then(dna.ui.hide); return elem; }, }; const webAppNetwork = { logName: 'network-log', logEvent(...eventItems: EventItem): void { console.info(eventItems.join(' - ')); const maxLogEvents = 250; const log = webAppNetwork.getLog(); log.push(eventItems); while (log.length > maxLogEvents) log.shift(); localStorage.setItem(webAppNetwork.logName, JSON.stringify(log)); }, getLog(): EventItem[] { return JSON.parse(localStorage.getItem(webAppNetwork.logName) || '[]'); }, }; const webAppTransformer = { dataTablesNormalizer(rows: unknown[][], numColumns?: number, indexRemoveColumn?: number): string[][] { // Ensures the table rows are all equal length arrays of strings. const size = numColumns ? numColumns : rows.length ? (rows[0]).length : 0; const normalize = (row: unknown[]) => { const toStr = (value: unknown, i: number) => row[i] = ['boolean', 'number'].includes(typeof value) ? String(value) : ''; row.forEach((value: unknown, i: number) => typeof value !== 'string' && toStr(value, i)); if (indexRemoveColumn !== undefined) row.splice(indexRemoveColumn, 1); while (row.length < size) row.push(''); while (row.length > size) row.pop(); }; rows.forEach(normalize); return rows; }, }; export { webAppUtil, webAppNetwork, webAppTransformer };