diff --git a/static/chart.mjs b/static/chart.mjs index b4faca2..743f780 100644 --- a/static/chart.mjs +++ b/static/chart.mjs @@ -4,17 +4,17 @@ /** * A chart of historical values. - * - * Curently this assumes all values are between 0 and 1, + * + * 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 {string} style style to draw in; falls back to the `data-style` attribute * @param {Duration} duration Time to display history for */ - constructor(canvas, strokeStyle="black", duration=20*Second) { + constructor(canvas, style=null, duration=20*Second) { this.canvas = canvas this.ctx = canvas.getContext("2d") this.duration = duration @@ -23,13 +23,12 @@ class HistoryChart { // 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.fillStyle = strokeStyle + this.ctx.fillStyle = style || canvas.dataset.color || "black" this.ctx.lineWdith = 2 this.running=true @@ -37,21 +36,34 @@ class HistoryChart { } /** - * Add an event point at a given time. - * - * These must always be added in time order. - * + * Set value to something at the current time. + * * This also cleans up the event list, * purging anything that is too old to be displayed. - * - * @param {Number} when Time the event happened + * * @param {Number} value Value for the event */ - Add(when, value) { - let now = Date.now() - let earliest = now - this.duration + Set(value) { + this.SetAt(value) + } - this.data.push([when, 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) { + let now = Date.now() + if (!when) when=now + + this.data.push([now, value]) + this.data.sort() + + let earliest = now - this.duration // Leave one old datapoint so we know the value when the window opens while ((this.data.length > 1) && (this.data[1][0] < earliest)) { this.data.shift() @@ -93,4 +105,19 @@ class HistoryChart { } } -export {HistoryChart} +/** + * 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 + */ +function FromSelector(selector, style, duration=20*Second) { + let canvas = document.querySelector(selector) + if (canvas) { + return new HistoryChart(canvas, style, duration) + } + return null +} +export {HistoryChart, FromSelector} diff --git a/static/index.html b/static/index.html index f751869..1eca0d1 100644 --- a/static/index.html +++ b/static/index.html @@ -95,9 +95,10 @@
- - - + + + +
diff --git a/static/keyer.mjs b/static/keyer.mjs index acb4ea0..34ccb6d 100644 --- a/static/keyer.mjs +++ b/static/keyer.mjs @@ -1,5 +1,3 @@ -import * as Chart from "./chart.mjs" - /** Silent period between words */ const PAUSE_WORD = -7 /** Silent period between letters */ @@ -188,25 +186,6 @@ class Keyer { return this.last } - /** - * Set up various charts by providing canvases for them. - * - * @param {Element} txCanvas - * @param {Element} straightCanvas - * @param {Element} ditCanvas - * @param {Element} dahCanvas - */ - SetCanvas(txCanvas=null, straightCanvas=null, ditCanvas=null, dahCanvas=null) { - for (let c of [this.txChart, this.straightChart, this.ditChart, this.dahChart]) { - if (c) c.Stop() - } - - this.txChart = txCanvas?new Chart.HistoryChart(txCanvas, "red"):null - this.straightChart =straightCanvas?new Chart.HistoryChart(straightCanvas, "teal"):null - this.ditChart =ditCanvas?new Chart.HistoryChart(ditCanvas, "olive"):null - this.dahChart =dahCanvas?new Chart.HistoryChart(dahCanvas, "purple"):null - } - /** * Return true if we are currently playing out something */ @@ -351,9 +330,6 @@ class Keyer { } else { this.endTxFunc() } - if (this.straightChart) { - this.straightChart.Add(Date.now(), down?1:0) - } } /** @@ -370,9 +346,6 @@ class Keyer { this.Enqueue(DIT) } } - if (this.ditChart) { - this.ditChart.Add(Date.now(), down?1:0) - } } /** @@ -389,9 +362,6 @@ class Keyer { this.Enqueue(DAH) } } - if (this.dahChart) { - this.dahChart.Add(Date.now(), down?1:0) - } } } diff --git a/static/vail.mjs b/static/vail.mjs index 672ba1c..7aadab7 100644 --- a/static/vail.mjs +++ b/static/vail.mjs @@ -2,6 +2,7 @@ import * as Keyer from "./keyer.mjs" import * as Buzzer from "./buzzer.mjs" import * as Inputs from "./inputs.mjs" import * as Repeaters from "./repeaters.mjs" +import * as Chart from "./chart.mjs" const DefaultRepeater = "General" const Millisecond = 1 @@ -37,19 +38,11 @@ class VailClient { this.lamp = new Buzzer.Lamp() this.buzzer = new Buzzer.ToneBuzzer() this.keyer = new Keyer.Keyer(() => this.beginTx(), () => this.endTx()) - this.roboKeyer = new Keyer.Keyer( - () => { - this.buzzer.Buzz() - this.lamp.Buzz() - }, - () => { - this.buzzer.Silence() - this.lamp.Silence() - } - ) + this.roboKeyer = new Keyer.Keyer(() => this.Buzz(), () => this.Silence()) // Set up various input methods - this.inputs = Inputs.SetupAll(this.keyer) + // Send this as the keyer so we can intercept dit and dah events for charts + this.inputs = Inputs.SetupAll(this) // VBand: Keep track of how the user wants the single key to behave for (let e of document.querySelectorAll("[data-singlekey]")) { @@ -88,7 +81,6 @@ class VailClient { this.setTelegraphBuzzer(e.target.checked) }) this.inputInit("#timing-chart", e => { - console.log("moo") this.setTimingCharts(e.target.checked) }) @@ -104,6 +96,88 @@ class VailClient { document.querySelector("#muted").classList.add("hidden") }) } + + /** + * Straight key change (keyer shim) + * + * @param down If key has been depressed + */ + Straight(down) { + this.keyer.Straight(down) + if (this.straightChart) this.straightChart.Set(down?1:0) + } + + /** + * Dit key change (keyer shim) + * + * @param down If the key has been depressed + */ + Dit(down) { + this.keyer.Dit(down) + if (this.ditChart) this.ditChart.Set(down?1:0) + } + + /** + * Dah key change (keyer shim) + * + * @param down If the key has been depressed + */ + Dah(down) { + this.keyer.Dah(down) + if (this.dahChart) this.dahChart.Set(down?1:0) + } + + Buzz() { + this.buzzer.Buzz() + this.lamp.Buzz() + if (this.rxChart) this.rxChart.Set(1) + } + + Silence() { + this.buzzer.Silence() + this.lamp.Silence() + if (this.rxChart) this.rxChart.Set(0) + } + + BuzzDuration(tx, when, duration) { + this.buzzer.BuzzDuration(tx, when, duration) + this.lamp.BuzzDuration(tx, when, duration) + + let chart = tx?this.txChart:this.rxChart + if (chart) { + chart.SetAt(1, when) + chart.SetAt(0, when) + } + } + + /** + * Start the side tone buzzer. + * + * Called from the keyer. + */ + beginTx() { + this.beginTxTime = Date.now() + this.buzzer.Buzz(true) + if (this.txChart) this.txChart.Set(1) + } + + /** + * Stop the side tone buzzer, and send out how long it was active. + * + * Called from the keyer + */ + endTx() { + if (!this.beginTxTime) { + return + } + let endTxTime = Date.now() + let duration = endTxTime - this.beginTxTime + this.buzzer.Silence(true) + this.repeater.Transmit(this.beginTxTime, duration) + this.beginTxTime = null + if (this.txChart) this.txChart.Set(0) + } + /** * Toggle timing charts. @@ -116,17 +190,17 @@ class VailClient { let chartsContainer = document.querySelector("#charts") if (enable) { chartsContainer.classList.remove("hidden") - this.keyer.SetCanvas( - document.querySelector("#txChart"), - document.querySelector("#straightChart"), - document.querySelector("#ditChart"), - document.querySelector("#dahChart"), - ) + this.ditChart = Chart.FromSelector("#ditChart") + this.dahChart = Chart.FromSelector("#dahChart") + this.txChart = Chart.FromSelector("#txChart") + this.rxChart = Chart.FromSelector("#rxChart") } else { chartsContainer.classList.add("hidden") - this.keyer.SetCanvas() + this.ditChart = null + this.dahChart = null + this.txChart = null + this.rxChart = null } - console.log("timing chart", enable) } /** @@ -226,7 +300,7 @@ class VailClient { } /** - * Set up an input. + * Set up an HTML input element. * * This reads any previously saved value and sets the input value to that. * When the input is updated, it saves the value it's updated to, @@ -263,7 +337,6 @@ class VailClient { outputWpmElement.value = (1200 / value).toFixed(1) } if (callback) { - console.log("callback", selector) callback(e) } }) @@ -280,28 +353,6 @@ class VailClient { this.buzzer.Error() } - /** - * Start the side tone buzzer. - */ - beginTx() { - this.beginTxTime = Date.now() - this.buzzer.Buzz(true) - } - - /** - * Stop the side tone buzzer, and send out how long it was active. - */ - endTx() { - if (!this.beginTxTime) { - return - } - let endTxTime = Date.now() - let duration = endTxTime - this.beginTxTime - this.buzzer.Silence(true) - this.repeater.Transmit(this.beginTxTime, duration) - this.beginTxTime = null - } - /** * Called by a repeater class when there's something received. * @@ -320,8 +371,7 @@ class VailClient { return } - this.buzzer.BuzzDuration(false, when, duration) - this.lamp.BuzzDuration(false, when, duration) + this.BuzzDuration(false, when, duration) this.rxDurations.unshift(duration) this.rxDurations.splice(20, 2)