import { Component , Input , OnDestroy , OnInit } from '@angular/core' ; import { MatDialog } from '@angular/material/dialog' ; import { MatSnackBar } from '@angular/material/snack-bar' ; import { Store } from '@ngrx/store' ; import Feature from 'ol/Feature' ; import LineString from 'ol/geom/LineString' ; import Point from 'ol/geom/Point' ; import Polygon from 'ol/geom/Polygon' ; import TileLayer from 'ol/layer/Tile' ; import VectorLayer from 'ol/layer/Vector' ; import Map from 'ol/Map' ; import VectorSource from 'ol/source/Vector' ; import { combineLatest , Observable , Subscription } from 'rxjs' ; import { filter , map , take } from 'rxjs/operators' ; import { MangolLayer } from '../../../../classes/Layer' ; import * as CursorActions from '../../../../store/cursor/cursor.actions' ; import * as FeatureinfoActions from '../../../../store/featureinfo/featureinfo.actions' ; import { FeatureinfoDictionary } from '../../../../store/featureinfo/featureinfo.reducers' ; import * as fromMangol from '../../../../store/mangol.reducers' ; import { FeatureinfoService } from '../../featureinfo.service' ; import { FeatureinfoTableDialogComponent } from '../featureinfo-table-dialog/featureinfo-table-dialog.component' ; @ Component ( { selector : 'mangol-featureinfo-results' , templateUrl : './featureinfo-results.component.html' , styleUrls : [ './featureinfo-results.component.scss' ] } ) export class FeatureinfoResultsComponent implements OnInit , OnDestroy { @ Input ( ) dictionary : FeatureinfoDictionary ; layer$ : Observable < MangolLayer > ; resultsLayer$ : Observable < VectorLayer < VectorSource < LineString | Polygon | Point > > > ; resultsFeatures$ : Observable < Feature < LineString | Polygon | Point > [ ] > ; tab$ : Observable < string > ; combinedSubscription : Subscription ; clickFunction : any = null ; constructor ( private store , private featureinfoService , public snackBar , public dialog ) { } ngOnInit ( ) { this . resultsLayer$ = this . store . select ( ( state ) => state . featureinfo . resultsLayer ) ; this . resultsFeatures$ = this . store . select ( ( state ) => state . featureinfo . resultsItems ) ; this . layer$ = this . store . select ( ( state ) => state . featureinfo . selectedLayer ) ; this . tab$ = this . store . select ( ( state ) => state . sidebar . selectedModule ) ; this . combinedSubscription = combineLatest ( [ this . tab$ , this . layer$ ] ) . subscribe ( ( [ selectedModule , layer ] ) => { this . store . dispatch ( new FeatureinfoActions . SetResultsItems ( [ ] ) ) ; if ( selectedModule === 'featureinfo' ) { if ( layer !== null ) { this . store . select ( ( state ) => state . map . map ) . pipe ( take ( 1 ) ) . subscribe ( ( m ) => { this . store . dispatch ( new CursorActions . SetMode ( { text : this . dictionary . clickOnMap , cursor : 'crosshair' } ) ) ; this . store . dispatch ( new CursorActions . SetVisible ( true ) ) ; if ( this . clickFunction !== null ) { m . un ( 'singleclick' , this . clickFunction ) ; } this . clickFunction = ( evt ) => this . _createClickFunction ( evt , layer , m ) ; m . on ( 'singleclick' , this . clickFunction ) ; } ) ; } else { this . _removeClickFunction ( ) ; } } else { this . _removeClickFunction ( ) ; } } ) ; } ngOnDestroy ( ) { this . store . dispatch ( new CursorActions . ResetMode ( ) ) ; this . resultsLayer$ . pipe ( filter ( ( r ) => r !== null ) , take ( 1 ) ) . subscribe ( ( r ) => { this . store . dispatch ( new FeatureinfoActions . SetResultsItems ( [ ] ) ) ; r . getSource ( ) . clear ( ) ; } ) ; if ( this . combinedSubscription ) { this . combinedSubscription . unsubscribe ( ) ; } } /**
     * Removes the click funciton if needed, plus resets the cursor style
     */ private _removeClickFunction ( ) { if ( this . clickFunction !== null ) { this . store . select ( ( state ) => state . map . map ) . pipe ( take ( 1 ) ) . subscribe ( ( m ) => { m . un ( 'singleclick' , this . clickFunction ) ; this . clickFunction = null ; } ) ; } this . store . dispatch ( new CursorActions . ResetMode ( ) ) ; } param evt param layer param m private _createClickFunction ( evt , layer , m ) { this . store . select ( ( state ) => state . featureinfo . resultsLayer ) . pipe ( take ( 1 ) ) . subscribe ( ( resultsLayer ) => { try { m . removeLayer ( resultsLayer ) ; } catch ( error ) { } resultsLayer . getSource ( ) . clear ( ) ; this . store . dispatch ( new FeatureinfoActions . SetResultsItems ( [ ] ) ) ; m . addLayer ( resultsLayer ) ; const coords = < [ number , number ] > evt . coordinate ; if ( layer . layer instanceof TileLayer ) { this . featureinfoService . getFeatureinfoUrl$ ( layer , m , coords ) . pipe ( take ( 1 ) ) . subscribe ( ( url ) => { this . featureinfoService . getFeatureinfo ( < string > url , layer . querySrs , m . getView ( ) . getProjection ( ) . getCode ( ) ) . subscribe ( ( features ) => { this . store . dispatch ( new FeatureinfoActions . SetResultsItems ( features ) ) ; this . _openSnackBar ( features . length ) ; } , ( error ) => { console . log ( error ) ; } ) ; } ) ; } else if ( layer . layer instanceof VectorLayer ) { const vectorFeatures = < Feature < LineString | Polygon | Point > [ ] > m . getFeaturesAtPixel ( evt . pixel , { layerFilter : ( lay ) => lay === < VectorLayer < VectorSource < LineString | Polygon | Point > > > ( layer . layer ) , hitTolerance : 5 } ) ; this . store . dispatch ( new FeatureinfoActions . SetResultsItems ( vectorFeatures ) ) ; this . _openSnackBar ( vectorFeatures . length ) ; } else { alert ( `Feature info for layer is not yet supported` ) ; } } ) ; } param hits private _openSnackBar ( hits ) { this . store . select ( ( state ) => state . featureinfo . snackbarDuration ) . pipe ( take ( 1 ) ) . subscribe ( ( snackbarDuration ) => { this . snackBar . open ( `${ this . dictionary . numberOfFeaturesFound }: ${ hits }` , `${ this . dictionary . closeSnackbar }` , { duration : snackbarDuration , panelClass : 'mangol-snackbar' } ) ; } ) ; } param feature getExpansionPanelTitle$ ( feature ) { return this . store . select ( ( state ) => state . featureinfo . selectedLayer ) . pipe ( take ( 1 ) , map ( ( selectedLayer ) => { const noPropTitle = this . dictionary . feature ; if ( ! ! selectedLayer . queryIdProperty ) { const props = feature . getProperties ( ) ; if ( props . hasOwnProperty ( selectedLayer . queryIdProperty ) ) { return props [ selectedLayer . queryIdProperty ] . toString ( ) . length > 0 ? props [ selectedLayer . queryIdProperty ] : noPropTitle ; } else { return noPropTitle ; } } else { return noPropTitle ; } } ) ) ; } /**
     * Opens a full table dialog
     */ openTableDialog ( ) { combineLatest ( [ this . layer$ , this . resultsFeatures$ ] ) . pipe ( take ( 1 ) ) . subscribe ( ( [ layer , resultsFeatures ] ) => { this . dialog . open ( FeatureinfoTableDialogComponent , { maxWidth : '90%' , maxHeight : '90%' , panelClass : 'mangol-dialog' , autoFocus : false , data : { layer : layer , features : resultsFeatures , dictionary : this . dictionary } } ) ; } ) ; } param feature showFeatureOnMap ( feature ) { this . resultsLayer$ . pipe ( take ( 1 ) ) . subscribe ( ( layer ) => { layer . getSource ( ) . addFeature ( feature ) ; } ) ; } param feature hideFeatureOnMap ( feature ) { this . resultsLayer$ . pipe ( take ( 1 ) ) . subscribe ( ( layer ) => { layer . getSource ( ) . removeFeature ( feature ) ; } ) ; } param feature zoomToFeature ( feature ) { this . store . select ( ( state ) => state . map . map ) . pipe ( take ( 1 ) ) . subscribe ( ( m ) => { m . getView ( ) . fit ( feature . getGeometry ( ) . getExtent ( ) , { duration : 500 } ) ; } ) ; } }