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
|
@@ -21,6 +21,8 @@ import TableEditor from '../tableeditor.js'
|
|
|
21
21
|
import * as Utils from '../utils.js'
|
|
22
22
|
import { LineString, Point, Polygon } from './features.js'
|
|
23
23
|
import Rules from '../rules.js'
|
|
24
|
+
import Orderable from '../orderable.js'
|
|
25
|
+
import { FeatureManager } from '../managers.js'
|
|
24
26
|
|
|
25
27
|
export const LAYER_TYPES = [
|
|
26
28
|
DefaultLayer,
|
|
@@ -40,8 +42,7 @@ export class DataLayer {
|
|
|
40
42
|
constructor(umap, leafletMap, data = {}) {
|
|
41
43
|
this._umap = umap
|
|
42
44
|
this.sync = umap.syncEngine.proxy(this)
|
|
43
|
-
this.
|
|
44
|
-
this._features = {}
|
|
45
|
+
this.features = new FeatureManager()
|
|
45
46
|
this._geojson = null
|
|
46
47
|
this._propertiesIndex = []
|
|
47
48
|
|
|
@@ -89,6 +90,12 @@ export class DataLayer {
|
|
|
89
90
|
if (!this.createdOnServer) {
|
|
90
91
|
if (this.showAtLoad()) this.show()
|
|
91
92
|
}
|
|
93
|
+
if (!this._needsFetch && !this._umap.fields.length) {
|
|
94
|
+
this.properties.fields = [
|
|
95
|
+
{ key: U.DEFAULT_LABEL_KEY, type: 'String' },
|
|
96
|
+
{ key: 'description', type: 'Text' },
|
|
97
|
+
]
|
|
98
|
+
}
|
|
92
99
|
|
|
93
100
|
// Only layers that are displayed on load must be hidden/shown
|
|
94
101
|
// Automatically, others will be shown manually, and thus will
|
|
@@ -140,6 +147,23 @@ export class DataLayer {
|
|
|
140
147
|
this.properties.rank = value
|
|
141
148
|
}
|
|
142
149
|
|
|
150
|
+
get fields() {
|
|
151
|
+
if (!this.properties.fields) this.properties.fields = []
|
|
152
|
+
return this.properties.fields
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
set fields(fields) {
|
|
156
|
+
this.properties.fields = fields
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
get fieldKeys() {
|
|
160
|
+
return this.fields.map((field) => field.key)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
get sortKey() {
|
|
164
|
+
return this.getProperty('sortKey') || U.DEFAULT_LABEL_KEY
|
|
165
|
+
}
|
|
166
|
+
|
|
143
167
|
getSyncMetadata() {
|
|
144
168
|
return {
|
|
145
169
|
subject: 'datalayer',
|
|
@@ -249,19 +273,14 @@ export class DataLayer {
|
|
|
249
273
|
const Class = LAYER_MAP[this.properties.type] || DefaultLayer
|
|
250
274
|
this.layer = new Class(this)
|
|
251
275
|
// Rendering layer changed, so let's force reset the feature rendering too.
|
|
252
|
-
this.
|
|
253
|
-
|
|
276
|
+
this.features.forEach((feature) => {
|
|
277
|
+
feature.makeUI()
|
|
278
|
+
this.showFeature(feature)
|
|
279
|
+
})
|
|
254
280
|
if (visible) this.show()
|
|
255
281
|
this.propagateRemote()
|
|
256
282
|
}
|
|
257
283
|
|
|
258
|
-
eachFeature(method, context) {
|
|
259
|
-
for (const idx of this._index) {
|
|
260
|
-
method.call(context || this, this._features[idx])
|
|
261
|
-
}
|
|
262
|
-
return this
|
|
263
|
-
}
|
|
264
|
-
|
|
265
284
|
async fetchData() {
|
|
266
285
|
if (!this.createdOnServer) return
|
|
267
286
|
if (this._loading) return
|
|
@@ -279,7 +298,7 @@ export class DataLayer {
|
|
|
279
298
|
}
|
|
280
299
|
|
|
281
300
|
dataChanged() {
|
|
282
|
-
if (!this.isLoaded()) return
|
|
301
|
+
if (!this.isLoaded() || this._batch) return
|
|
283
302
|
this._umap.onDataLayersChanged()
|
|
284
303
|
this.layer.dataChanged()
|
|
285
304
|
}
|
|
@@ -314,12 +333,6 @@ export class DataLayer {
|
|
|
314
333
|
}
|
|
315
334
|
}
|
|
316
335
|
|
|
317
|
-
reindex() {
|
|
318
|
-
const features = Object.values(this._features)
|
|
319
|
-
this.sortFeatures(features)
|
|
320
|
-
this._index = features.map((feature) => stamp(feature))
|
|
321
|
-
}
|
|
322
|
-
|
|
323
336
|
showAtZoom() {
|
|
324
337
|
const from = Number.parseInt(this.properties.fromZoom, 10)
|
|
325
338
|
const to = Number.parseInt(this.properties.toZoom, 10)
|
|
@@ -423,22 +436,20 @@ export class DataLayer {
|
|
|
423
436
|
}
|
|
424
437
|
|
|
425
438
|
addFeature(feature) {
|
|
426
|
-
const id = stamp(feature)
|
|
427
439
|
feature.connectToDataLayer(this)
|
|
428
|
-
this.
|
|
429
|
-
this._features[id] = feature
|
|
430
|
-
this.indexProperties(feature)
|
|
440
|
+
this.features.add(feature)
|
|
431
441
|
this._umap.featuresIndex[feature.getSlug()] = feature
|
|
442
|
+
// TODO: quid for remote data ?
|
|
443
|
+
this.inferFields(feature)
|
|
432
444
|
this.showFeature(feature)
|
|
433
445
|
this.dataChanged()
|
|
434
446
|
}
|
|
435
447
|
|
|
436
448
|
removeFeature(feature, sync) {
|
|
437
|
-
const id = stamp(feature)
|
|
438
449
|
// This feature was not yet added, may be after
|
|
439
450
|
// hitting Escape while drawing a new line or
|
|
440
451
|
// polygon, not yet valid (not enough points)
|
|
441
|
-
if (!this.
|
|
452
|
+
if (!this.features.has(feature.id)) return
|
|
442
453
|
if (sync !== false) {
|
|
443
454
|
const oldValue = feature.toGeoJSON()
|
|
444
455
|
feature.sync.delete(oldValue)
|
|
@@ -446,57 +457,66 @@ export class DataLayer {
|
|
|
446
457
|
this.hideFeature(feature)
|
|
447
458
|
delete this._umap.featuresIndex[feature.getSlug()]
|
|
448
459
|
feature.disconnectFromDataLayer(this)
|
|
449
|
-
this.
|
|
450
|
-
delete this._features[id]
|
|
460
|
+
this.features.del(feature)
|
|
451
461
|
if (this.isVisible()) this.dataChanged()
|
|
452
462
|
}
|
|
453
463
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
this._propertiesIndex.push(name)
|
|
464
|
-
this._propertiesIndex.sort()
|
|
464
|
+
inferFields(feature) {
|
|
465
|
+
if (!this.properties.fields) this.properties.fields = []
|
|
466
|
+
const keys = this.fieldKeys
|
|
467
|
+
for (const key in feature.properties) {
|
|
468
|
+
if (typeof feature.properties[key] !== 'object') {
|
|
469
|
+
if (key.indexOf('_') === 0) continue
|
|
470
|
+
if (keys.includes(key)) continue
|
|
471
|
+
this.properties.fields.push({ key, type: 'String' })
|
|
472
|
+
}
|
|
465
473
|
}
|
|
466
474
|
}
|
|
467
475
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
this
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
+
async confirmDeleteProperty(property) {
|
|
477
|
+
return this._umap.dialog
|
|
478
|
+
.confirm(
|
|
479
|
+
translate('Are you sure you want to delete this field on all the features?')
|
|
480
|
+
)
|
|
481
|
+
.then(() => {
|
|
482
|
+
this.deleteProperty(property)
|
|
483
|
+
})
|
|
476
484
|
}
|
|
477
485
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
486
|
+
async askForRenameProperty(property) {
|
|
487
|
+
return this._umap.dialog
|
|
488
|
+
.prompt(translate('Please enter the new name of this field'))
|
|
489
|
+
.then(({ prompt }) => {
|
|
490
|
+
if (!prompt || !this.validateName(prompt)) return
|
|
491
|
+
this.renameProperty(property, prompt)
|
|
492
|
+
})
|
|
481
493
|
}
|
|
482
494
|
|
|
483
495
|
renameProperty(oldName, newName) {
|
|
484
496
|
this.sync.startBatch()
|
|
485
|
-
this.
|
|
497
|
+
const oldFields = Utils.CopyJSON(this.fields)
|
|
498
|
+
for (const field of this.fields) {
|
|
499
|
+
if (field.key === oldName) {
|
|
500
|
+
field.key = newName
|
|
501
|
+
break
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
this.sync.update('properties.fields', this.fields, oldFields)
|
|
505
|
+
this.features.forEach((feature) => {
|
|
486
506
|
feature.renameProperty(oldName, newName)
|
|
487
507
|
})
|
|
488
508
|
this.sync.commitBatch()
|
|
489
|
-
this.deindexProperty(oldName)
|
|
490
|
-
this.indexProperty(newName)
|
|
491
509
|
}
|
|
492
510
|
|
|
493
511
|
deleteProperty(property) {
|
|
494
512
|
this.sync.startBatch()
|
|
495
|
-
this.
|
|
513
|
+
const oldFields = Utils.CopyJSON(this.fields)
|
|
514
|
+
this.fields = this.fields.filter((field) => field.key !== property)
|
|
515
|
+
this.sync.update('properties.fields', this.fields, oldFields)
|
|
516
|
+
this.features.forEach((feature) => {
|
|
496
517
|
feature.deleteProperty(property)
|
|
497
518
|
})
|
|
498
519
|
this.sync.commitBatch()
|
|
499
|
-
this.deindexProperty(property)
|
|
500
520
|
}
|
|
501
521
|
|
|
502
522
|
addProperty() {
|
|
@@ -508,7 +528,7 @@ export class DataLayer {
|
|
|
508
528
|
.prompt(translate('Please enter the name of the property'))
|
|
509
529
|
.then(({ prompt }) => {
|
|
510
530
|
if (!prompt || !this.validateName(prompt)) return
|
|
511
|
-
this.
|
|
531
|
+
this.properties.fields.push({ key: prompt, type: 'String' })
|
|
512
532
|
resolve()
|
|
513
533
|
})
|
|
514
534
|
return promise
|
|
@@ -519,39 +539,35 @@ export class DataLayer {
|
|
|
519
539
|
Alert.error(translate('Name “{name}” should not contain a dot.', { name }))
|
|
520
540
|
return false
|
|
521
541
|
}
|
|
522
|
-
if (this.
|
|
542
|
+
if (this.fieldKeys.includes(name)) {
|
|
523
543
|
Alert.error(translate('This name already exists: “{name}”', { name }))
|
|
524
544
|
return false
|
|
525
545
|
}
|
|
526
546
|
return true
|
|
527
547
|
}
|
|
528
548
|
|
|
529
|
-
allProperties() {
|
|
530
|
-
return this._propertiesIndex
|
|
531
|
-
}
|
|
532
|
-
|
|
533
549
|
sortedValues(property) {
|
|
534
|
-
return
|
|
550
|
+
return this.features
|
|
551
|
+
.all()
|
|
535
552
|
.map((feature) => feature.properties[property])
|
|
536
553
|
.filter((val, idx, arr) => arr.indexOf(val) === idx)
|
|
537
554
|
.sort(Utils.naturalSort)
|
|
538
555
|
}
|
|
539
556
|
|
|
540
557
|
addData(geojson, sync) {
|
|
558
|
+
let data = []
|
|
559
|
+
this._batch = true
|
|
541
560
|
try {
|
|
542
561
|
// Do not fail if remote data is somehow invalid,
|
|
543
562
|
// otherwise the layer becomes uneditable.
|
|
544
|
-
|
|
563
|
+
data = this.makeFeatures(geojson, sync)
|
|
545
564
|
} catch (err) {
|
|
546
565
|
console.debug('Error with DataLayer', this.id)
|
|
547
566
|
console.error(err)
|
|
548
|
-
return []
|
|
549
567
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
const sortKeys = this.getProperty('sortKey') || U.DEFAULT_LABEL_KEY
|
|
554
|
-
return Utils.sortFeatures(collection, sortKeys, U.lang)
|
|
568
|
+
this._batch = false
|
|
569
|
+
this.dataChanged()
|
|
570
|
+
return data
|
|
555
571
|
}
|
|
556
572
|
|
|
557
573
|
makeFeatures(geojson = {}, sync = true) {
|
|
@@ -563,7 +579,7 @@ export class DataLayer {
|
|
|
563
579
|
: geojson.features || geojson.geometries
|
|
564
580
|
if (!collection) return
|
|
565
581
|
const features = []
|
|
566
|
-
|
|
582
|
+
Utils.sortFeatures(collection, this.sortKey, U.lang)
|
|
567
583
|
for (const featureJson of collection) {
|
|
568
584
|
if (featureJson.geometry?.type === 'GeometryCollection') {
|
|
569
585
|
for (const geometry of featureJson.geometry.geometries) {
|
|
@@ -592,6 +608,14 @@ export class DataLayer {
|
|
|
592
608
|
// FIXME: deal with MultiPoint
|
|
593
609
|
feature = new Point(this._umap, this, geojson, id)
|
|
594
610
|
break
|
|
611
|
+
case 'MultiPoint':
|
|
612
|
+
if (geometry.coordinates?.length === 1) {
|
|
613
|
+
geojson.geometry.coordinates = geojson.geometry.coordinates[0]
|
|
614
|
+
feature = new Point(this._umap, this, geojson, id)
|
|
615
|
+
} else if (this._umap.editEnabled) {
|
|
616
|
+
Alert.error(translate('Cannot process MultiPoint'))
|
|
617
|
+
}
|
|
618
|
+
break
|
|
595
619
|
case 'MultiLineString':
|
|
596
620
|
case 'LineString':
|
|
597
621
|
feature = new LineString(this._umap, this, geojson, id)
|
|
@@ -602,11 +626,13 @@ export class DataLayer {
|
|
|
602
626
|
break
|
|
603
627
|
default:
|
|
604
628
|
console.debug(geojson)
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
629
|
+
if (this._umap.editEnabled) {
|
|
630
|
+
Alert.error(
|
|
631
|
+
translate('Skipping unknown geometry.type: {type}', {
|
|
632
|
+
type: geometry.type || 'undefined',
|
|
633
|
+
})
|
|
634
|
+
)
|
|
635
|
+
}
|
|
610
636
|
}
|
|
611
637
|
if (feature && !feature.isEmpty()) {
|
|
612
638
|
this.addFeature(feature)
|
|
@@ -713,9 +739,7 @@ export class DataLayer {
|
|
|
713
739
|
}
|
|
714
740
|
|
|
715
741
|
clear(sync = true) {
|
|
716
|
-
|
|
717
|
-
feature.del(sync)
|
|
718
|
-
}
|
|
742
|
+
this.features.forEach((feature) => feature.del(sync))
|
|
719
743
|
this.dataChanged()
|
|
720
744
|
}
|
|
721
745
|
|
|
@@ -731,14 +755,17 @@ export class DataLayer {
|
|
|
731
755
|
|
|
732
756
|
redraw() {
|
|
733
757
|
if (!this.isVisible()) return
|
|
734
|
-
this.
|
|
758
|
+
this.features.forEach((feature) => feature.redraw())
|
|
735
759
|
}
|
|
736
760
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
761
|
+
reindex() {
|
|
762
|
+
this.features.sort(this.sortKey)
|
|
763
|
+
if (this.isBrowsable()) {
|
|
764
|
+
this.resetLayer(true)
|
|
740
765
|
}
|
|
741
|
-
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
_editMetadata(container) {
|
|
742
769
|
const metadataFields = [
|
|
743
770
|
'properties.name',
|
|
744
771
|
'properties.description',
|
|
@@ -768,31 +795,38 @@ export class DataLayer {
|
|
|
768
795
|
],
|
|
769
796
|
]
|
|
770
797
|
DomUtil.createTitle(container, translate('Layer properties'), 'icon-layers')
|
|
771
|
-
|
|
798
|
+
const builder = new MutatingForm(this, metadataFields)
|
|
772
799
|
builder.on('set', ({ detail }) => {
|
|
773
800
|
this._umap.onDataLayersChanged()
|
|
774
801
|
if (detail.helper.field === 'properties.type') {
|
|
775
|
-
this.edit()
|
|
802
|
+
this.edit().then((panel) => panel.scrollTo('details#layer-properties'))
|
|
776
803
|
}
|
|
777
804
|
})
|
|
778
805
|
container.appendChild(builder.build())
|
|
806
|
+
}
|
|
779
807
|
|
|
808
|
+
_editLayerProperties(container) {
|
|
780
809
|
const layerFields = this.layer.getEditableProperties()
|
|
781
810
|
|
|
782
811
|
if (layerFields.length) {
|
|
783
|
-
builder = new MutatingForm(this, layerFields
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
812
|
+
const builder = new MutatingForm(this, layerFields)
|
|
813
|
+
const template = `
|
|
814
|
+
<details id="layer-properties">
|
|
815
|
+
<summary>${this.layer.getName()}: ${translate('settings')}</summary>
|
|
816
|
+
<fieldset data-ref=fieldset></fieldset>
|
|
817
|
+
</details>
|
|
818
|
+
`
|
|
819
|
+
const [details, { fieldset }] = Utils.loadTemplateWithRefs(template)
|
|
820
|
+
container.appendChild(details)
|
|
821
|
+
fieldset.appendChild(builder.build())
|
|
791
822
|
}
|
|
823
|
+
}
|
|
792
824
|
|
|
793
|
-
|
|
825
|
+
_editShapeProperties(container) {
|
|
826
|
+
const fields = [
|
|
794
827
|
'properties.color',
|
|
795
828
|
'properties.iconClass',
|
|
829
|
+
'properties.iconSize',
|
|
796
830
|
'properties.iconUrl',
|
|
797
831
|
'properties.iconOpacity',
|
|
798
832
|
'properties.opacity',
|
|
@@ -803,7 +837,7 @@ export class DataLayer {
|
|
|
803
837
|
'properties.fillOpacity',
|
|
804
838
|
]
|
|
805
839
|
|
|
806
|
-
builder = new MutatingForm(this,
|
|
840
|
+
const builder = new MutatingForm(this, fields, {
|
|
807
841
|
id: 'datalayer-advanced-properties',
|
|
808
842
|
})
|
|
809
843
|
const shapeFieldset = DomUtil.createFieldset(
|
|
@@ -811,8 +845,10 @@ export class DataLayer {
|
|
|
811
845
|
translate('Shape properties')
|
|
812
846
|
)
|
|
813
847
|
shapeFieldset.appendChild(builder.build())
|
|
848
|
+
}
|
|
814
849
|
|
|
815
|
-
|
|
850
|
+
_editAdvancedProperties(container) {
|
|
851
|
+
const fields = [
|
|
816
852
|
'properties.smoothFactor',
|
|
817
853
|
'properties.dashArray',
|
|
818
854
|
'properties.zoomTo',
|
|
@@ -821,7 +857,7 @@ export class DataLayer {
|
|
|
821
857
|
'properties.sortKey',
|
|
822
858
|
]
|
|
823
859
|
|
|
824
|
-
builder = new MutatingForm(this,
|
|
860
|
+
const builder = new MutatingForm(this, fields, {
|
|
825
861
|
id: 'datalayer-advanced-properties',
|
|
826
862
|
})
|
|
827
863
|
builder.on('set', ({ detail }) => {
|
|
@@ -834,8 +870,10 @@ export class DataLayer {
|
|
|
834
870
|
translate('Advanced properties')
|
|
835
871
|
)
|
|
836
872
|
advancedFieldset.appendChild(builder.build())
|
|
873
|
+
}
|
|
837
874
|
|
|
838
|
-
|
|
875
|
+
_editInteractionProperties(container) {
|
|
876
|
+
const fields = [
|
|
839
877
|
'properties.popupShape',
|
|
840
878
|
'properties.popupTemplate',
|
|
841
879
|
'properties.popupContentTemplate',
|
|
@@ -845,14 +883,16 @@ export class DataLayer {
|
|
|
845
883
|
'properties.outlinkTarget',
|
|
846
884
|
'properties.interactive',
|
|
847
885
|
]
|
|
848
|
-
builder = new MutatingForm(this,
|
|
886
|
+
const builder = new MutatingForm(this, fields)
|
|
849
887
|
const popupFieldset = DomUtil.createFieldset(
|
|
850
888
|
container,
|
|
851
889
|
translate('Interaction options')
|
|
852
890
|
)
|
|
853
891
|
popupFieldset.appendChild(builder.build())
|
|
892
|
+
}
|
|
854
893
|
|
|
855
|
-
|
|
894
|
+
_editTextPathProperties(container) {
|
|
895
|
+
const fields = [
|
|
856
896
|
'properties.textPath',
|
|
857
897
|
'properties.textPathColor',
|
|
858
898
|
'properties.textPathRepeat',
|
|
@@ -861,17 +901,77 @@ export class DataLayer {
|
|
|
861
901
|
'properties.textPathOffset',
|
|
862
902
|
'properties.textPathPosition',
|
|
863
903
|
]
|
|
864
|
-
builder = new MutatingForm(this,
|
|
904
|
+
const builder = new MutatingForm(this, fields)
|
|
865
905
|
const fieldset = DomUtil.createFieldset(container, translate('Line decoration'))
|
|
866
906
|
fieldset.appendChild(builder.build())
|
|
907
|
+
}
|
|
867
908
|
|
|
909
|
+
_editFields(container) {
|
|
910
|
+
const template = `
|
|
911
|
+
<details id="fields">
|
|
912
|
+
<summary>${translate('Manage Fields')}</summary>
|
|
913
|
+
<fieldset>
|
|
914
|
+
<ul data-ref=ul></ul>
|
|
915
|
+
<button type="button" data-ref=add><i class="icon icon-16 icon-add"></i>${translate('Add a new field')}</button>
|
|
916
|
+
</fieldset>
|
|
917
|
+
</details>
|
|
918
|
+
`
|
|
919
|
+
const [fieldset, { ul, add }] = Utils.loadTemplateWithRefs(template)
|
|
920
|
+
add.addEventListener('click', () => {
|
|
921
|
+
this.addProperty().then(() => {
|
|
922
|
+
this.edit().then((panel) => {
|
|
923
|
+
panel.scrollTo('details#fields')
|
|
924
|
+
})
|
|
925
|
+
})
|
|
926
|
+
})
|
|
927
|
+
container.appendChild(fieldset)
|
|
928
|
+
for (const field of this.fields) {
|
|
929
|
+
const [row, { rename, del }] = Utils.loadTemplateWithRefs(
|
|
930
|
+
`<li class="orderable" data-key="${field.key}">
|
|
931
|
+
<button class="icon icon-16 icon-edit" title="${translate('Rename this field')}" data-ref=rename></button>
|
|
932
|
+
<button class="icon icon-16 icon-delete" title="${translate('Delete this field')}" data-ref=del></button>
|
|
933
|
+
<i class="icon icon-16 icon-drag" title="${translate('Drag to reorder')}"></i>
|
|
934
|
+
${field.key}
|
|
935
|
+
</li>`
|
|
936
|
+
)
|
|
937
|
+
ul.appendChild(row)
|
|
938
|
+
rename.addEventListener('click', () => {
|
|
939
|
+
this.askForRenameProperty(field.key).then(() => {
|
|
940
|
+
this.edit().then((panel) => {
|
|
941
|
+
panel.scrollTo('details#fields')
|
|
942
|
+
})
|
|
943
|
+
})
|
|
944
|
+
})
|
|
945
|
+
del.addEventListener('click', () => {
|
|
946
|
+
this.confirmDeleteProperty(field.key).then(() => {
|
|
947
|
+
this.edit().then((panel) => {
|
|
948
|
+
panel.scrollTo('details#fields')
|
|
949
|
+
})
|
|
950
|
+
})
|
|
951
|
+
})
|
|
952
|
+
}
|
|
953
|
+
const onReorder = (src, dst, initialIndex, finalIndex) => {
|
|
954
|
+
const orderedKeys = Array.from(ul.querySelectorAll('li')).map(
|
|
955
|
+
(el) => el.dataset.key
|
|
956
|
+
)
|
|
957
|
+
const oldFields = Utils.CopyJSON(this.properties.fields)
|
|
958
|
+
this.properties.fields.sort(
|
|
959
|
+
(fieldA, fieldB) =>
|
|
960
|
+
orderedKeys.indexOf(fieldA.key) > orderedKeys.indexOf(fieldB.key)
|
|
961
|
+
)
|
|
962
|
+
this.sync.update('properties.fields', this.properties.fields, oldFields)
|
|
963
|
+
}
|
|
964
|
+
const orderable = new Orderable(ul, onReorder)
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
_editRemoteDataProperties(container) {
|
|
868
968
|
// XXX I'm not sure **why** this is needed (as it's set during `this.initialize`)
|
|
869
969
|
// but apparently it's needed.
|
|
870
970
|
if (!Utils.isObject(this.properties.remoteData)) {
|
|
871
971
|
this.properties.remoteData = {}
|
|
872
972
|
}
|
|
873
973
|
|
|
874
|
-
const
|
|
974
|
+
const fields = [
|
|
875
975
|
[
|
|
876
976
|
'properties.remoteData.url',
|
|
877
977
|
{ handler: 'Url', label: translate('Url'), helpEntries: ['formatURL'] },
|
|
@@ -899,7 +999,7 @@ export class DataLayer {
|
|
|
899
999
|
],
|
|
900
1000
|
]
|
|
901
1001
|
if (this._umap.properties.urls.ajax_proxy) {
|
|
902
|
-
|
|
1002
|
+
fields.push([
|
|
903
1003
|
'properties.remoteData.proxy',
|
|
904
1004
|
{
|
|
905
1005
|
handler: 'Switch',
|
|
@@ -907,14 +1007,14 @@ export class DataLayer {
|
|
|
907
1007
|
helpEntries: ['proxyRemoteData'],
|
|
908
1008
|
},
|
|
909
1009
|
])
|
|
910
|
-
|
|
1010
|
+
fields.push('properties.remoteData.ttl')
|
|
911
1011
|
}
|
|
912
1012
|
|
|
913
1013
|
const remoteDataContainer = DomUtil.createFieldset(
|
|
914
1014
|
container,
|
|
915
1015
|
translate('Remote data')
|
|
916
1016
|
)
|
|
917
|
-
builder = new MutatingForm(this,
|
|
1017
|
+
const builder = new MutatingForm(this, fields)
|
|
918
1018
|
remoteDataContainer.appendChild(builder.build())
|
|
919
1019
|
DomUtil.createButton(
|
|
920
1020
|
'button umap-verify',
|
|
@@ -923,12 +1023,9 @@ export class DataLayer {
|
|
|
923
1023
|
() => this.fetchRemoteData(true),
|
|
924
1024
|
this
|
|
925
1025
|
)
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
if (this._umap.properties.urls.datalayer_versions) {
|
|
929
|
-
this.buildVersionsFieldset(container)
|
|
930
|
-
}
|
|
1026
|
+
}
|
|
931
1027
|
|
|
1028
|
+
_buildAdvancedActions(container) {
|
|
932
1029
|
const advancedActions = DomUtil.createFieldset(
|
|
933
1030
|
container,
|
|
934
1031
|
translate('Advanced actions')
|
|
@@ -963,6 +1060,31 @@ export class DataLayer {
|
|
|
963
1060
|
}
|
|
964
1061
|
clone.addEventListener('click', () => this.clone().edit())
|
|
965
1062
|
if (this.createdOnServer) download.hidden = false
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
edit() {
|
|
1066
|
+
if (!this._umap.editEnabled) {
|
|
1067
|
+
return
|
|
1068
|
+
}
|
|
1069
|
+
const container = DomUtil.create('div', 'umap-layer-properties-container')
|
|
1070
|
+
this._editMetadata(container)
|
|
1071
|
+
this._editLayerProperties(container)
|
|
1072
|
+
this._editShapeProperties(container)
|
|
1073
|
+
this._editAdvancedProperties(container)
|
|
1074
|
+
this._editInteractionProperties(container)
|
|
1075
|
+
this._editTextPathProperties(container)
|
|
1076
|
+
this._editRemoteDataProperties(container)
|
|
1077
|
+
if (!this.isRemoteLayer()) {
|
|
1078
|
+
this._editFields(container)
|
|
1079
|
+
}
|
|
1080
|
+
this.rules.edit(container)
|
|
1081
|
+
|
|
1082
|
+
if (this._umap.properties.urls.datalayer_versions) {
|
|
1083
|
+
this.buildVersionsFieldset(container)
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
this._buildAdvancedActions(container)
|
|
1087
|
+
|
|
966
1088
|
const backButton = DomUtil.createButtonIcon(
|
|
967
1089
|
undefined,
|
|
968
1090
|
'icon-back',
|
|
@@ -973,7 +1095,7 @@ export class DataLayer {
|
|
|
973
1095
|
DomEvent.disableClickPropagation(backButton)
|
|
974
1096
|
DomEvent.on(backButton, 'click', this._umap.editDatalayers, this._umap)
|
|
975
1097
|
|
|
976
|
-
this._umap.editPanel.open({
|
|
1098
|
+
return this._umap.editPanel.open({
|
|
977
1099
|
content: container,
|
|
978
1100
|
highlight: 'layers',
|
|
979
1101
|
actions: [backButton],
|
|
@@ -1060,12 +1182,6 @@ export class DataLayer {
|
|
|
1060
1182
|
})
|
|
1061
1183
|
}
|
|
1062
1184
|
|
|
1063
|
-
featuresToGeoJSON() {
|
|
1064
|
-
const features = []
|
|
1065
|
-
this.eachFeature((feature) => features.push(feature.toGeoJSON()))
|
|
1066
|
-
return features
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
1185
|
async show() {
|
|
1070
1186
|
this._leafletMap.addLayer(this.layer)
|
|
1071
1187
|
if (!this.isLoaded()) await this.fetchData()
|
|
@@ -1078,10 +1194,11 @@ export class DataLayer {
|
|
|
1078
1194
|
}
|
|
1079
1195
|
|
|
1080
1196
|
toggle(force) {
|
|
1081
|
-
// From now on, do not try to how/
|
|
1082
|
-
// automatically this layer
|
|
1083
|
-
|
|
1197
|
+
// From now on, do not try to how/hide
|
|
1198
|
+
// automatically this layer, as user
|
|
1199
|
+
// has taken control on this.
|
|
1084
1200
|
this._forcedVisibility = true
|
|
1201
|
+
let display = force
|
|
1085
1202
|
if (force === undefined) {
|
|
1086
1203
|
if (!this.isVisible()) display = true
|
|
1087
1204
|
else display = false
|
|
@@ -1123,46 +1240,23 @@ export class DataLayer {
|
|
|
1123
1240
|
}
|
|
1124
1241
|
|
|
1125
1242
|
count() {
|
|
1126
|
-
return this.
|
|
1243
|
+
return this.features.count()
|
|
1127
1244
|
}
|
|
1128
1245
|
|
|
1129
1246
|
hasData() {
|
|
1130
|
-
return !!this.
|
|
1247
|
+
return !!this.count()
|
|
1131
1248
|
}
|
|
1132
1249
|
|
|
1133
1250
|
isVisible() {
|
|
1134
1251
|
return Boolean(this.layer && this._leafletMap.hasLayer(this.layer))
|
|
1135
1252
|
}
|
|
1136
1253
|
|
|
1137
|
-
getFeatureByIndex(index) {
|
|
1138
|
-
if (index === -1) index = this._index.length - 1
|
|
1139
|
-
const id = this._index[index]
|
|
1140
|
-
return this._features[id]
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
// TODO Add an index
|
|
1144
|
-
// For now, iterate on all the features.
|
|
1145
|
-
getFeatureById(id) {
|
|
1146
|
-
return Object.values(this._features).find((feature) => feature.id === id)
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
1254
|
getNextFeature(feature) {
|
|
1150
|
-
|
|
1151
|
-
const nextId = this._index[id + 1]
|
|
1152
|
-
return nextId
|
|
1153
|
-
? this._features[nextId]
|
|
1154
|
-
: this.getNextBrowsable().getFeatureByIndex(0)
|
|
1255
|
+
return this.features.next(feature) || this.getNextBrowsable().features.first()
|
|
1155
1256
|
}
|
|
1156
1257
|
|
|
1157
1258
|
getPreviousFeature(feature) {
|
|
1158
|
-
|
|
1159
|
-
return null
|
|
1160
|
-
}
|
|
1161
|
-
const id = this._index.indexOf(stamp(feature))
|
|
1162
|
-
const previousId = this._index[id - 1]
|
|
1163
|
-
return previousId
|
|
1164
|
-
? this._features[previousId]
|
|
1165
|
-
: this.getPreviousBrowsable().getFeatureByIndex(-1)
|
|
1259
|
+
return this.features.prev(feature) || this.getPreviousBrowsable().features.last()
|
|
1166
1260
|
}
|
|
1167
1261
|
|
|
1168
1262
|
getPreviousBrowsable() {
|
|
@@ -1174,11 +1268,9 @@ export class DataLayer {
|
|
|
1174
1268
|
}
|
|
1175
1269
|
|
|
1176
1270
|
umapGeoJSON() {
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
_umap_options: this.properties,
|
|
1181
|
-
}
|
|
1271
|
+
const geojson = this._umap.formatter.toFeatureCollection(this.features.all())
|
|
1272
|
+
geojson._umap_options = this.properties
|
|
1273
|
+
return geojson
|
|
1182
1274
|
}
|
|
1183
1275
|
|
|
1184
1276
|
getDOMOrder() {
|
|
@@ -1322,8 +1414,27 @@ export class DataLayer {
|
|
|
1322
1414
|
)) {
|
|
1323
1415
|
container.innerHTML = ''
|
|
1324
1416
|
if (this.layer.renderLegend) return this.layer.renderLegend(container)
|
|
1325
|
-
const
|
|
1326
|
-
|
|
1417
|
+
const keys = new Set(this.fieldKeys)
|
|
1418
|
+
const rules = new Map()
|
|
1419
|
+
for (const rule of this.rules) {
|
|
1420
|
+
rules.set(rule.condition, rule)
|
|
1421
|
+
}
|
|
1422
|
+
for (const rule of this._umap.rules) {
|
|
1423
|
+
if (!rules.has(rule.condition) && keys.has(rule.key)) {
|
|
1424
|
+
rules.set(rule.condition, rule)
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
if (rules.size) {
|
|
1428
|
+
const ul = Utils.loadTemplate('<ul class="rules-caption"></ul>')
|
|
1429
|
+
container.appendChild(ul)
|
|
1430
|
+
for (const [_, rule] of rules) {
|
|
1431
|
+
rule.renderLegend(ul)
|
|
1432
|
+
}
|
|
1433
|
+
} else {
|
|
1434
|
+
const color = Utils.loadTemplate('<span class="datalayer-color"></span>')
|
|
1435
|
+
color.style.backgroundColor = this.getColor()
|
|
1436
|
+
container.appendChild(color)
|
|
1437
|
+
}
|
|
1327
1438
|
}
|
|
1328
1439
|
}
|
|
1329
1440
|
|