import { HttpClient } from '@angular/common/http' ; import { Injectable } from '@angular/core' ; import * as xml2Json from 'xml-js' ; import VectorLayer from 'ol/layer/Vector' ; import { get , transformExtent } from 'ol/proj' ; import WfsSource from '../../../../common/layers/hs.source.WfsSource' ; import { CapabilitiesResponseWrapper } from '../../../../common/get-capabilities/capabilities-response-wrapper' ; import { HsAddDataCommonService } from '../../common/common.service' ; import { HsEventBusService } from '../../../core/event-bus.service' ; import { HsLayoutService } from '../../../layout/layout.service' ; import { HsMapService } from '../../../map/map.service' ; import { HsUrlTypeServiceModel } from '../models/url-type-service.model' ; import { HsUtilsService } from '../../../utils/utils.service' ; import { HsWfsGetCapabilitiesService } from '../../../../common/get-capabilities/wfs-get-capabilities.service' ; import { Layer } from 'ol/layer' ; import { Source } from 'ol/source' ; import { addLayerOptions } from '../types/layer-options.type' ; import { addLayersRecursivelyOptions } from '../types/recursive-options.type' ; import { urlDataObject } from '../types/data-object.type' ; @ Injectable ( { providedIn : 'root' , } ) export class HsUrlWfsService implements HsUrlTypeServiceModel { data : urlDataObject ; definedProjections : string [ ] ; loadingFeatures : boolean ; constructor ( private http , public hsUtilsService , public hsWfsGetCapabilitiesService , public hsMapService , public hsEventBusService , public hsLayoutService , public hsAddDataCommonService ) { this . setDataToDefault ( ) ; this . definedProjections = [ 'EPSG:3857' , 'EPSG:5514' , 'EPSG:4258' , 'EPSG:4326' , ] ; this . hsEventBusService . olMapLoads . subscribe ( ( ) => { this . data . map_projection = this . hsMapService . map . getView ( ) . getProjection ( ) . getCode ( ) . toUpperCase ( ) ; } ) ; } setDataToDefault ( ) { this . data = { add_all : null , bbox : null , folder_name : 'WFS' , layers : [ ] , map_projection : undefined , output_format : '' , output_formats : null , services : [ ] , srs : null , srss : [ ] , title : '' , version : '' , } ; } async addLayerFromCapabilities ( wrapper , style ? ) { if ( ! wrapper . response && ! wrapper . error ) { return ; } if ( wrapper . error ) { this . hsAddDataCommonService . throwParsingError ( wrapper . response . message ) ; return ; } try { const bbox = await this . parseCapabilities ( wrapper . response ) ; if ( this . hsAddDataCommonService . layerToSelect ) { this . hsAddDataCommonService . checkTheSelectedLayer ( this . data . services ) ; const collection = this . addLayers ( true , style ) ; this . zoomToBBox ( bbox ) ; return collection ; } } catch ( e ) { this . hsAddDataCommonService . throwParsingError ( e ) ; } } param response returns async parseCapabilities ( response ) { try { this . loadingFeatures = false ; let caps = xml2Json . xml2js ( response , { compact : true } ) ; if ( caps [ 'wfs:WFS_Capabilities' ] ) { caps = caps [ 'wfs:WFS_Capabilities' ] ; } else { caps = caps [ 'WFS_Capabilities' ] ; } this . parseWFSJson ( caps ) ; this . data . title = caps . ServiceIdentification . Title || 'Wfs layer' ; this . data . version = caps . ServiceIdentification . ServiceTypeVersion ; const layer = Array . isArray ( caps . FeatureTypeList . FeatureType ) ? caps . FeatureTypeList . FeatureType . find ( ( layer ) => layer . Name == this . hsAddDataCommonService . layerToSelect ) : caps . FeatureTypeList . FeatureType ; this . data . layers = Array . isArray ( caps . FeatureTypeList . FeatureType ) ? caps . FeatureTypeList . FeatureType : [ caps . FeatureTypeList . FeatureType ] ; if ( layer ) { this . data . bbox = layer . WGS84BoundingBox || layer . OutputFormats . WGS84BoundingBox ; const srsType = layer && layer . DefaultSRS ? 'SRS' : 'CRS' ; if ( layer [ 'Default' + srsType ] !== undefined ) { this . data . srss = [ layer [ 'Default' + srsType ] ] ; } else { this . data . srss = [ ] ; this . data . srss . push ( 'EPSG:4326' ) ; } const otherSRS = layer [ 'Other' + srsType ] ; if ( otherSRS ) { if ( typeof otherSRS == 'string' ) { this . data . srss . push ( otherSRS ) ; } else { for ( const srs of layer [ 'Other' + srsType ] ) { this . data . srss . push ( srs ) ; } } } if ( this . data . srss [ 0 ] === undefined ) { this . data . srss = [ caps . FeatureTypeList . FeatureType [ 0 ] [ 'Default' + srsType ] , ] ; for ( const srs of caps . FeatureTypeList . FeatureType [ 0 ] [ 'Other' + srsType ] ) { this . data . srss . push ( srs ) ; } } } this . data . output_format = this . getPreferredFormat ( this . data . version ) ; this . data . services = caps . FeatureTypeList . FeatureType [ 0 ] ? caps . FeatureTypeList . FeatureType : [ caps . FeatureTypeList . FeatureType ] ; this . data . srss = this . parseEPSG ( this . data . srss ) ; if ( this . data . srss . length == 0 ) { this . data . srss = [ 'EPSG:3857' ] ; } this . data . srs = ( ( ) => { for ( const srs of this . data . srss ) { if ( srs . includes ( '3857' ) ) { return srs ; } } return this . data . srss [ 0 ] ; } ) ( ) ; if ( ! this . hsAddDataCommonService . layerToSelect ) { setTimeout ( ( ) => { try { this . parseFeatureCount ( ) ; } catch ( e ) { throw new Error ( e ) ; } } ) ; } this . hsAddDataCommonService . loadingInfo = false ; return this . data . bbox ; } catch ( e ) { throw new Error ( e ) ; } } getPreferredFormat ( version ) { switch ( version ) { case '1.0.0' : return 'GML2' ; case '1.1.0' : return 'GML3' ; case '2.0.0' : return 'GML32' ; default : return 'GML3' ; } } parseFeatureCount ( ) { for ( const service of this . data . services ) { const url = [ this . hsWfsGetCapabilitiesService . service_url . split ( '?' ) [ 0 ] , this . hsUtilsService . paramsToURLWoEncode ( { service : 'wfs' , version : this . data . version , request : 'GetFeature' , typeName : service . Name , resultType : 'hits' , } ) , ] . join ( '?' ) ; this . http . get ( this . hsUtilsService . proxify ( url ) , { responseType : 'text' } ) . subscribe ( ( response ) => { const oParser = new DOMParser ( ) ; const oDOM = oParser . parseFromString ( response , 'application/xml' ) ; const doc = oDOM . documentElement ; service . featureCount = doc . getAttribute ( 'numberOfFeatures' ) ; if ( service . featureCount == 0 || ! service . featureCount ) { service . featureCount = doc . getAttribute ( 'numberMatched' ) ; } service . featureCount > 1000 ? ( service . limitFeatureCount = true ) : ( service . limitFeatureCount = false ) ; } , ( e ) => { this . hsAddDataCommonService . throwParsingError ( e ) ; } ) ; } } parseWFSJson ( json ) { try { for ( const key of Object . keys ( json ) ) { if ( key . includes ( ':' ) ) { json [ key . substring ( 4 ) ] = json [ key ] ; if ( typeof json [ key . substring ( 4 ) ] == 'object' ) { this . parseWFSJson ( json [ key ] ) ; } if ( json [ key . substring ( 4 ) ] && json [ key . substring ( 4 ) ] [ '_text' ] ) { json [ key . substring ( 4 ) ] = json [ key . substring ( 4 ) ] [ '_text' ] ; } delete json [ key ] ; } if ( typeof json [ key ] == 'object' ) { this . parseWFSJson ( json [ key ] ) ; if ( json [ key ] && json [ key ] [ '_text' ] ) { json [ key ] = json [ key ] [ '_text' ] ; } } } } catch ( e ) { throw new Error ( e ) ; } } parseEPSG ( srss ) { srss . forEach ( ( srs , index ) => { const epsgCode = srs . slice ( - 4 ) ; srss [ index ] = 'EPSG:' + epsgCode ; if ( ! get ( srss [ index ] ) ) { srss . splice ( srss . indexOf ( index ) , 1 ) ; } } ) ; return [ ... Array . from ( new Set ( srss ) ) ] . filter ( ( srs ) => this . definedProjections . includes ( srs ) ) ; } param checkedOnly addLayers ( checkedOnly , style ? ) { this . data . add_all = checkedOnly ; const collection = [ ] ; for ( const layer of this . data . services ) { this . addLayersRecursively ( layer , { style } , collection ) ; } this . hsAddDataCommonService . clearParams ( ) ; this . setDataToDefault ( ) ; this . hsAddDataCommonService . setPanelToCatalogue ( ) ; return collection ; } addLayersRecursively ( layer , options , collection ) { if ( ! this . data . add_all || layer . checked ) { const newLayer = this . addLayer ( layer , { layerName : layer . Name , folder : this . hsUtilsService . undefineEmptyString ( this . data . folder_name ) , crs : this . data . srs , sld : options . style ?. includes ( 'StyledLayerDescriptor' ) ? options . style : undefined , qml : options . style ?. includes ( 'qgis' ) ? options . style : undefined , } ) ; collection . push ( newLayer ) ; } if ( layer . Layer ) { for ( const sublayer of layer . Layer ) { this . addLayersRecursively ( sublayer , { style : options . style } , collection ) ; } } } param layer param layerName param folder param srs addLayer ( layer , options ) { const new_layer = new VectorLayer ( { properties : { name : options . layerName , title : layer . Title . replace ( /\//g , '&#47;' ) , path : options . folder , removable : true , sld : options . sld , qml : options . qml , wfsUrl : this . hsWfsGetCapabilitiesService . service_url . split ( '?' ) [ 0 ] , } , source : new WfsSource ( this . hsUtilsService , this . http , { data_version : this . data . version , output_format : this . data . output_format , crs : options . crs , provided_url : this . hsWfsGetCapabilitiesService . service_url . split ( '?' ) [ 0 ] , layer_name : options . layerName , map_projection : this . hsMapService . map . getView ( ) . getProjection ( ) , } ) , renderOrder : null , } ) ; this . hsMapService . map . addLayer ( new_layer ) ; this . hsLayoutService . setMainPanel ( 'layermanager' ) ; return new_layer ; } private zoomToBBox ( bbox ) { if ( ! bbox ) { return ; } if ( bbox . LowerCorner ) { bbox = [ bbox . LowerCorner . split ( ' ' ) [ 0 ] , bbox . LowerCorner . split ( ' ' ) [ 1 ] , bbox . UpperCorner . split ( ' ' ) [ 0 ] , bbox . UpperCorner . split ( ' ' ) [ 1 ] , ] ; } if ( ! this . data . map_projection ) { this . data . map_projection = this . hsMapService . map . getView ( ) . getProjection ( ) . getCode ( ) . toUpperCase ( ) ; } const extent = transformExtent ( bbox , 'EPSG:4326' , this . data . map_projection ) ; if ( extent ) { this . hsMapService . fitExtent ( extent ) ; } } }