import Feature from 'ol/Feature' ; import Geolocation from 'ol/Geolocation' ; import Rotate from 'ol/control/Rotate' ; import VectorLayer from 'ol/layer/Vector' ; import { Circle , Fill , Stroke , Style } from 'ol/style' ; import { Circle as CircleGeom , Geometry , Point } from 'ol/geom' ; import { Injectable } from '@angular/core' ; import { Vector } from 'ol/source' ; import { toRadians } from 'ol/math' ; import { HsLayoutService } from '../layout/layout.service' ; import { HsLogService } from '../../common/log/log.service' ; import { HsMapService } from '../map/map.service' ; import { HsUtilsService } from './../utils/utils.service' ; import { setRemovable , setShowInLayerManager , setTitle , } from '../../common/layer-extensions' ; @ Injectable ( { providedIn : 'root' , } ) export class HsGeolocationService { public type { boolean } description localization = false ; public type { boolean } description following = false ; gn = null ; positionFeature : Feature < Point > ; public description centering : boolean ; accuracyFeature : Feature < CircleGeom > ; geolocation : any ; clicked : any ; cancelClick : boolean ; style : any ; position_layer : any ; constructor ( public HsMapService , public HsLayoutService , public hsLog , public HsUtilsService ) { this . accuracyFeature = new Feature ( { known : false , geometry : new CircleGeom ( [ 0 , 0 ] , 1 ) , } ) as Feature < CircleGeom > ; this . positionFeature = new Feature ( { known : false , geometry : new Point ( [ 0 , 0 ] ) , } ) as Feature < Point > ; this . style = new Style ( { image : new Circle ( { fill : new Fill ( { color : [ 242 , 121 , 0 , 0.7 ] , } ) , stroke : new Stroke ( { color : [ 0xbb , 0x33 , 0x33 , 0.7 ] , } ) , radius : 5 , } ) , fill : new Fill ( { color : [ 0xbb , 0xbb , 0xbb , 0.2 ] , } ) , stroke : new Stroke ( { color : [ 0x66 , 0x66 , 0x00 , 0.8 ] , } ) , } ) ; this . HsMapService . loaded ( ) . then ( ( map ) => this . init ( map ) ) ; } getRotate ( ) { for ( const control of this . HsMapService . map . getControls ( ) . getArray ( ) ) { if ( control instanceof Rotate ) { return control ; } } } public description stopTracking ( ) { this . following = false ; const rotate = this . getRotate ( ) ; rotate . element . classList . add ( 'hidden' ) ; this . HsMapService . map . on ( 'pointermove' , ( ) => { this . centering = false ; } ) ; this . geolocation . setTracking ( false ) ; if ( this . gn !== null ) { this . gn . stop ( ) ; } this . HsMapService . map . getView ( ) . setRotation ( 0 ) ; } public description toggleTracking ( ) { if ( this . clicked ) { this . cancelClick = true ; if ( this . HsLayoutService . sidebarBottom ( ) ) { this . HsLayoutService . contentWrapper . querySelector ( '.hs-locationButton' ) . dispatchEvent ( new Event ( 'dblclick' ) ) ; } return ; } this . clicked = true ; setTimeout ( ( ) => { if ( this . cancelClick ) { this . cancelClick = false ; this . clicked = false ; return ; } if ( this . isCentered ( ) ) { if ( ! this . following ) { this . geolocation . on ( 'change:position' , ( ) => this . setNewPosition ( ) ) ; this . geolocation . setTracking ( true ) ; this . following = true ; this . setRotation ( ) ; this . geolocation . on ( 'change:heading' , ( ) => this . newRotation ( ) ) ; this . centering = true ; this . HsMapService . map . on ( 'pointermove' , ( ) => { this . centering = false ; } ) ; const rotate = this . getRotate ( ) ; rotate . element . classList . remove ( 'hidden' ) ; this . HsLayoutService . contentWrapper . querySelector ( 'button.ol-rotate' ) . classList . add ( 'active' ) ; } else { this . HsLayoutService . contentWrapper . querySelector ( 'button.ol-rotate' ) . classList . remove ( 'active' ) ; this . stopTracking ( ) ; } } else { if ( this . geolocation . getPosition ( ) ) { this . HsMapService . map . getView ( ) . setCenter ( this . geolocation . getPosition ( ) ) ; this . centering = true ; } } this . cancelClick = false ; this . clicked = false ; } , 500 ) ; } public description stopLocalization ( ) { this . localization = false ; this . HsMapService . map . removeLayer ( this . position_layer ) ; this . stopTracking ( ) ; } public description startLocalization ( ) { if ( ! this . localization ) { this . geolocation . setTracking ( true ) ; this . localization = true ; this . geolocation . once ( 'change:position' , ( ) => { this . setNewPosition ( ) ; this . HsMapService . map . getView ( ) . setCenter ( this . geolocation . getPosition ( ) ) ; this . HsMapService . map . addLayer ( this . position_layer ) ; this . position_layer . setZIndex ( 99 ) ; this . geolocation . setTracking ( false ) ; } ) ; } } public description isCentered ( ) { return ( JSON . stringify ( this . HsMapService . map . getView ( ) . getCenter ( ) ) === JSON . stringify ( this . positionFeature . getGeometry ( ) . getCoordinates ( ) ) ) ; } public description setNewPosition ( ) { const position = this . geolocation . getPosition ( ) ; this . positionFeature . getGeometry ( ) . setCoordinates ( position ) ; this . accuracyFeature . getGeometry ( ) . setCenterAndRadius ( position , this . geolocation . getAccuracy ( ) ) ; if ( this . centering ) { this . HsMapService . map . getView ( ) . setCenter ( position ) ; } } public description param e newRotation ( ) { this . HsUtilsService . debounce ( ( ) => { const heading = this . geolocation . getHeading ( ) ? this . geolocation . getHeading ( ) : null ; if ( heading ) { this . HsMapService . map . getView ( ) . setRotation ( heading ) ; } } , 150 , false , this ) ; } setRotation ( ) { this . hsLog . error ( 'Device rotation tracking currently not implemented' ) ; } param map public description init ( map ) { this . geolocation = new Geolocation ( { projection : this . HsMapService . getCurrentProj ( ) , trackingOptions : { enableHighAccuracy : true , } , } ) ; this . accuracyFeature . setStyle ( this . style ) ; this . positionFeature . setStyle ( this . style ) ; this . position_layer = new VectorLayer ( { source : new Vector ( ) , } ) ; setTitle ( this . position_layer , 'Position' ) ; setShowInLayerManager ( this . position_layer , false ) ; setRemovable ( this . position_layer , false ) ; const src = this . position_layer . getSource ( ) ; src . addFeature ( this . accuracyFeature ) ; src . addFeature ( this . positionFeature ) ; const reset = function ( ) { if ( this . gn !== undefined ) { if ( this . gn . isRunning ( ) && this . gn !== null ) { this . gn . stop ( ) ; map . getView ( ) . setRotation ( 0 ) ; this . HsLayoutService . contentWrapper . querySelector ( 'button.ol-rotate' ) . classList . remove ( 'active' ) ; } else { this . setRotation ( ) ; this . HsLayoutService . contentWrapper . querySelector ( 'button.ol-rotate' ) . classList . add ( 'active' ) ; } } } ; map . addControl ( new Rotate ( { resetNorth : reset , className : 'ol-rotate hidden' , autoHide : false , } ) ) ; } }