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, Geometry } from 'ol/geom'; import { MapBrowserEvent } from 'ol'; import { Types } from 'ol/MapBrowserEventType'; 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, Source } from 'ol/source'; import { Layer } from 'ol/layer'; import { GeoJSON } from 'ol/format'; import { Select } from 'ol/interaction'; import { IStyles } 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 = 0.05; @Input() features: Array>; @Input() selectedFeature: Feature; @Input() selectedItem: IItem; @Input() styles: IStyles; @Output() onFeatureSelected: EventEmitter> = new EventEmitter>(); @Output() onFeatureHover: EventEmitter> = new EventEmitter>(); private stylesCache: IStyles = {}; constructor(@Host() private layer: LayerVectorComponent, private itemService: ItemService, private map: MapComponent, private itemTypeService: ItemTypeService, private featureIconService$: FeatureIconService) { super(layer); this._format = new GeoJSON(); } geometry(feature: Feature) { const view = this.map.instance.getView(); const resolution = view.getResolution(); let geometry = feature.getGeometry(); const 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; } getSelectedStyle(feature: Feature): style.Style { const key = feature.get('itemType') + "_selected"; let evaluatedStyle: style.Style = undefined; const styleEntry = this.stylesCache[key]; if (styleEntry) { if (typeof styleEntry === 'function') { evaluatedStyle = styleEntry(feature); } else { evaluatedStyle = styleEntry; } } else { evaluatedStyle = this.stylesCache["selected"] as style.Style; } if (evaluatedStyle) { evaluatedStyle.setGeometry((feature: Feature) => this.geometry(feature)); } return evaluatedStyle as style.Style } ngOnInit() { this.strategy = loadingstrategy.bbox; this.format = new GeoJSON(); this._select = new Select({ style: null, hitTolerance: 10, layers: [this.layer.instance as Layer] }); this._hoverSelect = new Select({ style: (feature: Feature) => { return this.getSelectedStyle(feature); }, 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.onFeatureSelected.emit(e.selected[0]); } else { this.onFeatureSelected.emit(null); } }); this._hoverSelect.on('select', (e) => { if (e.selected.length > 0 && e.selected[0]) { this.onFeatureHover.emit(e.selected[0]); } else { this.onFeatureHover.emit(null); } }); this.instance = new Vector(this); this.host.instance.setSource(this.instance); this.host.instance.setStyle((feature) => { const itemType = feature.get('itemType'); let key = itemType + (this.selectedItem ? "_I" : ""); if (!this.stylesCache[key]) { if (this.itemTypeService.itemTypes[itemType]) { const itemTypeEntry = this.itemTypeService.itemTypes[itemType]; const fillColor = color.asArray(itemTypeEntry.iconColor); fillColor[3] = 0; this.stylesCache[key] = new style.Style({ image: itemTypeEntry.icon ? new style.Icon({ anchor: [0.5, 1], scale: 0.05, src: this.featureIconService$.getIconImageDataUrl(itemTypeEntry.icon) }) : null, stroke: new style.Stroke({ color: 'red', width: 1 }), fill: new style.Fill({ color: fillColor }), geometry: (feature: Feature) => this.geometry(feature) }); } else { key = 'file'; } } let evaluatedStyle = null; const styleEntry = this.stylesCache[key]; if (typeof styleEntry === 'function') { evaluatedStyle = styleEntry(feature); } else { evaluatedStyle = styleEntry; } if (evaluatedStyle && evaluatedStyle.geometry_ == null && !Array.isArray(evaluatedStyle)) { evaluatedStyle.setGeometry((feature) => this.geometry(feature)); } return evaluatedStyle; }); } 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) { const features = this._hoverSelect.getFeatures(); const 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) { const item = changes["selectedItem"].currentValue if (item) { this.map.instance.removeInteraction(this._hoverSelect); } else { this.map.instance.addInteraction(this._hoverSelect); } } if (changes["styles"]) { const styles = changes["styles"].currentValue; for (const key in styles) { if (styles.hasOwnProperty(key)) { this.stylesCache[key] = styles[key]; } } } } }