vail/static/scripts/chart.mjs

122 lines
3.1 KiB
JavaScript
Raw Normal View History

2023-01-17 12:25:20 -07:00
import * as time from "./time.mjs"
2022-04-24 11:17:15 -06:00
/**
* A chart of historical values.
*
* Curently this assumes all values are between 0 and 1,
2022-04-24 11:17:15 -06:00
* since that's all I need.
*/
class HistoryChart {
/**
* @param {Element} canvas Canvas element to draw on
* @param {string} style style to draw in; falls back to the `data-style` attribute
2022-04-24 11:17:15 -06:00
* @param {Duration} duration Time to display history for
*/
2023-01-17 12:25:20 -07:00
constructor(canvas, style=null, duration=20*time.Second) {
2022-04-24 11:17:15 -06:00
this.canvas = canvas
this.ctx = canvas.getContext("2d")
this.duration = duration
this.data = []
// One canvas pixel = 20ms
2023-01-17 12:25:20 -07:00
canvas.width = duration / (20 * time.Millisecond)
2022-04-24 11:17:15 -06:00
// Set origin to lower-left corner
this.ctx.scale(1, -1)
this.ctx.translate(0, -canvas.height)
this.ctx.fillStyle = style || canvas.dataset.color || "black"
2022-04-24 11:17:15 -06:00
this.ctx.lineWdith = 2
2022-04-24 17:13:56 -06:00
this.running=true
2022-04-24 11:17:15 -06:00
this.draw()
}
/**
* Set value to something at the current time.
*
2022-04-24 11:17:15 -06:00
* This also cleans up the event list,
* purging anything that is too old to be displayed.
*
2022-04-24 17:13:56 -06:00
* @param {Number} value Value for the event
2022-04-24 11:17:15 -06:00
*/
Set(value) {
this.SetAt(value)
}
/**
* Set value to something at the provided time.
*
* This also cleans up the event list,
* purging anything that is too old to be displayed.
*
* @param {Number} value Value for the event
* @param {Number} when Time to set the value
*/
SetAt(value, when=null) {
2022-04-24 11:17:15 -06:00
let now = Date.now()
if (!when) when=now
2022-04-24 19:42:57 -06:00
this.data.push([when, value])
this.data.sort()
2022-04-24 11:17:15 -06:00
let earliest = now - this.duration
2022-04-24 14:28:20 -06:00
// Leave one old datapoint so we know the value when the window opens
while ((this.data.length > 1) && (this.data[1][0] < earliest)) {
2022-04-24 11:17:15 -06:00
this.data.shift()
}
2022-04-24 17:13:56 -06:00
}
2022-04-24 11:17:15 -06:00
2022-04-24 17:13:56 -06:00
Stop() {
this.running = false
2022-04-24 11:17:15 -06:00
}
draw() {
let now = Date.now()
let earliest = now - this.duration
let xScale = this.canvas.width / this.duration
2022-04-24 19:58:17 -06:00
let yScale = this.canvas.height
2022-04-24 11:17:15 -06:00
let y = 0
2022-04-24 17:13:56 -06:00
let x = 0
2022-04-24 11:17:15 -06:00
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
2022-04-24 11:17:15 -06:00
for (let point of this.data) {
2022-04-24 17:13:56 -06:00
let x2 = (point[0] - earliest) * xScale
let y2 = point[1] * yScale
if (y > 0) {
this.ctx.fillRect(x, 0, x2-x, y)
}
x=x2
y=y2
}
if (y > 0) {
this.ctx.fillRect(x, 0, this.canvas.width, y)
2022-04-24 11:17:15 -06:00
}
2022-04-24 17:13:56 -06:00
if (this.running) {
requestAnimationFrame(() => this.draw())
}
2022-04-24 11:17:15 -06:00
}
}
/**
* Return a new chart based on an HTML selector
*
* @param selector HTML selector
* @param style fill style
* @param duration duration of chart window
* @returns new chart, or null if it couldn't find a canvas
*/
2023-01-17 12:25:20 -07:00
function FromSelector(selector, style, duration=20*time.Second) {
let canvas = document.querySelector(selector)
if (canvas) {
return new HistoryChart(canvas, style, duration)
}
return null
}
export {HistoryChart, FromSelector}