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
|
@@ -22,6 +22,8 @@ import {
|
|
|
22
22
|
PermanentCreditsControl,
|
|
23
23
|
TileLayerChooser,
|
|
24
24
|
LoadTemplateControl,
|
|
25
|
+
PrintControl,
|
|
26
|
+
SearchControl,
|
|
25
27
|
} from './controls.js'
|
|
26
28
|
import * as Utils from '../utils.js'
|
|
27
29
|
import * as Icon from './icon.js'
|
|
@@ -45,6 +47,7 @@ const ControlsMixin = {
|
|
|
45
47
|
'locate',
|
|
46
48
|
'measure',
|
|
47
49
|
'editinosm',
|
|
50
|
+
'print',
|
|
48
51
|
'tilelayers',
|
|
49
52
|
],
|
|
50
53
|
|
|
@@ -84,8 +87,9 @@ const ControlsMixin = {
|
|
|
84
87
|
true: translate('Exit Fullscreen'),
|
|
85
88
|
},
|
|
86
89
|
})
|
|
87
|
-
this._controls.search = new
|
|
90
|
+
this._controls.search = new SearchControl(this._umap)
|
|
88
91
|
this._controls.embed = new EmbedControl(this._umap)
|
|
92
|
+
this._controls.print = new PrintControl(this._umap)
|
|
89
93
|
this._controls.tilelayersChooser = new TileLayerChooser(this._umap)
|
|
90
94
|
this._controls.editinosm = new Control.EditInOSM({
|
|
91
95
|
position: 'topleft',
|
|
@@ -335,7 +339,7 @@ export const LeafletMap = BaseMap.extend({
|
|
|
335
339
|
const datalayer = this._umap.datalayers.visible()[0]
|
|
336
340
|
let feature
|
|
337
341
|
if (datalayer) {
|
|
338
|
-
const feature = datalayer.
|
|
342
|
+
const feature = datalayer.features.last()
|
|
339
343
|
if (feature) {
|
|
340
344
|
feature.zoomTo({ callback: this.options.noControl ? null : feature.view })
|
|
341
345
|
return
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
DomEvent,
|
|
3
|
+
DomUtil,
|
|
4
|
+
CircleMarker,
|
|
5
|
+
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
|
2
6
|
import { getLocale, translate } from '../i18n.js'
|
|
3
7
|
import { Request } from '../request.js'
|
|
4
8
|
import * as Utils from '../utils.js'
|
|
@@ -22,6 +26,9 @@ export default async function loadTemplate(name, feature, container) {
|
|
|
22
26
|
case 'Wikipedia':
|
|
23
27
|
klass = Wikipedia
|
|
24
28
|
break
|
|
29
|
+
case 'Route':
|
|
30
|
+
klass = Route
|
|
31
|
+
break
|
|
25
32
|
}
|
|
26
33
|
const content = new klass()
|
|
27
34
|
return await content.render(feature, container)
|
|
@@ -282,3 +289,66 @@ class Wikipedia extends PopupTemplate {
|
|
|
282
289
|
return body
|
|
283
290
|
}
|
|
284
291
|
}
|
|
292
|
+
|
|
293
|
+
class Route extends TitleMixin(PopupTemplate) {
|
|
294
|
+
async renderBody(feature) {
|
|
295
|
+
if (feature.type !== 'LineString' || feature.isMulti()) {
|
|
296
|
+
return super.renderBody(feature)
|
|
297
|
+
}
|
|
298
|
+
let prev
|
|
299
|
+
let dist = 0
|
|
300
|
+
const data = []
|
|
301
|
+
const latlngs = feature.ui.getLatLngs()
|
|
302
|
+
const map = feature._umap._leafletMap
|
|
303
|
+
const properties = feature.extendedProperties()
|
|
304
|
+
for (const latlng of latlngs) {
|
|
305
|
+
if (!latlng.alt) {
|
|
306
|
+
continue
|
|
307
|
+
}
|
|
308
|
+
if (prev) {
|
|
309
|
+
dist = map.distance(latlng, prev)
|
|
310
|
+
}
|
|
311
|
+
data.push([latlng.alt, dist])
|
|
312
|
+
prev = latlng
|
|
313
|
+
}
|
|
314
|
+
const [root, { altitude, chart }] = Utils.loadTemplateWithRefs(`
|
|
315
|
+
<div>
|
|
316
|
+
<p>
|
|
317
|
+
${translate('Distance:')} ${properties.measure} •
|
|
318
|
+
${translate('Gain:')} ${properties.gain} m ↗ •
|
|
319
|
+
${translate('Loss:')} ${properties.loss} m ↘ •
|
|
320
|
+
${translate('Altitude:')} <span data-ref="altitude">—</span> m
|
|
321
|
+
</p>
|
|
322
|
+
<object width="100%"
|
|
323
|
+
data="${feature._umap.getStaticPathFor('../vendors/simple-elevation-chart/elevation.svg')}"
|
|
324
|
+
data-elevation="${JSON.stringify(data)}"
|
|
325
|
+
data-ref="chart"
|
|
326
|
+
type="image/svg+xml">
|
|
327
|
+
</div>
|
|
328
|
+
`)
|
|
329
|
+
let marker
|
|
330
|
+
function removeMarker() {
|
|
331
|
+
if (marker) {
|
|
332
|
+
marker.remove()
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
chart.addEventListener('mouseout', removeMarker)
|
|
336
|
+
map.on('popupclose', removeMarker)
|
|
337
|
+
chart.addEventListener('chart:over', (event) => {
|
|
338
|
+
const dataset = event.detail.element.dataset
|
|
339
|
+
if (dataset.ele) {
|
|
340
|
+
altitude.textContent = dataset.ele
|
|
341
|
+
}
|
|
342
|
+
removeMarker()
|
|
343
|
+
const latlng = latlngs[dataset.index]
|
|
344
|
+
if (!latlng) return
|
|
345
|
+
marker = new CircleMarker(latlng, {
|
|
346
|
+
radius: 8,
|
|
347
|
+
fillColor: 'white',
|
|
348
|
+
fillOpacity: 1,
|
|
349
|
+
color: 'orange',
|
|
350
|
+
}).addTo(map)
|
|
351
|
+
})
|
|
352
|
+
return root
|
|
353
|
+
}
|
|
354
|
+
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
CircleMarker as BaseCircleMarker,
|
|
4
4
|
DomEvent,
|
|
5
5
|
DomUtil,
|
|
6
|
+
GeoJSON,
|
|
6
7
|
LatLng,
|
|
7
8
|
LatLngBounds,
|
|
8
9
|
LineUtil,
|
|
@@ -45,26 +46,29 @@ const FeatureMixin = {
|
|
|
45
46
|
this.on('contextmenu editable:vertex:contextmenu', this.onContextMenu)
|
|
46
47
|
this.on('click', this.onClick)
|
|
47
48
|
this.on('editable:edited', this.onCommit)
|
|
49
|
+
this.on('mouseover', this.onMouseOver)
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
onMouseOver: function () {
|
|
53
|
+
if (this._map._umap.editEnabled && !this._map._umap.editedFeature) {
|
|
54
|
+
this._map._umap.tooltip.open({
|
|
55
|
+
content: translate('Right-click to edit'),
|
|
56
|
+
anchor: this,
|
|
57
|
+
})
|
|
58
|
+
}
|
|
48
59
|
},
|
|
49
60
|
|
|
50
61
|
onClick: function (event) {
|
|
51
62
|
if (this._map.measureTools?.enabled()) return
|
|
52
63
|
this._popupHandlersAdded = true // Prevent leaflet from managing event
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
this.feature.datalayer.edit(event)
|
|
59
|
-
} else {
|
|
60
|
-
this.feature.toggleEditing(event)
|
|
61
|
-
}
|
|
62
|
-
} else if (!this._map.editTools?.drawing()) {
|
|
63
|
-
this._map._umap.editContextmenu.open(
|
|
64
|
-
event.originalEvent,
|
|
65
|
-
this.feature.getInplaceEditMenu(event)
|
|
66
|
-
)
|
|
64
|
+
if (event.originalEvent.shiftKey) {
|
|
65
|
+
if (event.originalEvent.ctrlKey || event.originalEvent.metaKey) {
|
|
66
|
+
this.feature.datalayer.edit(event)
|
|
67
|
+
} else if (!this.feature.isReadOnly()) {
|
|
68
|
+
this.feature.toggleEditing(event)
|
|
67
69
|
}
|
|
70
|
+
} else if (!this._map.editTools?.drawing()) {
|
|
71
|
+
this.feature.view(event)
|
|
68
72
|
}
|
|
69
73
|
DomEvent.stop(event)
|
|
70
74
|
},
|
|
@@ -91,8 +95,8 @@ const FeatureMixin = {
|
|
|
91
95
|
onContextMenu: function (event) {
|
|
92
96
|
DomEvent.stop(event)
|
|
93
97
|
const items = this.feature
|
|
94
|
-
.
|
|
95
|
-
.concat(this._map._umap.
|
|
98
|
+
.getContextMenu(event)
|
|
99
|
+
.concat(this._map._umap.getSharedContextMenu(event))
|
|
96
100
|
this._map._umap.contextmenu.open(event.originalEvent, items)
|
|
97
101
|
},
|
|
98
102
|
|
|
@@ -123,6 +127,7 @@ const PointMixin = {
|
|
|
123
127
|
},
|
|
124
128
|
|
|
125
129
|
_enableDragging: function () {
|
|
130
|
+
if (this._cluster) return
|
|
126
131
|
// TODO: start dragging after 1 second on mouse down
|
|
127
132
|
if (this._map._umap.editEnabled) {
|
|
128
133
|
if (!this.editEnabled()) this.enableEdit()
|
|
@@ -238,20 +243,33 @@ export const LeafletMarker = Marker.extend({
|
|
|
238
243
|
this._redraw()
|
|
239
244
|
this._resetZIndex()
|
|
240
245
|
},
|
|
246
|
+
|
|
247
|
+
_resetZIndex() {
|
|
248
|
+
// Override Leaflet default behaviour, which set the zIndex
|
|
249
|
+
// according to feature's y coordinate, and group features
|
|
250
|
+
// zIndex by their datalayer order
|
|
251
|
+
this._zIndex = this.feature.datalayer.getDOMOrder()
|
|
252
|
+
this._updateZIndex(0)
|
|
253
|
+
},
|
|
241
254
|
})
|
|
242
255
|
|
|
243
256
|
const PathMixin = {
|
|
244
|
-
|
|
257
|
+
maxVertex: 100,
|
|
258
|
+
onMouseOver: function () {
|
|
245
259
|
if (this._map.measureTools?.enabled()) {
|
|
246
260
|
this._map._umap.tooltip.open({ content: this.getMeasure(), anchor: this })
|
|
247
|
-
} else
|
|
248
|
-
|
|
249
|
-
content: translate('Click to edit'),
|
|
250
|
-
anchor: this,
|
|
251
|
-
})
|
|
261
|
+
} else {
|
|
262
|
+
FeatureMixin.onMouseOver.call(this)
|
|
252
263
|
}
|
|
253
264
|
},
|
|
254
265
|
|
|
266
|
+
shouldAllowGeometryEdit: function () {
|
|
267
|
+
const pointsCount = this._parts.reduce((acc, part) => acc + part.length, 0)
|
|
268
|
+
return (
|
|
269
|
+
pointsCount < this.maxVertex || this._map.getZoom() === this._map.getMaxZoom()
|
|
270
|
+
)
|
|
271
|
+
},
|
|
272
|
+
|
|
255
273
|
makeGeometryEditable: function () {
|
|
256
274
|
// Feature has been removed since then?
|
|
257
275
|
if (!this._map) return
|
|
@@ -260,20 +278,18 @@ const PathMixin = {
|
|
|
260
278
|
return
|
|
261
279
|
}
|
|
262
280
|
this._map.once('moveend', this.makeGeometryEditable, this)
|
|
263
|
-
|
|
264
|
-
|
|
281
|
+
if (this.shouldAllowGeometryEdit()) {
|
|
282
|
+
this.enableEdit()
|
|
283
|
+
} else {
|
|
265
284
|
this._map._umap.tooltip.open({
|
|
266
285
|
content: L._('Please zoom in to edit the geometry'),
|
|
267
286
|
})
|
|
268
287
|
this.disableEdit()
|
|
269
|
-
} else {
|
|
270
|
-
this.enableEdit()
|
|
271
288
|
}
|
|
272
289
|
},
|
|
273
290
|
|
|
274
291
|
addInteractions: function () {
|
|
275
292
|
FeatureMixin.addInteractions.call(this)
|
|
276
|
-
this.on('mouseover', this._onMouseOver)
|
|
277
293
|
this.on('drag editable:drag', this._onDrag)
|
|
278
294
|
this.on('popupopen', this.highlightPath)
|
|
279
295
|
this.on('popupclose', this._redraw)
|
|
@@ -285,6 +301,7 @@ const PathMixin = {
|
|
|
285
301
|
},
|
|
286
302
|
|
|
287
303
|
highlightPath: function () {
|
|
304
|
+
this.feature.activate()
|
|
288
305
|
this.parentClass.prototype.setStyle.call(this, {
|
|
289
306
|
fillOpacity: Math.sqrt(this.feature.getDynamicOption('fillOpacity', 1.0)),
|
|
290
307
|
opacity: 1.0,
|
|
@@ -296,6 +313,11 @@ const PathMixin = {
|
|
|
296
313
|
if (this._tooltip) this._tooltip.setLatLng(this.getCenter())
|
|
297
314
|
},
|
|
298
315
|
|
|
316
|
+
beforeAdd: function (map) {
|
|
317
|
+
this.options.renderer = this.feature.datalayer.renderer
|
|
318
|
+
this.parentClass.prototype.beforeAdd.call(this, map)
|
|
319
|
+
},
|
|
320
|
+
|
|
299
321
|
onAdd: function (map) {
|
|
300
322
|
this._container = null
|
|
301
323
|
FeatureMixin.onAdd.call(this, map)
|
|
@@ -323,17 +345,11 @@ const PathMixin = {
|
|
|
323
345
|
},
|
|
324
346
|
|
|
325
347
|
_redraw: function () {
|
|
348
|
+
this.feature.deactivate()
|
|
326
349
|
this.setStyle()
|
|
327
350
|
this.resetTooltip()
|
|
328
351
|
},
|
|
329
352
|
|
|
330
|
-
onVertexRawClick: function (event) {
|
|
331
|
-
this._map._umap.editContextmenu.open(
|
|
332
|
-
event.originalEvent,
|
|
333
|
-
this.feature.getInplaceEditVertexMenu(event)
|
|
334
|
-
)
|
|
335
|
-
},
|
|
336
|
-
|
|
337
353
|
isolateShape: function (atLatLng) {
|
|
338
354
|
if (!this.feature.isMulti()) return
|
|
339
355
|
const shape = this.enableEdit().deleteShapeAt(atLatLng)
|
|
@@ -444,6 +460,67 @@ export const LeafletPolyline = Polyline.extend({
|
|
|
444
460
|
},
|
|
445
461
|
})
|
|
446
462
|
|
|
463
|
+
export const RouteEditor = L.Editable.PolylineEditor.extend({
|
|
464
|
+
options: {
|
|
465
|
+
skipMiddleMarkers: true,
|
|
466
|
+
draggable: false,
|
|
467
|
+
},
|
|
468
|
+
|
|
469
|
+
getLatLngs: function () {
|
|
470
|
+
return this.feature._route
|
|
471
|
+
},
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
export const LeafletRoute = LeafletPolyline.extend({
|
|
475
|
+
initialize: function (feature, latlngs) {
|
|
476
|
+
this._route = GeoJSON.coordsToLatLngs(
|
|
477
|
+
feature.properties._umap_options.route?.coordinates
|
|
478
|
+
)
|
|
479
|
+
FeatureMixin.initialize.call(this, feature, latlngs)
|
|
480
|
+
delete this.dragging
|
|
481
|
+
},
|
|
482
|
+
|
|
483
|
+
addInteractions: function () {
|
|
484
|
+
PathMixin.addInteractions.call(this)
|
|
485
|
+
this.on('editable:drawing:clicked', this.onDrawingClick)
|
|
486
|
+
this.on('editable:vertex:dragend editable:vertex:deleted', this.onDrawingMoved)
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
getEditorClass: (tools) => {
|
|
490
|
+
return RouteEditor
|
|
491
|
+
},
|
|
492
|
+
|
|
493
|
+
getClass: () => LeafletRoute,
|
|
494
|
+
|
|
495
|
+
syncRoute() {
|
|
496
|
+
this.feature.properties._umap_options.route.coordinates = GeoJSON.latLngsToCoords(
|
|
497
|
+
this._route
|
|
498
|
+
)
|
|
499
|
+
},
|
|
500
|
+
|
|
501
|
+
onDrawingMoved: function (event) {
|
|
502
|
+
this.syncRoute()
|
|
503
|
+
if (this._route.length >= 2) {
|
|
504
|
+
this.feature.computeRoute()
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
onDrawingClick: function (event) {
|
|
509
|
+
this._route.push(event.latlng)
|
|
510
|
+
this.syncRoute()
|
|
511
|
+
if (this._route.length >= 2) {
|
|
512
|
+
this.feature.computeRoute()
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
|
|
516
|
+
shouldAllowGeometryEdit: function () {
|
|
517
|
+
return (
|
|
518
|
+
this._route.length < this.maxVertex ||
|
|
519
|
+
this._map.getZoom() === this._map.getMaxZoom()
|
|
520
|
+
)
|
|
521
|
+
},
|
|
522
|
+
})
|
|
523
|
+
|
|
447
524
|
export const LeafletPolygon = Polygon.extend({
|
|
448
525
|
parentClass: Polygon,
|
|
449
526
|
includes: [FeatureMixin, PathMixin],
|
|
@@ -4,6 +4,8 @@ import { MutatingForm } from './form/builder.js'
|
|
|
4
4
|
import { translate } from './i18n.js'
|
|
5
5
|
import Orderable from './orderable.js'
|
|
6
6
|
import * as Utils from './utils.js'
|
|
7
|
+
import * as Icon from './rendering/icon.js'
|
|
8
|
+
import { SCHEMA } from './schema.js'
|
|
7
9
|
|
|
8
10
|
const EMPTY_VALUES = ['', undefined, null]
|
|
9
11
|
|
|
@@ -12,12 +14,16 @@ class Rule {
|
|
|
12
14
|
return this._condition
|
|
13
15
|
}
|
|
14
16
|
|
|
17
|
+
get label() {
|
|
18
|
+
return this.name || this.condition
|
|
19
|
+
}
|
|
20
|
+
|
|
15
21
|
set condition(value) {
|
|
16
22
|
this._condition = value
|
|
17
23
|
this.parse()
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
constructor(umap, parent, condition = '',
|
|
26
|
+
constructor(umap, parent, condition = '', name = '', properties = {}) {
|
|
21
27
|
// TODO make this public properties when browser coverage is ok
|
|
22
28
|
// cf https://caniuse.com/?search=public%20class%20field
|
|
23
29
|
this._condition = null
|
|
@@ -32,8 +38,9 @@ class Rule {
|
|
|
32
38
|
this.parent = parent
|
|
33
39
|
this._umap = umap
|
|
34
40
|
this.active = true
|
|
35
|
-
this.
|
|
41
|
+
this.properties = properties
|
|
36
42
|
this.condition = condition
|
|
43
|
+
this.name = name
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
render(fields) {
|
|
@@ -95,7 +102,7 @@ class Rule {
|
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
getOption(option) {
|
|
98
|
-
return this.
|
|
105
|
+
return this.properties[option]
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
edit() {
|
|
@@ -108,23 +115,24 @@ class Rule {
|
|
|
108
115
|
placeholder: translate('key=value or key!=value'),
|
|
109
116
|
},
|
|
110
117
|
],
|
|
111
|
-
'
|
|
112
|
-
'
|
|
113
|
-
'
|
|
114
|
-
'
|
|
115
|
-
'
|
|
116
|
-
'
|
|
117
|
-
'
|
|
118
|
-
'
|
|
119
|
-
'
|
|
120
|
-
'
|
|
121
|
-
'
|
|
118
|
+
'name',
|
|
119
|
+
'properties.color',
|
|
120
|
+
'properties.iconClass',
|
|
121
|
+
'properties.iconUrl',
|
|
122
|
+
'properties.iconOpacity',
|
|
123
|
+
'properties.opacity',
|
|
124
|
+
'properties.weight',
|
|
125
|
+
'properties.fill',
|
|
126
|
+
'properties.fillColor',
|
|
127
|
+
'properties.fillOpacity',
|
|
128
|
+
'properties.smoothFactor',
|
|
129
|
+
'properties.dashArray',
|
|
122
130
|
]
|
|
123
131
|
const builder = new MutatingForm(this, options)
|
|
124
132
|
const container = document.createElement('div')
|
|
125
133
|
container.appendChild(builder.build())
|
|
126
134
|
const autocomplete = new AutocompleteDatalist(builder.helpers.condition.input)
|
|
127
|
-
const properties = this.parent.
|
|
135
|
+
const properties = this.parent.fieldKeys
|
|
128
136
|
autocomplete.suggestions = properties
|
|
129
137
|
autocomplete.input.addEventListener('input', (event) => {
|
|
130
138
|
const value = event.target.value
|
|
@@ -143,7 +151,7 @@ class Rule {
|
|
|
143
151
|
</button>`)
|
|
144
152
|
backButton.addEventListener('click', () =>
|
|
145
153
|
this.parent.edit().then((panel) => {
|
|
146
|
-
panel.
|
|
154
|
+
panel.scrollTo('details#rules')
|
|
147
155
|
})
|
|
148
156
|
)
|
|
149
157
|
|
|
@@ -160,7 +168,7 @@ class Rule {
|
|
|
160
168
|
<button class="icon icon-16 icon-eye" title="${translate('Toggle rule')}" data-ref=toggle></button>
|
|
161
169
|
<button class="icon icon-16 icon-edit show-on-edit" title="${translate('Edit')}" data-ref=edit></button>
|
|
162
170
|
<button class="icon icon-16 icon-delete show-on-edit" title="${translate('Delete rule')}" data-ref=remove></button>
|
|
163
|
-
<span>${this.
|
|
171
|
+
<span>${this.label || translate('empty rule')}</span>
|
|
164
172
|
<i class="icon icon-16 icon-drag" title="${translate('Drag to reorder')}"></i>
|
|
165
173
|
</li>
|
|
166
174
|
`
|
|
@@ -171,7 +179,7 @@ class Rule {
|
|
|
171
179
|
remove.addEventListener('click', () => {
|
|
172
180
|
if (!confirm(translate('Are you sure you want to delete this rule?'))) return
|
|
173
181
|
this._delete()
|
|
174
|
-
this.
|
|
182
|
+
this.parent.edit().then((panel) => panel.scrollTo('details#rules'))
|
|
175
183
|
})
|
|
176
184
|
toggle.addEventListener('click', () => {
|
|
177
185
|
this.active = !this.active
|
|
@@ -181,8 +189,11 @@ class Rule {
|
|
|
181
189
|
}
|
|
182
190
|
|
|
183
191
|
_delete() {
|
|
192
|
+
// TODO refactor this call to update
|
|
193
|
+
const oldRules = Utils.CopyJSON(this.parent.properties.rules || {})
|
|
184
194
|
this.parent.rules.rules = this.parent.rules.rules.filter((rule) => rule !== this)
|
|
185
195
|
this.parent.rules.commit()
|
|
196
|
+
this.parent.sync.update('properties.rules', this.parent.properties.rules, oldRules)
|
|
186
197
|
}
|
|
187
198
|
|
|
188
199
|
setter(key, value) {
|
|
@@ -191,6 +202,20 @@ class Rule {
|
|
|
191
202
|
this.parent.rules.commit()
|
|
192
203
|
this.parent.sync.update('properties.rules', this.parent.properties.rules, oldRules)
|
|
193
204
|
}
|
|
205
|
+
|
|
206
|
+
renderLegend(ul) {
|
|
207
|
+
const [li, { colorBox }] = Utils.loadTemplateWithRefs(
|
|
208
|
+
`<li><span class="color-box" data-ref=colorBox></span>${this.label}</li>`
|
|
209
|
+
)
|
|
210
|
+
const bgcolor = this.properties.color || this.parent.getColor()
|
|
211
|
+
const symbol = this.properties.iconUrl
|
|
212
|
+
colorBox.style.backgroundColor = bgcolor
|
|
213
|
+
if (symbol && symbol !== SCHEMA.iconUrl.default) {
|
|
214
|
+
const icon = Icon.makeElement(symbol, colorBox)
|
|
215
|
+
Icon.setContrast(icon, colorBox, symbol, bgcolor)
|
|
216
|
+
}
|
|
217
|
+
ul.appendChild(li)
|
|
218
|
+
}
|
|
194
219
|
}
|
|
195
220
|
|
|
196
221
|
export default class Rules {
|
|
@@ -203,9 +228,17 @@ export default class Rules {
|
|
|
203
228
|
load() {
|
|
204
229
|
this.rules = []
|
|
205
230
|
if (!this.parent.properties.rules?.length) return
|
|
206
|
-
for (const { condition, options } of this.parent.properties
|
|
231
|
+
for (const { condition, name, properties, options } of this.parent.properties
|
|
232
|
+
.rules) {
|
|
207
233
|
if (!condition) continue
|
|
208
|
-
|
|
234
|
+
const rule = new Rule(
|
|
235
|
+
this._umap,
|
|
236
|
+
this.parent,
|
|
237
|
+
condition,
|
|
238
|
+
name,
|
|
239
|
+
properties || options
|
|
240
|
+
)
|
|
241
|
+
this.rules.push(rule)
|
|
209
242
|
}
|
|
210
243
|
}
|
|
211
244
|
|
|
@@ -250,6 +283,19 @@ export default class Rules {
|
|
|
250
283
|
container.appendChild(body)
|
|
251
284
|
}
|
|
252
285
|
|
|
286
|
+
count() {
|
|
287
|
+
return this.rules.length
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
renderLegend(container, keys = new Set()) {
|
|
291
|
+
const ul = Utils.loadTemplate('<ul class="rules-caption"></ul>')
|
|
292
|
+
container.appendChild(ul)
|
|
293
|
+
for (const rule of this.rules) {
|
|
294
|
+
if (keys.size && !keys.has(rule.key)) continue
|
|
295
|
+
rule.renderLegend(ul)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
253
299
|
addRule() {
|
|
254
300
|
const rule = new Rule(this._umap, this.parent)
|
|
255
301
|
this.rules.push(rule)
|
|
@@ -259,17 +305,24 @@ export default class Rules {
|
|
|
259
305
|
commit() {
|
|
260
306
|
this.parent.properties.rules = this.rules.map((rule) => {
|
|
261
307
|
return {
|
|
308
|
+
name: rule.name,
|
|
262
309
|
condition: rule.condition,
|
|
263
|
-
|
|
310
|
+
properties: rule.properties,
|
|
264
311
|
}
|
|
265
312
|
})
|
|
266
313
|
}
|
|
267
314
|
|
|
268
|
-
getOption(
|
|
315
|
+
getOption(name, feature) {
|
|
269
316
|
for (const rule of this.rules) {
|
|
270
317
|
if (rule.match(feature.properties)) {
|
|
271
|
-
if (Utils.usableOption(rule.
|
|
318
|
+
if (Utils.usableOption(rule.properties, name)) return rule.properties[name]
|
|
272
319
|
}
|
|
273
320
|
}
|
|
274
321
|
}
|
|
322
|
+
|
|
323
|
+
*[Symbol.iterator]() {
|
|
324
|
+
for (const rule of this.rules) {
|
|
325
|
+
yield rule
|
|
326
|
+
}
|
|
327
|
+
}
|
|
275
328
|
}
|
|
@@ -147,6 +147,9 @@ export const SCHEMA = {
|
|
|
147
147
|
placeholder: translate('Example: key1,key2|Label 2,key3|Label 3|checkbox'),
|
|
148
148
|
label: translate('Filters keys'),
|
|
149
149
|
},
|
|
150
|
+
fields: {
|
|
151
|
+
type: Object,
|
|
152
|
+
},
|
|
150
153
|
fill: {
|
|
151
154
|
type: Boolean,
|
|
152
155
|
impacts: ['data'],
|
|
@@ -215,6 +218,7 @@ export const SCHEMA = {
|
|
|
215
218
|
choices: [
|
|
216
219
|
['Default', translate('Default')],
|
|
217
220
|
['Circle', translate('Circle')],
|
|
221
|
+
['LargeCircle', translate('Large Circle')],
|
|
218
222
|
['Drop', translate('Drop')],
|
|
219
223
|
['Ball', translate('Ball')],
|
|
220
224
|
['Raw', translate('None')],
|
|
@@ -231,6 +235,17 @@ export const SCHEMA = {
|
|
|
231
235
|
inheritable: true,
|
|
232
236
|
default: 1,
|
|
233
237
|
},
|
|
238
|
+
iconSize: {
|
|
239
|
+
type: Number,
|
|
240
|
+
impacts: ['data'],
|
|
241
|
+
min: 12,
|
|
242
|
+
max: 64,
|
|
243
|
+
step: 4,
|
|
244
|
+
label: translate('Icon size'),
|
|
245
|
+
helpText: translate('Will only affect raw and large circle icons.'),
|
|
246
|
+
inheritable: true,
|
|
247
|
+
default: 24,
|
|
248
|
+
},
|
|
234
249
|
iconUrl: {
|
|
235
250
|
type: String,
|
|
236
251
|
impacts: ['data'],
|
|
@@ -435,9 +450,17 @@ export const SCHEMA = {
|
|
|
435
450
|
['GeoRSSLink', translate('GeoRSS (only link)')],
|
|
436
451
|
['OSM', translate('OpenStreetMap')],
|
|
437
452
|
['Wikipedia', translate('Wikipedia')],
|
|
453
|
+
['Route', translate('Route')],
|
|
438
454
|
],
|
|
439
455
|
default: 'Default',
|
|
440
456
|
},
|
|
457
|
+
printControl: {
|
|
458
|
+
type: Boolean,
|
|
459
|
+
impacts: ['ui'],
|
|
460
|
+
nullable: true,
|
|
461
|
+
label: translate('Display the print control'),
|
|
462
|
+
default: null,
|
|
463
|
+
},
|
|
441
464
|
rank: {
|
|
442
465
|
type: Number,
|
|
443
466
|
impacts: ['datalayer-rank'],
|
|
@@ -450,6 +473,10 @@ export const SCHEMA = {
|
|
|
450
473
|
type: Object,
|
|
451
474
|
impacts: ['data'],
|
|
452
475
|
},
|
|
476
|
+
route: {
|
|
477
|
+
type: Object,
|
|
478
|
+
impacts: ['data'],
|
|
479
|
+
},
|
|
453
480
|
scaleControl: {
|
|
454
481
|
type: Boolean,
|
|
455
482
|
impacts: ['ui'],
|
|
@@ -43,7 +43,7 @@ export default class Share {
|
|
|
43
43
|
const list = document.createElement('ul')
|
|
44
44
|
list.classList.add('downloads')
|
|
45
45
|
this.container.appendChild(list)
|
|
46
|
-
for (const format of Object.keys(EXPORT_FORMATS)) {
|
|
46
|
+
for (const format of Object.keys(EXPORT_FORMATS).concat('jpg', 'png')) {
|
|
47
47
|
const button = Utils.loadTemplate(`
|
|
48
48
|
<li>
|
|
49
49
|
<button class="flat" type="button">
|
|
@@ -142,22 +142,29 @@ export default class Share {
|
|
|
142
142
|
|
|
143
143
|
async format(mode) {
|
|
144
144
|
const type = EXPORT_FORMATS[mode]
|
|
145
|
-
const
|
|
145
|
+
const features = this._umap.datalayers
|
|
146
|
+
.visible()
|
|
147
|
+
.reduce((acc, dl) => acc.concat(dl.features.visible()), [])
|
|
148
|
+
const content = await this._umap.formatter.stringify(features, mode)
|
|
146
149
|
const filename = Utils.slugify(this._umap.properties.name) + type.ext
|
|
147
150
|
return { content, filetype: type.filetype, filename }
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
async download(mode) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
if (!(mode in EXPORT_FORMATS)) {
|
|
155
|
+
this._umap.openPrinter(mode)
|
|
156
|
+
} else {
|
|
157
|
+
const { content, filetype, filename } = await this.format(mode)
|
|
158
|
+
const blob = new Blob([content], { type: filetype })
|
|
159
|
+
window.URL = window.URL || window.webkitURL
|
|
160
|
+
const el = document.createElement('a')
|
|
161
|
+
el.download = filename
|
|
162
|
+
el.href = window.URL.createObjectURL(blob)
|
|
163
|
+
el.style.display = 'none'
|
|
164
|
+
document.body.appendChild(el)
|
|
165
|
+
el.click()
|
|
166
|
+
document.body.removeChild(el)
|
|
167
|
+
}
|
|
161
168
|
}
|
|
162
169
|
}
|
|
163
170
|
|
|
@@ -39,7 +39,7 @@ export default class Slideshow extends WithTemplate {
|
|
|
39
39
|
get current() {
|
|
40
40
|
if (!this._current) {
|
|
41
41
|
const datalayer = this.defaultDatalayer()
|
|
42
|
-
if (datalayer) this._current = datalayer.
|
|
42
|
+
if (datalayer) this._current = datalayer.features.first()
|
|
43
43
|
}
|
|
44
44
|
return this._current
|
|
45
45
|
}
|