From 712d66113536a75b6104a8f55981cce48b8b52e7 Mon Sep 17 00:00:00 2001 From: e7d Date: Mon, 5 Jun 2023 15:42:15 +0200 Subject: [PATCH] performance related improvments --- js/gamepad.js | 99 +++++++++++++-------------------- templates/debug/template.js | 9 ++- templates/ds4/template.js | 36 +++++++----- templates/dualsense/template.js | 36 +++++++----- templates/xbox-one/template.js | 36 +++++++----- 5 files changed, 112 insertions(+), 104 deletions(-) diff --git a/js/gamepad.js b/js/gamepad.js index 203387a..c9f7df2 100644 --- a/js/gamepad.js +++ b/js/gamepad.js @@ -843,22 +843,20 @@ class Gamepad { const activeGamepad = this.getActive(); // save the buttons mapping of this template - this.mapping.buttons = []; - for (let index = 0; index < activeGamepad.buttons.length; index++) { + this.mapping.buttons = activeGamepad.buttons.map((_, index) => { const $button = document.querySelector(`[data-button='${index}']`); - if (!$button) break; - this.mapping.buttons[index] = $button; - } + return { $button, button: { pressed: null, value: null } }; + }); // save the axes mapping of this template - this.mapping.axes = []; - for (let index = 0; index < activeGamepad.axes.length; index++) { - const $axis = document.querySelector( - `[data-axis='${index}'], [data-axis-x='${index}'], [data-axis-y='${index}'], [data-axis-z='${index}']` - ); - if (!$axis) break; - this.mapping.axes[index] = $axis; - } + this.mapping.axes = activeGamepad.axes.map((_, index) => { + const { $axis, attribute } = ['data-axis', 'data-axis-x', 'data-axis-y'].reduce((acc, attribute) => { + if (acc.$axis) return acc; + const $axis = document.querySelector(`[${attribute}='${index}']`); + return $axis ? { $axis, attribute, axis: null } : acc; + }, {}); + return { $axis, attribute }; + }); // enqueue the initial display refresh this.pollStatus(true); @@ -908,28 +906,24 @@ class Gamepad { * @param {*} gamepad */ updateButtons(gamepad) { - // ensure we have a button updater callback - if ('function' !== typeof this.updateButton) return; - // update the buttons - for (let index = 0; index < gamepad.buttons.length; index++) { - // find the DOM element - const $button = this.mapping.buttons[index]; - if (!$button || $button.length === 0) { - // nothing to do for this button if no DOM element exists - continue; - } - - // read the button data - const button = gamepad.buttons[index]; + gamepad.buttons.forEach((updatedButton, index) => { + // get the button information + const { $button, button } = this.mapping.buttons[index]; + if (!$button) return; // update the display values - $button.setAttribute('data-pressed', button.pressed); - $button.setAttribute('data-value', button.value); + if (updatedButton.pressed !== button.pressed || updatedButton.value !== button.value) { + $button.setAttribute('data-pressed', updatedButton.pressed); + $button.setAttribute('data-value', updatedButton.value); - // hook the template defined button update method - this.updateButton($button); - } + // ensure we have a button updater callback and hook the template defined button update method + if ('function' === typeof this.updateButton) this.updateButton($button, updatedButton); + } + + // save the updated button + this.mapping.buttons[index].button = updatedButton; + }); } /** @@ -938,38 +932,23 @@ class Gamepad { * @param {*} gamepad */ updateAxes(gamepad) { - // ensure we have an axis updater callback - if ('function' !== typeof this.updateAxis) return; - // update the axes - for (let index = 0; index < gamepad.axes.length; index++) { - // find the DOM element - const $axis = this.mapping.axes[index]; - if (!$axis || $axis.length === 0) { - // nothing to do for this axis if no DOM element exists - continue; + gamepad.axes.forEach((updatedAxis, index) => { + // get the axis information + const { $axis, attribute, axis } = this.mapping.axes[index]; + if (!$axis) return; + + // update the display value + if (updatedAxis !== axis) { + $axis.setAttribute(attribute.replace('-axis', '-value'), updatedAxis); + + // ensure we have an axis updater callback and hook the template defined axis update method + if ('function' === typeof this.updateAxis) this.updateAxis($axis, attribute, updatedAxis); } - // read the axis data - const axis = gamepad.axes[index]; - - // update the display values - if ($axis.matches(`[data-axis='${index}']`)) { - $axis.setAttribute('data-value', axis); - } - if ($axis.matches(`[data-axis-x='${index}']`)) { - $axis.setAttribute('data-value-x', axis); - } - if ($axis.matches(`[data-axis-y='${index}']`)) { - $axis.setAttribute('data-value-y', axis); - } - if ($axis.matches(`[data-axis-z='${index}']`)) { - $axis.setAttribute('data-value-z', axis); - } - - // hook the template defined axis update method - this.updateAxis($axis); - } + // save the updated button + this.mapping.axes[index].axis = updatedAxis; + }); } /** diff --git a/templates/debug/template.js b/templates/debug/template.js index f31950d..218ce8a 100644 --- a/templates/debug/template.js +++ b/templates/debug/template.js @@ -5,8 +5,8 @@ window.gamepad.template = class DebugTemplate { constructor() { this.gamepad = window.gamepad; this.init(); - this.gamepad.updateButton = ($button) => this.updateElem($button); - this.gamepad.updateAxis = ($axis) => this.updateElem($axis, 6); + this.gamepad.updateButton = ($button, { value }) => this.updateElem($button, value); + this.gamepad.updateAxis = ($axis, _, axis) => this.updateElem($axis, axis, 6); } /** @@ -100,10 +100,9 @@ window.gamepad.template = class DebugTemplate { * @param {Element} $elem * @param {Number} precision */ - updateElem($elem, precision = 2) { + updateElem($elem, value, precision = 2) { this.updateTimestamp(); - let value = parseFloat($elem.attributes['data-value'].value, 10).toFixed(precision); - $elem.innerHTML = value; + $elem.innerHTML = value.toFixed(precision); let color = Math.floor(255 * 0.3 + 255 * 0.7 * Math.abs(value)); $elem.style.setProperty('color', `rgb(${color}, ${color}, ${color})`); } diff --git a/templates/ds4/template.js b/templates/ds4/template.js index 53e8233..741ffd3 100644 --- a/templates/ds4/template.js +++ b/templates/ds4/template.js @@ -4,8 +4,10 @@ window.gamepad.template = class DualShock4Template { */ constructor() { this.gamepad = window.gamepad; - this.gamepad.updateButton = ($button) => this.updateButton($button); - this.gamepad.updateAxis = ($axis) => this.updateAxis($axis); + this.gamepad.updateButton = this.updateButton.bind(this); + this.gamepad.updateAxis = this.updateAxis.bind(this); + this.rotateX = 0; + this.rotateY = 0; } /** @@ -16,19 +18,27 @@ window.gamepad.template = class DualShock4Template { delete this.gamepad.updateAxis; } - updateButton($button) { - if (!$button.matches('.trigger')) return; - const value = parseFloat($button.getAttribute('data-value'), 10); - $button.style.setProperty('opacity', this.gamepad.triggersMeter ? 1 : `${value * 100}%`); - $button.style.setProperty('clip-path', this.gamepad.triggersMeter ? `inset(${100 - value * 100}% 0px 0px 0pc)` : 'none'); + updateButton($button, button) { + if (!$button.matches('.trigger') || !button) return; + $button.style.setProperty('opacity', this.gamepad.triggersMeter ? 1 : `${button.value * 100}%`); + $button.style.setProperty('clip-path', this.gamepad.triggersMeter ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` : 'none'); } - updateAxis($axis) { + updateAxis($axis, attribute, axis) { if (!$axis.matches('.stick')) return; - const axisX = $axis.getAttribute('data-value-x'); - const axisY = $axis.getAttribute('data-value-y'); - $axis.style.setProperty('margin-top', `${axisY * 25}px`); - $axis.style.setProperty('margin-left', `${axisX * 25}px`); - $axis.style.setProperty('transform', `rotateX(${-parseFloat(axisY * 30, 8)}deg) rotateY(${parseFloat(axisX * 30, 8)}deg)`); + if (attribute === 'data-axis-x') { + $axis.style.setProperty('margin-left', `${axis * 25}px`); + this.rotateY = parseFloat(axis * 30, 8); + this.updateRotate($axis); + } + if (attribute === 'data-axis-y') { + $axis.style.setProperty('margin-top', `${axis * 25}px`); + this.rotateX = -parseFloat(axis * 30, 8); + this.updateRotate($axis); + } + } + + updateRotate($axis) { + $axis.style.setProperty('transform', `rotateX(${this.rotateX}deg) rotateY(${this.rotateY}deg)`); } }; diff --git a/templates/dualsense/template.js b/templates/dualsense/template.js index 54c90a8..15aac6f 100644 --- a/templates/dualsense/template.js +++ b/templates/dualsense/template.js @@ -4,8 +4,10 @@ window.gamepad.template = class DualSenseTemplate { */ constructor() { this.gamepad = window.gamepad; - this.gamepad.updateButton = ($button) => this.updateButton($button); - this.gamepad.updateAxis = ($axis) => this.updateAxis($axis); + this.gamepad.updateButton = this.updateButton.bind(this); + this.gamepad.updateAxis = this.updateAxis.bind(this); + this.rotateX = 0; + this.rotateY = 0; } /** @@ -16,19 +18,27 @@ window.gamepad.template = class DualSenseTemplate { delete this.gamepad.updateAxis; } - updateButton($button) { - if (!$button.matches('.trigger')) return; - const value = parseFloat($button.getAttribute('data-value'), 10); - $button.style.setProperty('opacity', this.gamepad.triggersMeter ? 1 : `${value * 100}%`); - $button.style.setProperty('clip-path', this.gamepad.triggersMeter ? `inset(${100 - value * 100}% 0px 0px 0pc)` : 'none'); + updateButton($button, button) { + if (!$button.matches('.trigger') || !button) return; + $button.style.setProperty('opacity', this.gamepad.triggersMeter ? 1 : `${button.value * 100}%`); + $button.style.setProperty('clip-path', this.gamepad.triggersMeter ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` : 'none'); } - updateAxis($axis) { + updateAxis($axis, attribute, axis) { if (!$axis.matches('.stick')) return; - const axisX = $axis.getAttribute('data-value-x'); - const axisY = $axis.getAttribute('data-value-y'); - $axis.style.setProperty('margin-top', `${axisY * 25}px`); - $axis.style.setProperty('margin-left', `${axisX * 25}px`); - $axis.style.setProperty('transform', `rotateX(${-parseFloat(axisY * 30, 8)}deg) rotateY(${parseFloat(axisX * 30, 8)}deg)`); + if (attribute === 'data-axis-x') { + $axis.style.setProperty('margin-left', `${axis * 25}px`); + this.rotateY = parseFloat(axis * 30, 8); + this.updateRotate($axis); + } + if (attribute === 'data-axis-y') { + $axis.style.setProperty('margin-top', `${axis * 25}px`); + this.rotateX = -parseFloat(axis * 30, 8); + this.updateRotate($axis); + } + } + + updateRotate($axis) { + $axis.style.setProperty('transform', `rotateX(${this.rotateX}deg) rotateY(${this.rotateY}deg)`); } }; diff --git a/templates/xbox-one/template.js b/templates/xbox-one/template.js index 2d8e583..9e63138 100644 --- a/templates/xbox-one/template.js +++ b/templates/xbox-one/template.js @@ -4,8 +4,10 @@ window.gamepad.template = class XboxOneTemplate { */ constructor() { this.gamepad = window.gamepad; - this.gamepad.updateButton = ($button) => this.updateButton($button); - this.gamepad.updateAxis = ($axis) => this.updateAxis($axis); + this.gamepad.updateButton = this.updateButton.bind(this); + this.gamepad.updateAxis = this.updateAxis.bind(this); + this.rotateX = 0; + this.rotateY = 0; } /** @@ -16,19 +18,27 @@ window.gamepad.template = class XboxOneTemplate { delete this.gamepad.updateAxis; } - updateButton($button) { - if (!$button.matches('.trigger')) return; - const value = parseFloat($button.getAttribute('data-value'), 10); - $button.style.setProperty('opacity', this.gamepad.triggersMeter ? 1 : `${value * 100}%`); - $button.style.setProperty('clip-path', this.gamepad.triggersMeter ? `inset(${100 - value * 100}% 0px 0px 0pc)` : 'none'); + updateButton($button, button) { + if (!$button.matches('.trigger') || !button) return; + $button.style.setProperty('opacity', this.gamepad.triggersMeter ? 1 : `${button.value * 100}%`); + $button.style.setProperty('clip-path', this.gamepad.triggersMeter ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` : 'none'); } - updateAxis($axis) { + updateAxis($axis, attribute, axis) { if (!$axis.matches('.stick')) return; - const axisX = $axis.getAttribute('data-value-x'); - const axisY = $axis.getAttribute('data-value-y'); - $axis.style.setProperty('margin-top', `${axisY * 25}px`); - $axis.style.setProperty('margin-left', `${axisX * 25}px`); - $axis.style.setProperty('transform', `rotateX(${-parseFloat(axisY * 30, 8)}deg) rotateY(${parseFloat(axisX * 30, 8)}deg)`); + if (attribute === 'data-axis-x') { + $axis.style.setProperty('margin-left', `${axis * 25}px`); + this.rotateY = parseFloat(axis * 30, 8); + this.updateRotate($axis); + } + if (attribute === 'data-axis-y') { + $axis.style.setProperty('margin-top', `${axis * 25}px`); + this.rotateX = -parseFloat(axis * 30, 8); + this.updateRotate($axis); + } + } + + updateRotate($axis) { + $axis.style.setProperty('transform', `rotateX(${this.rotateX}deg) rotateY(${this.rotateY}deg)`); } };