agentscape
Version:
Agentscape is a library for creating agent-based simulations. It provides a simple API for defining agents and their behavior, and for defining the environment in which the agents interact. Agentscape is designed to be flexible and extensible, allowing
116 lines (96 loc) • 3.32 kB
text/typescript
/* 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()
}
}