class Graph { constructor(canvas, color, maxHeight) { this.canvas = canvas; this.ctx = this.canvas.getContext("2d"); this.ctx.lineCap = 'round'; this.ctx.save(); this.scale = {x: 1, y: (this.canvas.height / maxHeight) || 1}; this.canvas.onresize = this.onresize(); this.setColor(color || "#000"); this.values = []; this.preDraw = this._dummyFunc; this.postDraw = this._dummyFunc; } getValue(i) { return this.values[i]; } getLength() { return this.values.length; } add(v) { this.values.push(v); } setColor(color) { this.color = color || "#000"; this.ctx.fillStyle = this.color; } updateScale() { this.onresize(); } onresize() { this.ctx.restore(); this.ctx.save(); this.ctx.fillStyle = this.color; this.ctx.translate(0, this.canvas.height); this.ctx.scale(this.scale.x, -this.scale.y); } draw() { this.preDraw(); this._draw(); this.postDraw(); } _draw() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.beginPath(); this.ctx.moveTo(0, 0); let step = this.canvas.width / (this.getLength() - 1); if (this.smooth) { for (let i = 0; i < this.getLength() - 2; i++) { let xc = (this.getValue(i) + this.getValue(i + 1)) / 2; this.ctx.quadraticCurveTo( step * i, this.getValue(i), (step * i + step * (i + 1)) / 2, xc ); } this.ctx.quadraticCurveTo( step * (this.getLength() - 1), this.getValue(this.getLength() - 2), step * this.getLength(), this.getValue(this.getLength() - 1) ); } else { for (let i = 0; i < this.getLength(); i++) { this.ctx.lineTo(step * i, this.getValue(i)); } } this.ctx.lineTo(this.canvas.width, 0); this.ctx.fill(); } _dummyFunc() {} } class MovingGraph extends Graph { constructor(canvas, color, maxHeight, bufferLength, bufferType) { super(canvas, color, maxHeight); let _bufferType = bufferType || Float32Array; this.buffer = new _bufferType(bufferLength || 64); this.offset = 0; } getValue(i) { return this.buffer[(this.offset + i) % this.buffer.length]; } getLength() { return this.buffer.length; } add(v) { this.buffer[this.offset] = v; this.offset = (this.offset + 1) % this.buffer.length; } }