import { Component , OnDestroy } from '@angular/core' ; import * as polygonClipping from 'polygon-clipping' ; import Feature from 'ol/Feature' ; import Polygon from 'ol/geom/Polygon' ; import VectorLayer from 'ol/layer/Vector' ; import polygonSplitter from 'polygon-splitter' ; import { Vector } from 'ol/source' ; import { HsDrawService } from '../draw.service' ; import { HsEventBusService } from '../../core/event-bus.service' ; import { HsLanguageService } from '../../language/language.service' ; import { HsMapService } from '../../map/map.service' ; import { HsQueryBaseService } from './../../query/query-base.service' ; import { HsQueryVectorService } from './../../query/query-vector.service' ; import { HsToastService } from '../../layout/toast/toast.service' ; import { defaultStyle } from '../../styles/styles' ; @ Component ( { selector : 'hs-draw-edit' , templateUrl : './draw-edit.component.html' , styleUrls : [ './draw-edit.component.scss' ] , } ) export class DrawEditComponent implements OnDestroy { vectorQueryFeatureSubscription ; editOptions = [ 'difference' , 'union' , 'intersection' , 'split' ] ; selectedType : 'difference' | 'union' | 'intersection' | 'split' ; selectedFeature ; editLayer = new VectorLayer ( { properties : { title : 'Layer editor helper' , queryable : true , showInLayerManager : false , sld : defaultStyle , } , source : new Vector ( { } ) , } ) ; constructor ( public HsDrawService , public HsQueryBaseService , public HsQueryVectorService , public HsLanguageService , public hsMapService , public hsToastService , public hsEventBusService ) { if ( this . HsDrawService . selectedLayer ) { this . HsDrawService . previouslySelected = this . HsDrawService . selectedLayer ; } else { this . HsDrawService . previouslySelected = null ; } this . checkFeatureGeometryType ( this . HsQueryVectorService . selector . getFeatures ( ) . getArray ( ) [ 0 ] ) ; this . hsMapService . loaded ( ) . then ( ( map ) => { map . addLayer ( this . editLayer ) ; } ) ; this . vectorQueryFeatureSubscription = this . hsEventBusService . vectorQueryFeatureSelection . subscribe ( ( data ) => { const selectorFeatures = data . selector . getFeatures ( ) . getArray ( ) ; if ( ! this . checkFeatureGeometryType ( selectorFeatures [ 0 ] ) ) { return ; } if ( selectorFeatures . length > 1 && this . editLayer != this . hsMapService . getLayerForFeature ( data . feature ) && this . selectedType == 'split' ) { if ( selectorFeatures . length == 3 ) { if ( selectorFeatures [ 2 ] . getGeometry ( ) . getType ( ) == 'LineString' ) { data . selector . getFeatures ( ) . remove ( selectorFeatures [ 1 ] ) ; this . hsToastService . createToastPopupMessage ( this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.featureEditor' ) , this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.onlyOneSplitLine' ) , { toastStyleClasses : 'bg-info text-light' , } ) ; } else { data . selector . getFeatures ( ) . pop ( ) ; } } if ( selectorFeatures . length == 2 && selectorFeatures [ 1 ] . getGeometry ( ) . getType ( ) != 'LineString' ) { this . deselectMultiple ( ) ; } } } ) ; } ngOnDestroy ( ) { this . hsMapService . loaded ( ) . then ( ( map ) => { map . removeLayer ( this . editLayer ) ; this . setType ( this . HsDrawService . type ) ; setTimeout ( ( ) => { if ( this . HsDrawService . previouslySelected ) { this . HsDrawService . selectedLayer = this . HsDrawService . previouslySelected ; this . HsDrawService . changeDrawSource ( ) ; } else { this . HsDrawService . fillDrawableLayers ( ) ; } } ) ; this . vectorQueryFeatureSubscription . unsubscribe ( ) ; } ) ; } /**
     * Check whether selected feature geometry type is valid
     * (Geometry operations work on polygon only)
     */ checkFeatureGeometryType ( feature ) { if ( ! feature ) { return false ; } const isValidType = feature . getGeometry ( ) . getType ( ) == 'Polygon' ; if ( ! isValidType ) { this . hsToastService . createToastPopupMessage ( this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.featureEditor' ) , 'Only polygon geometry can be edited' ) ; this . resetState ( ) ; } return isValidType ; } /**
     * Selects geometry operation (one of editOptions)
     */ selectGeomOperation ( option ) { const features = this . HsQueryVectorService . selector . getFeatures ( ) ; this . selectedType = option ; if ( this . HsDrawService . draw ) { const drawTypeRequired = option == 'split' ? 'LineString' : 'Polygon' ; if ( this . HsDrawService . type != drawTypeRequired ) { this . setType ( drawTypeRequired ) ; } } if ( this . selectedType == 'split' ) { if ( this . editLayer . getSource ( ) . getFeatures ( ) . length > 0 ) { this . editLayer . getSource ( ) . clear ( ) ; } if ( features . getLength ( ) > 1 ) { this . deselectMultiple ( ) ; } this . setType ( 'LineString' ) ; } else { if ( features . getLength ( ) > 1 ) { const featuresToRemove = features . getArray ( ) . filter ( ( feature ) => feature . getGeometry ( ) . getType ( ) != 'Polygon' ) ; for ( const feature of featuresToRemove ) { features . remove ( feature ) ; } } } } deselectMultiple ( index = 1 ) { this . hsToastService . createToastPopupMessage ( this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.featureEditor' ) , this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.onlyOneFeatureToEdit' ) , { toastStyleClasses : 'bg-info text-light' , } ) ; setTimeout ( ( ) => { try { const feature = this . HsQueryBaseService . selector . getFeatures ( ) . getArray ( ) [ index ] ; this . HsQueryBaseService . clearData ( 'features' ) ; this . HsQueryBaseService . selector . getFeatures ( ) . clear ( ) ; this . HsQueryBaseService . selector . getFeatures ( ) . push ( feature ) ; this . HsQueryVectorService . createFeatureAttributeList ( ) ; } catch ( error ) { console . error ( error ) ; } } ) ; } onDrawEnd ( e ) { setTimeout ( ( ) => { if ( this . selectedType == 'split' ) { const features = this . editLayer . getSource ( ) . getFeatures ( ) ; if ( features . length > 1 ) { this . HsQueryVectorService . removeFeature ( features [ 0 ] ) ; this . hsToastService . createToastPopupMessage ( this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.featureEditor' ) , this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.onlyOneSplitLine' ) , { toastStyleClasses : 'bg-info text-light' , } ) ; } } this . HsDrawService . addFeatureToSelector ( e . feature ) ; } ) ; } selectionMenuToggled ( ) { this . setType ( this . HsDrawService . type ) ; this . editLayer . getSource ( ) . clear ( ) ; } setType ( what ) { this . HsDrawService . selectedLayer = this . editLayer ; this . HsQueryBaseService . selector . setActive ( what === this . HsDrawService . type ) ; this . HsDrawService . modify . setActive ( what === this . HsDrawService . type ) ; const type = this . HsDrawService . setType ( what ) ; if ( type ) { this . HsDrawService . activateDrawing ( { onDrawEnd : ( e ) => this . onDrawEnd ( e ) } ) ; } if ( this . selectedType == 'split' && this . features . length > 1 ) { this . deselectMultiple ( 0 ) ; } } translateString ( module , text ) { return this . HsLanguageService . getTranslationIgnoreNonExisting ( module , text ) ; } setCoordinatesToFirstFeature ( coords ) { this . features [ 0 ] . feature . getGeometry ( ) . setCoordinates ( coords [ 0 ] , 'XY' ) ; } get features ( ) { return this . HsQueryBaseService . data . features ; } modify ( type ) { const features = [ ] ; const editCoords = [ ] ; this . features . forEach ( ( feature , idx ) => { if ( ( type == 'difference' && idx < 2 ) || type != 'difference' ) { features . push ( feature . feature . clone ( ) ) ; } } ) ; for ( const index in features ) { editCoords [ index ] = features [ index ] . getGeometry ( ) . getCoordinates ( ) ; } let newGeom ; let properties ; if ( type === 'split' ) { const splittingLine = this . features . length > 1 ? this . features [ 1 ] . feature : this . editLayer . getSource ( ) . getFeatures ( ) [ 0 ] ; newGeom = polygonSplitter ( { type : 'Polygon' , coordinates : editCoords [ 0 ] , } , { type : 'LineString' , coordinates : splittingLine . getGeometry ( ) . getCoordinates ( ) , } ) . geometry . coordinates ; properties = features [ 0 ] . getProperties ( ) ; } else { if ( type == 'union' || type == 'intersection' ) { const properties = { } ; for ( const f of features ) { Object . assign ( properties , f . getProperties ( ) ) ; } } newGeom = polygonClipping [ type ] ( editCoords [ 0 ] , ... editCoords . slice ( 1 ) ) ; } this [ type ] ( newGeom , properties ) ; } intersection ( newGeom , properties ) { if ( newGeom . length > 0 ) { this . setCoordinatesToFirstFeature ( newGeom ) ; this . features [ 0 ] . feature . setProperties ( properties ) ; this . resetState ( ) ; } else { this . hsToastService . createToastPopupMessage ( this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.featureEditor' ) , this . HsLanguageService . getTranslation ( 'DRAW.featureEditor.noIntersection' ) , { toastStyleClasses : 'bg-warning text-light' , } ) ; } } union ( newGeom , properties ) { const features = this . features ; const featuresLength = features . length ; for ( let i = 0 ; i <= featuresLength ; i ++ ) { if ( features . length != 1 ) { this . HsQueryVectorService . removeFeature ( features [ features . length - 1 ] . feature ) ; } } this . features [ 0 ] . feature . setProperties ( properties ) ; this . setCoordinatesToFirstFeature ( newGeom ) ; this . resetState ( ) ; } split ( coords , properties ) { for ( const c of coords ) { const layer = this . hsMapService . getLayerForFeature ( this . features [ 0 ] . feature ) ; const feature = new Feature ( Object . assign ( properties , { geometry : new Polygon ( c ) } ) ) ; layer . getSource ( ) . addFeature ( feature ) ; } for ( const feature of this . features ) { this . HsQueryVectorService . removeFeature ( feature . feature ) ; } this . resetState ( ) ; } difference ( newGeom , properties ) { if ( newGeom . length === 1 ) { this . setCoordinatesToFirstFeature ( newGeom ) ; } else { const layer = this . hsMapService . getLayerForFeature ( this . features [ 0 ] . feature ) ; for ( const geom of newGeom ) { const feature = new Feature ( new Polygon ( geom ) ) ; layer . getSource ( ) . addFeature ( feature ) ; } for ( const feature of this . features ) { this . HsQueryVectorService . removeFeature ( feature . feature ) ; } } this . resetState ( ) ; } resetState ( ) { this . editLayer . getSource ( ) . clear ( ) ; this . setType ( this . HsDrawService . type ) ; this . HsQueryBaseService . clearData ( 'features' ) ; this . HsQueryBaseService . selector . getFeatures ( ) . clear ( ) ; this . HsQueryBaseService . selector . setActive ( true ) ; } }