import { Injectable } from '@angular/core' ; import { GPX , GeoJSON , KML } from 'ol/format' ; import { Geometry } from 'ol/geom' ; import { Layer , Vector as VectorLayer } from 'ol/layer' ; import { Source , Vector as VectorSource } from 'ol/source' ; import { PROJECTIONS as epsg4326Aliases } from 'ol/proj/epsg4326' ; import { get as getProjection } from 'ol/proj' ; import { HsAddDataService } from '../add-data.service' ; import { HsCommonEndpointsService } from '../../../common/endpoints/endpoints.service' ; import { HsMapService } from '../../map/map.service' ; import { HsStylerService } from '../../styles/styler.service' ; import { HsUtilsService } from '../../utils/utils.service' ; import { HsVectorLayerOptions } from './vector-layer-options.type' ; import { VectorLayerDescriptor } from './vector-descriptors/vector-layer-descriptor' ; import { VectorSourceDescriptor } from './vector-descriptors/vector-source-descriptor' ; import { getHsLaymanSynchronizing , setDefinition , } from '../../../common/layer-extensions' ; @ Injectable ( { providedIn : 'root' , } ) export class HsAddDataVectorService { readUploadedFileAsText = ( inputFile ) => { const temporaryFileReader = new FileReader ( ) ; return new Promise ( ( resolve , reject ) => { temporaryFileReader . onerror = ( ) => { temporaryFileReader . abort ( ) ; reject ( new DOMException ( 'Problem parsing input file.' ) ) ; } ; temporaryFileReader . onload = ( ) => { resolve ( temporaryFileReader . result ) ; } ; temporaryFileReader . readAsText ( inputFile ) ; } ) ; } ; readUploadedFileAsURL = ( inputFile ) => { const temporaryFileReader = new FileReader ( ) ; return new Promise ( ( resolve , reject ) => { temporaryFileReader . onerror = ( ) => { temporaryFileReader . abort ( ) ; reject ( new DOMException ( 'Problem parsing input file.' ) ) ; } ; temporaryFileReader . onload = ( ) => { resolve ( temporaryFileReader . result ) ; } ; temporaryFileReader . readAsDataURL ( inputFile ) ; } ) ; } ; constructor ( public hsMapService , public hsUtilsService , public hsStylerService , public hsAddDataService , public hsCommonEndpointsService ) { } param type param url param name param title param abstract param addUnder param srs param options returns addVectorLayer ( type , url , name , title , abstract , srs , options , addUnder ? ) { return new Promise ( async ( resolve , reject ) => { try { const lyr = await this . createVectorLayer ( type , url , name , title , abstract , srs , options ) ; if ( this . hsUtilsService . undefineEmptyString ( url ) !== undefined ) { setDefinition ( lyr , { format : 'hs.format.WFS' , url : url , } ) ; } else { setDefinition ( lyr , { format : 'hs.format.WFS' , } ) ; } if ( this . hsMapService . map ) { this . hsAddDataService . addLayer ( lyr , addUnder ) ; } resolve ( lyr ) ; } catch ( ex ) { reject ( ex ) ; } } ) ; } param type param url param name param title param abstract param srs param options returns async createVectorLayer ( type , url , name , title , abstract , srs , options = { } ) { if ( type ?. toLowerCase ( ) != 'sparql' && type ?. toLowerCase ( ) != 'wfs' && url !== undefined ) { url = this . hsUtilsService . proxify ( url ) ; } if ( this . hsUtilsService . undefineEmptyString ( type ) === undefined ) { type = this . tryGuessTypeFromNameOrUrl ( url ) ; } let mapProjection ; if ( this . hsMapService . map ) { mapProjection = this . hsMapService . map . getView ( ) . getProjection ( ) . getCode ( ) ; } const descriptor = new VectorLayerDescriptor ( type , name , title , abstract , url , options , mapProjection ) ; const sourceDescriptor = new VectorSourceDescriptor ( type , url , srs , options , mapProjection ) ; const src = sourceDescriptor . sourceClass == VectorSource ? new sourceDescriptor . sourceClass ( sourceDescriptor . sourceParams ) : new sourceDescriptor . sourceClass ( sourceDescriptor ) ; descriptor . layerParams . source = src ; if ( descriptor . layerParams . style ) { Object . assign ( descriptor . layerParams , await this . hsStylerService . parseStyle ( descriptor . layerParams . style ) ) ; } const lyr = new VectorLayer ( descriptor . layerParams ) ; return lyr ; } fitExtent ( lyr ) { const src = lyr . getSource ( ) ; if ( src . getFeatures ( ) . length > 0 ) { this . tryFit ( src . getExtent ( ) , src ) ; } else { src . on ( 'change' , this . changeListener ( src ) ) ; } } setPanelToCatalogue ( ) { this . hsAddDataService . dsSelected = 'catalogue' ; } changeListener ( src ) { if ( src . getState ( ) == 'ready' ) { setTimeout ( ( ) => { if ( src . getFeatures ( ) . length == 0 ) { return ; } const extent = src . getExtent ( ) ; this . tryFit ( extent , src ) ; } , 1000 ) ; } } async awaitLayerSync ( layer ) { while ( getHsLaymanSynchronizing ( layer ) ) { await new Promise ( ( r ) => setTimeout ( r , 200 ) ) ; } return true ; } async addNewLayer ( data ) { const layer = await this . addVectorLayer ( data . features . length != 0 ? data . type : data . dataType , data . url || data . base64url , data . name , data . title , data . abstract , data . srs , { extractStyles : data . extract_styles , features : data . features , path : this . hsUtilsService . undefineEmptyString ( data . folder_name ) , access_rights : data . access_rights , workspace : this . hsCommonEndpointsService . endpoints . filter ( ( ep ) => ep . type == 'layman' ) [ 0 ] ?. user , queryCapabilities : data . dataType != 'kml' && data . dataType != 'gpx' && ! data . url ?. endsWith ( 'json' ) , } , data . addUnder ) ; this . fitExtent ( layer ) ; if ( data . saveToLayman ) { this . awaitLayerSync ( layer ) . then ( ( ) => { layer . getSource ( ) . dispatchEvent ( 'addfeature' ) ; } ) ; } return layer ; } isKml ( dataType , url ) { if ( dataType == 'kml' || url ?. endsWith ( 'kml' ) ) { return true ; } else { return false ; } } param extent param src tryFit ( extent , src ) { if ( ! isNaN ( extent [ 0 ] ) && ! isNaN ( extent [ 1 ] ) && ! isNaN ( extent [ 2 ] ) && ! isNaN ( extent [ 3 ] ) && this . hsMapService . map ) { this . hsMapService . fitExtent ( extent ) ; src . un ( 'change' , this . changeListener ) ; } } param name tryGuessTypeFromNameOrUrl ( url ) { if ( url !== undefined ) { if ( url . toLowerCase ( ) . endsWith ( 'kml' ) ) { return 'kml' ; } if ( url . toLowerCase ( ) . endsWith ( 'gpx' ) ) { return 'gpx' ; } if ( url . toLowerCase ( ) . endsWith ( 'geojson' ) || url . toLowerCase ( ) . endsWith ( 'json' ) ) { return 'geojson' ; } } } async createVectorObjectFromXml ( file , type ) { try { const uploadedContent = await this . readUploadedFileAsURL ( file ) ; const dataUrl = uploadedContent . toString ( ) ; const object = { url : dataUrl , name : file . name , title : file . name , type : type , } ; return object ; } catch ( e ) { console . log ( 'Uploaded file is not supported!' ) ; } } async readUploadedFile ( file ) { let uploadedData = { } ; const fileType = this . tryGuessTypeFromNameOrUrl ( file . name . toLowerCase ( ) ) ; switch ( fileType ) { case 'kml' : uploadedData = await this . createVectorObjectFromXml ( file , fileType ) ; break ; case 'gpx' : uploadedData = await this . convertUploadedData ( file ) ; break ; default : try { const fileContents = await this . readUploadedFileAsText ( file ) ; const fileToJSON = JSON . parse ( < string > fileContents ) ; if ( fileToJSON !== undefined ) { fileToJSON . name = file . name . split ( '.' ) [ 0 ] ; uploadedData = this . createVectorObjectFromJson ( fileToJSON ) ; return uploadedData ; } } catch ( e ) { console . log ( 'Uploaded file is not supported!' , e ) ; } } return uploadedData ; } param json createVectorObjectFromJson ( json ) { let features = [ ] ; const format = new GeoJSON ( ) ; const projection = format . readProjection ( json ) ; if ( json . features ?. length > 0 ) { features = format . readFeatures ( json ) ; this . transformFeaturesIfNeeded ( features , projection ) ; } const object = { name : json . name , title : json . name , srs : projection , features , } ; return object ; } transformFeaturesIfNeeded ( features , projection ) { const mapProjection = this . hsMapService . map . getView ( ) . getProjection ( ) ; if ( projection != mapProjection ) { projection = epsg4326Aliases . map ( ( proj ) => proj . getCode ( ) ) . some ( ( code ) => code === projection . getCode ( ) ) ? getProjection ( 'EPSG:4326' ) : projection ; features . forEach ( ( f ) => f . getGeometry ( ) . transform ( projection , mapProjection ) ) ; } } param file async convertUploadedData ( file ) { let parser ; const uploadedData = { } ; try { const uploadedContent = await this . readUploadedFileAsText ( file ) ; let fileType = this . tryGuessTypeFromNameOrUrl ( file . name . toLowerCase ( ) ) ; switch ( fileType ) { case 'kml' : parser = new KML ( ) ; uploadedData . features = parser . readFeatures ( uploadedContent ) ; break ; case 'gpx' : parser = new GPX ( ) ; uploadedData . features = parser . readFeatures ( uploadedContent ) ; fileType = 'json' ; break ; default : } if ( uploadedData ?. features ?. length > 0 ) { this . transformFeaturesIfNeeded ( uploadedData . features , parser . readProjection ( uploadedContent ) ) ; } uploadedData . title = file . name . split ( '.' ) [ 0 ] . trim ( ) ; uploadedData . name = uploadedData . title ; uploadedData . type = fileType ; return uploadedData ; } catch ( e ) { console . error ( 'Uploaded file is not supported' + e ) ; } } }