From 6379b64351cc5342da2469c8e0ff1f9d1cd85f2d Mon Sep 17 00:00:00 2001 From: Willem Dantuma Date: Wed, 12 Feb 2020 20:38:14 +0100 Subject: [PATCH 1/3] Refactor style cache --- projects/common-map/package.json | 2 +- .../src/fm-map/actions/map.actions.ts | 13 +- .../src/fm-map/common-map.module.ts | 3 + .../item-vector-source.component.ts | 353 ++++++++---------- .../src/fm-map/effects/map.effects.ts | 44 ++- .../src/fm-map/models/style.cache.ts | 5 + .../src/fm-map/reducers/map.reducer.ts | 13 +- .../fm-map/services/feature-icon.service.ts | 41 ++ .../src/fm/services/itemtype.service.ts | 8 +- 9 files changed, 258 insertions(+), 224 deletions(-) create mode 100644 projects/common-map/src/fm-map/models/style.cache.ts create mode 100644 projects/common-map/src/fm-map/services/feature-icon.service.ts diff --git a/projects/common-map/package.json b/projects/common-map/package.json index e204ec4..dddff35 100644 --- a/projects/common-map/package.json +++ b/projects/common-map/package.json @@ -6,7 +6,7 @@ }, "dependencies": { "ngx-openlayers": "1.0.0-next.13", - "ol": "^6.0.0" + "ol": "6.1.1" }, "peerDependencies": { "@angular/core": "^8.2.0", diff --git a/projects/common-map/src/fm-map/actions/map.actions.ts b/projects/common-map/src/fm-map/actions/map.actions.ts index fb4b0ab..b573a25 100644 --- a/projects/common-map/src/fm-map/actions/map.actions.ts +++ b/projects/common-map/src/fm-map/actions/map.actions.ts @@ -4,8 +4,7 @@ import { IMapState } from '../models/map.state'; import { IItemLayer } from '../models/item.layer'; import { IQueryState } from '../models/query.state'; import { IItem } from '@farmmaps/common'; -import { Feature } from 'ol'; -import { Extent } from 'ol/extent'; +import { Feature,Style } from 'ol'; export const SETSTATE = '[Map] SetState'; export const SETMAPSTATE = '[Map] MapState'; @@ -35,6 +34,7 @@ export const SELECTBASELAYER = '[Map] SelectBaseLayers'; export const SELECTOVERLAYLAYER = '[Map] SelectOverlayLayers'; export const ZOOMTOEXTENT = '[Map] ZoomToExtent'; export const DOQUERY = '[Map] DoQuery'; +export const SETSTYLE = '[Map] SetStyle'; export class SetState implements Action { readonly type = SETSTATE; @@ -204,6 +204,12 @@ export class DoQuery implements Action { constructor(public query:IQueryState) { } } +export class SetStyle implements Action { + readonly type = SETSTYLE; + + constructor(public itemType:string,public style:Style) { } +} + export type Actions = SetMapState | Init | SetParent @@ -231,5 +237,6 @@ export type Actions = SetMapState | ZoomToExtent | SetState | SetViewExtent - | DoQuery; + | DoQuery + | SetStyle; diff --git a/projects/common-map/src/fm-map/common-map.module.ts b/projects/common-map/src/fm-map/common-map.module.ts index b35a061..78d0635 100644 --- a/projects/common-map/src/fm-map/common-map.module.ts +++ b/projects/common-map/src/fm-map/common-map.module.ts @@ -58,6 +58,7 @@ import { MapRoutingModule } from './common-map-routing.module'; import { LegendComponent } from './components/legend/legend.component'; import { LayerVectorImageComponent } from './components/aol/layer-vector-image/layer-vector-image.component'; import { StateSerializerService } from './services/state-serializer.service'; +import {FeatureIconService} from './services/feature-icon.service'; import { GeolocationService } from './services/geolocation.service'; import {DeviceOrientationService} from './services/device-orientation.service'; import { WidgetStatusComponent } from './components/widget-status/widget-status.component'; @@ -131,6 +132,7 @@ export { AbstractItemListItemComponent, AbstractItemListComponent, StateSerializerService, + FeatureIconService, GeolocationService, DeviceOrientationService, IMapState, @@ -249,6 +251,7 @@ export class AppCommonMapModule { ngModule: AppCommonMapModule, providers: [ StateSerializerService, + FeatureIconService, GeolocationService, DeviceOrientationService, { provide: AbstractFeatureListComponent, useClass: FeatureListCroppingschemeComponent, multi: true }, diff --git a/projects/common-map/src/fm-map/components/aol/item-vector-source/item-vector-source.component.ts b/projects/common-map/src/fm-map/components/aol/item-vector-source/item-vector-source.component.ts index 4c43acb..08518ab 100644 --- a/projects/common-map/src/fm-map/components/aol/item-vector-source/item-vector-source.component.ts +++ b/projects/common-map/src/fm-map/components/aol/item-vector-source/item-vector-source.component.ts @@ -1,207 +1,146 @@ -import { Component, Host, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges, forwardRef, Inject, InjectionToken } from '@angular/core'; -import { LayerVectorComponent, SourceVectorComponent, MapComponent } from 'ngx-openlayers'; -import { ItemService,ItemTypeService,IItem, IItemType } from '@farmmaps/common'; - -import { Feature } from 'ol'; -import { Point } from 'ol/geom'; -import { MapBrowserEvent } from 'ol'; -import * as style from 'ol/style'; -import * as color from 'ol/color'; -import * as loadingstrategy from 'ol/loadingstrategy'; -import * as condition from 'ol/events/condition'; -import * as extent from 'ol/extent'; -import {Vector,Cluster} from 'ol/source'; -import {Layer} from 'ol/layer'; -import {GeoJSON} from 'ol/format'; -import {Select} from 'ol/interaction'; - -@Component({ - selector: 'fm-map-item-source-vector', - template: ``, - providers: [ - { provide: SourceVectorComponent , useExisting: forwardRef(() => ItemVectorSourceComponent) } - ] -}) -export class ItemVectorSourceComponent extends SourceVectorComponent implements OnInit, OnChanges { - instance: Vector; - private _format: GeoJSON; - private _select: Select; - private _hoverSelect: Select; - private _iconScale: number = 0.05; - @Input() features: Array; - @Input() selectedFeature: Feature; - @Input() selectedItem: IItem; - @Output() onFeaturesSelected: EventEmitter = new EventEmitter(); - private styleCache = { - 'file': new style.Style({ - image: new style.Icon({ - anchor: [0.5, 1], - scale: 0.05, - src: this.getIconImageDataUrl("fa fa-file-o") - }), - stroke: new style.Stroke({ - color: 'red', - width: 1 - }), - fill: new style.Fill({ - color: 'rgba(0, 0, 255, 0.1)' - }), - geometry: (feature) => this.geometry(feature) - }), - 'selected': new style.Style({ - image: new style.Icon({ - anchor: [0.5, 1], - scale: 0.08, - src: this.getIconImageDataUrl(null) - }), - stroke: new style.Stroke({ - color: 'red', - width: 3 - }), - fill: new style.Fill({ - color: 'rgba(0, 0, 255, 0.1)' - }), - geometry: (feature) => this.geometry(feature) - }) - }; - - constructor(@Host() private layer: LayerVectorComponent, private itemService: ItemService, @Host() private map: MapComponent, private itemTypeService: ItemTypeService) { - super(layer); - this._format = new GeoJSON(); - } - - geometry(feature: Feature) { - let view = this.map.instance.getView(); - let resolution = view.getResolution(); - var geometry = feature.getGeometry(); - let e = geometry.getExtent(); - //var size = Math.max((e[2] - e[0]) / resolution, (e[3] - e[1]) / resolution); - if (resolution > 12) { - geometry = new Point(extent.getCenter(e)); - } - return geometry; - } - - getIconImageDataUrl(iconClass:string, backgroundColor: string = "#c80a6e",color:string = "#ffffff"): string { - var canvas = document.createElement('canvas'); - canvas.width = 365; - canvas.height = 560; - var ctx = canvas.getContext('2d'); - ctx.lineWidth = 6; - ctx.fillStyle = backgroundColor; - ctx.strokeStyle = "#000000"; - var path = new Path2D("m182.9 551.7c0 0.1 0.2 0.3 0.2 0.3s175.2-269 175.2-357.4c0-130.1-88.8-186.7-175.4-186.9-86.6 0.2-175.4 56.8-175.4 186.9 0 88.4 175.3 357.4 175.3 357.4z"); - ctx.fill(path) - - var iconCharacter = ""; - if (iconClass != null) { - var element = document.createElement("i"); - element.style.display = "none"; - element.className = iconClass; - document.body.appendChild(element); - iconCharacter = getComputedStyle(element, "::before").content.replace(/"/g, ''); - let iconFont = "200px " +getComputedStyle(element, "::before").fontFamily - document.body.removeChild(element); - ctx.strokeStyle = color; - ctx.fillStyle = color; - ctx.lineWidth = 15; - ctx.font = iconFont; - var ts = ctx.measureText(iconCharacter); - ctx.fillText(iconCharacter, 182.9 - (ts.width / 2), 250); - ctx.strokeText(iconCharacter, 182.9 - (ts.width / 2), 250); - } - - return canvas.toDataURL(); - } - - ngOnInit() { - this.strategy = loadingstrategy.bbox; - this.format = new GeoJSON(); - this._select = new Select({ - style: (feature) => { - return this.styleCache['selected']; - }, - hitTolerance: 10, - layers: [this.layer.instance as Layer] - }); - this._hoverSelect = new Select({ - style: (feature) => { - return this.styleCache['selected']; - }, - hitTolerance: 10, - condition: (e: MapBrowserEvent) => { - return e.type == 'pointermove'; - }, - layers: [this.layer.instance as Layer] - }); - this.map.instance.addInteraction(this._select); - this.map.instance.addInteraction(this._hoverSelect); - this._select.on('select', (e) => { - if (e.selected.length > 0 && e.selected[0]) { - this.onFeaturesSelected.emit(e.selected[0]); - } else { - this.onFeaturesSelected.emit(null); - } - }); - this.instance = new Vector(this); - this.host.instance.setSource(this.instance); - - this.host.instance.setStyle((feature) => { - var key = feature.get('itemType') + (this.selectedItem?"_I":""); - if (!this.styleCache[key]) { - if (this.itemTypeService.itemTypes[key]) { - let itemType = this.itemTypeService.itemTypes[key]; - let fillColor = color.asArray(itemType.iconColor); - fillColor[3] = this.selectedItem?0:0.5; - this.styleCache[key] = new style.Style({ - image: itemType.icon ? new style.Icon({ - anchor: [0.5, 1], - scale: 0.05, - src: this.getIconImageDataUrl(itemType.icon) - }):null, - stroke: new style.Stroke({ - color: 'red', - width: 1 - }), - fill: new style.Fill({ - color: fillColor - }), - geometry: (feature) => this.geometry(feature) - }); - } else { - key = 'file'; - } - } - var styleEntry = this.styleCache[key]; - return styleEntry; - }); - } - - ngOnChanges(changes: SimpleChanges) { - if (changes["features"] && this.instance) { - this.instance.clear(true); - this._select.getFeatures().clear(); - this.instance.addFeatures(changes["features"].currentValue); - } - - if (changes["selectedFeature"] && this.instance) { - var features = this._select.getFeatures(); - var feature = changes["selectedFeature"].currentValue - //this.instance.clear(false); - //this.instance.addFeatures(features.getArray()); - features.clear(); - if (feature) { - //this.instance.removeFeature(feature); - features.push(feature) - } - } - if (changes["selectedItem"] && this.instance) { - var item = changes["selectedItem"].currentValue - if (item) { - this.map.instance.removeInteraction(this._hoverSelect); - } else { - this.map.instance.addInteraction(this._hoverSelect); - } - } - } -} +import { Component, Host, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges, forwardRef, Inject, InjectionToken } from '@angular/core'; +import { LayerVectorComponent, SourceVectorComponent, MapComponent } from 'ngx-openlayers'; +import { ItemService,ItemTypeService,IItem, IItemType } from '@farmmaps/common'; + +import { Feature } from 'ol'; +import { Point } from 'ol/geom'; +import { MapBrowserEvent } from 'ol'; +import * as style from 'ol/style'; +import * as color from 'ol/color'; +import * as loadingstrategy from 'ol/loadingstrategy'; +import * as condition from 'ol/events/condition'; +import * as extent from 'ol/extent'; +import {Vector,Cluster} from 'ol/source'; +import {Layer} from 'ol/layer'; +import {GeoJSON} from 'ol/format'; +import {Select} from 'ol/interaction'; +import {IStyleCache} from '../../../models/style.cache'; +import {FeatureIconService} from '../../../services/feature-icon.service'; + +@Component({ + selector: 'fm-map-item-source-vector', + template: ``, + providers: [ + { provide: SourceVectorComponent , useExisting: forwardRef(() => ItemVectorSourceComponent) } + ] +}) +export class ItemVectorSourceComponent extends SourceVectorComponent implements OnInit, OnChanges { + instance: Vector; + private _format: GeoJSON; + private _select: Select; + private _hoverSelect: Select; + private _iconScale: number = 0.05; + @Input() features: Array; + @Input() selectedFeature: Feature; + @Input() selectedItem: IItem; + @Output() onFeaturesSelected: EventEmitter = new EventEmitter(); + private styleCache:IStyleCache = {}; + + constructor(@Host() private layer: LayerVectorComponent, private itemService: ItemService, @Host() private map: MapComponent, private itemTypeService: ItemTypeService,private featureIconService$:FeatureIconService) { + super(layer); + this._format = new GeoJSON(); + } + + geometry(feature: Feature) { + let view = this.map.instance.getView(); + let resolution = view.getResolution(); + var geometry = feature.getGeometry(); + let e = geometry.getExtent(); + //var size = Math.max((e[2] - e[0]) / resolution, (e[3] - e[1]) / resolution); + if (resolution > 12) { + geometry = new Point(extent.getCenter(e)); + } + return geometry; + } + + ngOnInit() { + this.strategy = loadingstrategy.bbox; + this.format = new GeoJSON(); + this._select = new Select({ + style: (feature) => { + return this.styleCache['selected']; + }, + hitTolerance: 10, + layers: [this.layer.instance as Layer] + }); + this._hoverSelect = new Select({ + style: (feature) => { + return this.styleCache['selected']; + }, + hitTolerance: 10, + condition: (e: MapBrowserEvent) => { + return e.type == 'pointermove'; + }, + layers: [this.layer.instance as Layer] + }); + this.map.instance.addInteraction(this._select); + this.map.instance.addInteraction(this._hoverSelect); + this._select.on('select', (e) => { + if (e.selected.length > 0 && e.selected[0]) { + this.onFeaturesSelected.emit(e.selected[0]); + } else { + this.onFeaturesSelected.emit(null); + } + }); + this.instance = new Vector(this); + this.host.instance.setSource(this.instance); + + this.host.instance.setStyle((feature) => { + var key = feature.get('itemType') + (this.selectedItem?"_I":""); + if (!this.styleCache[key]) { + if (this.itemTypeService.itemTypes[key]) { + let itemType = this.itemTypeService.itemTypes[key]; + let fillColor = color.asArray(itemType.iconColor); + fillColor[3] = this.selectedItem?0:0.5; + this.styleCache[key] = new style.Style({ + image: itemType.icon ? new style.Icon({ + anchor: [0.5, 1], + scale: 0.05, + src: this.featureIconService$.getIconImageDataUrl(itemType.icon) + }):null, + stroke: new style.Stroke({ + color: 'red', + width: 1 + }), + fill: new style.Fill({ + color: fillColor + }), + }); + } else { + key = 'file'; + } + } + var styleEntry = this.styleCache[key]; + styleEntry.geometry = (feature) => this.geometry(feature); + return styleEntry; + }); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes["features"] && this.instance) { + this.instance.clear(true); + this._select.getFeatures().clear(); + this.instance.addFeatures(changes["features"].currentValue); + } + + if (changes["selectedFeature"] && this.instance) { + var features = this._select.getFeatures(); + var feature = changes["selectedFeature"].currentValue + //this.instance.clear(false); + //this.instance.addFeatures(features.getArray()); + features.clear(); + if (feature) { + //this.instance.removeFeature(feature); + features.push(feature) + } + } + if (changes["selectedItem"] && this.instance) { + var item = changes["selectedItem"].currentValue + if (item) { + this.map.instance.removeInteraction(this._hoverSelect); + } else { + this.map.instance.addInteraction(this._hoverSelect); + } + } + } +} diff --git a/projects/common-map/src/fm-map/effects/map.effects.ts b/projects/common-map/src/fm-map/effects/map.effects.ts index cf35add..1c6facf 100644 --- a/projects/common-map/src/fm-map/effects/map.effects.ts +++ b/projects/common-map/src/fm-map/effects/map.effects.ts @@ -19,10 +19,15 @@ import {commonReducers} from '@farmmaps/common'; import {commonActions} from '@farmmaps/common'; -import { IListItem, IItem } from '@farmmaps/common'; +import { IItem } from '@farmmaps/common'; import { FolderService, ItemService } from '@farmmaps/common'; import { tassign } from 'tassign'; +import {FeatureIconService} from '../services/feature-icon.service'; + +import * as style from 'ol/style'; + + @Injectable() export class MapEffects { private _geojsonFormat: GeoJSON; @@ -44,10 +49,41 @@ export class MapEffects { ofType(mapActions.INIT), withLatestFrom(this.store$.select(commonReducers.selectGetRootItems)), switchMap(([action, rootItems]) => { + let actions=[]; for (let rootItem of rootItems) { - if (rootItem.itemType == "UPLOADS_FOLDER") return of(new mapActions.SetParent(rootItem.code)); + if (rootItem.itemType == "UPLOADS_FOLDER") actions.push(new mapActions.SetParent(rootItem.code)); } - return []; + // initialize default feature styles + actions.push(new mapActions.SetStyle('file',new style.Style({ + image: new style.Icon({ + anchor: [0.5, 1], + scale: 0.05, + src: this.featureIconService$.getIconImageDataUrl("fa fa-file-o") + }), + stroke: new style.Stroke({ + color: 'red', + width: 1 + }), + fill: new style.Fill({ + color: 'rgba(0, 0, 255, 0.1)' + }) + }))); + actions.push(new mapActions.SetStyle('selected',new style.Style({ + image: new style.Icon({ + anchor: [0.5, 1], + scale: 0.08, + src: this.featureIconService$.getIconImageDataUrl(null) + }), + stroke: new style.Stroke({ + color: 'red', + width: 3 + }), + fill: new style.Fill({ + color: 'rgba(0, 0, 255, 0.1)' + }) + }))); + + return actions; } )); @@ -231,7 +267,7 @@ export class MapEffects { return of(newAction); })); - constructor(private actions$: Actions, private store$: Store, private folderService$: FolderService, private itemService$: ItemService) { + constructor(private actions$: Actions, private store$: Store, private folderService$: FolderService, private itemService$: ItemService,private featureIconService$:FeatureIconService) { this._geojsonFormat = new GeoJSON(); this._wktFormat = new WKT(); } diff --git a/projects/common-map/src/fm-map/models/style.cache.ts b/projects/common-map/src/fm-map/models/style.cache.ts new file mode 100644 index 0000000..96e5b9c --- /dev/null +++ b/projects/common-map/src/fm-map/models/style.cache.ts @@ -0,0 +1,5 @@ +import {Style} from 'ol'; + +export interface IStyleCache{ + [id: string]: Style; +}; \ No newline at end of file diff --git a/projects/common-map/src/fm-map/reducers/map.reducer.ts b/projects/common-map/src/fm-map/reducers/map.reducer.ts index 9374631..6641f22 100644 --- a/projects/common-map/src/fm-map/reducers/map.reducer.ts +++ b/projects/common-map/src/fm-map/reducers/map.reducer.ts @@ -4,6 +4,7 @@ import { IItemLayer,ItemLayer} from '../models/item.layer'; import { IMapState} from '../models/map.state'; import { IQueryState} from '../models/query.state'; import { IPeriodState} from '../models/period.state'; +import { IStyleCache} from '../models/style.cache'; import * as mapActions from '../actions/map.actions'; import {commonActions} from '@farmmaps/common'; import { createSelector, createFeatureSelector } from '@ngrx/store'; @@ -51,7 +52,8 @@ export interface State { selectedItemLayer: IItemLayer, projection: string, selectedBaseLayer: IItemLayer, - selectedOverlayLayer: IItemLayer + selectedOverlayLayer: IItemLayer, + styleCache:IStyleCache } export const initialState: State = { @@ -84,7 +86,8 @@ export const initialState: State = { projection: "EPSG:3857", selectedBaseLayer: null, selectedOverlayLayer: null, - selectedItemLayer: null + selectedItemLayer: null, + styleCache: {} } export function reducer(state = initialState, action: mapActions.Actions | commonActions.Actions | RouterNavigationAction): State { @@ -310,6 +313,12 @@ export function reducer(state = initialState, action: mapActions.Actions | commo return tassign(state, {}); } } + case mapActions.SETSTYLE:{ + let a = action as mapActions.SetStyle; + let styles = state.styleCache; + styles[a.itemType] = a.style; + return tassign(state,{styleCache:styles}); + } default: { return state; } diff --git a/projects/common-map/src/fm-map/services/feature-icon.service.ts b/projects/common-map/src/fm-map/services/feature-icon.service.ts new file mode 100644 index 0000000..70a5a17 --- /dev/null +++ b/projects/common-map/src/fm-map/services/feature-icon.service.ts @@ -0,0 +1,41 @@ +import { Injectable} from '@angular/core'; +import { Feature } from 'ol'; +import { Point } from 'ol/geom'; +import * as extent from 'ol/extent'; + + +@Injectable() +export class FeatureIconService { + + getIconImageDataUrl(iconClass:string, backgroundColor: string = "#c80a6e",color:string = "#ffffff"): string { + var canvas = document.createElement('canvas'); + canvas.width = 365; + canvas.height = 560; + var ctx = canvas.getContext('2d'); + ctx.lineWidth = 6; + ctx.fillStyle = backgroundColor; + ctx.strokeStyle = "#000000"; + var path = new Path2D("m182.9 551.7c0 0.1 0.2 0.3 0.2 0.3s175.2-269 175.2-357.4c0-130.1-88.8-186.7-175.4-186.9-86.6 0.2-175.4 56.8-175.4 186.9 0 88.4 175.3 357.4 175.3 357.4z"); + ctx.fill(path) + + var iconCharacter = ""; + if (iconClass != null) { + var element = document.createElement("i"); + element.style.display = "none"; + element.className = iconClass; + document.body.appendChild(element); + iconCharacter = getComputedStyle(element, "::before").content.replace(/"/g, ''); + let iconFont = "200px " +getComputedStyle(element, "::before").fontFamily + document.body.removeChild(element); + ctx.strokeStyle = color; + ctx.fillStyle = color; + ctx.lineWidth = 15; + ctx.font = iconFont; + var ts = ctx.measureText(iconCharacter); + ctx.fillText(iconCharacter, 182.9 - (ts.width / 2), 250); + ctx.strokeText(iconCharacter, 182.9 - (ts.width / 2), 250); + } + + return canvas.toDataURL(); + } +} \ No newline at end of file diff --git a/projects/common/src/fm/services/itemtype.service.ts b/projects/common/src/fm/services/itemtype.service.ts index 426ea45..f81f1ad 100644 --- a/projects/common/src/fm/services/itemtype.service.ts +++ b/projects/common/src/fm/services/itemtype.service.ts @@ -4,9 +4,7 @@ import {IItem} from '../models/item' import {AppConfig} from '../shared/app.config'; import {HttpClient, HttpXhrBackend} from '@angular/common/http'; -@Injectable({ - providedIn: 'root', -}) +@Injectable() export class ItemTypeService { public itemTypes: IItemTypes; private httpClient: HttpClient; @@ -15,10 +13,6 @@ export class ItemTypeService { this.httpClient = new HttpClient(xhrBackend); } - // itemService.getItemTypes().subscribe((itemTypes) => { - // this.itemTypes = itemTypes; - // }); - getIcon(itemType: string) { var icon = "fa fa-file-o"; if (this.itemTypes[itemType]) icon = this.itemTypes[itemType].icon; From 937dbe9b43f914afe2ed27a742e46919801b2edb Mon Sep 17 00:00:00 2001 From: Willem Dantuma Date: Wed, 12 Feb 2020 21:33:28 +0100 Subject: [PATCH 2/3] Use refactored styles --- .../item-vector-source.component.ts | 29 ++++++++++++++----- .../fm-map/components/map/map.component.html | 5 ++-- .../fm-map/components/map/map.component.ts | 3 ++ .../src/fm-map/models/style.cache.ts | 2 +- .../src/fm-map/reducers/map.reducer.ts | 12 ++++---- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/projects/common-map/src/fm-map/components/aol/item-vector-source/item-vector-source.component.ts b/projects/common-map/src/fm-map/components/aol/item-vector-source/item-vector-source.component.ts index 08518ab..977042e 100644 --- a/projects/common-map/src/fm-map/components/aol/item-vector-source/item-vector-source.component.ts +++ b/projects/common-map/src/fm-map/components/aol/item-vector-source/item-vector-source.component.ts @@ -14,7 +14,7 @@ import {Vector,Cluster} from 'ol/source'; import {Layer} from 'ol/layer'; import {GeoJSON} from 'ol/format'; import {Select} from 'ol/interaction'; -import {IStyleCache} from '../../../models/style.cache'; +import {IStyles} from '../../../models/style.cache'; import {FeatureIconService} from '../../../services/feature-icon.service'; @Component({ @@ -33,8 +33,9 @@ export class ItemVectorSourceComponent extends SourceVectorComponent implements @Input() features: Array; @Input() selectedFeature: Feature; @Input() selectedItem: IItem; + @Input() styles:IStyles; @Output() onFeaturesSelected: EventEmitter = new EventEmitter(); - private styleCache:IStyleCache = {}; + private stylesCache:IStyles = {}; constructor(@Host() private layer: LayerVectorComponent, private itemService: ItemService, @Host() private map: MapComponent, private itemTypeService: ItemTypeService,private featureIconService$:FeatureIconService) { super(layer); @@ -58,14 +59,14 @@ export class ItemVectorSourceComponent extends SourceVectorComponent implements this.format = new GeoJSON(); this._select = new Select({ style: (feature) => { - return this.styleCache['selected']; + return this.stylesCache['selected']; }, hitTolerance: 10, layers: [this.layer.instance as Layer] }); this._hoverSelect = new Select({ style: (feature) => { - return this.styleCache['selected']; + return this.stylesCache['selected']; }, hitTolerance: 10, condition: (e: MapBrowserEvent) => { @@ -87,12 +88,12 @@ export class ItemVectorSourceComponent extends SourceVectorComponent implements this.host.instance.setStyle((feature) => { var key = feature.get('itemType') + (this.selectedItem?"_I":""); - if (!this.styleCache[key]) { + if (!this.stylesCache[key]) { if (this.itemTypeService.itemTypes[key]) { let itemType = this.itemTypeService.itemTypes[key]; let fillColor = color.asArray(itemType.iconColor); fillColor[3] = this.selectedItem?0:0.5; - this.styleCache[key] = new style.Style({ + this.stylesCache[key] = new style.Style({ image: itemType.icon ? new style.Icon({ anchor: [0.5, 1], scale: 0.05, @@ -105,13 +106,13 @@ export class ItemVectorSourceComponent extends SourceVectorComponent implements fill: new style.Fill({ color: fillColor }), + geometry:(feature) => this.geometry(feature) }); } else { key = 'file'; } } - var styleEntry = this.styleCache[key]; - styleEntry.geometry = (feature) => this.geometry(feature); + var styleEntry = this.stylesCache[key]; return styleEntry; }); } @@ -142,5 +143,17 @@ export class ItemVectorSourceComponent extends SourceVectorComponent implements this.map.instance.addInteraction(this._hoverSelect); } } + if (changes["styles"] && this.instance) { + let styles = changes["styles"].currentValue; + for (const key in styles) { + if (styles.hasOwnProperty(key)) { + let style = styles[key]; + if(style.geometry == null) { + style.setGeometry((feature) => this.geometry(feature)); + } + this.stylesCache[key]=style; + } + } + } } } diff --git a/projects/common-map/src/fm-map/components/map/map.component.html b/projects/common-map/src/fm-map/components/map/map.component.html index fa08752..36993d1 100644 --- a/projects/common-map/src/fm-map/components/map/map.component.html +++ b/projects/common-map/src/fm-map/components/map/map.component.html @@ -16,7 +16,8 @@ searchCollapsed:searchCollapsed$|async, clearEnabled:clearEnabled$|async, period:period$|async, - compassHeading:compassHeading$|async + compassHeading:compassHeading$|async, + styles:styles$|async } as state">
@@ -32,7 +33,7 @@ - +
diff --git a/projects/common-map/src/fm-map/components/map/map.component.ts b/projects/common-map/src/fm-map/components/map/map.component.ts index 985f254..b95024b 100644 --- a/projects/common-map/src/fm-map/components/map/map.component.ts +++ b/projects/common-map/src/fm-map/components/map/map.component.ts @@ -14,6 +14,7 @@ import { ISelectedFeatures } from '../../models/selected.features'; import { IItemLayer } from '../../models/item.layer'; import { IQueryState } from '../../models/query.state'; import { IPeriodState } from '../../models/period.state'; +import {IStyles} from '../../models/style.cache'; import { IDroppedFile } from '../aol/file-drop-target/file-drop-target.component'; import { IMetaData } from '../meta-data-modal/meta-data-modal.component'; import { StateSerializerService } from '../../services/state-serializer.service'; @@ -74,6 +75,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit { public baseLayersCollapsed:boolean = true; public overlayLayersCollapsed: boolean = true; public extent$: Observable; + public styles$:Observable; @ViewChild('map', { static: false }) map; constructor(private store: Store, @@ -146,6 +148,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit { this.period$ = this.store.select(mapReducers.selectGetPeriod); this.position$ = this.geolocationService.getCurrentPosition(); this.compassHeading$ = this.deviceorientationService.getCurrentCompassHeading(); + this.styles$ = this.store.select(mapReducers.selectGetStyles); this.mapState$.pipe(withLatestFrom(this.queryState$)).subscribe((state) => { this.replaceUrl(state[0], state[1], true); diff --git a/projects/common-map/src/fm-map/models/style.cache.ts b/projects/common-map/src/fm-map/models/style.cache.ts index 96e5b9c..babd726 100644 --- a/projects/common-map/src/fm-map/models/style.cache.ts +++ b/projects/common-map/src/fm-map/models/style.cache.ts @@ -1,5 +1,5 @@ import {Style} from 'ol'; -export interface IStyleCache{ +export interface IStyles{ [id: string]: Style; }; \ No newline at end of file diff --git a/projects/common-map/src/fm-map/reducers/map.reducer.ts b/projects/common-map/src/fm-map/reducers/map.reducer.ts index 6641f22..f982ef0 100644 --- a/projects/common-map/src/fm-map/reducers/map.reducer.ts +++ b/projects/common-map/src/fm-map/reducers/map.reducer.ts @@ -4,7 +4,7 @@ import { IItemLayer,ItemLayer} from '../models/item.layer'; import { IMapState} from '../models/map.state'; import { IQueryState} from '../models/query.state'; import { IPeriodState} from '../models/period.state'; -import { IStyleCache} from '../models/style.cache'; +import { IStyles} from '../models/style.cache'; import * as mapActions from '../actions/map.actions'; import {commonActions} from '@farmmaps/common'; import { createSelector, createFeatureSelector } from '@ngrx/store'; @@ -53,7 +53,7 @@ export interface State { projection: string, selectedBaseLayer: IItemLayer, selectedOverlayLayer: IItemLayer, - styleCache:IStyleCache + styles:IStyles } export const initialState: State = { @@ -87,7 +87,7 @@ export const initialState: State = { selectedBaseLayer: null, selectedOverlayLayer: null, selectedItemLayer: null, - styleCache: {} + styles: {} } export function reducer(state = initialState, action: mapActions.Actions | commonActions.Actions | RouterNavigationAction): State { @@ -315,9 +315,9 @@ export function reducer(state = initialState, action: mapActions.Actions | commo } case mapActions.SETSTYLE:{ let a = action as mapActions.SetStyle; - let styles = state.styleCache; + let styles = tassign(state.styles); styles[a.itemType] = a.style; - return tassign(state,{styleCache:styles}); + return tassign(state,{styles:styles}); } default: { return state; @@ -345,6 +345,7 @@ export const getSelectedOverlayLayer = (state: State) => state.selectedOverlayLa export const getQuery = (state: State) => state.query; export const getSelectedItemLayer = (state: State) => state.selectedItemLayer; export const getPeriod = (state:State) => state.period; +export const getStyles = (state:State) => state.styles; export const selectMapState = createFeatureSelector(MODULE_NAME); export const selectGetMapState= createSelector(selectMapState, getMapState); @@ -367,5 +368,6 @@ export const selectGetSelectedOverlayLayer = createSelector(selectMapState, getS export const selectGetQuery = createSelector(selectMapState, getQuery); export const selectGetSelectedItemLayer = createSelector(selectMapState, getSelectedItemLayer); export const selectGetPeriod = createSelector(selectMapState, getPeriod); +export const selectGetStyles = createSelector(selectMapState, getStyles); From 252ce855c93297c6ce038697345b9633ce54debe Mon Sep 17 00:00:00 2001 From: Willem Dantuma Date: Wed, 12 Feb 2020 21:34:11 +0100 Subject: [PATCH 3/3] Add id4AuthconfigFactory --- src/app/app.module.ts | 1 + src/app/id4AuthconfigFactory.ts | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/app/id4AuthconfigFactory.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9a5b5d9..b5fc7c0 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -21,6 +21,7 @@ import { MenuComponent } from './menu/menu.component'; import {RegisterDeviceComponent} from './registerdevice/registerdevice.component'; import { SecureOAuthStorage} from '@farmmaps/common'; import { OAuthStorage } from 'angular-oauth2-oidc'; +import {Id4AuthconfigFactory} from './id4AuthconfigFactory'; export const BOOTSTRAP_EFFECTS = new InjectionToken('Bootstrap Effects'); diff --git a/src/app/id4AuthconfigFactory.ts b/src/app/id4AuthconfigFactory.ts new file mode 100644 index 0000000..e9776e4 --- /dev/null +++ b/src/app/id4AuthconfigFactory.ts @@ -0,0 +1,21 @@ +import { IAuthconfigFactory, AppConfig } from '@farmmaps/common'; +import { AuthConfig } from 'angular-oauth2-oidc'; + +export class Id4AuthconfigFactory implements IAuthconfigFactory { + constructor() { + + } + + getAuthConfig(appConfig: AppConfig): AuthConfig { + let authConfig: AuthConfig = new AuthConfig(); + authConfig.issuer = appConfig.getConfig("issuer"); + authConfig.redirectUri = window.location.origin + "/cb"; + authConfig.clientId = appConfig.getConfig("clientId"); + authConfig.customQueryParams = { audience: appConfig.getConfig("audience") }; + authConfig.scope = "api offline_access"; + authConfig.disableAtHashCheck = true; + authConfig.responseType = "code"; + authConfig.requireHttps = appConfig.getConfig("requireHttps"); + return authConfig; + } +}