multiple and general fixes and improvments
This commit is contained in:
parent
203d3bf110
commit
c3067194e4
@ -38,3 +38,6 @@ Please read below or use this video tutorial: https://youtu.be/vHzf_ESseTc
|
||||
- Adjust position and size of the source as you will
|
||||
|
||||
*: These gamepads work both wired and wireless via Bluetooth
|
||||
|
||||
## Credits
|
||||
DualShock 4 and Xbox One skins from [gamepadviewer.com](https://gamepadviewer.com/)
|
||||
|
@ -203,6 +203,8 @@
|
||||
<h3>Credits</h3>
|
||||
<p>All information and source code can be found on GitHub at <a target="_blank"
|
||||
href="https://github.com/e7d/gamepad-viewer">e7d/gamepad-viewer</a>.</p>
|
||||
<p>DualShock 4 and Xbox One skins from <a target="_blank"
|
||||
href="https://gamepadviewer.com/">gamepadviewer.com</a>.</p>
|
||||
</div>
|
||||
|
||||
<script src="js/jquery.min.js"></script>
|
||||
|
167
js/gamepad.js
167
js/gamepad.js
@ -24,6 +24,10 @@ class Gamepad {
|
||||
this.$helpPopout = $('#help-popout');
|
||||
this.$gamepadList = $('#gamepad-list');
|
||||
|
||||
// ensure the GamePad API is available on this browser
|
||||
this.assertGamepadAPI();
|
||||
|
||||
// overlay selectors
|
||||
this.backgroundStyle = [
|
||||
'transparent',
|
||||
'checkered',
|
||||
@ -42,10 +46,6 @@ class Gamepad {
|
||||
'black',
|
||||
'black',
|
||||
];
|
||||
|
||||
// ensure the GamePad API is available on this browser
|
||||
this.assertGamepadAPI();
|
||||
|
||||
this.initOverlaySelectors();
|
||||
|
||||
// gamepad collection default values
|
||||
@ -57,10 +57,11 @@ class Gamepad {
|
||||
name: 'Debug',
|
||||
},
|
||||
ds4: {
|
||||
id: /054c|54c|09cc|046d|0810|2563/, // 054c = Sony vendor code, 046d,0810,2563 = PS-like controllers vendor codes
|
||||
id: /054c|54c|7545|09cc|0104|0ce6|046d|0810|2563/, // 054c,7545 = Sony vendor code, 09cc,0104 = DS4 controllers product codes, 0ce6 = DualSense controller product code, 046d,0810,2563 = PS-like controllers vendor codes
|
||||
name: 'DualShock 4',
|
||||
colors: ['black', 'white', 'red', 'blue'],
|
||||
triggers: true,
|
||||
zoom: true,
|
||||
},
|
||||
// gamecube: {
|
||||
// id: /0079/, // 0079 = Nintendo GameCube vendor code
|
||||
@ -68,7 +69,7 @@ class Gamepad {
|
||||
// colors: ['black', 'purple'],
|
||||
// },
|
||||
// 'joy-con': {
|
||||
// id: /200e/, // 0079 = Joy-Con specific product code
|
||||
// id: /200e/, // 200e = Joy-Con specific product code
|
||||
// name: 'Joy-Con (L+R) Controllers',
|
||||
// colors: ['blue-red', 'grey-grey'],
|
||||
// },
|
||||
@ -78,19 +79,21 @@ class Gamepad {
|
||||
// colors: ['black'],
|
||||
// },
|
||||
// 'switch-pro': {
|
||||
// id: /057e|20d6/, // 057e = Nintendo Switch vendor code, 20d6 = Switch Pro-like vendor code
|
||||
// id: /057e|20d6|2009/, // 057e = Nintendo Switch vendor code, 20d6,2009 = Switch Pro-like vendor code
|
||||
// name: 'Switch Pro Controller',
|
||||
// colors: ['black'],
|
||||
// },
|
||||
telemetry: {
|
||||
id: /telemetry/,
|
||||
name: 'Telemetry',
|
||||
zoom: true
|
||||
},
|
||||
'xbox-one': {
|
||||
id: /045e|xinput|XInput/, // 045e = Microsoft vendor code, xinput = standard Windows controller
|
||||
name: 'Xbox One',
|
||||
colors: ['black', 'white'],
|
||||
triggers: true,
|
||||
},
|
||||
'telemetry': {
|
||||
id: /telemetry/, // 045e = Microsoft vendor code, xinput = standard Windows controller
|
||||
name: 'Telemetry'
|
||||
zoom: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -122,9 +125,6 @@ class Gamepad {
|
||||
axes: [],
|
||||
};
|
||||
|
||||
// // read hash
|
||||
// this.hash = this.readHash();
|
||||
|
||||
// listen for gamepad related events
|
||||
this.haveEvents = 'GamepadEvent' in window;
|
||||
if (this.haveEvents) {
|
||||
@ -306,6 +306,16 @@ class Gamepad {
|
||||
}, this.overlayDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the name, vendor and product from a gamepad identifier
|
||||
*
|
||||
* @param {string} id
|
||||
* @returns {object}
|
||||
*/
|
||||
toGamepadInfo(id) {
|
||||
return /(?<name>.*) \(.*Vendor: (?<vendor>[0-9a-f]{4}) Product: (?<product>[0-9a-f]{4})\)/.exec(id).groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of connected gamepads in the overlay
|
||||
*/
|
||||
@ -317,9 +327,9 @@ class Gamepad {
|
||||
if (!gamepad) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { name, vendor, product } = this.toGamepadInfo(gamepad.id);
|
||||
$options.push(
|
||||
`<option class='entry' value='${gamepad.id}'>${gamepad.id}</option>'`
|
||||
`<option class='entry' value='${vendor}-${product}'>${name}</option>`
|
||||
);
|
||||
}
|
||||
this.$gamepadSelect.append($options.join(''));
|
||||
@ -341,7 +351,7 @@ class Gamepad {
|
||||
}
|
||||
|
||||
const colorOptions = colors.map(
|
||||
(color) => `<option value='${color}'>${color}</option>`
|
||||
(color) => `<option value='${color}'>${color.charAt(0).toUpperCase()}${color.slice(1)}</option>`
|
||||
);
|
||||
this.$colorSelect.html(colorOptions);
|
||||
this.$colorOverlay.fadeIn();
|
||||
@ -539,7 +549,7 @@ class Gamepad {
|
||||
}
|
||||
}
|
||||
|
||||
return 'xbox-one';
|
||||
return 'debug';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -571,7 +581,8 @@ class Gamepad {
|
||||
// check the parameters for a selected gamepad
|
||||
const gamepadId = this.getUrlParam('gamepad');
|
||||
if (gamepadId) {
|
||||
if (gamepad.id === gamepadId) {
|
||||
const [vendor, product] = gamepadId.split('-');
|
||||
if (gamepad.id.includes(vendor) && gamepad.id.includes(product)) {
|
||||
this.map(gamepad.index);
|
||||
return;
|
||||
}
|
||||
@ -648,7 +659,8 @@ class Gamepad {
|
||||
this.identifier = this.identifiers[this.type];
|
||||
|
||||
// update the overlay selectors
|
||||
this.$gamepadSelect.val(gamepad.id);
|
||||
const { vendor, product } = this.toGamepadInfo(gamepad.id);
|
||||
this.$gamepadSelect.val(`${vendor}-${product}`);
|
||||
this.updateColors();
|
||||
this.updateTriggers();
|
||||
|
||||
@ -658,16 +670,6 @@ class Gamepad {
|
||||
// hide the help before displaying the template
|
||||
this.hideInstructions();
|
||||
this.hidePlaceholder();
|
||||
|
||||
// save statistics
|
||||
if (!!window.ga) {
|
||||
ga('send', 'event', {
|
||||
eventCategory: 'Gamepad',
|
||||
eventAction: 'map',
|
||||
eventLabel: 'Map',
|
||||
eventValue: this.identifier,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -707,16 +709,6 @@ class Gamepad {
|
||||
this.updateColors();
|
||||
this.updateTriggers();
|
||||
this.clearUrlParams();
|
||||
|
||||
// save statistics
|
||||
if (!!window.ga) {
|
||||
ga('send', 'event', {
|
||||
eventCategory: 'Gamepad',
|
||||
eventAction: 'disconnect',
|
||||
eventLabel: 'Disconnect',
|
||||
eventValue: this.identifier,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -733,11 +725,21 @@ class Gamepad {
|
||||
this.$gamepad.html(template);
|
||||
|
||||
// read for parameters to apply:
|
||||
const identifier = this.identifiers[this.type];
|
||||
// - color
|
||||
if (identifier.colors) {
|
||||
this.changeGamepadColor(this.getUrlParam('color'));
|
||||
} else {
|
||||
this.updateUrlParams({ color: undefined });
|
||||
}
|
||||
// - triggers mode
|
||||
if (identifier.triggers) {
|
||||
this.toggleTriggersMeter(this.getUrlParam('triggers') === 'meter');
|
||||
// - zoom$
|
||||
} else {
|
||||
this.updateUrlParams({ triggers: undefined });
|
||||
}
|
||||
// - zoom
|
||||
if (identifier.zoom) {
|
||||
window.setTimeout(() =>
|
||||
this.changeZoom(
|
||||
this.type === 'debug'
|
||||
@ -745,6 +747,9 @@ class Gamepad {
|
||||
: this.getUrlParam('zoom') || 'auto'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
this.updateUrlParams({ zoom: undefined });
|
||||
}
|
||||
|
||||
// save the buttons mapping of this template
|
||||
this.mapping.buttons = [];
|
||||
@ -773,7 +778,7 @@ class Gamepad {
|
||||
*/
|
||||
pollStatus(force = false) {
|
||||
// ensure that a gamepad is currently active
|
||||
if (this.index === null) return;
|
||||
if (this.index === null || this.index === this.disconnectedIndex) return;
|
||||
|
||||
// enqueue the next refresh
|
||||
window.requestAnimationFrame(this.pollStatus.bind(this));
|
||||
@ -786,8 +791,7 @@ class Gamepad {
|
||||
if (
|
||||
!force &&
|
||||
(!activeGamepad || activeGamepad.timestamp === this.lastTimestamp)
|
||||
)
|
||||
return;
|
||||
) return;
|
||||
this.lastTimestamp = activeGamepad.timestamp;
|
||||
|
||||
// actually update the active gamepad graphically
|
||||
@ -863,9 +867,18 @@ class Gamepad {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the active gamepad
|
||||
*
|
||||
* @param {string} gamepadId
|
||||
*/
|
||||
changeGamepad(gamepadId) {
|
||||
// get the index corresponding to the identifier of the gamepad
|
||||
const index = this.gamepads.findIndex(g => g && g.id === gamepadId);
|
||||
const index = this.gamepads.findIndex(g => {
|
||||
if (!g) return false;
|
||||
const { vendor, product } = this.toGamepadInfo(g.id);
|
||||
return `${vendor}-${product}` === gamepadId;
|
||||
});
|
||||
|
||||
// set the selected gamepad
|
||||
this.updateUrlParams({ gamepad: gamepadId !== 'auto' ? gamepadId : undefined });
|
||||
@ -919,16 +932,6 @@ class Gamepad {
|
||||
// update current settings
|
||||
this.updateUrlParams({ background: this.backgroundStyleName });
|
||||
this.$backgroundSelect.val(this.backgroundStyleName);
|
||||
|
||||
// save statistics
|
||||
if (!!window.ga) {
|
||||
ga('send', 'event', {
|
||||
eventCategory: 'Gamepad',
|
||||
eventAction: 'change-background-color',
|
||||
eventLabel: 'Change Background Color',
|
||||
eventValue: this.backgroundStyleName,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -975,16 +978,6 @@ class Gamepad {
|
||||
// update current settings
|
||||
this.updateUrlParams({ color: this.colorName });
|
||||
this.$colorSelect.val(this.colorName);
|
||||
|
||||
// save statistics
|
||||
if (!!window.ga) {
|
||||
ga('send', 'event', {
|
||||
eventCategory: 'Gamepad',
|
||||
eventAction: 'change-gamepad-color',
|
||||
eventLabel: 'Change Gamepad Color',
|
||||
eventValue: this.colorName,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1035,16 +1028,6 @@ class Gamepad {
|
||||
this.updateUrlParams({
|
||||
zoom: this.zoomMode === 'auto' ? undefined : this.zoomLevel,
|
||||
});
|
||||
|
||||
// save statistics
|
||||
if (!!window.ga) {
|
||||
ga('send', 'event', {
|
||||
eventCategory: 'Gamepad',
|
||||
eventAction: 'change-zoom',
|
||||
eventLabel: 'Change Zoom',
|
||||
eventValue: this.zoomLevel,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1066,16 +1049,6 @@ class Gamepad {
|
||||
}, 0);
|
||||
this.type = types[++typeIndex >= types.length ? 0 : typeIndex];
|
||||
|
||||
// save statistics
|
||||
if (!!window.ga) {
|
||||
ga('send', 'event', {
|
||||
eventCategory: 'Gamepad',
|
||||
eventAction: 'toggle-type',
|
||||
eventLabel: 'Toggle Type',
|
||||
eventValue: this.type,
|
||||
});
|
||||
}
|
||||
|
||||
// update current settings
|
||||
this.updateUrlParams({ type: this.type });
|
||||
|
||||
@ -1093,16 +1066,6 @@ class Gamepad {
|
||||
// update debug value
|
||||
this.debug = debug !== null ? debug : !this.debug;
|
||||
|
||||
// save statistics
|
||||
if (!!window.ga) {
|
||||
ga('send', 'event', {
|
||||
eventCategory: 'Gamepad',
|
||||
eventAction: 'toggle-debug',
|
||||
eventLabel: 'Toggle Debug',
|
||||
eventValue: this.debug,
|
||||
});
|
||||
}
|
||||
|
||||
// update current settings
|
||||
this.changeSkin(this.debug ? 'debug' : 'auto')
|
||||
}
|
||||
@ -1118,16 +1081,6 @@ class Gamepad {
|
||||
// display the help popout
|
||||
this.$helpPopout.toggleClass('active');
|
||||
this.helpVisible = this.$helpPopout.is('.active');
|
||||
|
||||
// save statistics
|
||||
if (!!window.ga) {
|
||||
ga('send', 'event', {
|
||||
eventCategory: 'Gamepad',
|
||||
eventAction: 'toggle-help',
|
||||
eventLabel: 'Toggle Help',
|
||||
eventValue: this.$helpPopout.is('active'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1152,7 +1105,7 @@ class Gamepad {
|
||||
/**
|
||||
* Reads an URL search parameter
|
||||
*
|
||||
* @param {*} name
|
||||
* @param {string} name
|
||||
* @returns {string|boolean|null}
|
||||
*/
|
||||
getUrlParam(name) {
|
||||
@ -1197,7 +1150,7 @@ class Gamepad {
|
||||
/**
|
||||
* Update url hash with new settings
|
||||
*
|
||||
* @param {*} newParams
|
||||
* @param {object} newParams
|
||||
*/
|
||||
updateUrlParams(newParams) {
|
||||
const params = Object.assign(this.getUrlParams(), newParams);
|
||||
|
4
js/jquery.min.js
vendored
4
js/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,5 +1,4 @@
|
||||
Sample: T818
|
||||
http://localhost:8081/?gamepad=Thrustmaster%20Thrustmaster%20Advance%20Racer%20(Vendor:%20044f%20Product:%20b696)&triggers=opacity&clutchIndex=6&clutchMin=1&clutchMax=-1&brakeIndex=1&brakeMin=1&brakeMax=-1&throttleIndex=5&throttleMin=1&throttleMax=-1&directionIndex=0&directionDegrees=900&type=telemetry
|
||||
|
||||
Sample: Xbox Controller
|
||||
http://localhost:8081/?gamepad=Microsoft%20Controller%20(STANDARD%20GAMEPAD%20Vendor:%20045e%20Product:%200b00)&triggers=opacity&brakeType=button&brakeIndex=6&brakeMin=0&brakeMax=1&throttleType=button&throttleIndex=7&throttleMin=0&throttleMax=1&directionIndex=0&directionDegrees=180&type=telemetry
|
||||
Samples:
|
||||
- T818: http://localhost:8081/?gamepad=044f-b696&type=telemetry&clutchIndex=6&clutchMin=1&clutchMax=-1&brakeIndex=1&brakeMin=1&brakeMax=-1&throttleIndex=5&throttleMin=1&throttleMax=-1&directionIndex=0&directionDegrees=900
|
||||
- Xbox Controller: http://localhost:8081/?gamepad=045e-0b00&type=telemetry&brakeType=button&brakeIndex=6&brakeMin=0&brakeMax=1&throttleType=button&throttleIndex=7&throttleMin=0&throttleMax=1&directionIndex=0&directionDegrees=180
|
||||
- Xbox Controller with clutch: http://localhost:8081/?gamepad=045e-0b00&type=telemetry&clutchType=button&clutchIndex=0&clutchMin=0&clutchMax=1&&brakeType=button&brakeIndex=6&brakeMin=0&brakeMax=1&throttleType=button&throttleIndex=7&throttleMin=0&throttleMax=1&directionIndex=0&directionDegrees=180
|
||||
|
@ -29,7 +29,7 @@
|
||||
}
|
||||
|
||||
.box.extra-large {
|
||||
width: 100%;
|
||||
width: 75%;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,21 @@
|
||||
<script async src="templates/debug/template.js"></script>
|
||||
<div class="info">
|
||||
<div class="container">
|
||||
<div id="info-id" class="box extra-large">
|
||||
<div id="info-name" class="box extra-large">
|
||||
<div class="content">
|
||||
<div class="label">ID</div>
|
||||
<div class="label">Name</div>
|
||||
<div class="value"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="info-vendor" class="box small">
|
||||
<div class="content">
|
||||
<div class="label">Vendor</div>
|
||||
<div class="value"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="info-product" class="box small">
|
||||
<div class="content">
|
||||
<div class="label">Product</div>
|
||||
<div class="value"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,35 +1,43 @@
|
||||
(() => {
|
||||
$id = $("#info-id .value");
|
||||
$timestamp = $("#info-timestamp .value");
|
||||
$index = $("#info-index .value");
|
||||
$mapping = $("#info-mapping .value");
|
||||
$rumble = $("#info-rumble .value");
|
||||
$axes = $(".axes .container");
|
||||
$buttons = $(".buttons .container");
|
||||
|
||||
gamepad = window.gamepad;
|
||||
activeGamepad = gamepad.getActive();
|
||||
|
||||
if (!activeGamepad) {
|
||||
function DebugTemplate(gamepad) {
|
||||
return {
|
||||
$name: $('#info-name .value'),
|
||||
$vendor: $('#info-vendor .value'),
|
||||
$product: $('#info-product .value'),
|
||||
$timestamp: $('#info-timestamp .value'),
|
||||
$index: $('#info-index .value'),
|
||||
$mapping: $('#info-mapping .value'),
|
||||
$rumble: $('#info-rumble .value'),
|
||||
$axes: $('.axes .container'),
|
||||
$buttons: $('.buttons .container'),
|
||||
activeGamepad: gamepad.getActive(),
|
||||
init: function () {
|
||||
if (!this.activeGamepad) {
|
||||
return;
|
||||
}
|
||||
|
||||
$id.html(activeGamepad.id);
|
||||
updateTimestamp();
|
||||
$index.html(activeGamepad.index);
|
||||
$mapping.html(activeGamepad.mapping || 'N/A');
|
||||
$rumble.html(
|
||||
activeGamepad.vibrationActuator
|
||||
? activeGamepad.vibrationActuator.type
|
||||
: "N/A"
|
||||
const { name, vendor, product } = gamepad.toGamepadInfo(this.activeGamepad.id);
|
||||
this.$name.html(name).attr('title', name);
|
||||
this.$vendor.html(vendor);
|
||||
this.$product.html(product);
|
||||
this.updateTimestamp();
|
||||
this.$index.html(this.activeGamepad.index);
|
||||
this.$mapping.html(this.activeGamepad.mapping || 'N/A');
|
||||
this.$rumble.html(
|
||||
this.activeGamepad.vibrationActuator
|
||||
? this.activeGamepad.vibrationActuator.type
|
||||
: 'N/A'
|
||||
);
|
||||
|
||||
this.initAxes();
|
||||
this.initButtons();
|
||||
gamepad.updateButton = ($button) => this.updateElem($button);
|
||||
gamepad.updateAxis = ($axis) => this.updateElem($axis, 6);
|
||||
},
|
||||
initAxes: function () {
|
||||
for (
|
||||
let axisIndex = 0;
|
||||
axisIndex < activeGamepad.axes.length;
|
||||
axisIndex < this.activeGamepad.axes.length;
|
||||
axisIndex++
|
||||
) {
|
||||
$axes.append(`
|
||||
this.$axes.append(`
|
||||
<div class="box medium">
|
||||
<div class="content">
|
||||
<div class="label">Axis ${axisIndex}</div>
|
||||
@ -38,13 +46,14 @@
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
},
|
||||
initButtons: function () {
|
||||
for (
|
||||
let buttonIndex = 0;
|
||||
buttonIndex < activeGamepad.buttons.length;
|
||||
buttonIndex < this.activeGamepad.buttons.length;
|
||||
buttonIndex++
|
||||
) {
|
||||
$buttons.append(`
|
||||
this.$buttons.append(`
|
||||
<div class="box small">
|
||||
<div class="content">
|
||||
<div class="label">B${buttonIndex}</div>
|
||||
@ -53,29 +62,22 @@
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
gamepad.updateButton = function ($button) {
|
||||
updateElem($button);
|
||||
};
|
||||
|
||||
gamepad.updateAxis = function ($axis) {
|
||||
updateElem($axis, 6);
|
||||
};
|
||||
|
||||
function updateElem($elem, precision = 2) {
|
||||
updateTimestamp();
|
||||
|
||||
let value = parseFloat($elem.attr("data-value"), 10).toFixed(precision);
|
||||
},
|
||||
updateElem: function ($elem, precision = 2) {
|
||||
this.updateTimestamp();
|
||||
let value = parseFloat($elem.attr('data-value'), 10).toFixed(precision);
|
||||
$elem.html(value);
|
||||
let color = Math.floor(255 * 0.3 + 255 * 0.7 * Math.abs(value));
|
||||
$elem.css({ color: `rgb(${color}, ${color}, ${color})` });
|
||||
}
|
||||
|
||||
function updateTimestamp() {
|
||||
activeGamepad = gamepad.getActive();
|
||||
if (!activeGamepad) {
|
||||
},
|
||||
updateTimestamp: function () {
|
||||
this.activeGamepad = gamepad.getActive();
|
||||
if (!this.activeGamepad) {
|
||||
return;
|
||||
}
|
||||
$timestamp.html(parseFloat(activeGamepad.timestamp).toFixed(3));
|
||||
}
|
||||
})();
|
||||
this.$timestamp.html(parseFloat(this.activeGamepad.timestamp).toFixed(3));
|
||||
},
|
||||
}.init();
|
||||
};
|
||||
|
||||
new DebugTemplate(window.gamepad);
|
||||
|
@ -1,33 +1,37 @@
|
||||
gamepad.updateButton = function ($button) {
|
||||
const value = parseFloat($button.attr("data-value"), 10);
|
||||
|
||||
if ($button.is(".trigger")) {
|
||||
function DualShock4Template(gamepad) {
|
||||
return {
|
||||
init: function () {
|
||||
gamepad.updateButton = function ($button) {
|
||||
const value = parseFloat($button.attr('data-value'), 10);
|
||||
if ($button.is('.trigger')) {
|
||||
$button.css(
|
||||
gamepad.triggersMeter
|
||||
? {
|
||||
opacity: 1,
|
||||
"clip-path": `inset(${(1 - value) * 100}% 0px 0px 0pc)`,
|
||||
'clip-path': `inset(${(1 - value) * 100}% 0px 0px 0pc)`,
|
||||
}
|
||||
: {
|
||||
opacity: `${value * 100}%`,
|
||||
"clip-path": "none",
|
||||
'clip-path': 'none',
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
gamepad.updateAxis = function ($axis) {
|
||||
const axisX = $axis.attr("data-value-x");
|
||||
const axisY = $axis.attr("data-value-y");
|
||||
|
||||
if ($axis.is(".stick")) {
|
||||
};
|
||||
gamepad.updateAxis = function ($axis) {
|
||||
const axisX = $axis.attr('data-value-x');
|
||||
const axisY = $axis.attr('data-value-y');
|
||||
if ($axis.is('.stick')) {
|
||||
$axis.css({
|
||||
"margin-top": axisY * 25,
|
||||
"margin-left": axisX * 25,
|
||||
'margin-top': axisY * 25,
|
||||
'margin-left': axisX * 25,
|
||||
transform: `rotateX(${-parseFloat(
|
||||
axisY * 30,
|
||||
8
|
||||
)}deg) rotateY(${parseFloat(axisX * 30, 8)}deg)`,
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
}.init();
|
||||
};
|
||||
new DualShock4Template(window.gamepad);
|
||||
|
@ -3,18 +3,22 @@
|
||||
display: flex;
|
||||
width: 650px;
|
||||
height: 120px;
|
||||
border-top-left-radius: 6px;
|
||||
border-bottom-left-radius: 6px;
|
||||
border-top-right-radius: 60px;
|
||||
border-bottom-right-radius: 60px;
|
||||
|
||||
--black-color: black;
|
||||
--white-color: white;
|
||||
--grey-color: grey;
|
||||
--main-bg-color: #444;
|
||||
--main-component-color: grey;
|
||||
--meter-idle-color: var(--grey-color);
|
||||
--clutch-color: blue;
|
||||
--brake-color: red;
|
||||
--throttle-color: lime;
|
||||
--main-bg-color: black;
|
||||
--main-component-color: #333;
|
||||
--clutch-color: #2D64B9;
|
||||
--brake-color: #A52725;
|
||||
--throttle-color: #0CA818;
|
||||
}
|
||||
|
||||
#gamepad #telemetry * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#gamepad #telemetry #chart {
|
||||
@ -22,6 +26,7 @@
|
||||
margin: 4px;
|
||||
background-color: var(--main-component-color);
|
||||
border: 1px solid var(--black-color);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#gamepad #telemetry #meters {
|
||||
@ -31,86 +36,68 @@
|
||||
}
|
||||
|
||||
#gamepad #telemetry #meters .meter {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
margin: 4px 2px;
|
||||
background-color: var(--main-component-color);
|
||||
border: 1px solid var(--black-color);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#gamepad #telemetry #meters .meter .value {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
color: var(--white-color);
|
||||
}
|
||||
|
||||
#gamepad #telemetry #meters .meter .bar {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
flex: 1;
|
||||
background-color: var(--main-component-color);
|
||||
border: 1px solid var(--black-color);
|
||||
}
|
||||
#gamepad #telemetry #meters .meter .bar .filler {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 0%;
|
||||
transition: height 100ms;
|
||||
}
|
||||
#gamepad #telemetry #meters #clutch.meter .bar .filler {
|
||||
#gamepad #telemetry #meters #clutch.meter .bar {
|
||||
background-color: var(--clutch-color);
|
||||
}
|
||||
#gamepad #telemetry #meters #brake.meter .bar .filler {
|
||||
#gamepad #telemetry #meters #brake.meter .bar {
|
||||
background-color: var(--brake-color);
|
||||
}
|
||||
#gamepad #telemetry #meters #throttle.meter .bar .filler {
|
||||
#gamepad #telemetry #meters #throttle.meter .bar {
|
||||
background-color: var(--throttle-color);
|
||||
}
|
||||
|
||||
#gamepad #telemetry #direction {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 120px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#gamepad #telemetry #direction #wheel {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
border-radius: 50%;
|
||||
background-color: var(--black-color);
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
border-radius: 50px;
|
||||
background-color: var(--main-component-color);
|
||||
}
|
||||
|
||||
#gamepad #telemetry #direction #wheel #wheel--center {
|
||||
display: block;
|
||||
#gamepad #telemetry #direction .center {
|
||||
position: absolute;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
top: 20%;
|
||||
left: 20%;
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
border-radius: 50%;
|
||||
background-color: var(--main-bg-color);
|
||||
}
|
||||
|
||||
#gamepad #telemetry #direction #wheel #wheel--indicator {
|
||||
#gamepad #telemetry #direction .indicator {
|
||||
display: block;
|
||||
width: 7%;
|
||||
width: 5%;
|
||||
height: 50%;
|
||||
background-color: var(--white-color);
|
||||
transform-origin: bottom;
|
||||
transform: rotate(0deg);
|
||||
transition: transform 100ms;
|
||||
}
|
||||
|
||||
#gamepad #telemetry #direction {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 120px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
@ -5,28 +5,20 @@
|
||||
<div id="chart"></div>
|
||||
<div id="meters">
|
||||
<div id="clutch" class="meter">
|
||||
<div class="bar"></div>
|
||||
<div class="value">0</div>
|
||||
<div class="bar">
|
||||
<div class="filler"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="brake" class="meter">
|
||||
<div class="bar"></div>
|
||||
<div class="value">0</div>
|
||||
<div class="bar">
|
||||
<div class="filler"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="throttle" class="meter">
|
||||
<div class="bar"></div>
|
||||
<div class="value">0</div>
|
||||
<div class="bar">
|
||||
<div class="filler"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="direction">
|
||||
<div id="wheel">
|
||||
<div id="wheel--indicator"></div>
|
||||
<div id="wheel--center"></div>
|
||||
</div>
|
||||
<div class="indicator"></div>
|
||||
<div class="center"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,77 +1,60 @@
|
||||
/**
|
||||
* The Telemetry template class
|
||||
*
|
||||
* @class TelemetryTemplate
|
||||
*/
|
||||
class TelemetryTemplate {
|
||||
/**
|
||||
* Creates an instance of TelemetryTemplate.
|
||||
*/
|
||||
constructor() {
|
||||
this.AXES = ['clutch', 'brake', 'throttle', 'direction'];
|
||||
|
||||
this.frequency = 1000 / 60;
|
||||
this.historyLength = 5000;
|
||||
this.length = this.historyLength / this.frequency;
|
||||
this.index = 0;
|
||||
|
||||
this.$clutchValue = document.querySelector('#clutch .value');
|
||||
this.$clutchBar = document.querySelector('#clutch .bar .filler');
|
||||
this.$brakeValue = document.querySelector('#brake .value');
|
||||
this.$brakeBar = document.querySelector('#brake .bar .filler');
|
||||
this.$throttleValue = document.querySelector('#throttle .value');
|
||||
this.$throttleBar = document.querySelector('#throttle .bar .filler');
|
||||
this.$directionIndicator = document.querySelector('#direction #wheel--indicator');
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
toPercentage(value, min, max) {
|
||||
// debugger;
|
||||
function TelemetryTemplate(gamepad) {
|
||||
return {
|
||||
$clutchBar: document.querySelector('#clutch .bar'),
|
||||
$clutchValue: document.querySelector('#clutch .value'),
|
||||
$brakeBar: document.querySelector('#brake .bar'),
|
||||
$brakeValue: document.querySelector('#brake .value'),
|
||||
$throttleBar: document.querySelector('#throttle .bar'),
|
||||
$throttleValue: document.querySelector('#throttle .value'),
|
||||
$directionIndicator: document.querySelector('#direction .indicator'),
|
||||
AXES: ['clutch', 'brake', 'throttle', 'direction'],
|
||||
frequency: gamepad.getUrlParam('fps') || 60,
|
||||
historyLength: gamepad.getUrlParam('history') || 5000,
|
||||
index: 0,
|
||||
init: function () {
|
||||
this.interval = 1000 / this.frequency;
|
||||
this.length = this.historyLength / this.interval;
|
||||
this.loadAxes();
|
||||
this.initChart();
|
||||
},
|
||||
toPercentage: function (value, min, max) {
|
||||
return value !== undefined
|
||||
? Math.round((value - min) * (100 / (max - min)))
|
||||
: 0;
|
||||
}
|
||||
|
||||
toDegrees(value, min, max) {
|
||||
},
|
||||
toDegrees: function (value, min, max) {
|
||||
const percentage = this.toPercentage(value, min, max);
|
||||
return (this.directionDegrees) * (percentage - 50) / 100;
|
||||
}
|
||||
|
||||
toAxisValue(gamepad, axis) {
|
||||
},
|
||||
toAxisValue: function (gamepad, axis) {
|
||||
const { [`${axis}Type`]: type, [`${axis}Index`]: index, [`${axis}Min`]: min, [`${axis}Max`]: max } = this[axis];
|
||||
const value = type === 'button' ? gamepad.buttons[index].value : gamepad.axes[index];
|
||||
return axis === 'direction' ? this.toDegrees(value, min, max) : this.toPercentage(value, min, max);
|
||||
}
|
||||
|
||||
loadAxes() {
|
||||
},
|
||||
loadAxes: function () {
|
||||
this.AXES.forEach((axis) => {
|
||||
this[axis] = {
|
||||
[`${axis}Type`]: (window.gamepad.getUrlParam(`${axis}Type`) || 'axis').replace('axis', 'axe'),
|
||||
[`${axis}Index`]: window.gamepad.getUrlParam(`${axis}Index`),
|
||||
[`${axis}Min`]: window.gamepad.getUrlParam(`${axis}Min`) || -1,
|
||||
[`${axis}Max`]: window.gamepad.getUrlParam(`${axis}Max`) || 1,
|
||||
[`${axis}Type`]: (gamepad.getUrlParam(`${axis}Type`) || 'axis').replace('axis', 'axe'),
|
||||
[`${axis}Index`]: gamepad.getUrlParam(`${axis}Index`),
|
||||
[`${axis}Min`]: gamepad.getUrlParam(`${axis}Min`) || -1,
|
||||
[`${axis}Max`]: gamepad.getUrlParam(`${axis}Max`) || 1,
|
||||
}
|
||||
});
|
||||
this.directionDegrees = window.gamepad.getUrlParam('directionDegrees') || 360;
|
||||
}
|
||||
|
||||
init() {
|
||||
this.loadAxes();
|
||||
|
||||
this.directionDegrees = gamepad.getUrlParam('directionDegrees') || 360;
|
||||
},
|
||||
initChart: function () {
|
||||
if (!window.google) {
|
||||
window.setTimeout(this.init.bind(this), 100);
|
||||
window.setTimeout(this.loadGoogleCharts.bind(this), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
google.charts.load('current', {
|
||||
packages: ['corechart', 'line'],
|
||||
});
|
||||
this.drawChart();
|
||||
},
|
||||
loadGoogleCharts: function () {
|
||||
google.charts.load('current', { packages: ['corechart', 'line'], });
|
||||
google.charts.setOnLoadCallback(this.drawChart.bind(this));
|
||||
}
|
||||
|
||||
drawChart() {
|
||||
this.initialData = [['Time', 'Clutch', 'Brake', 'Throttle']];
|
||||
},
|
||||
drawChart: function () {
|
||||
this.initialData = [['time', 'clutch', 'brake', 'throttle']];
|
||||
for (this.index = 0; this.index < this.length; this.index++) {
|
||||
this.initialData.push([this.index, 0, 0, 0]);
|
||||
}
|
||||
@ -98,46 +81,44 @@ class TelemetryTemplate {
|
||||
},
|
||||
minValue: 0,
|
||||
maxValue: 100,
|
||||
viewWindow: {
|
||||
min: 2,
|
||||
max: 102,
|
||||
}
|
||||
},
|
||||
colors: ['blue', 'red', 'lime'],
|
||||
colors: ['#2D64B9', '#A52725', '#0CA818'],
|
||||
legend: 'none'
|
||||
};
|
||||
this.chart = new google.visualization.LineChart(document.querySelector('#chart'));
|
||||
this.chart.draw(this.data, this.options);
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
update() {
|
||||
const gamepad = window.gamepad.getActive();
|
||||
if (!gamepad) return;
|
||||
|
||||
const [clutch, brake, throttle, direction] = this.AXES.map((axis) => this.toAxisValue(gamepad, axis));
|
||||
|
||||
},
|
||||
update: function () {
|
||||
const activeGamepad = gamepad.getActive();
|
||||
if (!activeGamepad) return;
|
||||
const [clutch, brake, throttle, direction] = this.AXES.map((axis) => this.toAxisValue(activeGamepad, axis));
|
||||
this.updateChart(clutch, brake, throttle);
|
||||
this.updateMeters(clutch, brake, throttle, direction);
|
||||
window.setTimeout(this.update.bind(this), this.frequency);
|
||||
}
|
||||
|
||||
updateChart(clutch, brake, throttle) {
|
||||
if (this.data.getNumberOfRows() > this.length) {
|
||||
this.data.removeRows(0, this.data.getNumberOfRows() - this.length);
|
||||
}
|
||||
window.setTimeout(this.update.bind(this), this.interval);
|
||||
},
|
||||
updateChart: function (clutch, brake, throttle) {
|
||||
this.data.removeRows(0, 1);
|
||||
this.data.addRow([this.index, clutch, brake, throttle]);
|
||||
this.chart.draw(this.data, this.options);
|
||||
this.index++;
|
||||
}
|
||||
|
||||
updateMeters(clutch, brake, throttle, direction) {
|
||||
},
|
||||
updateMeters: function (clutch, brake, throttle, direction) {
|
||||
Object.entries({ clutch, brake, throttle, direction }).forEach(([axis, value]) => {
|
||||
if (axis === 'direction') {
|
||||
this.$directionIndicator.style.transform = `rotate(${value}deg)`;
|
||||
return;
|
||||
}
|
||||
this[`$${axis}Value`].innerHTML = value;
|
||||
this[`$${axis}Value`].style.opacity = `${Math.round(33 + (value / 1.5))}%`;
|
||||
this[`$${axis}Bar`].style.height = `${value}%`;
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}.init();
|
||||
};
|
||||
|
||||
window.telemetryTemplate = new TelemetryTemplate();
|
||||
new TelemetryTemplate(window.gamepad);
|
||||
|
@ -1,33 +1,37 @@
|
||||
gamepad.updateButton = function ($button) {
|
||||
const value = parseFloat($button.attr("data-value"), 10);
|
||||
|
||||
if ($button.is(".trigger")) {
|
||||
function XboxOneTemplate(gamepad) {
|
||||
return {
|
||||
init: function () {
|
||||
gamepad.updateButton = function ($button) {
|
||||
const value = parseFloat($button.attr('data-value'), 10);
|
||||
if ($button.is('.trigger')) {
|
||||
$button.css(
|
||||
gamepad.triggersMeter
|
||||
? {
|
||||
opacity: 1,
|
||||
"clip-path": `inset(${(1 - value) * 100}% 0px 0px 0pc)`,
|
||||
'clip-path': `inset(${(1 - value) * 100}% 0px 0px 0pc)`,
|
||||
}
|
||||
: {
|
||||
opacity: `${value * 100}%`,
|
||||
"clip-path": "none",
|
||||
'clip-path': 'none',
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
gamepad.updateAxis = function ($axis) {
|
||||
const axisX = $axis.attr("data-value-x");
|
||||
const axisY = $axis.attr("data-value-y");
|
||||
|
||||
if ($axis.is(".stick")) {
|
||||
};
|
||||
gamepad.updateAxis = function ($axis) {
|
||||
const axisX = $axis.attr('data-value-x');
|
||||
const axisY = $axis.attr('data-value-y');
|
||||
if ($axis.is('.stick')) {
|
||||
$axis.css({
|
||||
"margin-top": axisY * 25,
|
||||
"margin-left": axisX * 25,
|
||||
'margin-top': axisY * 25,
|
||||
'margin-left': axisX * 25,
|
||||
transform: `rotateX(${-parseFloat(
|
||||
axisY * 30,
|
||||
8
|
||||
)}deg) rotateY(${parseFloat(axisX * 30, 8)}deg)`,
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
}.init();
|
||||
};
|
||||
new XboxOneTemplate(window.gamepad);
|
||||
|
Loading…
x
Reference in New Issue
Block a user