diff --git a/globe/globe.js b/globe/globe.js index 806e5697..b37b1036 100644 --- a/globe/globe.js +++ b/globe/globe.js @@ -85,6 +85,227 @@ DAT.Globe = function(container, opts) { var padding = 40; var PI_HALF = Math.PI / 2; + + var touchHandled; + var isPinchScaling; + var pinchStartX; + var clickTimer; + + //disabled pinch zooming by default due to as weird bugs in Safari but leaving in, in case someone else can fix it + var pinchZoomEnabled = opts.pinchZoomEnabled || false; + + /** + * (Modified from `jquery-ui-touchpunch`) + * Simulate a mouse event based on a corresponding touch event + * @param {Object} event A touch event + * @param {String} simulatedType The corresponding mouse event + */ + function simulateMouseEvent(event, simulatedType) { + + var touch; + + // Ignore multi-touch events + if(event.originalEvent){ + touch = event.originalEvent.changedTouches[0]; + + if (event.originalEvent.touches.length == 2) { + //handle pinching + isPinchScaling = true; + pinchStartX = event.originalEvent.touches[0].clientX; + onPinch(event); + + return; + } + else if (event.originalEvent.touches.length > 2){ + return; + } + } + else if(event.touches){ + touch = event.changedTouches[0]; + + if(event.touches.length == 2){ + //handle pinching + isPinchScaling = true; + pinchStartX = event.touches[0].clientX; + onPinch(event); + + return; + } + else if(event.touches.length > 2){ + return; + } + } + + event.preventDefault(); + + var simulatedEvent = document.createEvent('MouseEvents'); + + // Initialize the simulated mouse event using the touch event's coordinates + simulatedEvent.initMouseEvent( + simulatedType, // type + true, // bubbles + true, // cancelable + window, // view + 1, // detail + touch.screenX, // screenX + touch.screenY, // screenY + touch.clientX, // clientX + touch.clientY, // clientY + false, // ctrlKey + false, // altKey + false, // shiftKey + false, // metaKey + 0, // button + null // relatedTarget + ); + + // Dispatch the simulated event to the target element + event.target.dispatchEvent(simulatedEvent); + } + + function resetZoomOnDoubleTap(event){ + // check for double tap + if(pinchZoomEnabled) { + if ((event.originalEvent && event.originalEvent.touches.length == 1) || + (event.touches && event.touches.length == 1)) { + + if (clickTimer == null) { + clickTimer = setTimeout(function () { + clickTimer = null; + }, 500) + } else { + clearTimeout(clickTimer); + clickTimer = null; + + //reset zoom + zoom(-5000); + } + } + } + } + + function _onTouchStart (event) { + + resetZoomOnDoubleTap(event); + + var self = this; + + // Ignore the event if another widget is already being handled + if (touchHandled){ + return; + } + + // Set the flag to prevent other widgets from inheriting the touch event + touchHandled = true; + + // Track movement to determine if interaction was a click + self._touchMoved = false; + + // Simulate the mouseover event + simulateMouseEvent(event, 'mouseover'); + + // Simulate the mousemove event + simulateMouseEvent(event, 'mousemove'); + + // Simulate the mousedown event + simulateMouseEvent(event, 'mousedown'); + } + + + function _onTouchMove(event) { + if(isPinchScaling){ + onPinch(event); + return; + } + + // Ignore event if not handled + if (!touchHandled) { + return; + } + + // Interaction was not a click + this._touchMoved = true; + + // Simulate the mousemove event + simulateMouseEvent(event, 'mousemove'); + } + + function _onTouchEnd(event) { + + if(isPinchScaling){ + onPinch(event); + isPinchScaling = false + return; + } + + // Ignore event if not handled + if (!touchHandled) { + return; + } + + // Simulate the mouseup event + simulateMouseEvent(event, 'mouseup'); + + // Simulate the mouseout event + simulateMouseEvent(event, 'mouseout'); + + // If the touch interaction did not move, it should trigger a click + if (!this._touchMoved) { + + // Simulate the click event + simulateMouseEvent(event, 'click'); + } + + // Unset the flag to allow other widgets to inherit the touch event + touchHandled = false; + } + + function getPinchDistance(event){ + var dist; + + try{ + dist = Math.sqrt( + (event.touches[0].clientX-event.touches[1].clientX) * (event.touches[0].clientX-event.touches[1].clientX) + + (event.touches[0].clientY-event.touches[1].clientY) * (event.touches[0].clientY-event.touches[1].clientY) + ); + + dist = dist * 0.1; + dist = Math.min(dist, 25); + + var dir = (pinchStartX > event.touches[0].clientX) ? 1 : -1; + + dist = dist * dir; + } + catch(e){ + dist = null; + } + + return dist; + } + + function onPinch(event){ + if(pinchZoomEnabled){ + var dist = getPinchDistance(event) + if(dist != null){ + zoom(dist); + } + } + } + + + function addTouchHandlers(container){ + + var touchSupport = 'ontouchend' in document; + + //ignore browsers without touch + if(!touchSupport){ + return; + } + + container.addEventListener('touchstart', _onTouchStart, false); + } + + function init() { container.style.color = '#fff'; @@ -152,6 +373,8 @@ DAT.Globe = function(container, opts) { container.addEventListener('mousewheel', onMouseWheel, false); + addTouchHandlers(container); + document.addEventListener('keydown', onDocumentKeyDown, false); window.addEventListener('resize', onWindowResize, false); @@ -277,6 +500,11 @@ DAT.Globe = function(container, opts) { container.addEventListener('mouseup', onMouseUp, false); container.addEventListener('mouseout', onMouseOut, false); + container.addEventListener('touchend', _onTouchEnd, false); + container.addEventListener('touchmove', _onTouchMove, false); + + + mouseOnDown.x = - event.clientX; mouseOnDown.y = event.clientY; @@ -333,10 +561,14 @@ DAT.Globe = function(container, opts) { } } + function onWindowResize( event ) { - camera.aspect = container.offsetWidth / container.offsetHeight; - camera.updateProjectionMatrix(); - renderer.setSize( container.offsetWidth, container.offsetHeight ); + // this method fights with pinch zooming, needs to be disabled if pinch zooming + if(pinchZoomEnabled){ + camera.aspect = container.offsetWidth / container.offsetHeight; + camera.updateProjectionMatrix(); + renderer.setSize( container.offsetWidth, container.offsetHeight ); + } } function zoom(delta) {