Skip to content

Commit 7f12f2c

Browse files
authored
Merge pull request #715 from geoadmin/feat_PB-103_arg_constructor_features
PB-103 : arg constructor for SelectableLayers and children
2 parents b287c3d + 40b8ab5 commit 7f12f2c

8 files changed

+138
-151
lines changed

src/api/features/EditableFeature.class.js

+31-52
Original file line numberDiff line numberDiff line change
@@ -16,66 +16,45 @@ export const EditableFeatureTypes = {
1616
/** Describe a feature that can be edited by the user, such as feature from the current drawing */
1717
export default class EditableFeature extends SelectableFeature {
1818
/**
19-
* @param {String | Number} id Unique identifier for this feature (unique in the context it
20-
* comes from, not for the whole app)
21-
* @param {Number[][]} coordinates Coordinates [[x,y],[x2.y2],...] or [x,y] if point geometry
22-
* coordinates of this feature
23-
* @param {Object} geometry GeoJSON representation of this feature
24-
* @param {String} title Title of this feature
25-
* @param {String} description A description of this feature, can not be HTML content (only
26-
* text)
27-
* @param {EditableFeatureTypes} featureType Type of this editable feature
28-
* @param {FeatureStyleColor} textColor Color for the text of this feature
29-
* @param {FeatureStyleSize} textSize Size of the text for this feature
30-
* @param {FeatureStyleColor} fillColor Color of the icon (if defined)
31-
* @param {DrawingIcon} icon Icon that will be covering this feature, can be null
32-
* @param {FeatureStyleSize} iconSize Size of the icon (if defined) that will be covering this
33-
* feature
19+
* @param {String | Number} featureData.id Unique identifier for this feature (unique in the
20+
* context it comes from, not for the whole app)
21+
* @param {Number[][]} featureData.coordinates Coordinates [[x,y],[x2.y2],...] or [x,y] if point
22+
* geometry coordinates of this feature
23+
* @param {Object} featureData.geometry GeoJSON representation of this feature
24+
* @param {String} featureData.title Title of this feature
25+
* @param {String} featureData.description A description of this feature, can not be HTML
26+
* content (only text)
27+
* @param {EditableFeatureTypes} featureData.featureType Type of this editable feature
28+
* @param {FeatureStyleColor} featureData.textColor Color for the text of this feature
29+
* @param {FeatureStyleSize} featureData.textSize Size of the text for this feature
30+
* @param {FeatureStyleColor} featureData.fillColor Color of the icon (if defined)
31+
* @param {DrawingIcon} featureData.icon Icon that will be covering this feature, can be null
32+
* @param {FeatureStyleSize} featureData.iconSize Size of the icon (if defined) that will be
33+
* covering this feature
3434
*/
35-
constructor(
36-
id,
37-
coordinates,
38-
geometry,
39-
title = '',
40-
description = '',
41-
featureType,
42-
textColor = RED,
43-
textSize = MEDIUM,
44-
fillColor = RED,
45-
icon = null,
46-
iconSize = MEDIUM
47-
) {
48-
super(id, coordinates, title, description, geometry, true)
35+
constructor(featureData) {
36+
const {
37+
id,
38+
coordinates,
39+
geometry,
40+
title = '',
41+
description = '',
42+
featureType,
43+
textColor = RED,
44+
textSize = MEDIUM,
45+
fillColor = RED,
46+
icon = null,
47+
iconSize = MEDIUM,
48+
} = featureData
49+
super({ id, coordinates, title, description, geometry, isEditable: true })
4950
this._featureType = featureType
5051
this._textColor = textColor
5152
this._textSize = textSize
5253
this._fillColor = fillColor
5354
this._icon = icon
5455
this._iconSize = iconSize
5556
this._geodesicCoordinates = null
56-
}
57-
58-
/**
59-
* Create a new Editable Features. Omitted parameters means the default value of the constructor
60-
* will be used.
61-
*
62-
* @param {any} obj An object with key value pairs for the parameters of the constructor
63-
* @returns The new object
64-
*/
65-
static newFeature(obj) {
66-
return new EditableFeature(
67-
obj.id,
68-
obj.coordinates,
69-
obj.geometry,
70-
obj.title,
71-
obj.description,
72-
obj.featureType,
73-
obj.textColor,
74-
obj.textSize,
75-
obj.fillColor,
76-
obj.icon,
77-
obj.iconSize
78-
)
57+
this._isDragged = false
7958
}
8059

8160
/**

src/api/features/LayerFeature.class.js

+24-16
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,36 @@ import LayerTypes from '@/api/layers/LayerTypes.enum.js'
44
/** Describe a feature from the backend, so a feature linked to a backend layer. */
55
export default class LayerFeature extends SelectableFeature {
66
/**
7-
* @param {AbstractLayer} layer The layer in which this feature belongs
8-
* @param {Number | String} id The unique feature ID in the layer it is part of
9-
* @param {String} name The name (localized) of this feature
10-
* @param {Object | String} data Data for this feature's popup (or tooltip).
11-
* @param {Number[][]} coordinates Coordinate in the current projection ([[x,y],[x2,y2],...])
12-
* @param {Number[]} extent Extent of the feature expressed with two point, bottom left and top
13-
* right
14-
* @param {Object} geometry GeoJSON geometry (if exists)
7+
* @param {AbstractLayer} featureData.layer The layer in which this feature belongs
8+
* @param {Number | String} featureData.id The unique feature ID in the layer it is part of
9+
* @param {String} featureData.name The name (localized) of this feature
10+
* @param {Object | String} featureData.data Data for this feature's popup (or tooltip).
11+
* @param {[[Number, Number]]} featureData.coordinates Coordinate in the current projection
12+
* ([[x,y],[x2,y2],...])
13+
* @param {[Number, Number, Number, Number]} featureData.extent Extent of the feature expressed
14+
* with two point, bottom left and top right
15+
* @param {Object | null} [featureData.geometry=null] GeoJSON geometry (if exists). Default is
16+
* `null`
1517
*/
16-
constructor(layer, id, name, data, coordinates, extent, geometry = null) {
17-
super(id, coordinates, layer.name, name, geometry, false)
18+
constructor(featureData) {
19+
const { layer, id, name, data, coordinates, extent, geometry = null } = featureData
20+
super({
21+
// making sure we have a unique ID by use the layer ID with the feature ID
22+
id: `${layer.id}-${id}`,
23+
coordinates,
24+
// using the layer name as title (so that user can differentiate the source)
25+
title: layer.name,
26+
// and the name as description (so that we do not lose track of this data)
27+
description: name,
28+
extent,
29+
geometry,
30+
isEditable: false,
31+
})
1832
this.layer = layer
1933
this.data = data
20-
this.extent = extent
2134
// We can't trust the content of the popup data for external layers, and for KML layers.
2235
// For KML, the issue is that user can create text-rich (HTML) description with links, and such.
2336
// It would then be possible to do some XSS through this, so we need to sanitize this before showing it.
2437
this.popupDataCanBeTrusted = !this.layer.isExternal && this.layer.type !== LayerTypes.KML
2538
}
26-
27-
// overwriting get ID so that we use the layer ID with the feature ID
28-
get id() {
29-
return `${this.layer.id}-${this._id}`
30-
}
3139
}

src/api/features/SelectableFeature.class.js

+26-24
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,39 @@ import log from '@/utils/logging.js'
1515
*/
1616
export default class SelectableFeature extends EventEmitter {
1717
/**
18-
* @param {String | Number} id Unique identifier for this feature (unique in the context it
19-
* comes from, not for the whole app)
20-
* @param {Number[][]} coordinates [[x,y],[x2,y2],...] coordinates of the center of this feature
21-
* @param {String} title Title of this feature
22-
* @param {String} description A description of this feature, can not be HTML content (only
23-
* text)
24-
* @param {Object} geometry GeoJSON representation of this feature (if it has a geometry, for
25-
* points it isn't necessary)
26-
* @param {Boolean} isEditable Whether this feature is editable when selected (color, size,
27-
* etc...)
18+
* @param {String | Number} featureData.id Unique identifier for this feature (unique in the
19+
* context it comes from, not for the whole app)
20+
* @param {[[Number, Number]]} featureData.coordinates Coordinates of the center of this
21+
* feature. Format is [[x,y],[x2,y2],...]
22+
* @param {String} featureData.title Title of this feature
23+
* @param {String | null} [featureData.description=null] A description of this feature, cannot
24+
* be HTML content (only text). Default is `null`
25+
* @param {[Number, Number, Number, Number] | null} [featureData.extent=null] Extent of this
26+
* feature (if any) expressed as [minX, minY, maxX, maxY]. Default is `null`
27+
* @param {Object | null} [featureData.geometry=null] GeoJSON representation of this feature (if
28+
* it has a geometry, for points it isn't necessary). Default is `null`
29+
* @param {Boolean} [featureData.isEditable=false] Whether this feature is editable when
30+
* selected (color, size, etc...). Default is `false`
2831
*/
29-
constructor(id, coordinates, title, description, geometry = null, isEditable = false) {
32+
constructor(featureData) {
3033
super()
31-
this._id = id
34+
const {
35+
id,
36+
coordinates,
37+
title,
38+
description = null,
39+
extent = null,
40+
geometry = null,
41+
isEditable = false,
42+
} = featureData
43+
this.id = id
3244
// using the setter for coordinate (see below)
3345
this.coordinates = coordinates
3446
this.title = title
3547
this.description = description
3648
this.geometry = geometry
37-
this._isEditable = !!isEditable
38-
this._isDragged = false
49+
this.extent = extent
50+
this.isEditable = !!isEditable
3951
}
4052

4153
/**
@@ -63,11 +75,6 @@ export default class SelectableFeature extends EventEmitter {
6375
this.emitChangeEvent(changeType)
6476
}
6577

66-
get id() {
67-
return this._id
68-
}
69-
// ID is immutable, no setter
70-
7178
get coordinates() {
7279
return this._coordinates
7380
}
@@ -118,9 +125,4 @@ export default class SelectableFeature extends EventEmitter {
118125
this._description = newDescription
119126
this.emitStylingChangeEvent('description')
120127
}
121-
122-
get isEditable() {
123-
return this._isEditable
124-
}
125-
// isEditable is immutable, no setter
126128
}

src/api/features/features.api.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,15 @@ const getFeature = (layer, featureID, outputProjection, lang = 'en') => {
206206
}
207207

208208
resolve(
209-
new LayerFeature(
209+
new LayerFeature({
210210
layer,
211-
featureID,
212-
featureName,
213-
featureHtmlPopup,
214-
featureCoordinate,
215-
featureExtent,
216-
featureGeoJSONGeometry
217-
)
211+
id: featureID,
212+
name: featureName,
213+
data: featureHtmlPopup,
214+
coordinates: featureCoordinate,
215+
extent: featureExtent,
216+
geometry: featureGeoJSONGeometry,
217+
})
218218
)
219219
})
220220
.catch((error) => {

src/modules/drawing/components/useDrawingModeInteraction.composable.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export default function useDrawingModeInteraction({
115115
manner. This means that if e.g. a property inside of the editableFeature changes, an
116116
update must be triggered manually.*/
117117
feature.setProperties({
118-
editableFeature: EditableFeature.newFeature(args),
118+
editableFeature: new EditableFeature(args),
119119
// For backward compatibility with the legacy mf-geoadmin3 viewer we need to add the
120120
// feature type as proprietary property
121121
type: args.featureType.toLowerCase(),

src/store/plugins/reproject-selected-features-on-projection-change.plugin.js

+17-22
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,26 @@ const reprojectSelectedFeaturesOnProjectionChangePlugin = (store) => {
4141
state.features.selectedFeatures.forEach((selectedFeature) => {
4242
if (selectedFeature instanceof LayerFeature) {
4343
reprojectedSelectedFeatures.push(
44-
new LayerFeature(
45-
selectedFeature.layer,
46-
selectedFeature.id,
47-
selectedFeature.name,
48-
selectedFeature.data,
49-
reprojectCoordinates(selectedFeature.coordinates),
50-
projExtent(oldProjection, newProjection, selectedFeature.extent),
51-
selectedFeature.geometry
52-
)
44+
new LayerFeature({
45+
layer: selectedFeature.layer,
46+
id: selectedFeature.id,
47+
name: selectedFeature.name,
48+
data: selectedFeature.data,
49+
coordinates: reprojectCoordinates(selectedFeature.coordinates),
50+
extent: projExtent(
51+
oldProjection,
52+
newProjection,
53+
selectedFeature.extent
54+
),
55+
geometry: selectedFeature.geometry,
56+
})
5357
)
5458
} else if (selectedFeature.isEditable) {
5559
reprojectedSelectedFeatures.push(
56-
new EditableFeature(
57-
selectedFeature.id,
58-
reprojectCoordinates(selectedFeature.coordinates),
59-
selectedFeature.geometry,
60-
selectedFeature.time,
61-
selectedFeature.description,
62-
selectedFeature.featureType,
63-
selectedFeature.textColor,
64-
selectedFeature.textSize,
65-
selectedFeature.fillColor,
66-
selectedFeature.icon,
67-
selectedFeature.iconSize
68-
)
60+
new EditableFeature({
61+
...selectedFeature,
62+
coordinates: reprojectCoordinates(selectedFeature.coordinates),
63+
})
6964
)
7065
} else {
7166
log.debug('do not know what to do with this feature', selectedFeature)

src/utils/identifyOnVectorLayer.js

+30-27
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,17 @@ export function identifyGeoJSONFeatureAt(geoJsonLayer, coordinate, projection, r
107107
}
108108
return identifyInGeoJson(reprojectedGeoJSON, coordinate, projection, resolution).map(
109109
(feature) => {
110-
return new LayerFeature(
111-
geoJsonLayer,
112-
feature.id,
113-
feature.properties.station_name || feature.id,
114-
{ title: feature.properties.name, description: feature.properties.description },
115-
reprojectCoordinates(feature.geometry.coordinates, projection),
116-
null,
117-
reproject(feature.geometry, WGS84.epsg, projection.epsg)
118-
)
110+
return new LayerFeature({
111+
layer: geoJsonLayer,
112+
id: feature.id,
113+
name: feature.properties.station_name || feature.id,
114+
data: {
115+
title: feature.properties.name,
116+
description: feature.properties.description,
117+
},
118+
coordinates: reprojectCoordinates(feature.geometry.coordinates, projection),
119+
geometry: reproject(feature.geometry, WGS84.epsg, projection.epsg),
120+
})
119121
}
120122
)
121123
}
@@ -145,15 +147,17 @@ export function identifyKMLFeatureAt(kmlLayer, coordinate, projection, resolutio
145147
const convertedKml = kmlToGeoJSON(parseKml)
146148
return identifyInGeoJson(convertedKml, coordinate, projection, resolution).map(
147149
(feature) => {
148-
return new LayerFeature(
149-
kmlLayer,
150-
feature.id,
151-
kmlLayer.name,
152-
{ title: feature.properties.name, description: feature.properties.description },
153-
reprojectCoordinates(feature.geometry.coordinates, projection),
154-
null,
155-
reproject(feature.geometry, WGS84.epsg, projection.epsg)
156-
)
150+
return new LayerFeature({
151+
layer: kmlLayer,
152+
id: feature.id,
153+
name: kmlLayer.name,
154+
data: {
155+
title: feature.properties.name,
156+
description: feature.properties.description,
157+
},
158+
coordinates: reprojectCoordinates(feature.geometry.coordinates, projection),
159+
geometry: reproject(feature.geometry, WGS84.epsg, projection.epsg),
160+
})
157161
}
158162
)
159163
}
@@ -176,15 +180,14 @@ export function identifyGPXFeatureAt(gpxLayer, coordinate, projection, resolutio
176180
const convertedGpx = gpxToGeoJSON(parseGpx)
177181
return identifyInGeoJson(convertedGpx, coordinate, projection, resolution).map(
178182
(feature) => {
179-
return new LayerFeature(
180-
gpxLayer,
181-
`${gpxLayer.name}-${feature.properties?.name}`,
182-
feature.properties?.name,
183-
{ ...feature.properties },
184-
reprojectCoordinates(feature.geometry.coordinates, projection),
185-
null,
186-
reproject(feature.geometry, WGS84.epsg, projection.epsg)
187-
)
183+
return new LayerFeature({
184+
layer: gpxLayer,
185+
id: `${gpxLayer.name}-${feature.properties?.name}`,
186+
name: feature.properties?.name,
187+
data: { ...feature.properties },
188+
coordinates: reprojectCoordinates(feature.geometry.coordinates, projection),
189+
geometry: reproject(feature.geometry, WGS84.epsg, projection.epsg),
190+
})
188191
}
189192
)
190193
}

src/utils/kmlUtils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ export function getEditableFeatureFromKmlFeature(kmlFeature, availableIconSets)
405405
const geometry = new GeoJSON().writeGeometryObject(kmlFeature.getGeometry())
406406
const coordinates = extractOlFeatureCoordinates(kmlFeature)
407407

408-
return EditableFeature.newFeature({
408+
return new EditableFeature({
409409
id: featureId,
410410
featureType: featureType,
411411
title,

0 commit comments

Comments
 (0)