/* eslint-disable @typescript-eslint/no-explicit-any */ import ChartJS, { ChartConfiguration, ChartConfigurationCustomTypesPerDataset } from 'chart.js/auto' import { Color } from '../numbers' export interface DatasetOptions { label: string color?: Color } export interface ChartConstructor { root: HTMLElement datasets: DatasetOptions[] maxDataSize?: number axisLabels?: { x: string, y: string } title?: string width?: number } /** * Creates a time series chart. * The x-axis is time and the y-axis is a number. */ export default class TimeSeries { // private data: {x: number, y: number}[] = [] private chart: ChartJS<'line', number[], any> private width: number private maxDataSize: number constructor(opts: ChartConstructor) { const axisLabels = opts.axisLabels ?? { x: 'time', y: 'Y' } const title = opts.title ?? 'Time Series' this.maxDataSize = opts.maxDataSize ?? Infinity this.width = opts.width ?? 400 const canvas = document.createElement('canvas') const draggable = document.createElement('drag-pane') draggable.setAttribute('heading', title ) draggable.setAttribute('key', title) draggable.appendChild(canvas) opts.root.appendChild(draggable) canvas.width = this.width const datasets: ChartConfigurationCustomTypesPerDataset<'line', number[], any>['data']['datasets'] = opts.datasets.map((dataset) => { const borderColor = dataset.color?.toRGB() ?? Color.fromName('blue').toRGB() return { type: 'line', label: dataset.label, data: [], fill: false, borderColor, tension: 0.1 } }) const chartOptions: ChartConfiguration<'line', number[], any> = { type: 'line', data: { labels: [], datasets }, options: { scales: { x: { title: { display: true, text: axisLabels.x } }, y: { title: { display: true, text: axisLabels.y }, beginAtZero: true } } } } this.chart = new ChartJS<'line', number[], any>(canvas, chartOptions) } /** * Pushes data to the chart. * The data should be an array of numbers, where each array corresponds to a dataset * in the order they were added. */ public pushData(data: number[]): void { let didShift = false this.chart.data.datasets.forEach( dataset => { if (dataset.data.length > this.maxDataSize) { dataset.data.shift() didShift = true } }) if (didShift) { this.chart.data.labels.shift() } this.chart.data.datasets.forEach((dataset, i) => { dataset.data.push(data[i]) }) this.chart.data.labels.push('') this.chart.update() } }