umap-project 3.1.2__py3-none-any.whl → 3.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of umap-project might be problematic. Click here for more details.
- umap/__init__.py +1 -1
- umap/locale/en/LC_MESSAGES/django.mo +0 -0
- umap/locale/en/LC_MESSAGES/django.po +22 -18
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +21 -17
- umap/management/commands/export_pictogram.py +29 -0
- umap/management/commands/migrate_to_S3.py +5 -1
- umap/management/commands/purge_old_versions.py +8 -6
- umap/settings/__init__.py +21 -0
- umap/settings/base.py +3 -0
- umap/static/umap/content.css +7 -2
- umap/static/umap/css/contextmenu.css +58 -2
- umap/static/umap/css/form.css +175 -45
- umap/static/umap/css/icon.css +97 -3
- umap/static/umap/css/panel.css +31 -1
- umap/static/umap/img/16-white.svg +21 -40
- umap/static/umap/img/16.svg +1 -1
- umap/static/umap/img/24-white.svg +9 -9
- umap/static/umap/img/24.svg +23 -10
- umap/static/umap/img/source/16-white.svg +23 -41
- umap/static/umap/img/source/16.svg +1 -1
- umap/static/umap/img/source/24-white.svg +11 -11
- umap/static/umap/img/source/24.svg +25 -12
- umap/static/umap/js/modules/browser.js +1 -1
- umap/static/umap/js/modules/caption.js +8 -0
- umap/static/umap/js/modules/data/features.js +331 -202
- umap/static/umap/js/modules/data/layer.js +263 -152
- umap/static/umap/js/modules/facets.js +2 -2
- umap/static/umap/js/modules/form/builder.js +11 -7
- umap/static/umap/js/modules/form/fields.js +66 -26
- umap/static/umap/js/modules/formatter.js +78 -28
- umap/static/umap/js/modules/importer.js +6 -1
- umap/static/umap/js/modules/importers/opendata.js +138 -33
- umap/static/umap/js/modules/importers/openrouteservice.js +140 -0
- umap/static/umap/js/modules/managers.js +67 -0
- umap/static/umap/js/modules/printer.js +107 -0
- umap/static/umap/js/modules/rendering/controls.js +78 -2
- umap/static/umap/js/modules/rendering/icon.js +116 -87
- umap/static/umap/js/modules/rendering/layers/classified.js +8 -7
- umap/static/umap/js/modules/rendering/layers/cluster.js +199 -63
- umap/static/umap/js/modules/rendering/map.js +6 -2
- umap/static/umap/js/modules/rendering/template.js +71 -1
- umap/static/umap/js/modules/rendering/ui.js +111 -34
- umap/static/umap/js/modules/rules.js +76 -23
- umap/static/umap/js/modules/schema.js +27 -0
- umap/static/umap/js/modules/share.js +19 -12
- umap/static/umap/js/modules/slideshow.js +1 -1
- umap/static/umap/js/modules/sync/updaters.js +1 -6
- umap/static/umap/js/modules/tableeditor.js +13 -37
- umap/static/umap/js/modules/templates.js +7 -6
- umap/static/umap/js/modules/ui/bar.js +6 -1
- umap/static/umap/js/modules/ui/base.js +24 -9
- umap/static/umap/js/modules/ui/contextmenu.js +17 -7
- umap/static/umap/js/modules/ui/dialog.js +7 -4
- umap/static/umap/js/modules/ui/panel.js +7 -0
- umap/static/umap/js/modules/umap.js +84 -67
- umap/static/umap/js/modules/utils.js +8 -7
- umap/static/umap/js/umap.controls.js +22 -57
- umap/static/umap/locale/am_ET.js +81 -9
- umap/static/umap/locale/am_ET.json +81 -9
- umap/static/umap/locale/ar.js +81 -9
- umap/static/umap/locale/ar.json +81 -9
- umap/static/umap/locale/ast.js +81 -9
- umap/static/umap/locale/ast.json +81 -9
- umap/static/umap/locale/bg.js +81 -9
- umap/static/umap/locale/bg.json +81 -9
- umap/static/umap/locale/br.js +68 -29
- umap/static/umap/locale/br.json +68 -29
- umap/static/umap/locale/ca.js +88 -16
- umap/static/umap/locale/ca.json +88 -16
- umap/static/umap/locale/cs_CZ.js +81 -9
- umap/static/umap/locale/cs_CZ.json +81 -9
- umap/static/umap/locale/da.js +48 -9
- umap/static/umap/locale/da.json +48 -9
- umap/static/umap/locale/de.js +48 -9
- umap/static/umap/locale/de.json +48 -9
- umap/static/umap/locale/el.js +58 -13
- umap/static/umap/locale/el.json +58 -13
- umap/static/umap/locale/en.js +48 -9
- umap/static/umap/locale/en.json +48 -9
- umap/static/umap/locale/en_US.json +81 -9
- umap/static/umap/locale/es.js +48 -9
- umap/static/umap/locale/es.json +48 -9
- umap/static/umap/locale/et.js +81 -9
- umap/static/umap/locale/et.json +81 -9
- umap/static/umap/locale/eu.js +97 -25
- umap/static/umap/locale/eu.json +97 -25
- umap/static/umap/locale/fa_IR.js +81 -9
- umap/static/umap/locale/fa_IR.json +81 -9
- umap/static/umap/locale/fi.js +81 -9
- umap/static/umap/locale/fi.json +81 -9
- umap/static/umap/locale/fr.js +48 -9
- umap/static/umap/locale/fr.json +48 -9
- umap/static/umap/locale/gl.js +81 -9
- umap/static/umap/locale/gl.json +81 -9
- umap/static/umap/locale/he.js +81 -9
- umap/static/umap/locale/he.json +81 -9
- umap/static/umap/locale/hr.js +81 -9
- umap/static/umap/locale/hr.json +81 -9
- umap/static/umap/locale/hu.js +72 -27
- umap/static/umap/locale/hu.json +72 -27
- umap/static/umap/locale/id.js +81 -9
- umap/static/umap/locale/id.json +81 -9
- umap/static/umap/locale/is.js +81 -9
- umap/static/umap/locale/is.json +81 -9
- umap/static/umap/locale/it.js +48 -9
- umap/static/umap/locale/it.json +48 -9
- umap/static/umap/locale/ja.js +81 -9
- umap/static/umap/locale/ja.json +81 -9
- umap/static/umap/locale/ko.js +81 -9
- umap/static/umap/locale/ko.json +81 -9
- umap/static/umap/locale/lt.js +81 -9
- umap/static/umap/locale/lt.json +81 -9
- umap/static/umap/locale/ms.js +81 -9
- umap/static/umap/locale/ms.json +81 -9
- umap/static/umap/locale/nl.js +48 -9
- umap/static/umap/locale/nl.json +48 -9
- umap/static/umap/locale/no.js +81 -9
- umap/static/umap/locale/no.json +81 -9
- umap/static/umap/locale/pl.js +81 -9
- umap/static/umap/locale/pl.json +81 -9
- umap/static/umap/locale/pl_PL.json +81 -9
- umap/static/umap/locale/pt.js +81 -9
- umap/static/umap/locale/pt.json +81 -9
- umap/static/umap/locale/pt_BR.js +91 -19
- umap/static/umap/locale/pt_BR.json +91 -19
- umap/static/umap/locale/pt_PT.js +81 -9
- umap/static/umap/locale/pt_PT.json +81 -9
- umap/static/umap/locale/ro.js +81 -9
- umap/static/umap/locale/ro.json +81 -9
- umap/static/umap/locale/ru.js +81 -9
- umap/static/umap/locale/ru.json +81 -9
- umap/static/umap/locale/sk_SK.js +81 -9
- umap/static/umap/locale/sk_SK.json +81 -9
- umap/static/umap/locale/sl.js +81 -9
- umap/static/umap/locale/sl.json +81 -9
- umap/static/umap/locale/sr.js +81 -9
- umap/static/umap/locale/sr.json +81 -9
- umap/static/umap/locale/sv.js +81 -9
- umap/static/umap/locale/sv.json +81 -9
- umap/static/umap/locale/th_TH.js +81 -9
- umap/static/umap/locale/th_TH.json +81 -9
- umap/static/umap/locale/tr.js +81 -9
- umap/static/umap/locale/tr.json +81 -9
- umap/static/umap/locale/uk_UA.js +81 -9
- umap/static/umap/locale/uk_UA.json +81 -9
- umap/static/umap/locale/vi.js +81 -9
- umap/static/umap/locale/vi.json +81 -9
- umap/static/umap/locale/vi_VN.json +81 -9
- umap/static/umap/locale/zh.js +81 -9
- umap/static/umap/locale/zh.json +81 -9
- umap/static/umap/locale/zh_CN.json +81 -9
- umap/static/umap/locale/zh_TW.Big5.json +81 -9
- umap/static/umap/locale/zh_TW.js +98 -26
- umap/static/umap/locale/zh_TW.json +98 -26
- umap/static/umap/map.css +325 -102
- umap/static/umap/vars.css +1 -0
- umap/static/umap/vendors/betterknown/betterknown.mjs +287 -0
- umap/static/umap/vendors/editable/Leaflet.Editable.js +3 -1
- umap/static/umap/vendors/openrouteservice/ors-js-client.js +521 -0
- umap/static/umap/vendors/openrouteservice/ors-js-client.js.map +1 -0
- umap/static/umap/vendors/simple-elevation-chart/elevation.js +63 -0
- umap/static/umap/vendors/simple-elevation-chart/elevation.svg +8 -0
- umap/static/umap/vendors/snapdom/snapdom.min.mjs +3 -0
- umap/storage/fs.py +3 -2
- umap/storage/staticfiles.py +12 -0
- umap/templates/base.html +4 -1
- umap/templates/umap/css.html +0 -4
- umap/templates/umap/js.html +1 -3
- umap/tests/base.py +9 -1
- umap/tests/integration/test_basics.py +3 -1
- umap/tests/integration/test_conditional_rules.py +79 -37
- umap/tests/integration/test_datalayer.py +1 -1
- umap/tests/integration/test_draw_polygon.py +3 -5
- umap/tests/integration/test_draw_polyline.py +4 -6
- umap/tests/integration/test_draw_route.py +178 -0
- umap/tests/integration/test_edit_datalayer.py +1 -1
- umap/tests/integration/test_edit_map.py +1 -1
- umap/tests/integration/test_edit_marker.py +8 -8
- umap/tests/integration/test_edit_polygon.py +2 -2
- umap/tests/integration/test_export_map.py +84 -10
- umap/tests/integration/test_import.py +140 -0
- umap/tests/integration/test_map_preview.py +1 -1
- umap/tests/integration/test_optimistic_merge.py +72 -12
- umap/tests/integration/test_share.py +1 -1
- umap/tests/integration/test_tableeditor.py +10 -7
- umap/tests/integration/test_websocket_sync.py +4 -4
- umap/utils.py +37 -0
- umap/views.py +18 -2
- umap_project-3.3.0.dist-info/METADATA +76 -0
- {umap_project-3.1.2.dist-info → umap_project-3.3.0.dist-info}/RECORD +194 -188
- umap/static/umap/vendors/markercluster/MarkerCluster.Default.css +0 -60
- umap/static/umap/vendors/markercluster/MarkerCluster.css +0 -14
- umap/static/umap/vendors/markercluster/leaflet.markercluster.js +0 -2
- umap/static/umap/vendors/markercluster/leaflet.markercluster.js.map +0 -1
- umap_project-3.1.2.dist-info/METADATA +0 -68
- {umap_project-3.1.2.dist-info → umap_project-3.3.0.dist-info}/WHEEL +0 -0
- {umap_project-3.1.2.dist-info → umap_project-3.3.0.dist-info}/entry_points.txt +0 -0
- {umap_project-3.1.2.dist-info → umap_project-3.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,16 +3,21 @@ import {
|
|
|
3
3
|
DomUtil,
|
|
4
4
|
GeoJSON,
|
|
5
5
|
LineUtil,
|
|
6
|
-
stamp,
|
|
7
6
|
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
|
8
7
|
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
|
9
8
|
import { MutatingForm } from '../form/builder.js'
|
|
10
9
|
import { translate } from '../i18n.js'
|
|
10
|
+
import {
|
|
11
|
+
PREFERENCES as ORS_PREFERENCES,
|
|
12
|
+
PROFILES as ORS_PROFILES,
|
|
13
|
+
Importer as OpenRouteService,
|
|
14
|
+
} from '../importers/openrouteservice.js'
|
|
11
15
|
import loadPopup from '../rendering/popup.js'
|
|
12
16
|
import {
|
|
13
17
|
LeafletMarker,
|
|
14
18
|
LeafletPolygon,
|
|
15
19
|
LeafletPolyline,
|
|
20
|
+
LeafletRoute,
|
|
16
21
|
MaskPolygon,
|
|
17
22
|
} from '../rendering/ui.js'
|
|
18
23
|
import { SCHEMA } from '../schema.js'
|
|
@@ -84,6 +89,19 @@ class Feature {
|
|
|
84
89
|
this.pushGeometry()
|
|
85
90
|
}
|
|
86
91
|
|
|
92
|
+
get fields() {
|
|
93
|
+
// Fields are user defined properties
|
|
94
|
+
return [...this.datalayer.fields, ...this._umap.fields]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
setter(key, value) {
|
|
98
|
+
if (key === 'datalayer') {
|
|
99
|
+
this.changeDataLayer(value)
|
|
100
|
+
} else {
|
|
101
|
+
Utils.setObjectValue(this, key, value)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
87
105
|
isOnScreen(bounds) {
|
|
88
106
|
return this.ui?.isOnScreen(bounds)
|
|
89
107
|
}
|
|
@@ -198,14 +216,15 @@ class Feature {
|
|
|
198
216
|
if (this._umap.currentFeature === this) {
|
|
199
217
|
this.view()
|
|
200
218
|
}
|
|
201
|
-
this.datalayer.indexProperties(this)
|
|
202
219
|
}
|
|
203
220
|
this.redraw()
|
|
204
221
|
}
|
|
205
222
|
|
|
206
223
|
edit(event) {
|
|
207
224
|
if (!this._umap.editEnabled || this.isReadOnly()) return
|
|
208
|
-
if (this._umap.editedFeature === this && !event
|
|
225
|
+
if (this._umap.editedFeature === this && !event?.force) return
|
|
226
|
+
// If this feature is active (popup open), let's close it.
|
|
227
|
+
this.deactivate()
|
|
209
228
|
const container = DomUtil.create('div', 'umap-feature-container')
|
|
210
229
|
DomUtil.createTitle(
|
|
211
230
|
container,
|
|
@@ -221,51 +240,49 @@ class Feature {
|
|
|
221
240
|
container.appendChild(builder.build())
|
|
222
241
|
|
|
223
242
|
const properties = []
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
continue
|
|
243
|
+
for (const field of this.fields) {
|
|
244
|
+
let handler = 'Input'
|
|
245
|
+
if (field.key === 'description' || field.type === 'Text') {
|
|
246
|
+
handler = 'Textarea'
|
|
229
247
|
}
|
|
230
|
-
|
|
231
|
-
continue
|
|
232
|
-
}
|
|
233
|
-
properties.push([`properties.${property}`, { label: property }])
|
|
234
|
-
}
|
|
235
|
-
// We always want name and description for now (properties management to come)
|
|
236
|
-
properties.unshift('properties.description')
|
|
237
|
-
if (!labelKeyFound) {
|
|
238
|
-
labelKeyFound = U.DEFAULT_LABEL_KEY
|
|
248
|
+
properties.push([`properties.${field.key}`, { label: field.key, handler }])
|
|
239
249
|
}
|
|
240
|
-
properties.unshift([`properties.${labelKeyFound}`, { label: labelKeyFound }])
|
|
241
250
|
builder = new MutatingForm(this, properties, {
|
|
242
251
|
id: 'umap-feature-properties',
|
|
243
252
|
})
|
|
244
253
|
const form = builder.build()
|
|
245
254
|
container.appendChild(form)
|
|
246
255
|
const button = Utils.loadTemplate(
|
|
247
|
-
`<button type="button"><i class="icon icon-16 icon-add"></i>${translate('Add a new
|
|
256
|
+
`<button type="button"><i class="icon icon-16 icon-add"></i>${translate('Add a new field')}</button>`
|
|
248
257
|
)
|
|
249
258
|
button.addEventListener('click', () => {
|
|
250
259
|
this.datalayer.addProperty().then(() => this.edit({ force: true }))
|
|
251
260
|
})
|
|
252
261
|
form.appendChild(button)
|
|
253
262
|
this.appendEditFieldsets(container)
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
263
|
+
const [details, { fieldset }] = Utils.loadTemplateWithRefs(`
|
|
264
|
+
<details>
|
|
265
|
+
<summary>${translate('Advanced actions')}</summary>
|
|
266
|
+
<fieldset class="button-bar by2" data-ref=fieldset></fieldset>
|
|
267
|
+
</details>
|
|
268
|
+
`)
|
|
269
|
+
container.appendChild(details)
|
|
270
|
+
this.getAdvancedEditActions(fieldset)
|
|
271
|
+
const onPanelLoaded = this._umap.editPanel.open({ content: container })
|
|
272
|
+
onPanelLoaded.then(() => {
|
|
273
|
+
builder.form.querySelector('input')?.focus()
|
|
262
274
|
})
|
|
263
275
|
this._umap.editedFeature = this
|
|
264
276
|
if (!this.ui.isOnScreen(this._umap._leafletMap.getBounds())) this.zoomTo(event)
|
|
277
|
+
return onPanelLoaded
|
|
265
278
|
}
|
|
266
279
|
|
|
267
280
|
toggleEditing() {
|
|
268
|
-
this.
|
|
281
|
+
if (this._umap.editedFeature === this) {
|
|
282
|
+
this._umap.editPanel.close()
|
|
283
|
+
} else {
|
|
284
|
+
this.edit()
|
|
285
|
+
}
|
|
269
286
|
}
|
|
270
287
|
|
|
271
288
|
getAdvancedEditActions(container) {
|
|
@@ -378,8 +395,6 @@ class Feature {
|
|
|
378
395
|
|
|
379
396
|
connectToDataLayer(datalayer) {
|
|
380
397
|
this.datalayer = datalayer
|
|
381
|
-
// FIXME should be in layer/ui
|
|
382
|
-
this.ui.options.renderer = this.datalayer.renderer
|
|
383
398
|
}
|
|
384
399
|
|
|
385
400
|
disconnectFromDataLayer(datalayer) {
|
|
@@ -416,7 +431,6 @@ class Feature {
|
|
|
416
431
|
if (this.datalayer) {
|
|
417
432
|
this.datalayer.removeFeature(this)
|
|
418
433
|
}
|
|
419
|
-
|
|
420
434
|
datalayer.addFeature(this)
|
|
421
435
|
this.sync.upsert(this.toGeoJSON())
|
|
422
436
|
this.redraw()
|
|
@@ -505,21 +519,6 @@ class Feature {
|
|
|
505
519
|
})
|
|
506
520
|
}
|
|
507
521
|
|
|
508
|
-
getInplaceEditMenu() {
|
|
509
|
-
return [
|
|
510
|
-
{
|
|
511
|
-
action: () => this.toggleEditing(),
|
|
512
|
-
title: translate('Toggle edit mode (⇧+Click)'),
|
|
513
|
-
icon: 'icon-edit',
|
|
514
|
-
},
|
|
515
|
-
{
|
|
516
|
-
action: () => this.del(),
|
|
517
|
-
title: translate('Delete this feature'),
|
|
518
|
-
icon: 'icon-delete',
|
|
519
|
-
},
|
|
520
|
-
]
|
|
521
|
-
}
|
|
522
|
-
|
|
523
522
|
isFiltered() {
|
|
524
523
|
const filterKeys = this.datalayer.getFilterKeys()
|
|
525
524
|
const filter = this._umap.browser.options.filter
|
|
@@ -607,7 +606,7 @@ class Feature {
|
|
|
607
606
|
}
|
|
608
607
|
|
|
609
608
|
getRank() {
|
|
610
|
-
return this.datalayer.
|
|
609
|
+
return this.datalayer.features.getIndex(this)
|
|
611
610
|
}
|
|
612
611
|
|
|
613
612
|
redraw() {
|
|
@@ -622,9 +621,14 @@ class Feature {
|
|
|
622
621
|
}
|
|
623
622
|
}
|
|
624
623
|
|
|
625
|
-
|
|
624
|
+
getContextMenu(event) {
|
|
626
625
|
const permalink = this.getPermalink()
|
|
627
|
-
|
|
626
|
+
const items = []
|
|
627
|
+
if (this._umap.editEnabled && !this.isReadOnly()) {
|
|
628
|
+
items.push({
|
|
629
|
+
items: this.getEditContextMenu(event),
|
|
630
|
+
})
|
|
631
|
+
}
|
|
628
632
|
if (permalink) {
|
|
629
633
|
items.push({
|
|
630
634
|
label: translate('Permalink'),
|
|
@@ -646,32 +650,43 @@ class Feature {
|
|
|
646
650
|
this._umap.tooltip.open({ content: L._('✅ Copied!') })
|
|
647
651
|
},
|
|
648
652
|
})
|
|
649
|
-
if (this._umap.editEnabled && !this.isReadOnly()) {
|
|
650
|
-
items = items.concat(this.getContextMenuEditItems(event))
|
|
651
|
-
}
|
|
652
653
|
return items
|
|
653
654
|
}
|
|
654
655
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
656
|
+
getDrawingTools(event) {
|
|
657
|
+
return [
|
|
658
|
+
{
|
|
659
|
+
title: translate('Toggle edit mode (⇧+Click)'),
|
|
660
|
+
action: () => this.toggleEditing(),
|
|
661
|
+
icon: 'icon-edit',
|
|
662
|
+
},
|
|
663
|
+
]
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
getEditContextMenu(event) {
|
|
667
|
+
const items = []
|
|
668
|
+
const vertexClicked = event.vertex
|
|
669
|
+
if (vertexClicked) {
|
|
670
|
+
items.push(...this.getVertexTools(event))
|
|
671
|
+
} else {
|
|
672
|
+
items.push(...this.getDrawingTools(event))
|
|
662
673
|
}
|
|
663
|
-
items
|
|
674
|
+
items.push(
|
|
675
|
+
'-',
|
|
664
676
|
{
|
|
665
|
-
|
|
677
|
+
title: this._umap.help.displayLabel('EDIT_FEATURE_LAYER', false),
|
|
678
|
+
icon: 'icon-layers',
|
|
666
679
|
action: () => this.datalayer.edit(),
|
|
667
680
|
},
|
|
668
681
|
{
|
|
669
|
-
|
|
670
|
-
|
|
682
|
+
title: translate('Clone this feature'),
|
|
683
|
+
icon: 'icon-copy',
|
|
684
|
+
action: () => this.clone(),
|
|
671
685
|
},
|
|
672
686
|
{
|
|
673
|
-
|
|
674
|
-
|
|
687
|
+
title: translate('Delete this feature'),
|
|
688
|
+
icon: 'icon-delete',
|
|
689
|
+
action: () => this.del(),
|
|
675
690
|
}
|
|
676
691
|
)
|
|
677
692
|
return items
|
|
@@ -686,7 +701,10 @@ class Feature {
|
|
|
686
701
|
}
|
|
687
702
|
|
|
688
703
|
deactivate() {
|
|
689
|
-
if (this._umap.activeFeature === this)
|
|
704
|
+
if (this._umap.activeFeature === this) {
|
|
705
|
+
this._umap.activeFeature = undefined
|
|
706
|
+
this.ui.closePopup()
|
|
707
|
+
}
|
|
690
708
|
}
|
|
691
709
|
}
|
|
692
710
|
|
|
@@ -731,6 +749,7 @@ export class Point extends Feature {
|
|
|
731
749
|
return [
|
|
732
750
|
'properties._umap_options.color',
|
|
733
751
|
'properties._umap_options.iconClass',
|
|
752
|
+
'properties._umap_options.iconSize',
|
|
734
753
|
'properties._umap_options.iconUrl',
|
|
735
754
|
'properties._umap_options.iconOpacity',
|
|
736
755
|
]
|
|
@@ -764,11 +783,11 @@ export class Point extends Feature {
|
|
|
764
783
|
|
|
765
784
|
zoomTo(event) {
|
|
766
785
|
if (this.datalayer.isClustered() && !this.ui._icon) {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
super.zoomTo(event)
|
|
786
|
+
this.ui._cluster.zoomToCoverage().then(() => {
|
|
787
|
+
this.ui._cluster.spiderfy()
|
|
788
|
+
})
|
|
771
789
|
}
|
|
790
|
+
super.zoomTo(event)
|
|
772
791
|
}
|
|
773
792
|
}
|
|
774
793
|
|
|
@@ -785,16 +804,11 @@ class Path extends Feature {
|
|
|
785
804
|
this.ui.setLatLngs(latlngs)
|
|
786
805
|
}
|
|
787
806
|
|
|
788
|
-
connectToDataLayer(datalayer) {
|
|
789
|
-
super.connectToDataLayer(datalayer)
|
|
790
|
-
// We keep markers on their own layer on top of the paths.
|
|
791
|
-
this.ui.options.pane = this.datalayer.pane
|
|
792
|
-
}
|
|
793
|
-
|
|
794
807
|
edit(event) {
|
|
795
808
|
if (this._umap.editEnabled) {
|
|
796
|
-
super.edit(event)
|
|
809
|
+
const promise = super.edit(event)
|
|
797
810
|
if (!this.ui.editEnabled()) this.ui.makeGeometryEditable()
|
|
811
|
+
return promise
|
|
798
812
|
}
|
|
799
813
|
}
|
|
800
814
|
|
|
@@ -852,33 +866,6 @@ class Path extends Feature {
|
|
|
852
866
|
return other
|
|
853
867
|
}
|
|
854
868
|
|
|
855
|
-
getInplaceEditMenu(event) {
|
|
856
|
-
const items = super.getInplaceEditMenu()
|
|
857
|
-
if (this.isMulti()) {
|
|
858
|
-
items.push({
|
|
859
|
-
action: () => this.ui.enableEdit().deleteShapeAt(event.latlng),
|
|
860
|
-
title: translate('Delete this shape'),
|
|
861
|
-
icon: 'icon-delete-shape',
|
|
862
|
-
})
|
|
863
|
-
items.push({
|
|
864
|
-
action: () => this.ui.isolateShape(event.latlng),
|
|
865
|
-
title: translate('Extract shape to separate feature'),
|
|
866
|
-
icon: 'icon-extract-shape',
|
|
867
|
-
})
|
|
868
|
-
}
|
|
869
|
-
return items
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
getInplaceEditVertexMenu(event) {
|
|
873
|
-
return [
|
|
874
|
-
{
|
|
875
|
-
action: () => event.vertex.delete(),
|
|
876
|
-
title: translate('Delete this vertex (Alt+Click)'),
|
|
877
|
-
icon: 'icon-delete-vertex',
|
|
878
|
-
},
|
|
879
|
-
]
|
|
880
|
-
}
|
|
881
|
-
|
|
882
869
|
zoomTo({ easing, callback }) {
|
|
883
870
|
// Use bounds instead of centroid for paths.
|
|
884
871
|
easing = easing || this._umap.getProperty('easing')
|
|
@@ -893,62 +880,55 @@ class Path extends Feature {
|
|
|
893
880
|
if (callback) callback.call(this)
|
|
894
881
|
}
|
|
895
882
|
|
|
896
|
-
|
|
897
|
-
const items = super.
|
|
883
|
+
getContextMenu(event) {
|
|
884
|
+
const items = super.getContextMenu(event)
|
|
898
885
|
items.push({
|
|
899
886
|
label: translate('Display measure'),
|
|
900
887
|
action: () => Alert.info(this.ui.getMeasure()),
|
|
901
888
|
})
|
|
902
|
-
if (this._umap.editEnabled && !this.isReadOnly() && this.isMulti()) {
|
|
903
|
-
items.push(...this.getContextMenuMultiItems(event))
|
|
904
|
-
}
|
|
905
889
|
return items
|
|
906
890
|
}
|
|
907
891
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
'-',
|
|
892
|
+
getVertexTools(event) {
|
|
893
|
+
return [
|
|
911
894
|
{
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
},
|
|
895
|
+
action: () => event.vertex.delete(),
|
|
896
|
+
title: translate('Delete this vertex (Alt+Click)'),
|
|
897
|
+
icon: 'icon-delete-vertex',
|
|
916
898
|
},
|
|
917
899
|
]
|
|
918
|
-
const shape = this.ui.shapeAt(event.latlng)
|
|
919
|
-
if (this.ui._latlngs.indexOf(shape) > 0) {
|
|
920
|
-
items.push({
|
|
921
|
-
label: translate('Make main shape'),
|
|
922
|
-
action: () => {
|
|
923
|
-
this.ui.enableEdit().deleteShape(shape)
|
|
924
|
-
this.ui.editor.prependShape(shape)
|
|
925
|
-
},
|
|
926
|
-
})
|
|
927
|
-
}
|
|
928
|
-
return items
|
|
929
900
|
}
|
|
930
901
|
|
|
931
|
-
|
|
932
|
-
const items = super.
|
|
902
|
+
getDrawingTools(event) {
|
|
903
|
+
const items = super.getDrawingTools(event)
|
|
904
|
+
if (this.isMulti()) {
|
|
905
|
+
items.push(
|
|
906
|
+
{
|
|
907
|
+
title: translate('Extract shape to separate feature'),
|
|
908
|
+
icon: 'icon-extract-shape',
|
|
909
|
+
action: () => {
|
|
910
|
+
this.ui.isolateShape(event.latlng)
|
|
911
|
+
},
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
title: translate('Delete this shape'),
|
|
915
|
+
icon: 'icon-delete-shape',
|
|
916
|
+
action: () => this.ui.enableEdit().deleteShapeAt(event.latlng),
|
|
917
|
+
}
|
|
918
|
+
)
|
|
919
|
+
}
|
|
933
920
|
if (
|
|
934
921
|
this._umap?.editedFeature !== this &&
|
|
935
922
|
this.isSameClass(this._umap.editedFeature)
|
|
936
923
|
) {
|
|
937
924
|
items.push({
|
|
938
|
-
|
|
925
|
+
title: translate('Transfer shape to edited feature'),
|
|
926
|
+
icon: 'icon-transfer-shape',
|
|
939
927
|
action: () => {
|
|
940
928
|
this.transferShape(event.latlng, this._umap.editedFeature)
|
|
941
929
|
},
|
|
942
930
|
})
|
|
943
931
|
}
|
|
944
|
-
if (this.isMulti()) {
|
|
945
|
-
items.push({
|
|
946
|
-
label: translate('Extract shape to separate feature'),
|
|
947
|
-
action: () => {
|
|
948
|
-
this.ui.isolateShape(event.latlng)
|
|
949
|
-
},
|
|
950
|
-
})
|
|
951
|
-
}
|
|
952
932
|
return items
|
|
953
933
|
}
|
|
954
934
|
}
|
|
@@ -980,13 +960,63 @@ export class LineString extends Path {
|
|
|
980
960
|
}
|
|
981
961
|
|
|
982
962
|
getUIClass() {
|
|
983
|
-
|
|
963
|
+
const klass = super.getUIClass()
|
|
964
|
+
if (klass) return klass
|
|
965
|
+
if (this.isRoute()) {
|
|
966
|
+
return LeafletRoute
|
|
967
|
+
}
|
|
968
|
+
return LeafletPolyline
|
|
984
969
|
}
|
|
985
970
|
|
|
986
971
|
isSameClass(other) {
|
|
987
972
|
return other instanceof LineString
|
|
988
973
|
}
|
|
989
974
|
|
|
975
|
+
cancelRoute() {
|
|
976
|
+
const oldRoute = Utils.CopyJSON(this.properties._umap_options.route)
|
|
977
|
+
this.properties._umap_options.route.active = false
|
|
978
|
+
this.redraw()
|
|
979
|
+
this.edit()
|
|
980
|
+
this.sync.update('properties._umap_options.route', null, oldRoute)
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
restoreRoute() {
|
|
984
|
+
const oldRoute = Utils.CopyJSON(this.properties._umap_options.route)
|
|
985
|
+
this._ensureRoute()
|
|
986
|
+
delete this.properties._umap_options.route.active
|
|
987
|
+
this.redraw()
|
|
988
|
+
this.sync.update(
|
|
989
|
+
'properties._umap_options.route',
|
|
990
|
+
this.properties._umap_options.route,
|
|
991
|
+
oldRoute
|
|
992
|
+
)
|
|
993
|
+
this.edit().then((panel) => {
|
|
994
|
+
panel.scrollTo('details#edit-route')
|
|
995
|
+
})
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
toRoute() {
|
|
999
|
+
this._ensureRoute()
|
|
1000
|
+
this.properties._umap_options.route.coordinates = Utils.CopyJSON(this.coordinates)
|
|
1001
|
+
this.redraw()
|
|
1002
|
+
this.sync.update(
|
|
1003
|
+
'properties._umap_options.route',
|
|
1004
|
+
this.properties._umap_options.route,
|
|
1005
|
+
null
|
|
1006
|
+
)
|
|
1007
|
+
this.edit().then((panel) => {
|
|
1008
|
+
panel.scrollTo('details#edit-route')
|
|
1009
|
+
})
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
askForRouteSettings() {
|
|
1013
|
+
const container = Utils.loadTemplate(
|
|
1014
|
+
`<div><h3>${translate('Route settings')}</h3></div>`
|
|
1015
|
+
)
|
|
1016
|
+
container.appendChild(this.routeForm())
|
|
1017
|
+
return this._umap.dialog.open({ template: container })
|
|
1018
|
+
}
|
|
1019
|
+
|
|
990
1020
|
toPolygon() {
|
|
991
1021
|
const geojson = this.toGeoJSON()
|
|
992
1022
|
geojson.geometry.type = 'Polygon'
|
|
@@ -1001,15 +1031,51 @@ export class LineString extends Path {
|
|
|
1001
1031
|
this.del()
|
|
1002
1032
|
}
|
|
1003
1033
|
|
|
1034
|
+
isRoute() {
|
|
1035
|
+
return (
|
|
1036
|
+
!!this.properties._umap_options.route &&
|
|
1037
|
+
this.properties._umap_options.route.active !== false
|
|
1038
|
+
)
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1004
1041
|
getAdvancedEditActions(container) {
|
|
1005
1042
|
super.getAdvancedEditActions(container)
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1043
|
+
const button = Utils.loadTemplate(`
|
|
1044
|
+
<button class="button" type="button"><i class="icon icon-24 icon-polygon"></i>${translate('Transform to polygon')}</button>
|
|
1045
|
+
`)
|
|
1046
|
+
container.appendChild(button)
|
|
1047
|
+
button.addEventListener('click', () => this.toPolygon())
|
|
1048
|
+
if (this.isRoute()) {
|
|
1049
|
+
const button = Utils.loadTemplate(`
|
|
1050
|
+
<button class="button" type="button"><i class="icon icon-24 icon-polyline"></i>${translate('Transform to regular line')}</button>
|
|
1051
|
+
`)
|
|
1052
|
+
container.appendChild(button)
|
|
1053
|
+
button.addEventListener('click', () => this.cancelRoute())
|
|
1054
|
+
} else if (!this.isMulti() && this.coordinates.length < 10) {
|
|
1055
|
+
const button = Utils.loadTemplate(`
|
|
1056
|
+
<button class="button" type="button"><i class="icon icon-24 icon-route"></i>${translate('Transform to route')}</button>
|
|
1057
|
+
`)
|
|
1058
|
+
container.appendChild(button)
|
|
1059
|
+
button.addEventListener('click', () =>
|
|
1060
|
+
this.askForRouteSettings().then(() => {
|
|
1061
|
+
this.toRoute()
|
|
1062
|
+
this.computeRoute()
|
|
1063
|
+
})
|
|
1064
|
+
)
|
|
1065
|
+
} else if (this.properties._umap_options.route?.coordinates) {
|
|
1066
|
+
const button = Utils.loadTemplate(`
|
|
1067
|
+
<button class="button" type="button"><i class="icon icon-24 icon-route"></i>${translate('Restore route')}</button>
|
|
1068
|
+
`)
|
|
1069
|
+
container.appendChild(button)
|
|
1070
|
+
button.addEventListener('click', () => this.restoreRoute())
|
|
1071
|
+
}
|
|
1072
|
+
if (this._umap.properties.ORSAPIKey) {
|
|
1073
|
+
const button = Utils.loadTemplate(`
|
|
1074
|
+
<button class="button" type="button"><i class="icon icon-24 icon-mountain"></i>${translate('Compute elevations')}</button>
|
|
1075
|
+
`)
|
|
1076
|
+
container.appendChild(button)
|
|
1077
|
+
button.addEventListener('click', () => this.computeElevation())
|
|
1078
|
+
}
|
|
1013
1079
|
}
|
|
1014
1080
|
|
|
1015
1081
|
_mergeShapes(from, to) {
|
|
@@ -1061,38 +1127,40 @@ export class LineString extends Path {
|
|
|
1061
1127
|
return !LineUtil.isFlat(this.coordinates) && this.coordinates.length > 1
|
|
1062
1128
|
}
|
|
1063
1129
|
|
|
1064
|
-
|
|
1065
|
-
const items = super.
|
|
1066
|
-
const
|
|
1067
|
-
if (
|
|
1130
|
+
getVertexTools(event) {
|
|
1131
|
+
const items = super.getVertexTools(event)
|
|
1132
|
+
const index = event.vertex.getIndex()
|
|
1133
|
+
if (index !== 0 && index !== event.vertex.getLastIndex()) {
|
|
1068
1134
|
items.push({
|
|
1069
|
-
|
|
1070
|
-
|
|
1135
|
+
title: translate('Split line'),
|
|
1136
|
+
icon: 'icon-split-line',
|
|
1137
|
+
action: () => event.vertex.split(),
|
|
1138
|
+
})
|
|
1139
|
+
} else if (index === 0 || index === event.vertex.getLastIndex()) {
|
|
1140
|
+
items.push({
|
|
1141
|
+
title: this._umap.help.displayLabel('CONTINUE_LINE', false),
|
|
1142
|
+
icon: 'icon-continue-line',
|
|
1143
|
+
action: () => event.vertex.continue(),
|
|
1071
1144
|
})
|
|
1072
|
-
}
|
|
1073
|
-
if (vertexClicked) {
|
|
1074
|
-
const index = event.vertex.getIndex()
|
|
1075
|
-
if (index !== 0 && index !== event.vertex.getLastIndex()) {
|
|
1076
|
-
items.push({
|
|
1077
|
-
label: translate('Split line'),
|
|
1078
|
-
action: () => event.vertex.split(),
|
|
1079
|
-
})
|
|
1080
|
-
} else if (index === 0 || index === event.vertex.getLastIndex()) {
|
|
1081
|
-
items.push({
|
|
1082
|
-
label: this._umap.help.displayLabel('CONTINUE_LINE'),
|
|
1083
|
-
action: () => event.vertex.continue(),
|
|
1084
|
-
})
|
|
1085
|
-
}
|
|
1086
1145
|
}
|
|
1087
1146
|
return items
|
|
1088
1147
|
}
|
|
1089
1148
|
|
|
1090
|
-
|
|
1091
|
-
const items = super.
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1149
|
+
getDrawingTools(event) {
|
|
1150
|
+
const items = super.getDrawingTools(event)
|
|
1151
|
+
if (this.isMulti()) {
|
|
1152
|
+
items.push({
|
|
1153
|
+
title: translate('Merge lines'),
|
|
1154
|
+
icon: 'icon-merge',
|
|
1155
|
+
action: () => this.mergeShapes(),
|
|
1156
|
+
})
|
|
1157
|
+
} else {
|
|
1158
|
+
items.push({
|
|
1159
|
+
title: translate('Transform to polygon'),
|
|
1160
|
+
icon: 'icon-polygon',
|
|
1161
|
+
action: () => this.toPolygon(),
|
|
1162
|
+
})
|
|
1163
|
+
}
|
|
1096
1164
|
return items
|
|
1097
1165
|
}
|
|
1098
1166
|
|
|
@@ -1101,23 +1169,64 @@ export class LineString extends Path {
|
|
|
1101
1169
|
return Object.assign({ gain, loss }, super.extendedProperties())
|
|
1102
1170
|
}
|
|
1103
1171
|
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
if (index === 0 || index === event.vertex.getLastIndex()) {
|
|
1108
|
-
items.push({
|
|
1109
|
-
action: () => event.vertex.continue(),
|
|
1110
|
-
title: translate('Continue line'),
|
|
1111
|
-
icon: 'icon-continue-line',
|
|
1112
|
-
})
|
|
1113
|
-
} else {
|
|
1114
|
-
items.push({
|
|
1115
|
-
action: () => event.vertex.split(),
|
|
1116
|
-
title: translate('Split line'),
|
|
1117
|
-
icon: 'icon-split-line',
|
|
1118
|
-
})
|
|
1172
|
+
_ensureRoute() {
|
|
1173
|
+
if (!this.properties._umap_options.route) {
|
|
1174
|
+
this.properties._umap_options.route = {}
|
|
1119
1175
|
}
|
|
1120
|
-
|
|
1176
|
+
this.properties._umap_options.route.profile ??= ORS_PROFILES[0][0]
|
|
1177
|
+
this.properties._umap_options.route.preference ??= ORS_PREFERENCES[0][0]
|
|
1178
|
+
this.properties._umap_options.route.elevation ??= false
|
|
1179
|
+
this.properties._umap_options.route.coordinates ??= []
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
routeForm() {
|
|
1183
|
+
this._ensureRoute()
|
|
1184
|
+
const metadatas = [
|
|
1185
|
+
[
|
|
1186
|
+
'profile',
|
|
1187
|
+
{
|
|
1188
|
+
handler: 'Select',
|
|
1189
|
+
selectOptions: ORS_PROFILES,
|
|
1190
|
+
label: translate('Profile'),
|
|
1191
|
+
},
|
|
1192
|
+
],
|
|
1193
|
+
[
|
|
1194
|
+
'elevation',
|
|
1195
|
+
{
|
|
1196
|
+
handler: 'Switch',
|
|
1197
|
+
label: translate('Compute elevations'),
|
|
1198
|
+
},
|
|
1199
|
+
],
|
|
1200
|
+
[
|
|
1201
|
+
'preference',
|
|
1202
|
+
{
|
|
1203
|
+
handler: 'Select',
|
|
1204
|
+
selectOptions: ORS_PREFERENCES,
|
|
1205
|
+
label: translate('Route preference'),
|
|
1206
|
+
},
|
|
1207
|
+
],
|
|
1208
|
+
]
|
|
1209
|
+
const form = new MutatingForm(this.properties._umap_options.route, metadatas, {
|
|
1210
|
+
umap: this._umap,
|
|
1211
|
+
})
|
|
1212
|
+
return form.build()
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
_editRoute(container) {
|
|
1216
|
+
const template = `
|
|
1217
|
+
<details id="edit-route">
|
|
1218
|
+
<summary>${translate('Route settings')}</summary>
|
|
1219
|
+
<fieldset data-ref=fieldset></fieldset>
|
|
1220
|
+
</details>
|
|
1221
|
+
`
|
|
1222
|
+
const [details, { fieldset }] = Utils.loadTemplateWithRefs(template)
|
|
1223
|
+
container.appendChild(details)
|
|
1224
|
+
fieldset.appendChild(this.routeForm())
|
|
1225
|
+
const button = Utils.loadTemplate(
|
|
1226
|
+
`<button data-ref=button type="button">${translate('Compute route')}</button>`
|
|
1227
|
+
)
|
|
1228
|
+
fieldset.appendChild(button)
|
|
1229
|
+
button.addEventListener('click', async () => this.computeRoute())
|
|
1121
1230
|
}
|
|
1122
1231
|
|
|
1123
1232
|
addExtraEditFieldset(container) {
|
|
@@ -1135,6 +1244,34 @@ export class LineString extends Path {
|
|
|
1135
1244
|
})
|
|
1136
1245
|
const fieldset = DomUtil.createFieldset(container, translate('Line decoration'))
|
|
1137
1246
|
fieldset.appendChild(builder.build())
|
|
1247
|
+
if (this._umap.properties.ORSAPIKey && this.isRoute()) {
|
|
1248
|
+
this._editRoute(container)
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
async computeElevation() {
|
|
1253
|
+
if (!this._umap.properties.ORSAPIKey) return
|
|
1254
|
+
const importer = new OpenRouteService(this._umap)
|
|
1255
|
+
const geometry = await importer.elevation(this.geometry)
|
|
1256
|
+
if (geometry?.type) {
|
|
1257
|
+
const oldGeometry = Utils.CopyJSON(this._geometry)
|
|
1258
|
+
this.geometry = geometry
|
|
1259
|
+
this.ui.resetTooltip()
|
|
1260
|
+
this.sync.update('geometry', this.geometry, oldGeometry)
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
async computeRoute() {
|
|
1265
|
+
if (!this._umap.properties.ORSAPIKey) return
|
|
1266
|
+
const importer = new OpenRouteService(this._umap)
|
|
1267
|
+
await importer.directions(this.properties._umap_options.route).then((geometry) => {
|
|
1268
|
+
if (geometry?.type) {
|
|
1269
|
+
const oldGeometry = Utils.CopyJSON(this._geometry)
|
|
1270
|
+
this.geometry = geometry
|
|
1271
|
+
this.ui.resetTooltip()
|
|
1272
|
+
this.sync.update('geometry', this.geometry, oldGeometry)
|
|
1273
|
+
}
|
|
1274
|
+
})
|
|
1138
1275
|
}
|
|
1139
1276
|
}
|
|
1140
1277
|
|
|
@@ -1241,29 +1378,21 @@ export class Polygon extends Path {
|
|
|
1241
1378
|
)
|
|
1242
1379
|
}
|
|
1243
1380
|
|
|
1244
|
-
|
|
1245
|
-
const items = super.
|
|
1246
|
-
items.push({
|
|
1247
|
-
action: () => this.ui.startHole(event),
|
|
1248
|
-
title: translate('Start a hole here'),
|
|
1249
|
-
icon: 'icon-hole',
|
|
1250
|
-
})
|
|
1251
|
-
return items
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
getContextMenuEditItems(event) {
|
|
1255
|
-
const items = super.getContextMenuEditItems(event)
|
|
1381
|
+
getDrawingTools(event) {
|
|
1382
|
+
const items = super.getDrawingTools(event)
|
|
1256
1383
|
const shape = this.ui.shapeAt(event.latlng)
|
|
1257
1384
|
// No multi and no holes.
|
|
1258
1385
|
if (shape && !this.isMulti() && (LineUtil.isFlat(shape) || shape.length === 1)) {
|
|
1259
1386
|
items.push({
|
|
1260
|
-
|
|
1387
|
+
title: translate('Transform to lines'),
|
|
1388
|
+
icon: 'icon-polyline',
|
|
1261
1389
|
action: () => this.toLineString(),
|
|
1262
1390
|
})
|
|
1263
1391
|
}
|
|
1264
1392
|
items.push({
|
|
1265
|
-
|
|
1393
|
+
title: translate('Start a hole here'),
|
|
1266
1394
|
action: () => this.ui.startHole(event),
|
|
1395
|
+
icon: 'icon-hole',
|
|
1267
1396
|
})
|
|
1268
1397
|
return items
|
|
1269
1398
|
}
|