spenibus.net
2019-07-10 19:57:32 GMT

PC steering wheel viewer update, now with gearbox

You can check the [original post][1]. Just a little code update, now with the gearbox, pure CSS rendering, adaptive resolution and pixel perfect alignment. Demo ---- <center><iframe width="560" height="315" src="https://www.youtube.com/embed/vJhXbPwUJ-w" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></center> wheel.html ---------- ```` <!DOCTYPE html> <html> <head> <title>Wheel</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <script src="wheel.js" type="text/javascript"></script> <link href="wheel2.css" rel="stylesheet" type="text/css" /> <link href="wheelScalable.css" rel="stylesheet" type="text/css" /> </head> <body class="index"> <div id="viewer"> <span id="unitRef"></span> <span class="viewerCol"> <span id="wheel"> <span id="wheelA"> <span id="wheelB"> <span id="wheelC"> <span class="partA"></span> <span class="partB"></span> <span class="partC"></span> </span> </span> <span id="wheelTopNotch"></span> </span> </span> </span> <span class="viewerCol"> <span id="gears"> <span id="gearRowBack"><span></span></span> <span id="gearCol1" class="gearCol forward"><span></span></span> <span id="gearCol2" class="gearCol forward"><span></span></span> <span id="gearCol3" class="gearCol forward"><span></span></span> <span id="gearCol4" class="gearCol reverse"><span></span></span> <span id="gearColNegative1" class="gearColNegative gearColNegativeTop "><span></span></span> <span id="gearColNegative2" class="gearColNegative gearColNegativeTop "><span></span></span> <span id="gearColNegative3" class="gearColNegative gearColNegativeTop "><span></span></span> <span id="gearColNegative4" class="gearColNegative gearColNegativeBottom"><span></span></span> <span id="gearColNegative5" class="gearColNegative gearColNegativeBottom"><span></span></span> <span id="gearColNegative6" class="gearColNegative gearColNegativeBottom"><span></span></span> <span id="gearRowFront"><span></span></span> <span id="gearStick"><span class="gearN"></span></span> </span> <span id="pedals"> <span id="clutch" class="pedal"><span><span></span></span></span> <span id="brake" class="pedal"><span><span></span></span></span> <span id="throttle" class="pedal"><span><span></span></span></span> </span> </span> </div> <div> <legend><input type="checkbox" id="showDisplay"> Show device data</legend> </div> <div id="dataDisplay">waiting for input</div> </body> </html> ```` wheelScalable.css --------- ```` body { background-color:transparent; margin:0; padding:0; } #unitRef { display:block; width:1vw; height:1vw; background-color:green; position:fixed; left:-2vw; } #viewer { display:inline-block; height:50vw; background-color:rgba(0,0,0,0.2); font-size:0; white-space:nowrap; border-bottom:1vw red solid; } .viewerCol { display:inline-block; vertical-align:bottom; height:100%; } /******************************************************************************/ #wheel_old { display:inline-block; background-color:rgba(0,255,0,0.2); height:46vw; margin:2vw; display:none; } #wheel { display:inline-block; position:relative; } #wheelTopNotch { width:2vw; height:4vw; background-color:#468; position:absolute; left:18vw; top: -1vw; } #wheelA { display:inline-block; width:38vw; height:38vw; margin:4vw; border:1vw solid #468; border:1vw solid black; border-radius:22vw; overflow:hidden; position:relative; } #wheelB { margin:-1vw; display:inline-block; width:34vw; height:34vw; border:3vw solid #ACF; border:3vw solid #AAA; border-radius:22vw; overflow:hidden; position:relative; } #wheelC { margin:-1vw; display:inline-block; width:32vw; height:32vw; border:2vw solid #468; border:2vw solid black; border-radius:22vw; overflow:hidden; position:relative; } #wheel .partA { display:inline-block; width:60vw; height:60vw; border:5vw solid #468; border-radius:35vw; position:absolute; left:-19vw; top: 15vw; } #wheel .partB { display:inline-block; background-color:#468; width:8vw; height:20vw; position:absolute; left:12vw; top: 16vw; } /******************************************************************************/ #gears { display:inline-block; margin:2vw 2vw 0vw 0vw; position:relative; } .gearCol { display:inline-block; vertical-align:bottom; width:4vw; height:18vw; margin:1vw; background-color:black; border-radius:2vw; position:relative; } .gearCol > span { display:inline-block; vertical-align:top; background-color:#AAA; width:2vw; height:16vw; margin:1vw; border-radius:1vw; } #gearRowBack { display:block; background-color:black; width:22vw; height:4vw; border-radius:2vw; position:absolute; left:1vw; top:8vw; } #gearRowFront { display:block; background-color:#AAA; width:20vw; height:2vw; border-radius:2vw; position:absolute; left:2vw; top:9vw; } #gearCol4 { height:11vw; } #gearCol4 > span { height:9vw; } .gearColNegative { position:absolute; display:inline-block; border:1vw solid #AAA; } .gearColNegative > span { width:2vw; height:4vw; display:inline-block; border:1vw solid black; } .gearColNegativeTop ,.gearColNegativeTop > span { border-radius: 0vw 0vw 20vw 20vw; border-top:none; } .gearColNegativeBottom ,.gearColNegativeBottom > span { border-radius: 20vw 20vw 0vw 0vw; border-bottom:none; } #gearColNegative1 { top:4vw; left:3vw; } #gearColNegative2 { top:4vw; left:9vw; } #gearColNegative3 { top:4vw; left:15vw; border-right:none; border-radius: 0vw 0vw 0vw 20vw; } #gearColNegative3 > span { border-right:none; border-radius: 0vw 0vw 0vw 20vw; width:1vw; } #gearColNegative4 { top:10vw; left:3vw; } #gearColNegative5 { top:10vw; left:9vw; } #gearColNegative6 { top:10vw; left:15vw; } #gearStick { display:block; background-color:#246; width: 6vw; height:6vw; border-radius:3vw; position:absolute; top: 7vw; left:6vw; } #gearStick > span { display:block; background-color:#ACF; width:4vw; height:4vw; border-radius:2vw; margin:1vw; } #gearStick.gearF1 { top: 0vw; left:0vw; } #gearStick.gearF2 { top: 14vw; left:0vw; } #gearStick.gearF3 { top: 0vw; left:6vw; } #gearStick.gearF4 { top: 14vw; left:6vw; } #gearStick.gearF5 { top: 0vw; left:12vw; } #gearStick.gearF6 { top: 14vw; left:12vw; } #gearStick.gearR1 { top: 14vw; left:18vw; } /******************************************************************************/ #pedals { display:block; margin:2vw 2vw 0vw 0vw; } .pedal { display:inline-block; vertical-align:bottom; background-color:#AAA; width:4vw; height:22vw; margin:0 1vw; border:1vw solid black; } .pedal > span { display:inline-block; vertical-align:top; background-color:#AAA; width:100%; height:50%; } #throttle { background-color:#0A0; } #brake { background-color:#C00; } #clutch { background-color:#FA0; } ```` wheel.js -------- ```` /******************************************************************************* pc steering wheel animated viewer probably firefox only 2019-08-10 19:55 +0000 /******************************************************************************/ console.log('wheel'); let interval; /* // chrome compatibility if(!('ongamepadconnected' in window)) { console.log('no event'); interval = setInterval( z=>{ console.log('polling'); window.dispatchEvent(new CustomEvent('gamepadconnected')) }, 1000); } */ let device; let dataDisplay; let showDisplay; // mapping the axes let axisIndexWheel = 0; let axisIndexThrottle = 1; let axisIndexBrake = 2; let axisIndexClutch = 3; let axisIndexClutchAlt = 5; // mapping the buttons let btnIndexR1 = 11; let btnIndexF1 = 12; let btnIndexF2 = 13; let btnIndexF3 = 14; let btnIndexF4 = 15; let btnIndexF5 = 16; let btnIndexF6 = 17; // elements references let elemWheel; let elemThrottle; let elemBrake; let elemClutch; let elemGearStick; // misc let axisWheelFullRotation = 900; // degrees let loopStartTime = (new Date()).getTime(); let loopEndTime = (new Date()).getTime(); //let renderRate = 1000/100; //****************************************************************************** window.addEventListener('DOMContentLoaded', function(e) { console.log('loaded'); // style: convert vw into px for scalability with pixel perfect alignment let xhr = new XMLHttpRequest(); xhr.open('GET', './wheelScalable.css', true); xhr.responseType = 'text'; xhr.onload = function(data){ let val = data.target.responseText; // get unit ref for pixel perfect consistency let unit = Math.floor( window.getComputedStyle( document.getElementById('unitRef') ) .getPropertyValue('width') .match(/([\d\.]+)/)[1] ); let r = /([^\d])([\d\.]+)(\s*vw)/g; let m; while(m = r.exec(val)) { val = val.replace( new RegExp(m[0], 'g') ,m[1]+ unit * parseInt(m[2]) +'px' ); } let s = document.createElement('style'); s.textContent = val; document.head.appendChild(s); } xhr.send(); dataDisplay = document.getElementById('dataDisplay'); showDisplay = document.getElementById('showDisplay'); elemWheel = document.getElementById('wheel'); elemThrottle = document.querySelector('#throttle > span'); elemBrake = document.querySelector('#brake > span'); elemClutch = document.querySelector('#clutch > span'); elemGearStick = document.querySelector('#gearStick'); /* window.addEventListener('gamepadconnected', function(e) { if(e.gamepad.id.match(/g920.*wheel/i)) { wheelDevice = e.gamepad; gameLoop(); return; } }); */ gameLoop(); }); //****************************************************************************** function gameLoop() { /* framerate limiter * loopStartTime = (new Date()).getTime(); let delta = loopStartTime-loopEndTime; if(delta < renderRate) { requestAnimationFrame(gameLoop); return; } console.log('render delta: '+delta+'ms') */ wheelDevice = null; let gps = navigator.getGamepads(); for(let gp of gps) { if(gp.id.match(/g920.*wheel/i)) { wheelDevice = gp; break; } } if(wheelDevice) { //******************************************************* data gathering let axisValueWheel = wheelDevice.axes[axisIndexWheel]; let axisValueThrottle = wheelDevice.axes[axisIndexThrottle]; let axisValueBrake = wheelDevice.axes[axisIndexBrake]; //let axisValueClutch = wheelDevice.axes[axisIndexClutch]; let axisValueClutch = wheelDevice.axes[axisIndexClutch] || wheelDevice.axes[axisIndexClutchAlt]; // convert wheel axis to angle axisValueWheel = Math.round(axisWheelFullRotation / 2 * axisValueWheel * 1000) / 1000; // normalize pedals axes to range 0-1 axisValueThrottle = (axisValueThrottle * -1 + 1) / 2; axisValueBrake = (axisValueBrake * -1 + 1) / 2; axisValueClutch = (axisValueClutch * -1 + 1) / 2; //********************************************************* data display let debugText = '-'; if(showDisplay.checked) { debugText = '\n[id]\n '+wheelDevice.id+'\n'; debugText += '\n[Axes]'; wheelDevice.axes.forEach((a,i)=>{ debugText += "\n "+i+' : '+a; }); debugText += '\n\n[Buttons]'; wheelDevice.buttons.forEach((b,i)=>{ debugText += "\n "+i+' : pressed:'+b.pressed+' touched:'+b.touched; }); debugText = '<pre>\n[Computed]\n' +' wheel: '+axisValueWheel +'deg\n' +' thottle: '+axisValueThrottle+'\n' +' brake: '+axisValueBrake +'\n' +' clutch: '+axisValueClutch +'\n' +'</pre>' +'<pre>'+debugText+'</pre>' ; } dataDisplay.innerHTML = debugText; //************************************************************** visuals axisValueWheel = 'rotate('+axisValueWheel+'deg)'; if(elemWheel.style.transform != axisValueWheel) { elemWheel.style.transform = axisValueWheel; } axisValueThrottle = (100 - axisValueThrottle * 100)+'%'; if(elemThrottle.style.height != axisValueThrottle) { elemThrottle.style.height = axisValueThrottle; } axisValueBrake = (100 - axisValueBrake * 100)+'%'; if(elemBrake.style.height != axisValueBrake) { elemBrake.style.height = axisValueBrake; } axisValueClutch = (100 - axisValueClutch * 100)+'%'; if(elemClutch.style.height != axisValueClutch) { elemClutch.style.height = axisValueClutch; } let gearStickClass = '' +(wheelDevice.buttons[btnIndexR1].pressed ? ' gearR1' : '') +(wheelDevice.buttons[btnIndexF1].pressed ? ' gearF1' : '') +(wheelDevice.buttons[btnIndexF2].pressed ? ' gearF2' : '') +(wheelDevice.buttons[btnIndexF3].pressed ? ' gearF3' : '') +(wheelDevice.buttons[btnIndexF4].pressed ? ' gearF4' : '') +(wheelDevice.buttons[btnIndexF5].pressed ? ' gearF5' : '') +(wheelDevice.buttons[btnIndexF6].pressed ? ' gearF6' : '') ; if(elemGearStick.classList != gearStickClass) { elemGearStick.classList = gearStickClass } } //loopEndTime = (new Date()).getTime(); requestAnimationFrame(gameLoop); /* let angle = Math.round(wheelFullRotation / 2 * axis0value * 1000) / 1000; nodeAxis0.textContent = axis0value+' : '+angle+'deg'; wheelGfx.style.transform = 'rotate('+angle+'deg)'; */ //transform: rotate(20deg); /* var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads : []); if (!gamepads) { return; } var gp = gamepads[0]; if (buttonPressed(gp.buttons[0])) { b--; } else if (buttonPressed(gp.buttons[2])) { b++; } if (buttonPressed(gp.buttons[1])) { a++; } else if (buttonPressed(gp.buttons[3])) { a--; } ball.style.left = a * 2 + "px"; ball.style.top = b * 2 + "px"; */ } ```` [1]: http://spenibus.net/b/p/F/PC-steering-wheel-viewer-prototype-in-html-javascript