From 1c907398f39fca88cf2e1b31c90e6868c1aac6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-=C3=89tienne=20Lord?= <7397743+pelord@users.noreply.github.com> Date: Tue, 20 Oct 2020 10:01:27 -0400 Subject: [PATCH] feat(search-result) add a emphasis feature for line and poly too deep in view (#750) * feat(search-result) add a emphasis feature for line and poly too deep in view * wip --- packages/integration/ng-package.json | 6 +- packages/integration/ng-package.prod.json | 4 +- .../search-results-tool.component.ts | 102 ++++++++++++++++-- 3 files changed, 101 insertions(+), 11 deletions(-) diff --git a/packages/integration/ng-package.json b/packages/integration/ng-package.json index da6ad98583..1c9b022151 100644 --- a/packages/integration/ng-package.json +++ b/packages/integration/ng-package.json @@ -5,8 +5,10 @@ "lib": { "entryFile": "src/public_api.ts", "umdModuleIds": { - "@igo2/auth": "auth", - "@igo2/geo": "geo", + "@igo2/auth": "igoAuth", + "@igo2/geo": "igoGeo", + "ol/Feature": "olFeature", + "ol/geom/Point": "olPoint", "ol/format/GeoJSON": "olFormatGeoJSON", "ol/style": "olstyle", "@igo2/core": "core", diff --git a/packages/integration/ng-package.prod.json b/packages/integration/ng-package.prod.json index e4137124df..d733554d0c 100644 --- a/packages/integration/ng-package.prod.json +++ b/packages/integration/ng-package.prod.json @@ -4,8 +4,10 @@ "lib": { "entryFile": "src/public_api.ts", "umdModuleIds": { - "@igo2/auth": "auth", + "@igo2/auth": "igoAuth", "@igo2/geo": "igoGeo", + "ol/Feature": "olFeature", + "ol/geom/Point": "olPoint", "ol/format/GeoJSON": "olFormatGeoJSON", "ol/style": "olstyle", "@igo2/core": "igoCore", diff --git a/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.ts b/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.ts index c4e733df6f..6e9e142dd3 100644 --- a/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.ts +++ b/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.ts @@ -1,7 +1,11 @@ import { Component, ChangeDetectionStrategy, Input, OnInit, ElementRef, OnDestroy } from '@angular/core'; -import { Observable, BehaviorSubject, Subscription } from 'rxjs'; +import { Observable, BehaviorSubject, Subscription, combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; import olFormatGeoJSON from 'ol/format/GeoJSON'; +import olFeature from 'ol/Feature'; +import olPoint from 'ol/geom/Point'; + +import { ConfigService } from '@igo2/core'; import { EntityStore, @@ -13,16 +17,19 @@ import { import { LayerService, - LayerOptions, FEATURE, Feature, FeatureMotion, - LAYER, SearchResult, IgoMap, moveToOlFeatures, Research, - createOverlayDefaultStyle + createOverlayDefaultStyle, + featuresAreTooDeepInView, + featureToOl, + featureFromOl, + getSelectedMarkerStyle, + createOverlayMarkerStyle } from '@igo2/geo'; import { MapState } from '../../map/map.state'; @@ -50,6 +57,14 @@ export class SearchResultsToolComponent implements OnInit, OnDestroy { */ @Input() showIcons: boolean = true; + private hasFeatureEmphasisOnSelection: boolean = false; + + private focusedOrResolution$$: Subscription; + private selectedOrResolution$$: Subscription; + private focusedResult$: BehaviorSubject = new BehaviorSubject(undefined); + private abstractFocusedResult: Feature; + private abstractSelectedResult: Feature; + /** * Store holding the search results * @internal @@ -109,8 +124,13 @@ export class SearchResultsToolComponent implements OnInit, OnDestroy { private searchState: SearchState, private elRef: ElementRef, public toolState: ToolState, - private directionState: DirectionState - ) {} + private directionState: DirectionState, + configService: ConfigService + ) { + this.hasFeatureEmphasisOnSelection = configService.getConfig( + 'hasFeatureEmphasisOnSelection' + ); + } ngOnInit() { this.searchTerm$$ = this.searchState.searchTerm$.subscribe((searchTerm: string) => { @@ -140,11 +160,75 @@ export class SearchResultsToolComponent implements OnInit, OnDestroy { }, FlexibleComponent.transitionTime + 50); } }); + + if (this.hasFeatureEmphasisOnSelection) { + this.focusedOrResolution$$ = combineLatest([ + this.focusedResult$, + this.map.viewController.resolution$ + ]).subscribe((bunch: [SearchResult, number]) => this.buildResultEmphasis(bunch[0], 'focused')); + + this.selectedOrResolution$$ = combineLatest([ + this.searchState.selectedResult$, + this.map.viewController.resolution$ + ]).subscribe((bunch: [SearchResult, number]) => this.buildResultEmphasis(bunch[0], 'selected')); + + } + } + + private buildResultEmphasis( + result: SearchResult, + trigger: 'selected' | 'focused' | undefined) { + this.clearFeatureEmphasis(trigger); + if (!result || !result.data.geometry) { + return; + } + const myOlFeature = featureToOl(result.data, this.map.projection); + const olGeometry = myOlFeature.getGeometry(); + if (result.data.geometry.type !== 'Point') { + if (featuresAreTooDeepInView(this.map, olGeometry.getExtent(), 0.0025)) { + const extent = olGeometry.getExtent(); + const x = extent[0] + (extent[2] - extent[0]) / 2; + const y = extent[1] + (extent[3] - extent[1]) / 2; + const feature1 = new olFeature({ + name: `${trigger}AbstractResult'`, + geometry: new olPoint([x, y]), + }); + const abstractResult = featureFromOl(feature1, this.map.projection); + abstractResult.meta.style = trigger === 'focused' ? createOverlayMarkerStyle() : getSelectedMarkerStyle(abstractResult); + abstractResult.meta.style.setZIndex(2000); + this.map.overlay.addFeature(abstractResult, FeatureMotion.None); + if (trigger === 'focused') { + this.abstractFocusedResult = abstractResult; + } + if (trigger === 'selected') { + this.abstractSelectedResult = abstractResult; + } + } else { + this.clearFeatureEmphasis(trigger); + } + } + } + + private clearFeatureEmphasis(trigger: 'selected' | 'focused' | undefined) { + if (trigger === 'focused' && this.abstractFocusedResult) { + this.map.overlay.removeFeature(this.abstractFocusedResult); + this.abstractFocusedResult = undefined; + } + if (trigger === 'selected' && this.abstractSelectedResult) { + this.map.overlay.removeFeature(this.abstractSelectedResult); + this.abstractSelectedResult = undefined; + } } ngOnDestroy() { this.topPanelState$$.unsubscribe(); this.searchTerm$$.unsubscribe(); + if (this.selectedOrResolution$$) { + this.selectedOrResolution$$.unsubscribe(); + } + if (this.focusedOrResolution$$) { + this.focusedOrResolution$$.unsubscribe(); + } } /** @@ -153,6 +237,7 @@ export class SearchResultsToolComponent implements OnInit, OnDestroy { * @param result A search result that could be a feature */ onResultFocus(result: SearchResult) { + this.focusedResult$.next(result); if (result.meta.dataType === FEATURE) { if (this.map.viewController.getZoom() < 11 && (result.data.geometry.type === 'MultiLineString' || result.data.geometry.type === 'LineString')) { result.data.meta.style = createOverlayDefaultStyle({strokeWidth: 10}); @@ -166,6 +251,7 @@ export class SearchResultsToolComponent implements OnInit, OnDestroy { } onResultUnfocus(result: SearchResult) { + this.focusedResult$.next(undefined); if (result.meta.dataType !== FEATURE) { return; } @@ -263,11 +349,11 @@ export class SearchResultsToolComponent implements OnInit, OnDestroy { zoomToFeatureExtent() { if (this.feature.geometry) { - const olFeature = this.format.readFeature(this.feature, { + const localOlFeature = this.format.readFeature(this.feature, { dataProjection: this.feature.projection, featureProjection: this.map.projection }); - moveToOlFeatures(this.map, [olFeature], FeatureMotion.Zoom); + moveToOlFeatures(this.map, [localOlFeature], FeatureMotion.Zoom); } }