From d0892f4c57eba0feba2f5a2d406b0982d1c1f99a Mon Sep 17 00:00:00 2001 From: Fabian Jeglinski Date: Fri, 3 May 2019 17:02:53 +0200 Subject: [PATCH] improve color saving; improve property handling --- .../add-layer.component.ts | 6 +- src/app/app.module.ts | 10 +- src/app/map/map.component.html | 10 +- src/app/map/map.component.scss | 21 ++- src/app/map/map.component.ts | 133 +++++++++++------- src/app/models/RawLayer.ts | 63 +++++---- 6 files changed, 159 insertions(+), 84 deletions(-) diff --git a/src/app/add-layer-component/add-layer.component.ts b/src/app/add-layer-component/add-layer.component.ts index 99b3bca..0328539 100644 --- a/src/app/add-layer-component/add-layer.component.ts +++ b/src/app/add-layer-component/add-layer.component.ts @@ -36,7 +36,8 @@ export class AddLayerComponent { if (data) { this.formData.layerName = data.name; this.formData.layerData = data.data; - this.formData.color = Utils.rgbToHex(data.color[0],data.color[1],data.color[2]); + const colorRgb = data.getDefaultColor(); + this.formData.color = Utils.rgbToHex(colorRgb[0],colorRgb[1],colorRgb[2]); this.editMode = true; } } @@ -75,7 +76,8 @@ export class AddLayerComponent { } onSubmit() { - const rawLayer = new RawLayer(this.formData.layerName, this.formData.layerData, Utils.hexToRgba(this.formData.color)); + const rawLayer = new RawLayer(this.formData.layerName, this.formData.layerData); + rawLayer.saveDefaultColor(Utils.hexToRgba(this.formData.color)); this.close(rawLayer); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index fcfdb9f..1a99c54 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -8,7 +8,14 @@ import { LeafletMapComponent } from './leaflet-map/leaflet-map.component'; import {HttpClient, HttpClientModule} from "@angular/common/http"; import {FormsModule} from "@angular/forms"; import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; -import {MatCardModule, MatDialogModule, MatGridListModule, MatInputModule, MatToolbarModule} from "@angular/material"; +import { + MatCardModule, + MatDialogModule, + MatGridListModule, + MatInputModule, + MatTableModule, + MatToolbarModule +} from "@angular/material"; import {DragDropModule} from "@angular/cdk/drag-drop"; import { AddLayerComponent } from './add-layer-component/add-layer.component'; @@ -31,6 +38,7 @@ import { AddLayerComponent } from './add-layer-component/add-layer.component'; DragDropModule, MatInputModule, MatDialogModule, + MatTableModule, ], entryComponents: [ AddLayerComponent diff --git a/src/app/map/map.component.html b/src/app/map/map.component.html index 81eeb76..90c8198 100644 --- a/src/app/map/map.component.html +++ b/src/app/map/map.component.html @@ -22,8 +22,14 @@ Layer Properties -
- {{ currentFeatureInfo | json}} +
+ {{item.key}} +
+ {{item.value}} +
+ edit + delete +
diff --git a/src/app/map/map.component.scss b/src/app/map/map.component.scss index e421ac2..10159fa 100644 --- a/src/app/map/map.component.scss +++ b/src/app/map/map.component.scss @@ -38,8 +38,6 @@ } .layer-control-area { - - .layer-list { max-width: 100%; border: solid 1px #ccc; @@ -73,6 +71,25 @@ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } } + + .layer-property-area { + + .mat-card-content { + + .entry { + display: flex; + height: 3rem; + align-items: center; + margin: 0 0 .125rem 0; + border: 1px black solid; + padding: .5rem; + + .controls { + margin-left: auto; + } + } + } + } } .cdk-drag-preview { diff --git a/src/app/map/map.component.ts b/src/app/map/map.component.ts index 1d51692..6baa826 100644 --- a/src/app/map/map.component.ts +++ b/src/app/map/map.component.ts @@ -13,6 +13,10 @@ import LayerGroup from 'ol/layer/Group'; import {Collection} from "openlayers"; import {EPSG} from "../enums/EPSG"; import {inAndOut} from 'ol/easing'; +import {Feature} from 'ol/Feature'; +import Style from 'ol/style/Style'; +import Stroke from 'ol/style/Stroke'; +import Fill from 'ol/style/Fill'; /** * TODO: add description @@ -50,6 +54,35 @@ export class MapComponent implements OnInit { */ public currentFeatureInfo: any; + public propertyMockData = JSON.parse('{\n' + + '\t"FL": "345",\n' + + '\t"FLST_LABEL": "93\\/0",\n' + + '\t"FLAECHE_HA": 0.19303757998400001,\n' + + '\t"FBID": "DEHBEE0433450039",\n' + + '\t"FELDBL_NR": "043345-0039",\n' + + '\t"BESCHRIFT": "?",\n' + + '\t"NUTZER": "?",\n' + + '\t"TEILRAUM": "Blockland - Waller Feldmark",\n' + + '\t"BAUM17Code": "-",\n' + + '\t"B_AUM_2017": "-",\n' + + '\t"Parz_Code": "-",\n' + + '\t"Nutzung": "Grünland",\n' + + '\t"Nat_schutz": "-",\n' + + '\t"Gebiet": "Blockland",\n' + + '\t"Thema": "Informationen Agrarflächen",\n' + + '\t"Flurstck": "Flst. 345: 93\\/0"\n' + + '}'); + + /** + * A simple cache to save styles + */ + private styleCache: { [key: string]: Style } = {}; + + /** + * A simple feature cache + */ + private featureCache: { [key: string]: Feature } = {}; + constructor(public dialog: MatDialog) { } @@ -117,62 +150,64 @@ export class MapComponent implements OnInit { return; } const pixel = this.map.getEventPixel(evt.originalEvent); - this.displayFeatureInfo(pixel); + const features = this.map.getFeaturesAtPixel(pixel); + if (features && features.length > 0) { + this.displayFeatureInfo(features[0]); + this.highlightFeature(features[0]); + } else { + // reapply original style to last highlighted feature + if (this.featureCache['lastHighlighted']) { + this.featureCache['lastHighlighted'].setStyle(this.styleCache['lastHighlightedStyle']); + } + // reset cache for feature and style + this.featureCache['lastHighlighted'] = null; + this.styleCache['lastHighlightedStyle'] = null; + this.currentFeatureInfo = null; + } }); } /** - * Gets all feature infos for each feature at the given pixel. - * @param pixel + * Prepared feature properties and shows them + * @param features */ - private displayFeatureInfo(pixel) { - const features = []; - this.map.forEachFeatureAtPixel(pixel, (feature) => { - features.push(feature) - } - ); - - if (features.length == 0) { - this.currentFeatureInfo = 'Too many features. Please zoom in to see feature infos'; - } else if (features.length == 1) { - features.forEach(feature => { - const properties = feature.getProperties(); - delete properties.geometry; - this.currentFeatureInfo = properties; - }) - } else { - this.currentFeatureInfo = null; - } + private displayFeatureInfo(feature: Feature) { + const properties = feature.getProperties(); + delete properties.geometry; + this.currentFeatureInfo = properties; }; - // private colorPolygons(feature: Feature, resolution: any) { - // const styles = { - // black: new Style({ - // stroke: new Stroke({ - // color: '#86665a', - // width: 1 - // }), - // fill: new Fill({ - // color: 'rgba(121,85,72, 0.4)', - // }) - // }), - // green: new Style({ - // stroke: new Stroke({ - // color: '#b8c633', - // width: 1 - // }), - // fill: new Fill({ - // color: 'rgba(205,220,57,0.4)', - // }) - // }) - // } - // // console.log(feature.getProperties()['Grünland'],feature.getProperties()); - // if (feature.getProperties()['Nutzung'] === 'Grünland') { - // return styles.green; - // } else { - // return styles.black; - // } - // } + /** + * Highlights a Features + * @param feature + */ + private highlightFeature(feature: Feature) { + // init case + if (!this.styleCache['defaultHighlight']) { + this.styleCache['defaultHighlight'] = new Style({ + stroke: new Stroke({ + color: 'rgb(245, 64, 41)', + width: 2 + }), + fill: new Fill({ + color: 'rgba(245, 64, 41, 0.1)', + }) + }) + } + + // reapply saved feature and style + if (this.featureCache['lastHighlighted']) { + this.featureCache['lastHighlighted'].setStyle(this.styleCache['lastHighlightedStyle']); + } + // save current feature and style + this.featureCache['lastHighlighted'] = feature; + this.styleCache['lastHighlightedStyle'] = feature.getStyle(); + + // set new feature style + feature.setStyle(this.styleCache['defaultHighlight']); + } + + /** * Opens a dialog to create a new custom layer diff --git a/src/app/models/RawLayer.ts b/src/app/models/RawLayer.ts index bca6468..174454d 100644 --- a/src/app/models/RawLayer.ts +++ b/src/app/models/RawLayer.ts @@ -6,7 +6,7 @@ import Style from 'ol/style/Style'; import Stroke from 'ol/style/Stroke'; import Fill from 'ol/style/Fill'; import {Config} from "../misc/Config"; - +import {Feature} from 'ol/Feature'; /** * Represents a raw (not processed) map layer */ @@ -19,14 +19,8 @@ export class RawLayer { /** * Data of Layer (normally in geojson format) */ - public data: string, - /** - * Layer stroke color as number array with opacity like -> [255, 255, 255, 0.5] - * The fill color is an opaque decreased derivation of this value. - */ - public color: number[] + public data: string ) { - this.saveColorToGeoJSON(); } /** @@ -35,16 +29,10 @@ export class RawLayer { * @param layer */ public static fromVectorLayer(layer: VectorLayer): RawLayer { - const writer = new GeoJSON(); const source = layer.getSource(); - - // get default style values const features = source.getFeatures(); - const featureProperties = features[0].getProperties(); - const rawLayerColor = featureProperties[Config.GEO_JSON_PREFIX]['default-style-stroke']; - - const geoJSONString = writer.writeFeatures(features,{featureProjection: EPSG.openLayersDefault}); - return new RawLayer(layer.get('name'), geoJSONString, rawLayerColor); + const geoJSONString = RawLayer.featuresToGeoJSON(features); + return new RawLayer(layer.get('name'), geoJSONString); } /** @@ -53,10 +41,7 @@ export class RawLayer { */ public static toVectorLayer(rawLayer: RawLayer): VectorLayer { const vectorSource = new VectorSource(); - const geoJSON = new GeoJSON(); - // load geoJSON features from rawLayer - const features = geoJSON.readFeatures(rawLayer.data, {featureProjection: EPSG.openLayersDefault}); - + const features = RawLayer.geoJSONToFeatures(rawLayer.data); // apply style to all features features.forEach(feature => { // TODO @@ -87,20 +72,42 @@ export class RawLayer { } /** - * Adds the RawLayer color property to all feature properties from data attribute + * Saves a default color property to geoJSON */ - private saveColorToGeoJSON() { - const geoJSON = new GeoJSON(); - // load geoJSON features from rawLayer - const features = geoJSON.readFeatures(this.data, {featureProjection: EPSG.openLayersDefault}); + public saveDefaultColor(color: number[]) { + const features = RawLayer.geoJSONToFeatures(this.data); features.forEach(feature => { // save default color in feature properties const stylesToSave = {}; stylesToSave[Config.GEO_JSON_PREFIX] = {}; - stylesToSave[Config.GEO_JSON_PREFIX]['default-style-stroke'] = this.color; - stylesToSave[Config.GEO_JSON_PREFIX]['default-style-fill'] = [...this.color.slice(0, 3), 0.1]; + stylesToSave[Config.GEO_JSON_PREFIX]['default-style-stroke'] = color; + stylesToSave[Config.GEO_JSON_PREFIX]['default-style-fill'] = [...color.slice(0, 3), 0.1]; feature.setProperties(stylesToSave); }) - this.data = geoJSON.writeFeatures(features, {featureProjection: EPSG.openLayersDefault}); + this.data = RawLayer.featuresToGeoJSON(features); + } + + /** + * Reads the default color property from geoJSON + */ + public getDefaultColor(): number[]{ + const features = RawLayer.geoJSONToFeatures(this.data); + const featureProperties = features[0].getProperties(); + return featureProperties[Config.GEO_JSON_PREFIX]['default-style-stroke']; + } + + /** + * Creates the features from geoJSON + */ + private static geoJSONToFeatures(geoJSON: string): Feature[] { + return new GeoJSON().readFeatures(geoJSON, {featureProjection: EPSG.openLayersDefault}); + } + + /** + * Creates geoJSON string from features + * @param features + */ + private static featuresToGeoJSON(features: Feature[]): string { + return new GeoJSON().writeFeatures(features, {featureProjection: EPSG.openLayersDefault}); } }