From 0f5bd684c7f1da555fa40020ac85884c3b9c3bb1 Mon Sep 17 00:00:00 2001 From: e7d Date: Fri, 9 Jun 2023 18:28:25 +0200 Subject: [PATCH] remove Google Charts dependency from telemetry template --- js/gamepad.js | 12 +- templates/debug/template.js | 2 +- templates/ds4/template.js | 2 +- templates/dualsense/template.js | 2 +- templates/telemetry/template.html | 2 +- templates/telemetry/template.js | 180 ++++++++++++++---------------- templates/xbox-one/template.js | 2 +- 7 files changed, 92 insertions(+), 110 deletions(-) diff --git a/js/gamepad.js b/js/gamepad.js index 6ba7b13..4134903 100644 --- a/js/gamepad.js +++ b/js/gamepad.js @@ -754,22 +754,22 @@ class Gamepad { * Loads the template script and stylesheet */ loadTemplateAssets() { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = `templates/${this.type}/template.css`; + this.$gamepad.appendChild(link); + const script = document.createElement('script'); script.async = true; script.src = `templates/${this.type}/template.js`; script.onload = () => { // initialize the template - this.template = new this.templateClass(); + this.template = new this.TemplateClass(); // enqueue the initial display refresh this.startTemplate(); } this.$gamepad.appendChild(script); - - const link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = `templates/${this.type}/template.css`; - this.$gamepad.appendChild(link); } /** diff --git a/templates/debug/template.js b/templates/debug/template.js index 131a47b..095d22e 100644 --- a/templates/debug/template.js +++ b/templates/debug/template.js @@ -1,4 +1,4 @@ -window.gamepad.templateClass = class DebugTemplate { +window.gamepad.TemplateClass = class DebugTemplate { /** * Instanciates a new debug template */ diff --git a/templates/ds4/template.js b/templates/ds4/template.js index e17c1b4..dc47642 100644 --- a/templates/ds4/template.js +++ b/templates/ds4/template.js @@ -1,4 +1,4 @@ -window.gamepad.templateClass = class DualShock4Template { +window.gamepad.TemplateClass = class DualShock4Template { /** * Instanciates a new DualShock 4 controller template */ diff --git a/templates/dualsense/template.js b/templates/dualsense/template.js index 4f10a33..66c146b 100644 --- a/templates/dualsense/template.js +++ b/templates/dualsense/template.js @@ -1,4 +1,4 @@ -window.gamepad.templateClass = class DualSenseTemplate { +window.gamepad.TemplateClass = class DualSenseTemplate { /** * Instanciates a new DualSense controller template */ diff --git a/templates/telemetry/template.html b/templates/telemetry/template.html index 1fca8c6..c08f0f4 100644 --- a/templates/telemetry/template.html +++ b/templates/telemetry/template.html @@ -1,5 +1,5 @@
-
+
diff --git a/templates/telemetry/template.js b/templates/telemetry/template.js index 6faddd0..aad2ae7 100644 --- a/templates/telemetry/template.js +++ b/templates/telemetry/template.js @@ -1,4 +1,4 @@ -gamepad.templateClass = class TelemetryTemplate { +window.gamepad.TemplateClass = class TelemetryTemplate { /** * Instanciates a new telemetry template */ @@ -7,7 +7,7 @@ gamepad.templateClass = class TelemetryTemplate { this.gamepad = window.gamepad; this.loadSelectors(); - this.loadUrlParams(); + this.loadParams(); if (!this.AXES.some((axis) => this[axis].index)) { this.wizard(); @@ -71,6 +71,7 @@ gamepad.templateClass = class TelemetryTemplate { loadSelectors() { this.$telemetry = document.querySelector('#telemetry'); this.$chart = this.$telemetry.querySelector('#chart'); + this.chartContext = this.$chart.getContext('2d'); this.$meters = this.$telemetry.querySelector('#meters'); this.$clutch = this.$telemetry.querySelector('#clutch'); this.$clutchBar = this.$clutch.querySelector('.bar'); @@ -90,17 +91,18 @@ gamepad.templateClass = class TelemetryTemplate { /** * Loads the params from the URL */ - loadUrlParams() { + loadParams() { this.withChart = gamepad.getUrlParam('chart') !== 'false'; - this.historyLength = gamepad.getUrlParam('history') || 5000; - + this.chartColors = { + clutch: '#2D64B9', + brake: '#A52725', + throttle: '#0CA818', + } + this.historyLength = +(gamepad.getUrlParam('history') || 5000); this.withMeters = gamepad.getUrlParam('meters') !== 'false'; - this.withSteering = gamepad.getUrlParam('steeringIndex') !== null; this.angle = gamepad.getUrlParam('angle') || 360; - this.frequency = gamepad.getUrlParam('fps') || 60; - this.AXES.forEach((axis) => { this[axis] = { type: (gamepad.getUrlParam(`${axis}Type`) || 'axis').replace('axis', 'axe'), @@ -129,95 +131,46 @@ gamepad.templateClass = class TelemetryTemplate { } } - async setupChart() { - if (!this.withChart) return; - return new Promise((resolve) => { - const script = document.createElement('script'); - script.async = true; - script.src = `https://www.gstatic.com/charts/loader.js`; - script.onload = () => { - if (!google || !google.visualization) { - this.loadGoogleCharts(resolve); - return; - } - this.drawChart(resolve); - }; - this.gamepad.$gamepad.appendChild(script); - }); - } - /** - * Initializes the live chart + * Set the canvas size to the actual pixel size with pixel ratio * 2 */ - async init() { - this.interval = 1000 / this.frequency; - this.length = this.historyLength / this.interval; - - this.setupTemplate(); - await this.setupChart(); - - this.running = true; - this.update(); - } - - /** - * Loads the Google Charts library - */ - loadGoogleCharts(resolve) { - google.charts.load('current', { packages: ['corechart', 'line'], }); - google.charts.setOnLoadCallback(this.drawChart.bind(this, resolve)); + scaleChart() { + const { width, height } = this.$chart.getBoundingClientRect(); + const pixelRatio = window.devicePixelRatio; + console.log(pixelRatio); + this.$chart.width = width * pixelRatio * 2; + this.$chart.height = height * pixelRatio * 2; + this.chartContext.scale(pixelRatio, pixelRatio); + this.$chart.style.width = `${width}px`; + this.$chart.style.height = `${height}px`; } /** * Draws the live chart with the initial data and starts the draw update loop */ - drawChart(resolve) { + setupChart() { + if (!this.withChart) return; + + this.scaleChart(); const now = Date.now(); - const initialData = [['time', 'clutch', 'brake', 'throttle']]; - for (let index = now - this.historyLength; index < now; index += this.interval) { - initialData.push([index, 0, 0, 0]); + this.chartData = []; + for (let timestamp = now - this.historyLength; timestamp < now; timestamp += this.interval) { + this.chartData.push({ timestamp, clutch: 0, brake: 0, throttle: 0 }); } - this.data = google.visualization.arrayToDataTable(initialData); - this.options = { - backgroundColor: 'transparent', - chartArea: { - left: 0, - top: 0, - width: '100%', - height: '100%', - backgroundColor: 'transparent', - }, - hAxis: { - textPosition: 'none', - gridlines: { - color: 'transparent', - }, - viewWindow: { - min: now - this.historyLength, - max: now - } - }, - vAxis: { - textPosition: 'none', - gridlines: { - color: 'transparent', - }, - minValue: 0, - maxValue: 100, - viewWindow: { - min: 2, - max: 102, - } - }, - colors: ['#2D64B9', '#A52725', '#0CA818'], - legend: 'none', - tooltip: { - trigger: 'none' - } - }; - this.chart = new google.visualization.LineChart(document.querySelector('#chart')); - this.chart.draw(this.data, this.options); - resolve(); + } + + /** + * Initializes the live chart + */ + init() { + this.interval = 1000 / this.frequency; + this.length = this.historyLength / this.interval; + + this.setupTemplate(); + this.setupChart(); + + this.running = true; + this.update(); } /** @@ -228,29 +181,58 @@ gamepad.templateClass = class TelemetryTemplate { const gamepad = this.gamepad.getActive(); const [clutch, brake, throttle, steering] = this.AXES.map((axis) => this.toAxisValue(gamepad, axis)); - if (this.withChart) this.updateChart(clutch, brake, throttle); + if (this.withChart) this.drawChart(clutch, brake, throttle); if (this.withMeters) this.updateMeters(clutch, brake, throttle); if (this.withSteering) this.updateSteering(steering); - window.setTimeout(this.update.bind(this), this.interval); + window.setTimeout(() => this.update(), this.interval); } /** - * Updates the live chart with the latest data + * Updates the data used to draw the cart + * + * @param {number} now + * @param {number} clutch + * @param {number} brake + * @param {number} throttle + */ + updateChartData(now, clutch, brake, throttle) { + let remove = 0; + for (let index = 0; index < this.chartData.length - 1; index++) { + if (this.chartData[index].timestamp < now - this.historyLength) { + remove++; + } else { + break; + } + } + this.chartData.splice(0, remove); + this.chartData.push({ timestamp: now, clutch, brake, throttle }); + } + + /** + * Draws the whole chart wuth the latest data * * @param {number} clutch * @param {number} brake * @param {number} throttle */ - updateChart(clutch, brake, throttle) { + drawChart(clutch, brake, throttle) { const now = Date.now(); - this.data.removeRows(0, this.data.getFilteredRows([{ column: 0, maxValue: now - this.historyLength }]).length); - this.data.addRow([now, clutch, brake, throttle]); - this.options.hAxis.viewWindow = { - min: now - this.historyLength, - max: now - }; - this.chart.draw(this.data, this.options); + this.updateChartData(now, clutch, brake, throttle); + + this.chartContext.clearRect(0, 0, this.$chart.width, this.$chart.height); + this.AXES.forEach((axis) => { + if (axis === 'steering') return; + this.chartContext.beginPath(); + this.chartData.forEach((entry, index) => { + const x = (entry.timestamp + this.historyLength - now) / this.historyLength * this.$chart.width; + const y = (101 - (entry[axis] || 0)) * this.$chart.height / 100; + this.chartContext[index === 0 ? 'moveTo' : 'lineTo'](x, y); + }); + this.chartContext.lineWidth = 4; + this.chartContext.strokeStyle = this.chartColors[axis]; + this.chartContext.stroke(); + }); } /** diff --git a/templates/xbox-one/template.js b/templates/xbox-one/template.js index eb1089d..52d8807 100644 --- a/templates/xbox-one/template.js +++ b/templates/xbox-one/template.js @@ -1,4 +1,4 @@ -window.gamepad.templateClass = class XboxOneTemplate { +window.gamepad.TemplateClass = class XboxOneTemplate { /** * Instanciates a new Xbox One controller template */