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)