diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1a99c54..2b7e565 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -18,13 +18,17 @@ import { } from "@angular/material"; import {DragDropModule} from "@angular/cdk/drag-drop"; import { AddLayerComponent } from './add-layer-component/add-layer.component'; +import {FeatureManagerComponent} from "./feature-management/feature-manager/feature-manager.component"; +import {CustomColorEntryComponent} from "./feature-management/custom-color-entry/custom-color-entry.component"; @NgModule({ declarations: [ AppComponent, MapComponent, LeafletMapComponent, - AddLayerComponent + AddLayerComponent, + FeatureManagerComponent, + CustomColorEntryComponent ], imports: [ BrowserModule, diff --git a/src/app/enums/CustomProperties.ts b/src/app/enums/CustomProperties.ts new file mode 100644 index 0000000..e492f7e --- /dev/null +++ b/src/app/enums/CustomProperties.ts @@ -0,0 +1,7 @@ +/** + * An enum that presents all custom property keys + */ +export enum CustomProperties { + DEFAULT_COLOR_STROKE = 'default-style-stroke', + DEFAULT_COLOR_FILL = 'default-style-fill' +} diff --git a/src/app/feature-management/custom-color-entry/custom-color-entry.component.html b/src/app/feature-management/custom-color-entry/custom-color-entry.component.html new file mode 100644 index 0000000..32abf4c --- /dev/null +++ b/src/app/feature-management/custom-color-entry/custom-color-entry.component.html @@ -0,0 +1,11 @@ +
+ Default Color: +
+
+ edit + delete +
+
diff --git a/src/app/feature-management/custom-color-entry/custom-color-entry.component.scss b/src/app/feature-management/custom-color-entry/custom-color-entry.component.scss new file mode 100644 index 0000000..c0b5861 --- /dev/null +++ b/src/app/feature-management/custom-color-entry/custom-color-entry.component.scss @@ -0,0 +1,19 @@ +.entry { + display: flex; + height: 3rem; + align-items: center; + margin: 0 0 .125rem 0; + border: 1px black solid; + padding: .5rem; + + .controls { + margin-left: auto; + } + + .color-preview { + margin-left: .5rem; + height: 2rem; + width: 2rem; + border: 2px solid; + } +} diff --git a/src/app/feature-management/custom-color-entry/custom-color-entry.component.ts b/src/app/feature-management/custom-color-entry/custom-color-entry.component.ts new file mode 100644 index 0000000..9cfa383 --- /dev/null +++ b/src/app/feature-management/custom-color-entry/custom-color-entry.component.ts @@ -0,0 +1,47 @@ +import {Component, EventEmitter, Input, Output} from "@angular/core"; +import {CustomProperties} from "../../enums/CustomProperties"; +import {Utils} from "../../misc/Utils"; + +/** + * This component represents an entry of the custom properties section inside the feature management and + * is responsible to show and makes changes to the color property. + */ +@Component({ + selector: 'lm-custom-color-entry', + templateUrl: 'custom-color-entry.component.html', + styleUrls: ['custom-color-entry.component.scss'] +}) +export class CustomColorEntryComponent { + + + _colors: any; + @Input() set colors(value: any) { + this._colors = value; + } + + get colors(): any { + return this._colors; + } + + get strokeColor(): number[] { + return this.colors[CustomProperties.DEFAULT_COLOR_STROKE]; + } + + get strokeColorAsRgba(): string { + return Utils.colorArrayToRgba(this.strokeColor); + } + + get fillColor(): number[] { + return this.colors[CustomProperties.DEFAULT_COLOR_FILL]; + } + + get fillColorAsRgba(): string { + return Utils.colorArrayToRgba(this.fillColor); + } + + @Output('colorChanged') colorChangeEmitter: EventEmitter = new EventEmitter(); + + startEditDialog() { + this.colorChangeEmitter.emit(this.colors); + } +} diff --git a/src/app/feature-management/feature-manager/feature-manager.component.html b/src/app/feature-management/feature-manager/feature-manager.component.html new file mode 100644 index 0000000..a17173e --- /dev/null +++ b/src/app/feature-management/feature-manager/feature-manager.component.html @@ -0,0 +1,28 @@ +
+
+

Properties

+
+
+ {{item.key}} +
+ {{item.value}} +
+ edit + delete +
+
+
+

Custom Properties

+
+ + + + + + + + + + +
diff --git a/src/app/feature-management/feature-manager/feature-manager.component.scss b/src/app/feature-management/feature-manager/feature-manager.component.scss new file mode 100644 index 0000000..db6e094 --- /dev/null +++ b/src/app/feature-management/feature-manager/feature-manager.component.scss @@ -0,0 +1,17 @@ +.header, +.entry { + display: flex; + height: 3rem; + align-items: center; + margin: 0 0 .125rem 0; + border: 1px black solid; + padding: .5rem; + + .controls { + margin-left: auto; + } +} + +.header{ + background-color: whitesmoke; +} diff --git a/src/app/feature-management/feature-manager/feature-manager.component.ts b/src/app/feature-management/feature-manager/feature-manager.component.ts new file mode 100644 index 0000000..9a36a5e --- /dev/null +++ b/src/app/feature-management/feature-manager/feature-manager.component.ts @@ -0,0 +1,66 @@ +import {Component, Input} from "@angular/core"; +// import {Feature} from 'ol/Feature'; +import {Config} from "../../misc/Config"; +import {CustomProperties} from "../../enums/CustomProperties"; +import {Feature} from 'ol/Feature'; + +/** + * This component manages all properties of the current feature. It does not matter if it is a simple geo json + * property or a custom property (custom properties are special properties that are just understand by life map + * like color of the feature). All changes that were made to the properties are saved in the geo json of + * the RawLayer object from which the open layer feature based. + */ +@Component({ + selector: 'lm-feature-manager', + templateUrl: 'feature-manager.component.html', + styleUrls: ['feature-manager.component.scss'] +}) +export class FeatureManagerComponent { + + /** + * The feature that is selected to manage + */ + private _curFeature: Feature; + @Input() set curFeature(value: Feature) { + this._curFeature = value; + } + + get curFeature(): Feature { + return this._curFeature; + } + + /** + * Returns the properties of curFeature + */ + get curProperties(): any { + const properties = this.curFeature.getProperties(); + delete properties.geometry; + delete properties[Config.GEO_JSON_PREFIX]; + return properties; + + } + + /** + * Returns the custom properties of curFeature + */ + get curCustomProperties(): any { + const properties = this.curFeature.getProperties(); + return properties[Config.GEO_JSON_PREFIX]; + + } + + /** + * Returns the default color properties of the current feature + */ + get curCustomDefaultColor(): any { + const colors = {}; + colors[CustomProperties.DEFAULT_COLOR_STROKE] = this.curCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE]; + colors[CustomProperties.DEFAULT_COLOR_FILL] = this.curCustomProperties[CustomProperties.DEFAULT_COLOR_FILL]; + return colors; + } + + defaultColorChanged(colors: any) { + console.log('Default colors changed!', colors); + } +} + diff --git a/src/app/map/map.component.html b/src/app/map/map.component.html index 90c8198..9747b83 100644 --- a/src/app/map/map.component.html +++ b/src/app/map/map.component.html @@ -16,21 +16,13 @@ -
+
Layer Properties -
- {{item.key}} -
- {{item.value}} -
- edit - delete -
-
+
diff --git a/src/app/map/map.component.scss b/src/app/map/map.component.scss index 10159fa..a863ddd 100644 --- a/src/app/map/map.component.scss +++ b/src/app/map/map.component.scss @@ -71,25 +71,6 @@ 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 c8d912b..62dd618 100644 --- a/src/app/map/map.component.ts +++ b/src/app/map/map.component.ts @@ -17,6 +17,7 @@ import {Feature} from 'ol/Feature'; import Style from 'ol/style/Style'; import Stroke from 'ol/style/Stroke'; import Fill from 'ol/style/Fill'; +import {FeatureManagerComponent} from "../feature-management/feature-manager/feature-manager.component"; /** * TODO: add description @@ -29,6 +30,7 @@ import Fill from 'ol/style/Fill'; export class MapComponent implements OnInit { @ViewChild('mapContainer') mapContainer: ElementRef; + @ViewChild(FeatureManagerComponent) featureManager: FeatureManagerComponent; public map: Map; public baseLayer: TileLayer; @@ -49,15 +51,10 @@ export class MapComponent implements OnInit { */ public cursorCoordinates: string; - /** - * The properties of the current feature. The current layer is the layer beneath the cursor. - */ - public currentFeatureInfo: any; - /** * A simple cache that holds different Features and styles */ - private cache : { [key: string]: Feature | Style } = { + private cache: { [key: string]: Feature | Style } = { /** * Contains the feature that is currently selected */ @@ -76,12 +73,12 @@ export class MapComponent implements OnInit { /** * Default style for selected feature */ - defaultSelectedStyle : null, + defaultSelectedStyle: null, /** * Default style for a highlighted feauture */ - defaultHighlightStyle:null + defaultHighlightStyle: null }; @@ -157,7 +154,7 @@ export class MapComponent implements OnInit { const features = this.map.getFeaturesAtPixel(pixel); if (features && features.length > 0) { this.map.getTargetElement().style.cursor = 'pointer'; - this.displayFeatureInfo(features[0]); + this.featureManager.curFeature = features[0]; this.highlightFeature(features[0]); } else { this.map.getTargetElement().style.cursor = ''; @@ -168,7 +165,7 @@ export class MapComponent implements OnInit { // reset cache for feature and style this.cache.lastHighlightedFeature = null; this.cache.lastHighlightedStyle = null; - this.currentFeatureInfo = null; + this.featureManager.curFeature = null; } }); @@ -177,31 +174,21 @@ export class MapComponent implements OnInit { const pixel = this.map.getEventPixel(evt.originalEvent); const features = this.map.getFeaturesAtPixel(pixel); - if (this.cache.selectedFeature) { - // use lastHighlightedStyle because the original style is saved there - this.cache.selectedFeature.setStyle(this.cache.lastHighlightedStyle); - // this.styleCache['lastHighlightedStyle'] = null; - this.cache.selectedFeature = null; - } else if (features && features.length > 0) { - this.map.getTargetElement().style.cursor = ''; - this.displayFeatureInfo(features[0]); - this.cache.selectedFeature = features[0]; - this.cache.lastHighlightedFeature = null; - features[0].setStyle(this.cache.defaultSelectedStyle); - } + if (this.cache.selectedFeature) { + // use lastHighlightedStyle because the original style is saved there + this.cache.selectedFeature.setStyle(this.cache.lastHighlightedStyle); + // this.styleCache['lastHighlightedStyle'] = null; + this.cache.selectedFeature = null; + } else if (features && features.length > 0) { + this.map.getTargetElement().style.cursor = ''; + this.featureManager.curFeature = features[0]; + this.cache.selectedFeature = features[0]; + this.cache.lastHighlightedFeature = null; + features[0].setStyle(this.cache.defaultSelectedStyle); + } }); } - /** - * Prepared feature properties and shows them - * @param features - */ - private displayFeatureInfo(feature: Feature) { - const properties = feature.getProperties(); - delete properties.geometry; - this.currentFeatureInfo = properties; - }; - /** * Highlights a Features * @param feature @@ -416,7 +403,7 @@ export class MapComponent implements OnInit { ] }; const rawLayer = new RawLayer('Mock Data Layer', JSON.stringify(data)); - rawLayer.saveDefaultColor([125,125,125]) + rawLayer.saveDefaultColor([125, 125, 125]) const customLayer = RawLayer.toVectorLayer(rawLayer); this.centerLayerOnMap(customLayer); this.customLayerCollection.push(customLayer); diff --git a/src/app/misc/Config.ts b/src/app/misc/Config.ts index 01c991d..af47bf3 100644 --- a/src/app/misc/Config.ts +++ b/src/app/misc/Config.ts @@ -1,3 +1,4 @@ export class Config{ - static readonly GEO_JSON_PREFIX: string = 'GANE'; + static readonly GEO_JSON_PREFIX: string = 'LM'; + static readonly DEFAULT_FILL_OPACITY_TO_STROKE: number = 0.1; } diff --git a/src/app/misc/Utils.ts b/src/app/misc/Utils.ts index f789883..65a6c84 100644 --- a/src/app/misc/Utils.ts +++ b/src/app/misc/Utils.ts @@ -25,4 +25,20 @@ export class Utils { opacity ] : null; } + + public static colorArrayToRgba(colors: number[]): string{ + let tmp = 'rgba('; + for(let i = 0; i < 4; i++){ + const color = colors[i]; + if(color){ + tmp+= color+','; + }else { + tmp += '1'; + } + } + // remove last comma + tmp = tmp.replace(/,\s*$/, ""); + tmp += ')'; + return tmp; + } } diff --git a/src/app/models/RawLayer.ts b/src/app/models/RawLayer.ts index 132572f..b36dfbd 100644 --- a/src/app/models/RawLayer.ts +++ b/src/app/models/RawLayer.ts @@ -7,6 +7,7 @@ import Stroke from 'ol/style/Stroke'; import Fill from 'ol/style/Fill'; import {Config} from "../misc/Config"; import {Feature} from 'ol/Feature'; +import {CustomProperties} from "../enums/CustomProperties"; /** * Represents a raw (not processed) map layer @@ -51,11 +52,11 @@ export class RawLayer { if (featureCustomProperties && featureCustomProperties['default-style-stroke']) { feature.setStyle(new Style({ stroke: new Stroke({ - color: featureCustomProperties['default-style-stroke'], + color: featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE], width: 1 }), fill: new Fill({ - color: featureCustomProperties['default-style-fill'] + color: featureCustomProperties[CustomProperties.DEFAULT_COLOR_FILL] }) })); } @@ -78,10 +79,9 @@ export class RawLayer { const features = RawLayer.geoJSONToFeatures(this.data); features.forEach(feature => { // save default color in feature properties - const properties = { - 'default-style-stroke': color, - 'default-style-fill': [...color.slice(0, 3), 0.1] - }; + const properties = {}; + properties[CustomProperties.DEFAULT_COLOR_STROKE] = color; + properties[CustomProperties.DEFAULT_COLOR_FILL] = [...color.slice(0, 3), Config.DEFAULT_FILL_OPACITY_TO_STROKE]; RawLayer.saveCustomProperties(feature, properties); }) this.data = RawLayer.featuresToGeoJSON(features); @@ -93,8 +93,8 @@ export class RawLayer { public getDefaultColor(): number[] { const features = RawLayer.geoJSONToFeatures(this.data); const featureCustomProperties = RawLayer.getCustomProperties(features[0]); - if (featureCustomProperties && featureCustomProperties['default-style-stroke']) { - return featureCustomProperties['default-style-stroke']; + if (featureCustomProperties && featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE]) { + return featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE]; } return null; }