From 639f40161340c4aaf3766e9da0430b3edfe20814 Mon Sep 17 00:00:00 2001 From: tanabee8 Date: Thu, 3 Sep 2020 00:22:06 +0900 Subject: [PATCH 1/2] add window.orientation --- aframe/src/location-based/gps-camera.js | 594 ++++++++++++------------ 1 file changed, 297 insertions(+), 297 deletions(-) diff --git a/aframe/src/location-based/gps-camera.js b/aframe/src/location-based/gps-camera.js index 64fd1e24..d86ffaa7 100644 --- a/aframe/src/location-based/gps-camera.js +++ b/aframe/src/location-based/gps-camera.js @@ -1,151 +1,151 @@ AFRAME.registerComponent('gps-camera', { - _watchPositionId: null, - originCoords: null, - currentCoords: null, - lookControls: null, - heading: null, - schema: { - simulateLatitude: { - type: 'number', - default: 0, - }, - simulateLongitude: { - type: 'number', - default: 0, - }, - simulateAltitude: { - type: 'number', - default: 0, - }, - positionMinAccuracy: { - type: 'int', - default: 100, - }, - alert: { - type: 'boolean', - default: false, - }, - minDistance: { - type: 'int', - default: 0, - }, - maxDistance: { - type: 'int', - default: 0, - } - }, - update: function() { - if (this.data.simulateLatitude !== 0 && this.data.simulateLongitude !== 0) { - localPosition = Object.assign({}, this.currentCoords || {}); - localPosition.longitude = this.data.simulateLongitude; - localPosition.latitude = this.data.simulateLatitude; - localPosition.altitude = this.data.simulateAltitude; - this.currentCoords = localPosition; - - // re-trigger initialization for new origin - this.originCoords = null; - this._updatePosition(); - } - }, - init: function () { - if (!this.el.components['look-controls']) { - return; - } - - this.loader = document.createElement('DIV'); - this.loader.classList.add('arjs-loader'); - document.body.appendChild(this.loader); - - window.addEventListener('gps-entity-place-added', function () { - // if places are added after camera initialization is finished - if (this.originCoords) { - window.dispatchEvent(new CustomEvent('gps-camera-origin-coord-set')); - } - if (this.loader && this.loader.parentElement) { - document.body.removeChild(this.loader) - } - }.bind(this)); - - this.lookControls = this.el.components['look-controls']; - - // listen to deviceorientation event - var eventName = this._getDeviceOrientationEventName(); - this._onDeviceOrientation = this._onDeviceOrientation.bind(this); - - // if Safari - if (!!navigator.userAgent.match(/Version\/[\d.]+.*Safari/)) { - // iOS 13+ - if (typeof DeviceOrientationEvent.requestPermission === 'function') { - var handler = function () { - console.log('Requesting device orientation permissions...') - DeviceOrientationEvent.requestPermission(); - document.removeEventListener('touchend', handler); - }; - - document.addEventListener('touchend', function () { handler() }, false); - - alert('After camera permission prompt, please tap the screen to activate geolocation.'); - } else { - var timeout = setTimeout(function () { - alert('Please enable device orientation in Settings > Safari > Motion & Orientation Access.') - }, 750); - window.addEventListener(eventName, function () { - clearTimeout(timeout); - }); - } - } - - window.addEventListener(eventName, this._onDeviceOrientation, false); - - this._watchPositionId = this._initWatchGPS(function (position) { - if (this.data.simulateLatitude !== 0 && this.data.simulateLongitude !== 0) { - localPosition = Object.assign({}, position.coords); - localPosition.longitude = this.data.simulateLongitude; - localPosition.latitude = this.data.simulateLatitude; - localPosition.altitude = this.data.simulateAltitude; - this.currentCoords = localPosition; - } - else { - this.currentCoords = position.coords; - } - - this._updatePosition(); - }.bind(this)); - }, - - tick: function () { - if (this.heading === null) { - return; - } - this._updateRotation(); - }, - - remove: function () { - if (this._watchPositionId) { - navigator.geolocation.clearWatch(this._watchPositionId); - } - this._watchPositionId = null; - - var eventName = this._getDeviceOrientationEventName(); - window.removeEventListener(eventName, this._onDeviceOrientation, false); - }, + _watchPositionId: null, + originCoords: null, + currentCoords: null, + lookControls: null, + heading: null, + schema: { + simulateLatitude: { + type: 'number', + default: 0, + }, + simulateLongitude: { + type: 'number', + default: 0, + }, + simulateAltitude: { + type: 'number', + default: 0, + }, + positionMinAccuracy: { + type: 'int', + default: 100, + }, + alert: { + type: 'boolean', + default: false, + }, + minDistance: { + type: 'int', + default: 0, + }, + maxDistance: { + type: 'int', + default: 0, + } + }, + update: function () { + if (this.data.simulateLatitude !== 0 && this.data.simulateLongitude !== 0) { + localPosition = Object.assign({}, this.currentCoords || {}); + localPosition.longitude = this.data.simulateLongitude; + localPosition.latitude = this.data.simulateLatitude; + localPosition.altitude = this.data.simulateAltitude; + this.currentCoords = localPosition; + + // re-trigger initialization for new origin + this.originCoords = null; + this._updatePosition(); + } + }, + init: function () { + if (!this.el.components['look-controls']) { + return; + } + + this.loader = document.createElement('DIV'); + this.loader.classList.add('arjs-loader'); + document.body.appendChild(this.loader); + + window.addEventListener('gps-entity-place-added', function () { + // if places are added after camera initialization is finished + if (this.originCoords) { + window.dispatchEvent(new CustomEvent('gps-camera-origin-coord-set')); + } + if (this.loader && this.loader.parentElement) { + document.body.removeChild(this.loader) + } + }.bind(this)); + + this.lookControls = this.el.components['look-controls']; + + // listen to deviceorientation event + var eventName = this._getDeviceOrientationEventName(); + this._onDeviceOrientation = this._onDeviceOrientation.bind(this); + + // if Safari + if (!!navigator.userAgent.match(/Version\/[\d.]+.*Safari/)) { + // iOS 13+ + if (typeof DeviceOrientationEvent.requestPermission === 'function') { + var handler = function () { + console.log('Requesting device orientation permissions...') + DeviceOrientationEvent.requestPermission(); + document.removeEventListener('touchend', handler); + }; + + document.addEventListener('touchend', function () { handler() }, false); + + alert('After camera permission prompt, please tap the screen to activate geolocation.'); + } else { + var timeout = setTimeout(function () { + alert('Please enable device orientation in Settings > Safari > Motion & Orientation Access.') + }, 750); + window.addEventListener(eventName, function () { + clearTimeout(timeout); + }); + } + } + + window.addEventListener(eventName, this._onDeviceOrientation, false); + + this._watchPositionId = this._initWatchGPS(function (position) { + if (this.data.simulateLatitude !== 0 && this.data.simulateLongitude !== 0) { + localPosition = Object.assign({}, position.coords); + localPosition.longitude = this.data.simulateLongitude; + localPosition.latitude = this.data.simulateLatitude; + localPosition.altitude = this.data.simulateAltitude; + this.currentCoords = localPosition; + } + else { + this.currentCoords = position.coords; + } + + this._updatePosition(); + }.bind(this)); + }, + + tick: function () { + if (this.heading === null) { + return; + } + this._updateRotation(); + }, + + remove: function () { + if (this._watchPositionId) { + navigator.geolocation.clearWatch(this._watchPositionId); + } + this._watchPositionId = null; + + var eventName = this._getDeviceOrientationEventName(); + window.removeEventListener(eventName, this._onDeviceOrientation, false); + }, /** * Get device orientation event name, depends on browser implementation. * @returns {string} event name */ - _getDeviceOrientationEventName: function () { - if ('ondeviceorientationabsolute' in window) { - var eventName = 'deviceorientationabsolute' - } else if ('ondeviceorientation' in window) { - var eventName = 'deviceorientation' - } else { - var eventName = '' - console.error('Compass not supported') - } - - return eventName - }, + _getDeviceOrientationEventName: function () { + if ('ondeviceorientationabsolute' in window) { + var eventName = 'deviceorientationabsolute' + } else if ('ondeviceorientation' in window) { + var eventName = 'deviceorientation' + } else { + var eventName = '' + console.error('Compass not supported') + } + + return eventName + }, /** * Get current user position. @@ -154,99 +154,99 @@ AFRAME.registerComponent('gps-camera', { * @param {function} onError * @returns {Promise} */ - _initWatchGPS: function (onSuccess, onError) { - if (!onError) { - onError = function (err) { - console.warn('ERROR(' + err.code + '): ' + err.message) - - if (err.code === 1) { - // User denied GeoLocation, let their know that - alert('Please activate Geolocation and refresh the page. If it is already active, please check permissions for this website.'); - return; - } - - if (err.code === 3) { - alert('Cannot retrieve GPS position. Signal is absent.'); - return; - } - }; - } - - if ('geolocation' in navigator === false) { - onError({ code: 0, message: 'Geolocation is not supported by your browser' }); - return Promise.resolve(); - } - - // https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition - return navigator.geolocation.watchPosition(onSuccess, onError, { - enableHighAccuracy: true, - maximumAge: 0, - timeout: 27000, - }); - }, + _initWatchGPS: function (onSuccess, onError) { + if (!onError) { + onError = function (err) { + console.warn('ERROR(' + err.code + '): ' + err.message) + + if (err.code === 1) { + // User denied GeoLocation, let their know that + alert('Please activate Geolocation and refresh the page. If it is already active, please check permissions for this website.'); + return; + } + + if (err.code === 3) { + alert('Cannot retrieve GPS position. Signal is absent.'); + return; + } + }; + } + + if ('geolocation' in navigator === false) { + onError({ code: 0, message: 'Geolocation is not supported by your browser' }); + return Promise.resolve(); + } + + // https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition + return navigator.geolocation.watchPosition(onSuccess, onError, { + enableHighAccuracy: true, + maximumAge: 0, + timeout: 27000, + }); + }, /** * Update user position. * * @returns {void} */ - _updatePosition: function () { - // don't update if accuracy is not good enough - if (this.currentCoords.accuracy > this.data.positionMinAccuracy) { - if (this.data.alert && !document.getElementById('alert-popup')) { - var popup = document.createElement('div'); - popup.innerHTML = 'GPS signal is very poor. Try move outdoor or to an area with a better signal.' - popup.setAttribute('id', 'alert-popup'); - document.body.appendChild(popup); - } - return; - } - - var alertPopup = document.getElementById('alert-popup'); - if (this.currentCoords.accuracy <= this.data.positionMinAccuracy && alertPopup) { - document.body.removeChild(alertPopup); - } - - if (!this.originCoords) { - // first camera initialization - this.originCoords = this.currentCoords; - this._setPosition(); - - var loader = document.querySelector('.arjs-loader'); - if (loader) { - loader.remove(); - } - window.dispatchEvent(new CustomEvent('gps-camera-origin-coord-set')); - } else { - this._setPosition(); - } - }, - _setPosition: function () { - var position = this.el.getAttribute('position'); - - // compute position.x - var dstCoords = { - longitude: this.currentCoords.longitude, - latitude: this.originCoords.latitude, - }; - - position.x = this.computeDistanceMeters(this.originCoords, dstCoords); - position.x *= this.currentCoords.longitude > this.originCoords.longitude ? 1 : -1; - - // compute position.z - var dstCoords = { - longitude: this.originCoords.longitude, - latitude: this.currentCoords.latitude, - } - - position.z = this.computeDistanceMeters(this.originCoords, dstCoords); - position.z *= this.currentCoords.latitude > this.originCoords.latitude ? -1 : 1; - - // update position - this.el.setAttribute('position', position); - - window.dispatchEvent(new CustomEvent('gps-camera-update-position', { detail: { position: this.currentCoords, origin: this.originCoords } })); - }, + _updatePosition: function () { + // don't update if accuracy is not good enough + if (this.currentCoords.accuracy > this.data.positionMinAccuracy) { + if (this.data.alert && !document.getElementById('alert-popup')) { + var popup = document.createElement('div'); + popup.innerHTML = 'GPS signal is very poor. Try move outdoor or to an area with a better signal.' + popup.setAttribute('id', 'alert-popup'); + document.body.appendChild(popup); + } + return; + } + + var alertPopup = document.getElementById('alert-popup'); + if (this.currentCoords.accuracy <= this.data.positionMinAccuracy && alertPopup) { + document.body.removeChild(alertPopup); + } + + if (!this.originCoords) { + // first camera initialization + this.originCoords = this.currentCoords; + this._setPosition(); + + var loader = document.querySelector('.arjs-loader'); + if (loader) { + loader.remove(); + } + window.dispatchEvent(new CustomEvent('gps-camera-origin-coord-set')); + } else { + this._setPosition(); + } + }, + _setPosition: function () { + var position = this.el.getAttribute('position'); + + // compute position.x + var dstCoords = { + longitude: this.currentCoords.longitude, + latitude: this.originCoords.latitude, + }; + + position.x = this.computeDistanceMeters(this.originCoords, dstCoords); + position.x *= this.currentCoords.longitude > this.originCoords.longitude ? 1 : -1; + + // compute position.z + var dstCoords = { + longitude: this.originCoords.longitude, + latitude: this.currentCoords.latitude, + } + + position.z = this.computeDistanceMeters(this.originCoords, dstCoords); + position.z *= this.currentCoords.latitude > this.originCoords.latitude ? -1 : 1; + + // update position + this.el.setAttribute('position', position); + + window.dispatchEvent(new CustomEvent('gps-camera-update-position', { detail: { position: this.currentCoords, origin: this.originCoords } })); + }, /** * Returns distance in meters between source and destination inputs. * @@ -259,28 +259,28 @@ AFRAME.registerComponent('gps-camera', { * * @returns {number} distance | Number.MAX_SAFE_INTEGER */ - computeDistanceMeters: function (src, dest, isPlace) { - var dlongitude = THREE.Math.degToRad(dest.longitude - src.longitude); - var dlatitude = THREE.Math.degToRad(dest.latitude - src.latitude); + computeDistanceMeters: function (src, dest, isPlace) { + var dlongitude = THREE.Math.degToRad(dest.longitude - src.longitude); + var dlatitude = THREE.Math.degToRad(dest.latitude - src.latitude); - var a = (Math.sin(dlatitude / 2) * Math.sin(dlatitude / 2)) + Math.cos(THREE.Math.degToRad(src.latitude)) * Math.cos(THREE.Math.degToRad(dest.latitude)) * (Math.sin(dlongitude / 2) * Math.sin(dlongitude / 2)); - var angle = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - var distance = angle * 6378160; + var a = (Math.sin(dlatitude / 2) * Math.sin(dlatitude / 2)) + Math.cos(THREE.Math.degToRad(src.latitude)) * Math.cos(THREE.Math.degToRad(dest.latitude)) * (Math.sin(dlongitude / 2) * Math.sin(dlongitude / 2)); + var angle = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + var distance = angle * 6378160; - // if function has been called for a place, and if it's too near and a min distance has been set, - // return max distance possible - to be handled by the caller - if (isPlace && this.data.minDistance && this.data.minDistance > 0 && distance < this.data.minDistance) { - return Number.MAX_SAFE_INTEGER; - } + // if function has been called for a place, and if it's too near and a min distance has been set, + // return max distance possible - to be handled by the caller + if (isPlace && this.data.minDistance && this.data.minDistance > 0 && distance < this.data.minDistance) { + return Number.MAX_SAFE_INTEGER; + } - // if function has been called for a place, and if it's too far and a max distance has been set, - // return max distance possible - to be handled by the caller - if (isPlace && this.data.maxDistance && this.data.maxDistance > 0 && distance > this.data.maxDistance) { - return Number.MAX_SAFE_INTEGER; - } + // if function has been called for a place, and if it's too far and a max distance has been set, + // return max distance possible - to be handled by the caller + if (isPlace && this.data.maxDistance && this.data.maxDistance > 0 && distance > this.data.maxDistance) { + return Number.MAX_SAFE_INTEGER; + } - return distance; - }, + return distance; + }, /** * Compute compass heading. @@ -291,39 +291,39 @@ AFRAME.registerComponent('gps-camera', { * * @returns {number} compass heading */ - _computeCompassHeading: function (alpha, beta, gamma) { + _computeCompassHeading: function (alpha, beta, gamma) { - // Convert degrees to radians - var alphaRad = alpha * (Math.PI / 180); - var betaRad = beta * (Math.PI / 180); - var gammaRad = gamma * (Math.PI / 180); + // Convert degrees to radians + var alphaRad = alpha * (Math.PI / 180); + var betaRad = beta * (Math.PI / 180); + var gammaRad = gamma * (Math.PI / 180); - // Calculate equation components - var cA = Math.cos(alphaRad); - var sA = Math.sin(alphaRad); - var sB = Math.sin(betaRad); - var cG = Math.cos(gammaRad); - var sG = Math.sin(gammaRad); + // Calculate equation components + var cA = Math.cos(alphaRad); + var sA = Math.sin(alphaRad); + var sB = Math.sin(betaRad); + var cG = Math.cos(gammaRad); + var sG = Math.sin(gammaRad); - // Calculate A, B, C rotation components - var rA = - cA * sG - sA * sB * cG; - var rB = - sA * sG + cA * sB * cG; + // Calculate A, B, C rotation components + var rA = - cA * sG - sA * sB * cG; + var rB = - sA * sG + cA * sB * cG; - // Calculate compass heading - var compassHeading = Math.atan(rA / rB); + // Calculate compass heading + var compassHeading = Math.atan(rA / rB); - // Convert from half unit circle to whole unit circle - if (rB < 0) { - compassHeading += Math.PI; - } else if (rA < 0) { - compassHeading += 2 * Math.PI; - } + // Convert from half unit circle to whole unit circle + if (rB < 0) { + compassHeading += Math.PI; + } else if (rA < 0) { + compassHeading += 2 * Math.PI; + } - // Convert radians to degrees - compassHeading *= 180 / Math.PI; + // Convert radians to degrees + compassHeading *= 180 / Math.PI; - return compassHeading; - }, + return compassHeading; + }, /** * Handler for device orientation event. @@ -331,34 +331,34 @@ AFRAME.registerComponent('gps-camera', { * @param {Event} event * @returns {void} */ - _onDeviceOrientation: function (event) { - if (event.webkitCompassHeading !== undefined) { - if (event.webkitCompassAccuracy < 50) { - this.heading = event.webkitCompassHeading; - } else { - console.warn('webkitCompassAccuracy is event.webkitCompassAccuracy'); - } - } else if (event.alpha !== null) { - if (event.absolute === true || event.absolute === undefined) { - this.heading = this._computeCompassHeading(event.alpha, event.beta, event.gamma); - } else { - console.warn('event.absolute === false'); - } - } else { - console.warn('event.alpha === null'); - } - }, + _onDeviceOrientation: function (event) { + if (event.webkitCompassHeading !== undefined) { + if (event.webkitCompassAccuracy < 50) { + this.heading = event.webkitCompassHeading + window.orientation; + } else { + console.warn('webkitCompassAccuracy is event.webkitCompassAccuracy'); + } + } else if (event.alpha !== null) { + if (event.absolute === true || event.absolute === undefined) { + this.heading = this._computeCompassHeading(event.alpha, event.beta, event.gamma); + } else { + console.warn('event.absolute === false'); + } + } else { + console.warn('event.alpha === null'); + } + }, /** * Update user rotation data. * * @returns {void} */ - _updateRotation: function () { - var heading = 360 - this.heading; - var cameraRotation = this.el.getAttribute('rotation').y; - var yawRotation = THREE.Math.radToDeg(this.lookControls.yawObject.rotation.y); - var offset = (heading - (cameraRotation - yawRotation)) % 360; - this.lookControls.yawObject.rotation.y = THREE.Math.degToRad(offset); - }, + _updateRotation: function () { + var heading = 360 - this.heading; + var cameraRotation = this.el.getAttribute('rotation').y; + var yawRotation = THREE.Math.radToDeg(this.lookControls.yawObject.rotation.y); + var offset = (heading - (cameraRotation - yawRotation)) % 360; + this.lookControls.yawObject.rotation.y = THREE.Math.degToRad(offset); + }, }); From dab0992f29f326abf9a966328add8efe7bedbf46 Mon Sep 17 00:00:00 2001 From: tanabee8 Date: Thu, 3 Sep 2020 01:42:53 +0900 Subject: [PATCH 2/2] fix indentation --- aframe/src/location-based/gps-camera.js | 594 ++++++++++++------------ 1 file changed, 297 insertions(+), 297 deletions(-) diff --git a/aframe/src/location-based/gps-camera.js b/aframe/src/location-based/gps-camera.js index d86ffaa7..60e9f4a1 100644 --- a/aframe/src/location-based/gps-camera.js +++ b/aframe/src/location-based/gps-camera.js @@ -1,151 +1,151 @@ AFRAME.registerComponent('gps-camera', { - _watchPositionId: null, - originCoords: null, - currentCoords: null, - lookControls: null, - heading: null, - schema: { - simulateLatitude: { - type: 'number', - default: 0, - }, - simulateLongitude: { - type: 'number', - default: 0, - }, - simulateAltitude: { - type: 'number', - default: 0, - }, - positionMinAccuracy: { - type: 'int', - default: 100, - }, - alert: { - type: 'boolean', - default: false, - }, - minDistance: { - type: 'int', - default: 0, - }, - maxDistance: { - type: 'int', - default: 0, - } - }, - update: function () { - if (this.data.simulateLatitude !== 0 && this.data.simulateLongitude !== 0) { - localPosition = Object.assign({}, this.currentCoords || {}); - localPosition.longitude = this.data.simulateLongitude; - localPosition.latitude = this.data.simulateLatitude; - localPosition.altitude = this.data.simulateAltitude; - this.currentCoords = localPosition; - - // re-trigger initialization for new origin - this.originCoords = null; - this._updatePosition(); - } - }, - init: function () { - if (!this.el.components['look-controls']) { - return; - } - - this.loader = document.createElement('DIV'); - this.loader.classList.add('arjs-loader'); - document.body.appendChild(this.loader); - - window.addEventListener('gps-entity-place-added', function () { - // if places are added after camera initialization is finished - if (this.originCoords) { - window.dispatchEvent(new CustomEvent('gps-camera-origin-coord-set')); - } - if (this.loader && this.loader.parentElement) { - document.body.removeChild(this.loader) - } - }.bind(this)); - - this.lookControls = this.el.components['look-controls']; - - // listen to deviceorientation event - var eventName = this._getDeviceOrientationEventName(); - this._onDeviceOrientation = this._onDeviceOrientation.bind(this); - - // if Safari - if (!!navigator.userAgent.match(/Version\/[\d.]+.*Safari/)) { - // iOS 13+ - if (typeof DeviceOrientationEvent.requestPermission === 'function') { - var handler = function () { - console.log('Requesting device orientation permissions...') - DeviceOrientationEvent.requestPermission(); - document.removeEventListener('touchend', handler); - }; - - document.addEventListener('touchend', function () { handler() }, false); - - alert('After camera permission prompt, please tap the screen to activate geolocation.'); - } else { - var timeout = setTimeout(function () { - alert('Please enable device orientation in Settings > Safari > Motion & Orientation Access.') - }, 750); - window.addEventListener(eventName, function () { - clearTimeout(timeout); - }); - } - } - - window.addEventListener(eventName, this._onDeviceOrientation, false); - - this._watchPositionId = this._initWatchGPS(function (position) { - if (this.data.simulateLatitude !== 0 && this.data.simulateLongitude !== 0) { - localPosition = Object.assign({}, position.coords); - localPosition.longitude = this.data.simulateLongitude; - localPosition.latitude = this.data.simulateLatitude; - localPosition.altitude = this.data.simulateAltitude; - this.currentCoords = localPosition; - } - else { - this.currentCoords = position.coords; - } - - this._updatePosition(); - }.bind(this)); - }, - - tick: function () { - if (this.heading === null) { - return; - } - this._updateRotation(); - }, - - remove: function () { - if (this._watchPositionId) { - navigator.geolocation.clearWatch(this._watchPositionId); - } - this._watchPositionId = null; - - var eventName = this._getDeviceOrientationEventName(); - window.removeEventListener(eventName, this._onDeviceOrientation, false); - }, + _watchPositionId: null, + originCoords: null, + currentCoords: null, + lookControls: null, + heading: null, + schema: { + simulateLatitude: { + type: 'number', + default: 0, + }, + simulateLongitude: { + type: 'number', + default: 0, + }, + simulateAltitude: { + type: 'number', + default: 0, + }, + positionMinAccuracy: { + type: 'int', + default: 100, + }, + alert: { + type: 'boolean', + default: false, + }, + minDistance: { + type: 'int', + default: 0, + }, + maxDistance: { + type: 'int', + default: 0, + } + }, + update: function () { + if (this.data.simulateLatitude !== 0 && this.data.simulateLongitude !== 0) { + localPosition = Object.assign({}, this.currentCoords || {}); + localPosition.longitude = this.data.simulateLongitude; + localPosition.latitude = this.data.simulateLatitude; + localPosition.altitude = this.data.simulateAltitude; + this.currentCoords = localPosition; + + // re-trigger initialization for new origin + this.originCoords = null; + this._updatePosition(); + } + }, + init: function () { + if (!this.el.components['look-controls']) { + return; + } + + this.loader = document.createElement('DIV'); + this.loader.classList.add('arjs-loader'); + document.body.appendChild(this.loader); + + window.addEventListener('gps-entity-place-added', function () { + // if places are added after camera initialization is finished + if (this.originCoords) { + window.dispatchEvent(new CustomEvent('gps-camera-origin-coord-set')); + } + if (this.loader && this.loader.parentElement) { + document.body.removeChild(this.loader) + } + }.bind(this)); + + this.lookControls = this.el.components['look-controls']; + + // listen to deviceorientation event + var eventName = this._getDeviceOrientationEventName(); + this._onDeviceOrientation = this._onDeviceOrientation.bind(this); + + // if Safari + if (!!navigator.userAgent.match(/Version\/[\d.]+.*Safari/)) { + // iOS 13+ + if (typeof DeviceOrientationEvent.requestPermission === 'function') { + var handler = function () { + console.log('Requesting device orientation permissions...') + DeviceOrientationEvent.requestPermission(); + document.removeEventListener('touchend', handler); + }; + + document.addEventListener('touchend', function () { handler() }, false); + + alert('After camera permission prompt, please tap the screen to activate geolocation.'); + } else { + var timeout = setTimeout(function () { + alert('Please enable device orientation in Settings > Safari > Motion & Orientation Access.') + }, 750); + window.addEventListener(eventName, function () { + clearTimeout(timeout); + }); + } + } + + window.addEventListener(eventName, this._onDeviceOrientation, false); + + this._watchPositionId = this._initWatchGPS(function (position) { + if (this.data.simulateLatitude !== 0 && this.data.simulateLongitude !== 0) { + localPosition = Object.assign({}, position.coords); + localPosition.longitude = this.data.simulateLongitude; + localPosition.latitude = this.data.simulateLatitude; + localPosition.altitude = this.data.simulateAltitude; + this.currentCoords = localPosition; + } + else { + this.currentCoords = position.coords; + } + + this._updatePosition(); + }.bind(this)); + }, + + tick: function () { + if (this.heading === null) { + return; + } + this._updateRotation(); + }, + + remove: function () { + if (this._watchPositionId) { + navigator.geolocation.clearWatch(this._watchPositionId); + } + this._watchPositionId = null; + + var eventName = this._getDeviceOrientationEventName(); + window.removeEventListener(eventName, this._onDeviceOrientation, false); + }, /** * Get device orientation event name, depends on browser implementation. * @returns {string} event name */ - _getDeviceOrientationEventName: function () { - if ('ondeviceorientationabsolute' in window) { - var eventName = 'deviceorientationabsolute' - } else if ('ondeviceorientation' in window) { - var eventName = 'deviceorientation' - } else { - var eventName = '' - console.error('Compass not supported') - } - - return eventName - }, + _getDeviceOrientationEventName: function () { + if ('ondeviceorientationabsolute' in window) { + var eventName = 'deviceorientationabsolute' + } else if ('ondeviceorientation' in window) { + var eventName = 'deviceorientation' + } else { + var eventName = '' + console.error('Compass not supported') + } + + return eventName + }, /** * Get current user position. @@ -154,99 +154,99 @@ AFRAME.registerComponent('gps-camera', { * @param {function} onError * @returns {Promise} */ - _initWatchGPS: function (onSuccess, onError) { - if (!onError) { - onError = function (err) { - console.warn('ERROR(' + err.code + '): ' + err.message) - - if (err.code === 1) { - // User denied GeoLocation, let their know that - alert('Please activate Geolocation and refresh the page. If it is already active, please check permissions for this website.'); - return; - } - - if (err.code === 3) { - alert('Cannot retrieve GPS position. Signal is absent.'); - return; - } - }; - } - - if ('geolocation' in navigator === false) { - onError({ code: 0, message: 'Geolocation is not supported by your browser' }); - return Promise.resolve(); - } - - // https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition - return navigator.geolocation.watchPosition(onSuccess, onError, { - enableHighAccuracy: true, - maximumAge: 0, - timeout: 27000, - }); - }, + _initWatchGPS: function (onSuccess, onError) { + if (!onError) { + onError = function (err) { + console.warn('ERROR(' + err.code + '): ' + err.message) + + if (err.code === 1) { + // User denied GeoLocation, let their know that + alert('Please activate Geolocation and refresh the page. If it is already active, please check permissions for this website.'); + return; + } + + if (err.code === 3) { + alert('Cannot retrieve GPS position. Signal is absent.'); + return; + } + }; + } + + if ('geolocation' in navigator === false) { + onError({ code: 0, message: 'Geolocation is not supported by your browser' }); + return Promise.resolve(); + } + + // https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition + return navigator.geolocation.watchPosition(onSuccess, onError, { + enableHighAccuracy: true, + maximumAge: 0, + timeout: 27000, + }); + }, /** * Update user position. * * @returns {void} */ - _updatePosition: function () { - // don't update if accuracy is not good enough - if (this.currentCoords.accuracy > this.data.positionMinAccuracy) { - if (this.data.alert && !document.getElementById('alert-popup')) { - var popup = document.createElement('div'); - popup.innerHTML = 'GPS signal is very poor. Try move outdoor or to an area with a better signal.' - popup.setAttribute('id', 'alert-popup'); - document.body.appendChild(popup); - } - return; - } - - var alertPopup = document.getElementById('alert-popup'); - if (this.currentCoords.accuracy <= this.data.positionMinAccuracy && alertPopup) { - document.body.removeChild(alertPopup); - } - - if (!this.originCoords) { - // first camera initialization - this.originCoords = this.currentCoords; - this._setPosition(); - - var loader = document.querySelector('.arjs-loader'); - if (loader) { - loader.remove(); - } - window.dispatchEvent(new CustomEvent('gps-camera-origin-coord-set')); - } else { - this._setPosition(); - } - }, - _setPosition: function () { - var position = this.el.getAttribute('position'); - - // compute position.x - var dstCoords = { - longitude: this.currentCoords.longitude, - latitude: this.originCoords.latitude, - }; - - position.x = this.computeDistanceMeters(this.originCoords, dstCoords); - position.x *= this.currentCoords.longitude > this.originCoords.longitude ? 1 : -1; - - // compute position.z - var dstCoords = { - longitude: this.originCoords.longitude, - latitude: this.currentCoords.latitude, - } - - position.z = this.computeDistanceMeters(this.originCoords, dstCoords); - position.z *= this.currentCoords.latitude > this.originCoords.latitude ? -1 : 1; - - // update position - this.el.setAttribute('position', position); - - window.dispatchEvent(new CustomEvent('gps-camera-update-position', { detail: { position: this.currentCoords, origin: this.originCoords } })); - }, + _updatePosition: function () { + // don't update if accuracy is not good enough + if (this.currentCoords.accuracy > this.data.positionMinAccuracy) { + if (this.data.alert && !document.getElementById('alert-popup')) { + var popup = document.createElement('div'); + popup.innerHTML = 'GPS signal is very poor. Try move outdoor or to an area with a better signal.' + popup.setAttribute('id', 'alert-popup'); + document.body.appendChild(popup); + } + return; + } + + var alertPopup = document.getElementById('alert-popup'); + if (this.currentCoords.accuracy <= this.data.positionMinAccuracy && alertPopup) { + document.body.removeChild(alertPopup); + } + + if (!this.originCoords) { + // first camera initialization + this.originCoords = this.currentCoords; + this._setPosition(); + + var loader = document.querySelector('.arjs-loader'); + if (loader) { + loader.remove(); + } + window.dispatchEvent(new CustomEvent('gps-camera-origin-coord-set')); + } else { + this._setPosition(); + } + }, + _setPosition: function () { + var position = this.el.getAttribute('position'); + + // compute position.x + var dstCoords = { + longitude: this.currentCoords.longitude, + latitude: this.originCoords.latitude, + }; + + position.x = this.computeDistanceMeters(this.originCoords, dstCoords); + position.x *= this.currentCoords.longitude > this.originCoords.longitude ? 1 : -1; + + // compute position.z + var dstCoords = { + longitude: this.originCoords.longitude, + latitude: this.currentCoords.latitude, + } + + position.z = this.computeDistanceMeters(this.originCoords, dstCoords); + position.z *= this.currentCoords.latitude > this.originCoords.latitude ? -1 : 1; + + // update position + this.el.setAttribute('position', position); + + window.dispatchEvent(new CustomEvent('gps-camera-update-position', { detail: { position: this.currentCoords, origin: this.originCoords } })); + }, /** * Returns distance in meters between source and destination inputs. * @@ -259,28 +259,28 @@ AFRAME.registerComponent('gps-camera', { * * @returns {number} distance | Number.MAX_SAFE_INTEGER */ - computeDistanceMeters: function (src, dest, isPlace) { - var dlongitude = THREE.Math.degToRad(dest.longitude - src.longitude); - var dlatitude = THREE.Math.degToRad(dest.latitude - src.latitude); + computeDistanceMeters: function (src, dest, isPlace) { + var dlongitude = THREE.Math.degToRad(dest.longitude - src.longitude); + var dlatitude = THREE.Math.degToRad(dest.latitude - src.latitude); - var a = (Math.sin(dlatitude / 2) * Math.sin(dlatitude / 2)) + Math.cos(THREE.Math.degToRad(src.latitude)) * Math.cos(THREE.Math.degToRad(dest.latitude)) * (Math.sin(dlongitude / 2) * Math.sin(dlongitude / 2)); - var angle = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - var distance = angle * 6378160; + var a = (Math.sin(dlatitude / 2) * Math.sin(dlatitude / 2)) + Math.cos(THREE.Math.degToRad(src.latitude)) * Math.cos(THREE.Math.degToRad(dest.latitude)) * (Math.sin(dlongitude / 2) * Math.sin(dlongitude / 2)); + var angle = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + var distance = angle * 6378160; - // if function has been called for a place, and if it's too near and a min distance has been set, - // return max distance possible - to be handled by the caller - if (isPlace && this.data.minDistance && this.data.minDistance > 0 && distance < this.data.minDistance) { - return Number.MAX_SAFE_INTEGER; - } + // if function has been called for a place, and if it's too near and a min distance has been set, + // return max distance possible - to be handled by the caller + if (isPlace && this.data.minDistance && this.data.minDistance > 0 && distance < this.data.minDistance) { + return Number.MAX_SAFE_INTEGER; + } - // if function has been called for a place, and if it's too far and a max distance has been set, - // return max distance possible - to be handled by the caller - if (isPlace && this.data.maxDistance && this.data.maxDistance > 0 && distance > this.data.maxDistance) { - return Number.MAX_SAFE_INTEGER; - } + // if function has been called for a place, and if it's too far and a max distance has been set, + // return max distance possible - to be handled by the caller + if (isPlace && this.data.maxDistance && this.data.maxDistance > 0 && distance > this.data.maxDistance) { + return Number.MAX_SAFE_INTEGER; + } - return distance; - }, + return distance; + }, /** * Compute compass heading. @@ -291,39 +291,39 @@ AFRAME.registerComponent('gps-camera', { * * @returns {number} compass heading */ - _computeCompassHeading: function (alpha, beta, gamma) { + _computeCompassHeading: function (alpha, beta, gamma) { - // Convert degrees to radians - var alphaRad = alpha * (Math.PI / 180); - var betaRad = beta * (Math.PI / 180); - var gammaRad = gamma * (Math.PI / 180); + // Convert degrees to radians + var alphaRad = alpha * (Math.PI / 180); + var betaRad = beta * (Math.PI / 180); + var gammaRad = gamma * (Math.PI / 180); - // Calculate equation components - var cA = Math.cos(alphaRad); - var sA = Math.sin(alphaRad); - var sB = Math.sin(betaRad); - var cG = Math.cos(gammaRad); - var sG = Math.sin(gammaRad); + // Calculate equation components + var cA = Math.cos(alphaRad); + var sA = Math.sin(alphaRad); + var sB = Math.sin(betaRad); + var cG = Math.cos(gammaRad); + var sG = Math.sin(gammaRad); - // Calculate A, B, C rotation components - var rA = - cA * sG - sA * sB * cG; - var rB = - sA * sG + cA * sB * cG; + // Calculate A, B, C rotation components + var rA = - cA * sG - sA * sB * cG; + var rB = - sA * sG + cA * sB * cG; - // Calculate compass heading - var compassHeading = Math.atan(rA / rB); + // Calculate compass heading + var compassHeading = Math.atan(rA / rB); - // Convert from half unit circle to whole unit circle - if (rB < 0) { - compassHeading += Math.PI; - } else if (rA < 0) { - compassHeading += 2 * Math.PI; - } + // Convert from half unit circle to whole unit circle + if (rB < 0) { + compassHeading += Math.PI; + } else if (rA < 0) { + compassHeading += 2 * Math.PI; + } - // Convert radians to degrees - compassHeading *= 180 / Math.PI; + // Convert radians to degrees + compassHeading *= 180 / Math.PI; - return compassHeading; - }, + return compassHeading; + }, /** * Handler for device orientation event. @@ -331,34 +331,34 @@ AFRAME.registerComponent('gps-camera', { * @param {Event} event * @returns {void} */ - _onDeviceOrientation: function (event) { - if (event.webkitCompassHeading !== undefined) { - if (event.webkitCompassAccuracy < 50) { - this.heading = event.webkitCompassHeading + window.orientation; - } else { - console.warn('webkitCompassAccuracy is event.webkitCompassAccuracy'); - } - } else if (event.alpha !== null) { - if (event.absolute === true || event.absolute === undefined) { - this.heading = this._computeCompassHeading(event.alpha, event.beta, event.gamma); - } else { - console.warn('event.absolute === false'); - } - } else { - console.warn('event.alpha === null'); - } - }, + _onDeviceOrientation: function (event) { + if (event.webkitCompassHeading !== undefined) { + if (event.webkitCompassAccuracy < 50) { + this.heading = event.webkitCompassHeading + window.orientation; + } else { + console.warn('webkitCompassAccuracy is event.webkitCompassAccuracy'); + } + } else if (event.alpha !== null) { + if (event.absolute === true || event.absolute === undefined) { + this.heading = this._computeCompassHeading(event.alpha, event.beta, event.gamma); + } else { + console.warn('event.absolute === false'); + } + } else { + console.warn('event.alpha === null'); + } + }, /** * Update user rotation data. * * @returns {void} */ - _updateRotation: function () { - var heading = 360 - this.heading; - var cameraRotation = this.el.getAttribute('rotation').y; - var yawRotation = THREE.Math.radToDeg(this.lookControls.yawObject.rotation.y); - var offset = (heading - (cameraRotation - yawRotation)) % 360; - this.lookControls.yawObject.rotation.y = THREE.Math.degToRad(offset); - }, + _updateRotation: function () { + var heading = 360 - this.heading; + var cameraRotation = this.el.getAttribute('rotation').y; + var yawRotation = THREE.Math.radToDeg(this.lookControls.yawObject.rotation.y); + var offset = (heading - (cameraRotation - yawRotation)) % 360; + this.lookControls.yawObject.rotation.y = THREE.Math.degToRad(offset); + }, });