Chart is now a class, for easy usin'

This commit is contained in:
Neale Pickett 2022-04-24 13:17:15 -04:00
parent 96decf8166
commit 125579ec70
2 changed files with 106 additions and 61 deletions

View File

@ -2,67 +2,7 @@
<html>
<head>
<title>Chart-O-Matic</title>
<script>
data = []
const Millisecond = 1
const Second = 1000 * Millisecond
const ChartWidth = 20 * Second
function draw(canvas) {
let ctx = canvas.getContext("2d")
let now = Date.now()
let begin = now - ChartWidth
let xScale = canvas.width / ChartWidth
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.save()
// Make 0,0 be the lower-left corner, like in PostScript
ctx.scale(1, -1)
ctx.translate(0, -canvas.height)
ctx.strokeStyle = "red"
ctx.lineWidth = 2
let y = 0
ctx.moveTo(0, y)
ctx.beginPath()
for (let point of data) {
let x = (point[0] - begin) * xScale
ctx.lineTo(x, y)
y = point[1] * canvas.height
ctx.lineTo(x, y)
}
ctx.stroke()
ctx.restore()
requestAnimationFrame(() => draw(canvas))
}
function update() {
let now = Date.now()
let earliest = now - ChartWidth
data.push([now, Math.sin(now/Second)>0?1:0])
while (data[0][0] < earliest) {
data.shift()
}
}
function init() {
let canvas = document.querySelector("#chart")
canvas.width = ChartWidth / (20 * Millisecond)
setInterval(update, 50 * Millisecond)
draw(canvas)
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init)
} else {
init()
}
</script>
<script type="module" src="chart.mjs"></script>
</head>
<body>
<h1>The Amazing Chart-O-Matic</h1>

105
static/chart.mjs Normal file
View File

@ -0,0 +1,105 @@
/** @typedef {Number} Duration */
const Millisecond = 1
const Second = 1000 * Millisecond
/**
* A chart of historical values.
*
* Curently this assumes all values are between 0 and 1,
* since that's all I need.
*/
class HistoryChart {
/**
* @param {Element} canvas Canvas element to draw on
* @param {string} strokeStyle strokeStyle to draw in
* @param {Duration} duration Time to display history for
*/
constructor(canvas, strokeStyle, duration) {
this.canvas = canvas
this.ctx = canvas.getContext("2d")
this.duration = duration
this.data = []
this.max = 1
this.min = 0
// One canvas pixel = 20ms
canvas.width = duration / (20 * Millisecond)
// Set origin to lower-left corner
this.ctx.scale(1, -1)
this.ctx.translate(0, -canvas.height)
this.ctx.strokeStyle = strokeStyle
this.ctx.lineWdith = 2
this.draw()
}
/**
* Add an event point at a given time.
*
* These must always be added in time order.
*
* This also cleans up the event list,
* purging anything that is too old to be displayed.
*
* @param when Time the event happened
* @param value Value for the event
*/
Add(when, value) {
let now = Date.now()
let earliest = now - this.duration
this.data.push([when, value])
while (this.data[0][0] < earliest) {
this.data.shift()
}
console.log(this.data)
}
draw() {
let now = Date.now()
let earliest = now - this.duration
let xScale = this.canvas.width / this.duration
let y = 0
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.ctx.moveTo(0, y)
this.ctx.beginPath()
for (let point of this.data) {
let x = (point[0] - earliest) * xScale
this.ctx.lineTo(x, y)
y = point[1] * this.canvas.height
this.ctx.lineTo(x, y)
}
this.ctx.stroke()
requestAnimationFrame(() => this.draw())
}
}
export {HistoryChart}
// XXX: remove after testing
let chart
function init() {
let canvas = document.querySelector("#chart")
chart = new HistoryChart(canvas, "red", 20 * Second)
setInterval(update, 500 * Millisecond)
}
function update() {
let now = Date.now()
chart.Add(now, Math.sin(now/Second)/2 + 0.5)
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init)
} else {
init()
}