several bugfixes; apply color change to rawlayer and vectorlayer; enable color reset

This commit is contained in:
Fabian Jeglinski
2019-05-24 17:27:38 +02:00
parent 5d75f023ad
commit 240d0c9997
6 changed files with 211 additions and 135 deletions
@@ -9,7 +9,7 @@
cpOutputFormat="hex"
[cpOKButton]="true"
[cpCancelButton]="true"
(colorPickerSelect)="selectedColor = $event"
(colorPickerSelect)="onColorPicked($event)"
>edit</i>
<i *ngIf="!isDefaultColor" class="material-icons" (click)="resetColor()">delete</i>
</div>
@@ -1,11 +1,11 @@
import {Component, EventEmitter, Input, OnInit, Output} from "@angular/core";
import {CustomProperties} from "../../enums/CustomProperties";
import {Utils} from "../../misc/Utils";
import {Config} from "../../misc/Config";
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {CustomProperties} from '../../enums/CustomProperties';
import {Utils} from '../../misc/Utils';
import {Config} from '../../misc/Config';
/**
* 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.
* is responsible to show and makes changes to the color properties.
*/
@Component({
selector: 'lm-custom-color-entry',
@@ -14,16 +14,28 @@ import {Config} from "../../misc/Config";
})
export class CustomColorEntryComponent implements OnInit {
@Input() colors: any;
private _colors: any;
@Input() set colors(value: any) {
this._colors = value;
if (this._colors[CustomProperties.COLOR_STROKE]) {
this.isDefaultColor = false;
this.definePreviewStyle();
}
}
private _selectedColor: any;
set selectedColor(value: any) {
get colors(): any {
return this._colors;
}
private _selectedColor: string;
set selectedColor(value: string) {
this._selectedColor = value;
this.applyColor(value);
this.colorChangeEmitter.emit(this.colors);
}
get selectedColor() :any{
get selectedColor(): string {
return this._selectedColor;
}
@@ -39,7 +51,7 @@ export class CustomColorEntryComponent implements OnInit{
return Utils.colorArrayToRgba(color);
}
// - not default color properties
// - no default color properties
get strokeColorAsRgba(): string {
const color = this.colors[CustomProperties.COLOR_STROKE];
return Utils.colorArrayToRgba(color);
@@ -50,7 +62,6 @@ export class CustomColorEntryComponent implements OnInit{
return Utils.colorArrayToRgba(color);
}
@Output('colorChanged') colorChangeEmitter: EventEmitter<any> = new EventEmitter();
/**
@@ -61,7 +72,7 @@ export class CustomColorEntryComponent implements OnInit{
/**
* A simple flag that is true, if the default color is active
*/
isDefaultColor : boolean;
isDefaultColor: boolean = true;
ngOnInit() {
this.definePreviewStyle();
@@ -71,18 +82,16 @@ export class CustomColorEntryComponent implements OnInit{
* Returns the style for the preview. If a color was defined, this color is used. If not, the default color is used
* instead.
*/
definePreviewStyle(): any {
definePreviewStyle() {
let styles = {
'border-color': this.defaultStrokeColorAsRgba,
'background-color': this.defaultFillColorAsRgba
};
this.isDefaultColor = true;
if (this.selectedColor) {
if (!this.isDefaultColor) {
styles = {
'border-color': this.strokeColorAsRgba,
'background-color': this.fillColorAsRgba
};
this.isDefaultColor = false;
}
this.previewStyle = styles;
}
@@ -91,20 +100,30 @@ export class CustomColorEntryComponent implements OnInit{
* Saves the given hex value to colors object as not default color
* @param value
*/
applyColor(value: any) {
applyColor(value: string) {
this.colors[CustomProperties.COLOR_STROKE] = Utils.hexToRgba(value);
this.colors[CustomProperties.COLOR_FILL] = Utils.hexToRgba(value, Config.DEFAULT_FILL_OPACITY_TO_STROKE);
this.definePreviewStyle();
}
/**
* TODO add description
* Resets the custom color
*/
resetColor() {
this.colors[CustomProperties.COLOR_STROKE] = null;
this.colors[CustomProperties.COLOR_FILL] = null;
this.isDefaultColor = true;
this._selectedColor = null;
this.definePreviewStyle();
this.colorChangeEmitter.emit(this.colors);
}
/**
* Eventhandler that is fired when a color is picked
* @param event
*/
onColorPicked(color: string) {
this.selectedColor = color;
this.isDefaultColor = false;
}
}
@@ -23,8 +23,8 @@
<!-- <i class="material-icons">delete</i>-->
<!-- </div>-->
<!--</div>-->
<lm-custom-color-entry [colors]="curCustomDefaultColor"
(colorChanged)="defaultColorChanged($event)"></lm-custom-color-entry>
<lm-custom-color-entry [colors]="curFeatureColors"
(colorChanged)="onFeatureColorChanged($event)"></lm-custom-color-entry>
<div class="button-container">
<button>Abbrechen</button>
<button>Speichern</button>
@@ -1,8 +1,8 @@
import {Component, Input} from "@angular/core";
// import {Feature} from 'ol/Feature';
import {Config} from "../../misc/Config";
import {CustomProperties} from "../../enums/CustomProperties";
import {Component, Input, Output, EventEmitter} from '@angular/core';
import {Config} from '../../misc/Config';
import {CustomProperties} from '../../enums/CustomProperties';
import {Feature} from 'ol/Feature';
import {RawLayer} from 'src/app/models/RawLayer';
/**
* This component manages all properties of the current feature. It does not matter if it is a simple geo json
@@ -29,6 +29,11 @@ export class FeatureManagerComponent {
return this._curFeature;
}
/**
* An event emitter that is fired if a feature is changed,
*/
@Output('featureChange') featureChangeEmitter: EventEmitter<Feature> = new EventEmitter();
/**
* Returns the properties of curFeature
*/
@@ -37,7 +42,6 @@ export class FeatureManagerComponent {
delete properties.geometry;
delete properties[Config.GEO_JSON_PREFIX];
return properties;
}
/**
@@ -46,13 +50,12 @@ export class FeatureManagerComponent {
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 {
get curFeatureColors(): 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];
@@ -61,8 +64,14 @@ export class FeatureManagerComponent {
return colors;
}
defaultColorChanged(colors: any) {
console.log('Default colors changed!', colors);
/**
* Event handler if the color set of a feature was changed
* @param colors
*/
onFeatureColorChanged(colors: any) {
RawLayer.saveCustomProperties(this.curFeature, colors);
this.curFeature.setStyle(RawLayer.determineColorStyle(colors));
this.featureChangeEmitter.emit(this.curFeature);
}
}
+84 -56
View File
@@ -5,19 +5,19 @@ import TileLayer from 'ol/layer/Tile';
import {fromLonLat, transform} from 'ol/proj';
import VectorLayer from 'ol/layer/Vector';
import {OSM} from 'ol/source';
import {CdkDragDrop} from "@angular/cdk/drag-drop";
import {MatDialog} from "@angular/material";
import {AddLayerComponent} from "../add-layer-component/add-layer.component";
import {RawLayer} from "../models/RawLayer";
import {CdkDragDrop} from '@angular/cdk/drag-drop';
import {MatDialog} from '@angular/material';
import {AddLayerComponent} from '../add-layer-component/add-layer.component';
import {RawLayer} from '../models/RawLayer';
import LayerGroup from 'ol/layer/Group';
import {Collection} from "openlayers";
import {EPSG} from "../enums/EPSG";
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';
import {FeatureManagerComponent} from "../feature-management/feature-manager/feature-manager.component";
import {FeatureManagerComponent} from '../feature-management/feature-manager/feature-manager.component';
/**
* TODO: add description
@@ -60,6 +60,11 @@ export class MapComponent implements OnInit {
*/
selectedFeature: null,
// /**
// * The layer of the selected feature
// */
// selectedLayer: null,
/**
* The feature that was highlighted at least
*/
@@ -76,7 +81,7 @@ export class MapComponent implements OnInit {
defaultSelectedStyle: null,
/**
* Default style for a highlighted feauture
* Default style for a highlighted feature
*/
defaultHighlightStyle: null
};
@@ -127,18 +132,18 @@ export class MapComponent implements OnInit {
})
});
this.addMapEventlistener();
this.addMapEventListener();
this.addFeatureManagerEventListener();
// without this line the map is only visible after resizing window
requestAnimationFrame(() => {
this.map.updateSize();
})
});
}
/**
* Adds all map event listener
*/
private addMapEventlistener() {
private addMapEventListener() {
// get current cursor coordinates to transform and display them
this.map.on('pointermove', (evt) => {
const tmpCoords = transform(evt.coordinate, EPSG.openLayersDefault, EPSG.wgs84);
@@ -152,6 +157,7 @@ export class MapComponent implements OnInit {
}
const pixel = this.map.getEventPixel(evt.originalEvent);
const features = this.map.getFeaturesAtPixel(pixel);
if (features && features.length > 0) {
this.map.getTargetElement().style.cursor = 'pointer';
this.featureManager.curFeature = features[0];
@@ -172,20 +178,42 @@ export class MapComponent implements OnInit {
// handle feature selection
this.map.on('click', (evt) => {
const pixel = this.map.getEventPixel(evt.originalEvent);
const features = this.map.getFeaturesAtPixel(pixel);
// const features = this.map.getFeaturesAtPixel(pixel);
let selectedFeature;
// let selectedLayer;
// get the feature and the according layer
this.map.forEachFeatureAtPixel(pixel, (feature, layer) => {
selectedFeature = feature;
// selectedLayer = layer;
return true;
});
if (this.cache.selectedFeature) {
// use lastHighlightedStyle because the original style is saved there
if (this.cache.lastHighlightedStyle) {
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);
}
this.cache.selectedFeature = null;
// this.cache.selectedLayer = null;
} else if (selectedFeature) {
this.map.getTargetElement().style.cursor = '';
this.cache.selectedFeature = selectedFeature;
// this.cache.selectedLayer = selectedLayer;
this.featureManager.curFeature = this.cache.selectedFeature;
this.cache.lastHighlightedFeature = null;
this.cache.selectedFeature.setStyle(this.cache.defaultSelectedStyle);
}
});
}
/**
* Adds all feature manager event listener
*/
private addFeatureManagerEventListener() {
this.featureManager.featureChangeEmitter.subscribe(() => {
// - reset selection values
// this.cache.selectedFeature = null;
this.cache.lastHighlightedStyle = null;
});
}
@@ -282,7 +310,7 @@ export class MapComponent implements OnInit {
size: this.map.getSize(),
duration: 888,
easing: inAndOut
}
};
this.map.getView().fit(customLayer.getSource().getExtent(), options);
}
@@ -298,7 +326,7 @@ export class MapComponent implements OnInit {
fill: new Fill({
color: 'rgba(245, 64, 41, 0.3)',
})
})
});
this.cache.defaultHighlightStyle = new Style({
stroke: new Stroke({
@@ -308,7 +336,7 @@ export class MapComponent implements OnInit {
fill: new Fill({
color: 'rgba(245, 64, 41, 0.1)',
})
})
});
}
/**
@@ -316,22 +344,22 @@ export class MapComponent implements OnInit {
*/
private addMockData() {
const data = {
"type": "FeatureCollection",
"name": "background",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
'type': 'FeatureCollection',
'name': 'background',
'crs': {
'type': 'name',
'properties': {
'name': 'urn:ogc:def:crs:OGC:1.3:CRS84'
}
},
"features": [{
"type": "Feature",
"properties": {
"name": "Layer 1"
'features': [{
'type': 'Feature',
'properties': {
'name': 'Layer 1'
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
'geometry': {
'type': 'MultiPolygon',
'coordinates': [
[
[
[8.801864395832126, 53.14770721254275],
@@ -344,13 +372,13 @@ export class MapComponent implements OnInit {
}
},
{
"type": "Feature",
"properties": {
"name": "Layer 2"
'type': 'Feature',
'properties': {
'name': 'Layer 2'
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
'geometry': {
'type': 'MultiPolygon',
'coordinates': [
[
[
[8.807787400997881, 53.1477644198588],
@@ -363,13 +391,13 @@ export class MapComponent implements OnInit {
}
},
{
"type": "Feature",
"properties": {
"name": "Layer 3"
'type': 'Feature',
'properties': {
'name': 'Layer 3'
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
'geometry': {
'type': 'MultiPolygon',
'coordinates': [
[
[
[8.80207966021419, 53.14392919393571],
@@ -382,13 +410,13 @@ export class MapComponent implements OnInit {
}
},
{
"type": "Feature",
"properties": {
"name": "Layer 4"
'type': 'Feature',
'properties': {
'name': 'Layer 4'
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
'geometry': {
'type': 'MultiPolygon',
'coordinates': [
[
[
[8.808654874418039, 53.143631496039035],
@@ -403,7 +431,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);
+65 -45
View File
@@ -1,13 +1,13 @@
import VectorLayer from 'ol/layer/Vector';
import GeoJSON from 'ol/format/GeoJSON';
import {Vector as VectorSource} from 'ol/source';
import {EPSG} from "../enums/EPSG";
import {EPSG} from '../enums/EPSG';
import Style from 'ol/style/Style';
import Stroke from 'ol/style/Stroke';
import Fill from 'ol/style/Fill';
import {Config} from "../misc/Config";
import {Config} from '../misc/Config';
import {Feature} from 'ol/Feature';
import {CustomProperties} from "../enums/CustomProperties";
import {CustomProperties} from '../enums/CustomProperties';
/**
* Represents a raw (not processed) map layer
@@ -38,7 +38,7 @@ export class RawLayer {
}
/**
* Creates a VectorLayer instance from a RawLayer and applies the layer color to all features
* Creates a VectorLayer instance from a RawLayer and applies the layer or custom color to all features
* @param rawLayer
*/
public static toVectorLayer(rawLayer: RawLayer): VectorLayer {
@@ -46,21 +46,9 @@ export class RawLayer {
const features = RawLayer.geoJSONToFeatures(rawLayer.data);
// apply style to all features
features.forEach(feature => {
// TODO
// determine if this feature has a own color! If so, do not apply default color and use own color.
const featureCustomProperties = RawLayer.getCustomProperties(feature);
if (featureCustomProperties && featureCustomProperties['default-style-stroke']) {
feature.setStyle(new Style({
stroke: new Stroke({
color: featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE],
width: 1
}),
fill: new Fill({
color: featureCustomProperties[CustomProperties.DEFAULT_COLOR_FILL]
})
}));
}
})
feature.setStyle(this.determineColorStyle(featureCustomProperties));
});
// add features to source
vectorSource.addFeatures(features);
@@ -72,33 +60,6 @@ export class RawLayer {
});
}
/**
* Saves a default color property to geoJSON
*/
public saveDefaultColor(color: number[]) {
const features = RawLayer.geoJSONToFeatures(this.data);
features.forEach(feature => {
// save default color in feature properties
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);
}
/**
* Reads the default color property from geoJSON
*/
public getDefaultColor(): number[] {
const features = RawLayer.geoJSONToFeatures(this.data);
const featureCustomProperties = RawLayer.getCustomProperties(features[0]);
if (featureCustomProperties && featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE]) {
return featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE];
}
return null;
}
/**
* Creates the features from geoJSON
*/
@@ -135,4 +96,63 @@ export class RawLayer {
const featureProperties = feature.getProperties();
return featureProperties[Config.GEO_JSON_PREFIX];
}
/**
* Determines which color style should be applied. If no custom color property is provided, the default
* color is used.
* @param featureCustomProperties
*/
public static determineColorStyle(featureCustomProperties: { [key: string]: any }): Style {
if (featureCustomProperties && featureCustomProperties[CustomProperties.COLOR_STROKE]) {
return new Style({
stroke: new Stroke({
color: featureCustomProperties[CustomProperties.COLOR_STROKE],
width: 1
}),
fill: new Fill({
color: featureCustomProperties[CustomProperties.COLOR_FILL]
})
});
} else if (featureCustomProperties && featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE]) {
return new Style({
stroke: new Stroke({
color: featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE],
width: 1
}),
fill: new Fill({
color: featureCustomProperties[CustomProperties.DEFAULT_COLOR_FILL]
})
});
} else {
throw new Error('no color properties are defined');
}
}
/**
* Saves a default color property to geoJSON
*/
public saveDefaultColor(color: number[]) {
const features = RawLayer.geoJSONToFeatures(this.data);
features.forEach(feature => {
// save default color in feature properties
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);
}
/**
* Reads the default color property from geoJSON
*/
public getDefaultColor(): number[] {
const features = RawLayer.geoJSONToFeatures(this.data);
const featureCustomProperties = RawLayer.getCustomProperties(features[0]);
if (featureCustomProperties && featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE]) {
return featureCustomProperties[CustomProperties.DEFAULT_COLOR_STROKE];
}
return null;
}
}