function throttle(func, ms) { var isThrottled = false, savedArgs, savedThis; function wrapper() { if (isThrottled) { savedArgs = arguments; savedThis = this; return; } func.apply(this, arguments); isThrottled = true; setTimeout(function() { isThrottled = false; if (savedArgs) { wrapper.apply(savedThis, savedArgs); savedArgs = savedThis = null; } }, ms); } return wrapper; } function callNativeApp(name, msg) { try { webkit.messageHandlers[name].postMessage(msg); return true; } catch(err) { console.warn('The native context does not exist yet'); return false; } } var rcLastPublish = null; function rcPublish() { callNativeApp('control', controlMessage); rcLastPublish = new Date(); } rcPublishThrottled = throttle(rcPublish, 30); setInterval(function() { if (rcLastPublish !== null && new Date() - rcLastPublish > 800) { rcPublishThrottled(); } }, 50); var body = document.querySelector('body'); var stickLeft = document.querySelector('.stick-left'); var stickRight = document.querySelector('.stick-right'); var controlMessage = { x: 0, y: 0, z: 0, r: 0 }; function onStickTouchMove(touch) { var target = touch.target; var targetRect = target.getBoundingClientRect(); var stickPointer = target.querySelector('.stick-pointer'); var offsetX = touch.clientX - targetRect.left; var offsetY = touch.clientY - targetRect.top; var x = 2 * offsetX / targetRect.width; var y = 2 * offsetY / targetRect.height; x = Math.max(0, x); x = Math.min(2, x); y = Math.max(0, y); y = Math.min(2, y); stickPointer.style.left = (x * 50) + '%'; stickPointer.style.top = (y * 50) + '%'; x -= 1; y = 1 - y; if (target.matches('.stick-left')) { controlMessage.z = Math.round((y + 1) * 500); controlMessage.r = Math.round(x * 1000); } else if (target.matches('.stick-right')) { controlMessage.x = Math.round(y * 1000); controlMessage.y = Math.round(x * 1000); } } body.addEventListener('touchmove', function (e) { e.preventDefault(); }); function stickTouchStart(e) { setControlMode(); callNativeApp('controlStart'); onStickTouchMove(e.changedTouches[0]); rcPublishThrottled(); e.stopPropagation(); e.preventDefault(); } function stickTouchMove(e) { onStickTouchMove(e.changedTouches[0]); rcPublishThrottled(); e.stopPropagation(); e.preventDefault(); } function stickTouchEnd(e) { var pointer = e.target.querySelector('.stick-pointer'); if (e.target.matches('.stick-left')) { controlMessage.r = 0; pointer.style.left = '50%'; } else if (e.target.matches('.stick-right')) { controlMessage.x = 0; controlMessage.y = 0; pointer.style.left = '50%'; pointer.style.top = '50%'; } rcPublishThrottled(); } stickLeft.addEventListener('touchmove', stickTouchMove); stickRight.addEventListener('touchmove', stickTouchMove); stickLeft.addEventListener('touchstart', stickTouchStart); stickRight.addEventListener('touchstart', stickTouchStart); stickLeft.addEventListener('touchend', stickTouchEnd); stickRight.addEventListener('touchend', stickTouchEnd);