diff --git a/package.json b/package.json index 098de7c94..b2c5eecab 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "private": true, "scripts": { "start": "npm run dev", - "dev": "vite --port 8080", + "dev": "vite --port 8080 --host --cors", "preview": "npm run build:prod && vite preview --port 8080 --outDir dist/production", "preview:dev": "npm run build:dev && vite preview --port 8080 --outDir dist/development", "preview:int": "npm run build:int && vite preview --port 8080 --outDir dist/integration", diff --git a/src/api/__tests__/features.api.spec.js b/src/api/__tests__/features.api.spec.js index b2cda19f4..8bf8022fb 100644 --- a/src/api/__tests__/features.api.spec.js +++ b/src/api/__tests__/features.api.spec.js @@ -47,7 +47,7 @@ describe('Validate features api', () => { expect(reconstructed.description).to.be.equal(testObject.description) expect(reconstructed.icon).to.be.equal(testObject.icon) - /* If theses classes are extended to save more data than what is serialized, these tests + /* If these classes are extended to save more data than what is serialized, these tests will need to be changed*/ expect(reconstructed.textColor).to.deep.equal(testObject.textColor) expect(reconstructed.textSize).to.deep.equal(testObject.textSize) diff --git a/src/api/features.api.js b/src/api/features.api.js index 8b39f178b..ed9af06fe 100644 --- a/src/api/features.api.js +++ b/src/api/features.api.js @@ -1,4 +1,4 @@ -import { Icon } from '@/api/icon.api' +import { DrawingIcon } from '@/api/icon.api' import { API_BASE_URL } from '@/config' import { CoordinateSystems } from '@/utils/coordinateUtils' import EventEmitter from '@/utils/EventEmitter.class' @@ -10,15 +10,17 @@ import { MEDIUM, RED, } from '@/utils/featureStyleUtils' +import { getEditableFeatureFromLegacyKmlFeature } from '@/utils/legacyKmlUtils' import log from '@/utils/logging' import axios from 'axios' import { Icon as openlayersIcon } from 'ol/style' +import Feature from 'ol/Feature' import { featureStyleFunction } from '@/modules/drawing/lib/style' import { GeodesicGeometries } from '@/utils/geodesicManager' /** * Representation of a feature that can be selected by the user on the map. This feature can be - * edited if the corresponding flag says so (it will then fires "change" events any time one - * property of the instance has changed) + * edited if the corresponding flag says so (it will then fire "change" events any time one property + * of the instance has changed) * * This will then be specialized in (at least) two flavor of features, layer feature (coming from * our backend, with extra information attached) and drawing feature (that can be modified by the @@ -26,7 +28,7 @@ import { GeodesicGeometries } from '@/utils/geodesicManager' * * @abstract */ -export class Feature extends EventEmitter { +export class SelectableFeature extends EventEmitter { /** * @param {String | Number} id Unique identifier for this feature (unique in the context it * comes from, not for the whole app) @@ -42,9 +44,9 @@ export class Feature extends EventEmitter { super() this._id = id // using the setter for coordinate (see below) - this._coordinates = coordinates - this._title = title - this._description = description + this.coordinates = coordinates + this.title = title + this.description = description this._isEditable = !!isEditable this._isDragged = false } @@ -95,6 +97,10 @@ export class Feature extends EventEmitter { this._coordinates = newCoordinates } this.emitChangeEvent('coordinates') + } else if (newCoordinates === null) { + this._coordinates = newCoordinates + } else { + log.error(`feature.api new coordinates is not an array`, newCoordinates) } } get lastCoordinate() { @@ -132,12 +138,12 @@ export const EditableFeatureTypes = { } /** Describe a feature that can be edited by the user, such as feature from the current drawing */ -export class EditableFeature extends Feature { +export class EditableFeature extends SelectableFeature { /** * @param {String | Number} id Unique identifier for this feature (unique in the context it * comes from, not for the whole app) - * @param {Number[][]} coordinates [[x,y],[x2.y2],...] coordinates of this feature in EPSG:3857 - * (metric mercator) + * @param {Number[][]} coordinates [[x,y],[x2.y2],...] or [x,y] if point geometry coordinates of + * this feature in EPSG:3857 (metric mercator) * @param {String} title Title of this feature * @param {String} description A description of this feature, can not be HTML content (only * text) @@ -145,7 +151,7 @@ export class EditableFeature extends Feature { * @param {FeatureStyleColor} textColor Color for the text of this feature * @param {FeatureStyleSize} textSize Size of the text for this feature * @param {FeatureStyleColor} fillColor Color of the icon (if defined) - * @param {Icon} icon Icon that will be covering this feature, can be null + * @param {DrawingIcon} icon Icon that will be covering this feature, can be null * @param {FeatureStyleSize} iconSize Size of the icon (if defined) that will be covering this * feature */ @@ -196,7 +202,7 @@ export class EditableFeature extends Feature { /** * This function returns a stripped down version of this object ready to be serialized. * - * @returns The version of the object that can be serialized + * @returns {Object} The version of the object that can be serialized */ getStrippedObject() { /* Warning: Changing this method will break the compability of KML files */ @@ -217,7 +223,7 @@ export class EditableFeature extends Feature { /** * Regenerates the full version of an editable feature given a stripped version. * - * @param {stripped EditableFeature} o A stripped down version of the editable Feature + * @param {Object} o A stripped down version of the editable Feature * @returns The full version of the editable Feature */ static recreateObject(o) { @@ -230,28 +236,43 @@ export class EditableFeature extends Feature { FeatureStyleColor.recreateObject(o.textColor), FeatureStyleSize.recreateObject(o.textSize), FeatureStyleColor.recreateObject(o.fillColor), - o.icon ? Icon.recreateObject(o.icon) : null, + o.icon ? DrawingIcon.recreateObject(o.icon) : null, FeatureStyleSize.recreateObject(o.iconSize) ) } /** * This method deserializes an editable feature that is stored in the extra properties of an - * openlayers feature. It then recreates a fully functional olFeature with the correct styling. + * openlayers feature. If there is no editable feature to deserialize (e.g. in the case of a kml + * that was generated with mf-geoadmin3), the editable feature is instead reconstructed with the + * styling information stored in the official ' diff --git a/src/modules/drawing/components/drawingInteraction.mixin.js b/src/modules/drawing/components/drawingInteraction.mixin.js index b49cfdf86..2711f8755 100644 --- a/src/modules/drawing/components/drawingInteraction.mixin.js +++ b/src/modules/drawing/components/drawingInteraction.mixin.js @@ -79,14 +79,20 @@ const drawingInteractionMixin = { onAddFeature(event) { const feature = event.feature if (!feature.getId()) { - // setting a unique ID for each feature (using the feature metadata as seed for the UID generation) - const uid = getUid(feature) + /* setting a unique ID for each feature. getUid() is unique as long as the app + isn't reloaded. The first part is a time stamp to guarante uniqueness even after + reloading the app. Ps: We can not fully rely on the time stamp as some browsers may + make the timestamp less precise to increase privacy. */ + const uid = + 'drawing_feature_' + + Math.trunc(Date.now() / 1000) + + ('000' + getUid(feature)).slice(-3) feature.setId(uid) const args = typeof this.editableFeatureArgs === 'function' ? this.editableFeatureArgs() : this.editableFeatureArgs - args.id = `drawing_feature_${uid}` + args.id = uid args.coordinates = null /* applying extra properties that should be stored with that feature. Openlayers will diff --git a/src/modules/drawing/lib/style.js b/src/modules/drawing/lib/style.js index dd98b784f..b01db3818 100644 --- a/src/modules/drawing/lib/style.js +++ b/src/modules/drawing/lib/style.js @@ -133,7 +133,8 @@ export function featureStyleFunction(feature, resolution) { image: editableFeature.generateOpenlayersIcon(), text: new Text({ text: editableFeature.title, - font: editableFeature.font, + //font: editableFeature.font, + font: `normal 16px Helvetica`, fill: new Fill({ color: editableFeature.textColor.fill, }), diff --git a/src/modules/infobox/InfoboxModule.vue b/src/modules/infobox/InfoboxModule.vue index 2957a9b92..02894c80c 100644 --- a/src/modules/infobox/InfoboxModule.vue +++ b/src/modules/infobox/InfoboxModule.vue @@ -1,6 +1,11 @@ diff --git a/src/modules/map/components/LocationPopup.vue b/src/modules/map/components/LocationPopup.vue index c559f2800..4955b7932 100644 --- a/src/modules/map/components/LocationPopup.vue +++ b/src/modules/map/components/LocationPopup.vue @@ -2,85 +2,88 @@
-
+ -
+
- {{ clickCoordinatesLV95 }} + {{ coordinateLV95 }} - +
-
+ -
+
- {{ clickCoordinatesLV03 }} + {{ coordinateLV03 }} - +
-
+ -
+
- {{ clickCoordinatesPlainWGS84 }} + {{ coordinateWGS84Plain }} - +
- {{ clickCoordinatesWGS84 }} + {{ coordinateWGS84 }}
-
+
UTM
-
+
- {{ clickCoordinatesUTM }} + {{ coordinateUTM }} - +
-
{{ 'MGRS' }}
-
+
{{ 'MGRS' }}
+
- {{ clickCoordinatesMGRS }} + {{ coordinateMGRS }} - +
-
+ -
- - {{ clickWhat3Words }} +
+ + {{ what3Words }} - +
-
+
-
+ -
- {{ height?.heightInMeter }} m / - {{ height?.heightInFeet }} ft - +
+ {{ heightInMeter }} m / + {{ heightInFeet }} ft +
-