UNPKG

terriajs

Version:

Geospatial data visualization platform.

175 lines (151 loc) 6.32 kB
'use strict'; import React from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; import URI from 'urijs'; import Rectangle from 'terriajs-cesium/Source/Core/Rectangle'; import GeoJsonCatalogItem from '../../../Models/GeoJsonCatalogItem'; import ObserveModelMixin from '../../ObserveModelMixin'; import Styles from './tool_button.scss'; import TerriaError from '../../../Core/TerriaError'; import CesiumCartographic from 'terriajs-cesium/Source/Core/Cartographic.js'; import Icon from "../../Icon.jsx"; import defined from 'terriajs-cesium/Source/Core/defined'; const MyLocation = createReactClass({ displayName: 'MyLocation', mixins: [ObserveModelMixin], propTypes: { terria: PropTypes.object.isRequired }, _marker: undefined, /* eslint-disable-next-line camelcase */ UNSAFE_componentWillMount() { this._marker = new GeoJsonCatalogItem(this.props.terria); }, getInitialState() { return {}; }, getLocation() { if (navigator.geolocation) { const options = { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }; if (!this.augmentedVirtualityEnabled()) { // When Augmented Virtuality is not enabled then just get a single position update. navigator.geolocation.getCurrentPosition( this.zoomToMyLocation, this.handleLocationError, options ); } else { // When Augmented Virtuality is enabled then we effectively toggle into watch mode and the position is repeatedly updated. const watchId = navigator.geolocation.watchPosition( this.zoomToMyLocation, this.handleLocationError, options ); this.setState({watchId: watchId}); } } else { this.props.terria.error.raiseEvent(new TerriaError({ sender: this, title: 'Error getting location', message: 'Your browser cannot provide your location.' })); } }, zoomToMyLocation(position) { const longitude = position.coords.longitude; const latitude = position.coords.latitude; if (this.augmentedVirtualityEnabled()) { // Note: Specifiying the value of 27500m here enables this function to approximately mimic the behaviour of // the else case from the cameras inital view and when the viewer pan/zooms out to much. // We use the flag variable flown so that the user is flown to the current location when this function is // first fired, but subsuquently the updates are jump location moves, since we assume that the movements are // small and flyTo performs badly when the increments are small (slow and unresponsive). this.props.terria.augmentedVirtuality.moveTo(CesiumCartographic.fromDegrees(longitude, latitude), 27500, !defined(this.state.flown)); this.setState({flown: true}); } else { // west, south, east, north, result const rectangle = Rectangle.fromDegrees(longitude - 0.1, latitude - 0.1, longitude + 0.1, latitude + 0.1); this.props.terria.currentViewer.zoomTo(rectangle); } this._marker.name = 'My Location'; this._marker.data = { type: 'Feature', geometry: { type: 'Point', coordinates: [longitude, latitude] }, properties: { title: 'Location', longitude: longitude, latitude: latitude } }; this._marker.style = { 'marker-size': 25, 'marker-color': '#08ABD5', 'stroke': '#ffffff', 'stroke-width': 3 }; this._marker.load(); if (this._marker.isEnabled !== true) { this._marker.isEnabled = true; } }, handleLocationError(err) { let message = err.message; if (message && message.indexOf('Only secure origins are allowed') === 0) { // This is actually the recommended way to check for this error. // https://developers.google.com/web/updates/2016/04/geolocation-on-secure-contexts-only const uri = new URI(window.location); const secureUrl = uri.protocol('https').toString(); message = 'Your browser can only provide your location when using https. You may be able to use ' + secureUrl + ' instead.'; } this.props.terria.error.raiseEvent(new TerriaError({ sender: this, title: 'Error getting location', message: message })); }, augmentedVirtualityEnabled() { return defined(this.props.terria.augmentedVirtuality) && this.props.terria.augmentedVirtuality.enabled; }, followMeEnabled() { if (defined(this.state.watchId)) { return true; } return false; }, disableFollowMe() { if (defined(this.state.watchId)) { navigator.geolocation.clearWatch(this.state.watchId); this.setState({watchId: undefined}); this.setState({flown: undefined}); } }, handleCick() { if (this.followMeEnabled()) { this.disableFollowMe(); } else { this.getLocation(); } }, render() { let toggleStyle = Styles.btn; if (this.followMeEnabled()) { toggleStyle = Styles.btnPrimary; } return <div className={Styles.toolButton}> <button type='button' className={toggleStyle} title='go to my location' onClick={this.handleCick}> <Icon glyph={Icon.GLYPHS.geolocation}/> </button> </div>; }, }); export default MyLocation;