umap-project 3.2.0__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 +15 -15
- umap/settings/base.py +2 -0
- umap/static/umap/css/contextmenu.css +58 -2
- umap/static/umap/css/form.css +175 -45
- umap/static/umap/css/icon.css +20 -0
- 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/caption.js +8 -0
- umap/static/umap/js/modules/data/features.js +317 -173
- umap/static/umap/js/modules/data/layer.js +17 -18
- umap/static/umap/js/modules/form/builder.js +11 -7
- umap/static/umap/js/modules/form/fields.js +10 -7
- umap/static/umap/js/modules/formatter.js +42 -20
- umap/static/umap/js/modules/importer.js +6 -1
- umap/static/umap/js/modules/importers/opendata.js +125 -37
- umap/static/umap/js/modules/importers/openrouteservice.js +140 -0
- umap/static/umap/js/modules/managers.js +12 -4
- 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 +113 -82
- umap/static/umap/js/modules/rendering/layers/cluster.js +199 -63
- umap/static/umap/js/modules/rendering/map.js +5 -1
- umap/static/umap/js/modules/rendering/template.js +71 -1
- umap/static/umap/js/modules/rendering/ui.js +98 -34
- umap/static/umap/js/modules/schema.js +24 -0
- umap/static/umap/js/modules/share.js +19 -12
- 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/umap.js +67 -61
- umap/static/umap/js/umap.controls.js +22 -57
- umap/static/umap/locale/am_ET.js +39 -4
- umap/static/umap/locale/am_ET.json +39 -4
- umap/static/umap/locale/ar.js +39 -4
- umap/static/umap/locale/ar.json +39 -4
- umap/static/umap/locale/ast.js +39 -4
- umap/static/umap/locale/ast.json +39 -4
- umap/static/umap/locale/bg.js +39 -4
- umap/static/umap/locale/bg.json +39 -4
- umap/static/umap/locale/br.js +39 -4
- umap/static/umap/locale/br.json +39 -4
- umap/static/umap/locale/ca.js +39 -4
- umap/static/umap/locale/ca.json +39 -4
- umap/static/umap/locale/cs_CZ.js +39 -4
- umap/static/umap/locale/cs_CZ.json +39 -4
- umap/static/umap/locale/da.js +47 -12
- umap/static/umap/locale/da.json +47 -12
- umap/static/umap/locale/de.js +39 -4
- umap/static/umap/locale/de.json +39 -4
- umap/static/umap/locale/el.js +39 -4
- umap/static/umap/locale/el.json +39 -4
- umap/static/umap/locale/en.js +39 -4
- umap/static/umap/locale/en.json +39 -4
- umap/static/umap/locale/en_US.json +39 -4
- umap/static/umap/locale/es.js +47 -12
- umap/static/umap/locale/es.json +47 -12
- umap/static/umap/locale/et.js +39 -4
- umap/static/umap/locale/et.json +39 -4
- umap/static/umap/locale/eu.js +79 -44
- umap/static/umap/locale/eu.json +79 -44
- umap/static/umap/locale/fa_IR.js +39 -4
- umap/static/umap/locale/fa_IR.json +39 -4
- umap/static/umap/locale/fi.js +39 -4
- umap/static/umap/locale/fi.json +39 -4
- umap/static/umap/locale/fr.js +39 -4
- umap/static/umap/locale/fr.json +39 -4
- umap/static/umap/locale/gl.js +39 -4
- umap/static/umap/locale/gl.json +39 -4
- umap/static/umap/locale/he.js +39 -4
- umap/static/umap/locale/he.json +39 -4
- umap/static/umap/locale/hr.js +39 -4
- umap/static/umap/locale/hr.json +39 -4
- umap/static/umap/locale/hu.js +39 -4
- umap/static/umap/locale/hu.json +39 -4
- umap/static/umap/locale/id.js +39 -4
- umap/static/umap/locale/id.json +39 -4
- umap/static/umap/locale/is.js +39 -4
- umap/static/umap/locale/is.json +39 -4
- umap/static/umap/locale/it.js +39 -4
- umap/static/umap/locale/it.json +39 -4
- umap/static/umap/locale/ja.js +39 -4
- umap/static/umap/locale/ja.json +39 -4
- umap/static/umap/locale/ko.js +39 -4
- umap/static/umap/locale/ko.json +39 -4
- umap/static/umap/locale/lt.js +39 -4
- umap/static/umap/locale/lt.json +39 -4
- umap/static/umap/locale/ms.js +39 -4
- umap/static/umap/locale/ms.json +39 -4
- umap/static/umap/locale/nl.js +39 -4
- umap/static/umap/locale/nl.json +39 -4
- umap/static/umap/locale/no.js +39 -4
- umap/static/umap/locale/no.json +39 -4
- umap/static/umap/locale/pl.js +39 -4
- umap/static/umap/locale/pl.json +39 -4
- umap/static/umap/locale/pl_PL.json +39 -4
- umap/static/umap/locale/pt.js +39 -4
- umap/static/umap/locale/pt.json +39 -4
- umap/static/umap/locale/pt_BR.js +39 -4
- umap/static/umap/locale/pt_BR.json +39 -4
- umap/static/umap/locale/pt_PT.js +39 -4
- umap/static/umap/locale/pt_PT.json +39 -4
- umap/static/umap/locale/ro.js +39 -4
- umap/static/umap/locale/ro.json +39 -4
- umap/static/umap/locale/ru.js +39 -4
- umap/static/umap/locale/ru.json +39 -4
- umap/static/umap/locale/sk_SK.js +39 -4
- umap/static/umap/locale/sk_SK.json +39 -4
- umap/static/umap/locale/sl.js +39 -4
- umap/static/umap/locale/sl.json +39 -4
- umap/static/umap/locale/sr.js +39 -4
- umap/static/umap/locale/sr.json +39 -4
- umap/static/umap/locale/sv.js +39 -4
- umap/static/umap/locale/sv.json +39 -4
- umap/static/umap/locale/th_TH.js +39 -4
- umap/static/umap/locale/th_TH.json +39 -4
- umap/static/umap/locale/tr.js +39 -4
- umap/static/umap/locale/tr.json +39 -4
- umap/static/umap/locale/uk_UA.js +39 -4
- umap/static/umap/locale/uk_UA.json +39 -4
- umap/static/umap/locale/vi.js +39 -4
- umap/static/umap/locale/vi.json +39 -4
- umap/static/umap/locale/vi_VN.json +39 -4
- umap/static/umap/locale/zh.js +39 -4
- umap/static/umap/locale/zh.json +39 -4
- umap/static/umap/locale/zh_CN.json +39 -4
- umap/static/umap/locale/zh_TW.Big5.json +39 -4
- umap/static/umap/locale/zh_TW.js +98 -63
- umap/static/umap/locale/zh_TW.json +98 -63
- umap/static/umap/map.css +90 -41
- umap/static/umap/vars.css +1 -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/staticfiles.py +12 -0
- umap/templates/umap/css.html +0 -4
- umap/templates/umap/js.html +1 -3
- umap/tests/integration/test_basics.py +2 -0
- umap/tests/integration/test_conditional_rules.py +17 -17
- 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_map.py +1 -1
- umap/tests/integration/test_edit_marker.py +7 -7
- umap/tests/integration/test_edit_polygon.py +2 -2
- umap/tests/integration/test_export_map.py +74 -10
- umap/tests/integration/test_map_preview.py +1 -1
- umap/tests/integration/test_share.py +1 -1
- umap/tests/integration/test_tableeditor.py +4 -4
- umap/tests/integration/test_websocket_sync.py +4 -4
- umap/utils.py +5 -1
- umap/views.py +2 -0
- {umap_project-3.2.0.dist-info → umap_project-3.3.0.dist-info}/METADATA +8 -8
- {umap_project-3.2.0.dist-info → umap_project-3.3.0.dist-info}/RECORD +169 -165
- 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.2.0.dist-info → umap_project-3.3.0.dist-info}/WHEEL +0 -0
- {umap_project-3.2.0.dist-info → umap_project-3.3.0.dist-info}/entry_points.txt +0 -0
- {umap_project-3.2.0.dist-info → umap_project-3.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -298,7 +298,7 @@ export class DataLayer {
|
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
dataChanged() {
|
|
301
|
-
if (!this.isLoaded()) return
|
|
301
|
+
if (!this.isLoaded() || this._batch) return
|
|
302
302
|
this._umap.onDataLayersChanged()
|
|
303
303
|
this.layer.dataChanged()
|
|
304
304
|
}
|
|
@@ -547,22 +547,27 @@ export class DataLayer {
|
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
sortedValues(property) {
|
|
550
|
-
return
|
|
550
|
+
return this.features
|
|
551
|
+
.all()
|
|
551
552
|
.map((feature) => feature.properties[property])
|
|
552
553
|
.filter((val, idx, arr) => arr.indexOf(val) === idx)
|
|
553
554
|
.sort(Utils.naturalSort)
|
|
554
555
|
}
|
|
555
556
|
|
|
556
557
|
addData(geojson, sync) {
|
|
558
|
+
let data = []
|
|
559
|
+
this._batch = true
|
|
557
560
|
try {
|
|
558
561
|
// Do not fail if remote data is somehow invalid,
|
|
559
562
|
// otherwise the layer becomes uneditable.
|
|
560
|
-
|
|
563
|
+
data = this.makeFeatures(geojson, sync)
|
|
561
564
|
} catch (err) {
|
|
562
565
|
console.debug('Error with DataLayer', this.id)
|
|
563
566
|
console.error(err)
|
|
564
|
-
return []
|
|
565
567
|
}
|
|
568
|
+
this._batch = false
|
|
569
|
+
this.dataChanged()
|
|
570
|
+
return data
|
|
566
571
|
}
|
|
567
572
|
|
|
568
573
|
makeFeatures(geojson = {}, sync = true) {
|
|
@@ -821,6 +826,7 @@ export class DataLayer {
|
|
|
821
826
|
const fields = [
|
|
822
827
|
'properties.color',
|
|
823
828
|
'properties.iconClass',
|
|
829
|
+
'properties.iconSize',
|
|
824
830
|
'properties.iconUrl',
|
|
825
831
|
'properties.iconOpacity',
|
|
826
832
|
'properties.opacity',
|
|
@@ -1176,12 +1182,6 @@ export class DataLayer {
|
|
|
1176
1182
|
})
|
|
1177
1183
|
}
|
|
1178
1184
|
|
|
1179
|
-
featuresToGeoJSON() {
|
|
1180
|
-
const features = []
|
|
1181
|
-
this.features.forEach((feature) => features.push(feature.toGeoJSON()))
|
|
1182
|
-
return features
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
1185
|
async show() {
|
|
1186
1186
|
this._leafletMap.addLayer(this.layer)
|
|
1187
1187
|
if (!this.isLoaded()) await this.fetchData()
|
|
@@ -1194,10 +1194,11 @@ export class DataLayer {
|
|
|
1194
1194
|
}
|
|
1195
1195
|
|
|
1196
1196
|
toggle(force) {
|
|
1197
|
-
// From now on, do not try to how/
|
|
1198
|
-
// automatically this layer
|
|
1199
|
-
|
|
1197
|
+
// From now on, do not try to how/hide
|
|
1198
|
+
// automatically this layer, as user
|
|
1199
|
+
// has taken control on this.
|
|
1200
1200
|
this._forcedVisibility = true
|
|
1201
|
+
let display = force
|
|
1201
1202
|
if (force === undefined) {
|
|
1202
1203
|
if (!this.isVisible()) display = true
|
|
1203
1204
|
else display = false
|
|
@@ -1267,11 +1268,9 @@ export class DataLayer {
|
|
|
1267
1268
|
}
|
|
1268
1269
|
|
|
1269
1270
|
umapGeoJSON() {
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
_umap_options: this.properties,
|
|
1274
|
-
}
|
|
1271
|
+
const geojson = this._umap.formatter.toFeatureCollection(this.features.all())
|
|
1272
|
+
geojson._umap_options = this.properties
|
|
1273
|
+
return geojson
|
|
1275
1274
|
}
|
|
1276
1275
|
|
|
1277
1276
|
getDOMOrder() {
|
|
@@ -70,7 +70,11 @@ export class Form extends Utils.WithEvents {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
setter(field, value) {
|
|
73
|
-
|
|
73
|
+
if ('setter' in this.obj) {
|
|
74
|
+
this.obj.setter(field, value)
|
|
75
|
+
} else {
|
|
76
|
+
Utils.setObjectValue(this.obj, field, value)
|
|
77
|
+
}
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
restoreField(field) {
|
|
@@ -104,9 +108,13 @@ export class Form extends Utils.WithEvents {
|
|
|
104
108
|
finish() {}
|
|
105
109
|
|
|
106
110
|
getTemplate(helper) {
|
|
111
|
+
let tpl = helper.getTemplate()
|
|
112
|
+
if (helper.properties.label && !tpl.includes(helper.properties.label)) {
|
|
113
|
+
tpl = `<label>${helper.properties.label}${tpl}</label>`
|
|
114
|
+
}
|
|
107
115
|
return `
|
|
108
116
|
<div class="formbox" data-ref=container>
|
|
109
|
-
${
|
|
117
|
+
${tpl}
|
|
110
118
|
<small class="help-text" data-ref=helpText></small>
|
|
111
119
|
</div>`
|
|
112
120
|
}
|
|
@@ -171,11 +179,7 @@ export class MutatingForm extends Form {
|
|
|
171
179
|
|
|
172
180
|
setter(field, value) {
|
|
173
181
|
const oldValue = this.getter(field)
|
|
174
|
-
|
|
175
|
-
this.obj.setter(field, value)
|
|
176
|
-
} else {
|
|
177
|
-
super.setter(field, value)
|
|
178
|
-
}
|
|
182
|
+
super.setter(field, value)
|
|
179
183
|
if ('render' in this.obj) {
|
|
180
184
|
this.obj.render([field], this)
|
|
181
185
|
}
|
|
@@ -582,6 +582,9 @@ Fields.SlideshowDelay = class extends Fields.IntSelect {
|
|
|
582
582
|
Fields.DataLayerSwitcher = class extends Fields.Select {
|
|
583
583
|
getOptions() {
|
|
584
584
|
const options = []
|
|
585
|
+
if (this.properties.allowEmpty) {
|
|
586
|
+
options.push([null, translate('Import in a new layer')])
|
|
587
|
+
}
|
|
585
588
|
this.builder._umap.datalayers.reverse().map((datalayer) => {
|
|
586
589
|
if (
|
|
587
590
|
datalayer.isLoaded() &&
|
|
@@ -595,7 +598,7 @@ Fields.DataLayerSwitcher = class extends Fields.Select {
|
|
|
595
598
|
}
|
|
596
599
|
|
|
597
600
|
toHTML() {
|
|
598
|
-
return this.obj.datalayer
|
|
601
|
+
return this.obj.datalayer?.id
|
|
599
602
|
}
|
|
600
603
|
|
|
601
604
|
toJS() {
|
|
@@ -604,7 +607,7 @@ Fields.DataLayerSwitcher = class extends Fields.Select {
|
|
|
604
607
|
|
|
605
608
|
set() {
|
|
606
609
|
this.builder._umap.lastUsedDataLayer = this.toJS()
|
|
607
|
-
this.
|
|
610
|
+
this.builder.setter(this.field, this.toJS())
|
|
608
611
|
}
|
|
609
612
|
}
|
|
610
613
|
|
|
@@ -863,6 +866,7 @@ Fields.IconUrl = class extends Fields.BlurInput {
|
|
|
863
866
|
const loadCollection = (name) => {
|
|
864
867
|
icons.innerHTML = ''
|
|
865
868
|
const collection = this.pictogramCollections[name || collectionsNames[0]]
|
|
869
|
+
if (!collection) return
|
|
866
870
|
const sorted = Object.entries(collection.categories).sort(([a], [b]) =>
|
|
867
871
|
Utils.naturalSort(a, b, U.lang)
|
|
868
872
|
)
|
|
@@ -1303,11 +1307,10 @@ Fields.Range = class extends Fields.FloatInput {
|
|
|
1303
1307
|
const step = this.properties.step || 1
|
|
1304
1308
|
const digits = step < 1 ? 1 : 0
|
|
1305
1309
|
const id = `range-${this.properties.label || this.name}`
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
) {
|
|
1310
|
+
const range = this.properties.max - this.properties.min
|
|
1311
|
+
const ticks = this.properties.ticks || Math.min(20, range / step)
|
|
1312
|
+
const tickStep = range / ticks
|
|
1313
|
+
for (let i = this.properties.min; i <= this.properties.max; i += tickStep) {
|
|
1311
1314
|
const ii = i.toFixed(digits)
|
|
1312
1315
|
options += `<option value="${ii}" label="${ii}"></option>`
|
|
1313
1316
|
}
|
|
@@ -17,33 +17,18 @@ const parseTextGeom = async (geom) => {
|
|
|
17
17
|
|
|
18
18
|
export const EXPORT_FORMATS = {
|
|
19
19
|
geojson: {
|
|
20
|
-
formatter: async (umap) => JSON.stringify(umap.toGeoJSON(), null, 2),
|
|
21
20
|
ext: '.geojson',
|
|
22
21
|
filetype: 'application/json',
|
|
23
22
|
},
|
|
24
23
|
gpx: {
|
|
25
|
-
formatter: async (umap) => await umap.formatter.toGPX(umap.toGeoJSON()),
|
|
26
24
|
ext: '.gpx',
|
|
27
25
|
filetype: 'application/gpx+xml',
|
|
28
26
|
},
|
|
29
27
|
kml: {
|
|
30
|
-
formatter: async (umap) => await umap.formatter.toKML(umap.toGeoJSON()),
|
|
31
28
|
ext: '.kml',
|
|
32
29
|
filetype: 'application/vnd.google-earth.kml+xml',
|
|
33
30
|
},
|
|
34
31
|
csv: {
|
|
35
|
-
formatter: async (umap) => {
|
|
36
|
-
const table = []
|
|
37
|
-
umap.eachFeature((feature) => {
|
|
38
|
-
const row = feature.toGeoJSON().properties
|
|
39
|
-
const center = feature.center
|
|
40
|
-
delete row._umap_options
|
|
41
|
-
row.Latitude = center.lat
|
|
42
|
-
row.Longitude = center.lng
|
|
43
|
-
table.push(row)
|
|
44
|
-
})
|
|
45
|
-
return csv2geojson.dsv.csvFormat(table)
|
|
46
|
-
},
|
|
47
32
|
ext: '.csv',
|
|
48
33
|
filetype: 'text/csv',
|
|
49
34
|
},
|
|
@@ -180,17 +165,54 @@ export class Formatter {
|
|
|
180
165
|
}
|
|
181
166
|
}
|
|
182
167
|
|
|
183
|
-
async
|
|
168
|
+
async stringify(features, format) {
|
|
169
|
+
switch (format) {
|
|
170
|
+
case 'csv':
|
|
171
|
+
return await this.toCSV(features)
|
|
172
|
+
case 'gpx':
|
|
173
|
+
return await this.toGPX(features)
|
|
174
|
+
case 'kml':
|
|
175
|
+
return await this.toKML(features)
|
|
176
|
+
case 'geojson':
|
|
177
|
+
return await this.toGeoJSON(features)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async toGPX(features) {
|
|
184
182
|
const togpx = await import('../../vendors/geojson-to-gpx/index.js')
|
|
185
|
-
for (const feature of
|
|
183
|
+
for (const feature of features) {
|
|
186
184
|
feature.properties.desc = feature.properties.description
|
|
187
185
|
}
|
|
188
|
-
const gpx = togpx.default(
|
|
186
|
+
const gpx = togpx.default(this.toFeatureCollection(features))
|
|
189
187
|
return new XMLSerializer().serializeToString(gpx)
|
|
190
188
|
}
|
|
191
189
|
|
|
192
|
-
async toKML(
|
|
190
|
+
async toKML(features) {
|
|
193
191
|
const tokml = await import('../../vendors/tokml/tokml.es.js')
|
|
194
|
-
return tokml.toKML(
|
|
192
|
+
return tokml.toKML(this.toFeatureCollection(features))
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
toFeatureCollection(features) {
|
|
196
|
+
return {
|
|
197
|
+
type: 'FeatureCollection',
|
|
198
|
+
features: features.map((f) => f.toGeoJSON()),
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async toGeoJSON(features) {
|
|
203
|
+
return JSON.stringify(this.toFeatureCollection(features), null, 2)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async toCSV(features) {
|
|
207
|
+
const table = []
|
|
208
|
+
for (const feature of features) {
|
|
209
|
+
const row = feature.toGeoJSON().properties
|
|
210
|
+
const center = feature.center
|
|
211
|
+
delete row._umap_options
|
|
212
|
+
row.Latitude = center.lat
|
|
213
|
+
row.Longitude = center.lng
|
|
214
|
+
table.push(row)
|
|
215
|
+
}
|
|
216
|
+
return csv2geojson.dsv.csvFormat(table)
|
|
195
217
|
}
|
|
196
218
|
}
|
|
@@ -17,7 +17,7 @@ const TEMPLATE = `
|
|
|
17
17
|
<input type="file" multiple autofocus onchange />
|
|
18
18
|
<textarea onchange placeholder="${translate('Paste your data here')}"></textarea>
|
|
19
19
|
<input class="highlightable" type="url" placeholder="${translate('Provide an URL here')}" onchange />
|
|
20
|
-
<button class="
|
|
20
|
+
<button type=button class="importers" hidden data-ref="importersButton"><i class="icon icon-16 icon-magic"></i>${translate('Import helpers')}</button>
|
|
21
21
|
</fieldset>
|
|
22
22
|
<fieldset class="formbox">
|
|
23
23
|
<legend class="counter" data-help="importFormats">${translate(
|
|
@@ -169,8 +169,13 @@ export default class Importer extends Utils.WithTemplate {
|
|
|
169
169
|
this.onChange()
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
set layer(layer) {
|
|
173
|
+
this._layer = layer
|
|
174
|
+
}
|
|
175
|
+
|
|
172
176
|
get layer() {
|
|
173
177
|
return (
|
|
178
|
+
this._layer ||
|
|
174
179
|
this._umap.datalayers[this.layerId] ||
|
|
175
180
|
this._umap.createDirtyDataLayer({ name: this.layerName })
|
|
176
181
|
)
|
|
@@ -8,11 +8,21 @@ const PORTALS = [
|
|
|
8
8
|
url: 'https://data.ampmetropole.fr',
|
|
9
9
|
platform: 'opendatasoft',
|
|
10
10
|
},
|
|
11
|
+
{
|
|
12
|
+
name: 'Auverge-Rhône-Alpes',
|
|
13
|
+
url: 'https://admin.open-datara.fr',
|
|
14
|
+
platform: 'prodige',
|
|
15
|
+
},
|
|
11
16
|
{
|
|
12
17
|
name: 'Bordeaux Métropole',
|
|
13
18
|
url: 'https://opendata.bordeaux-metropole.fr',
|
|
14
19
|
platform: 'opendatasoft',
|
|
15
20
|
},
|
|
21
|
+
{
|
|
22
|
+
name: 'Nouvelle Aquitaine',
|
|
23
|
+
url: 'https://admin.sigena.fr',
|
|
24
|
+
platform: 'prodige',
|
|
25
|
+
},
|
|
16
26
|
{
|
|
17
27
|
name: 'Région Centre-Val de Loire',
|
|
18
28
|
url: 'https://data.centrevaldeloire.fr',
|
|
@@ -33,6 +43,21 @@ const PORTALS = [
|
|
|
33
43
|
url: 'https://data.iledefrance.fr',
|
|
34
44
|
platform: 'opendatasoft',
|
|
35
45
|
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Martinique',
|
|
48
|
+
url: 'https://admin.geomartinique.fr',
|
|
49
|
+
platform: 'prodige',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'Région Pays de la Loire',
|
|
53
|
+
url: 'https://admin.sigloire.fr',
|
|
54
|
+
platform: 'prodige',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'Saint-Pierre et Miquelon',
|
|
58
|
+
url: 'https://admin.geospm.com',
|
|
59
|
+
platform: 'prodige',
|
|
60
|
+
},
|
|
36
61
|
{
|
|
37
62
|
name: 'Toulouse Métropole',
|
|
38
63
|
url: 'https://data.toulouse-metropole.fr',
|
|
@@ -57,29 +82,54 @@ const TEMPLATE = `
|
|
|
57
82
|
<option disabled selected value="">${translate('Choose a dataset')}</option>
|
|
58
83
|
</select>
|
|
59
84
|
<input type="hidden" name="geofield" data-ref="geofield">
|
|
60
|
-
<label><input type="checkbox" name="in_bbox">${translate('Limit results to current map view')}</label>
|
|
85
|
+
<label data-ref="in_bbox" hidden><input type="checkbox" name="in_bbox">${translate('Limit results to current map view')}</label>
|
|
61
86
|
</div>
|
|
62
87
|
</div>
|
|
63
88
|
`
|
|
64
89
|
|
|
65
|
-
|
|
66
|
-
constructor(umap,
|
|
90
|
+
class Connector {
|
|
91
|
+
constructor(umap, baseUrl) {
|
|
67
92
|
this.umap = umap
|
|
68
|
-
this.
|
|
69
|
-
this.id = 'opendata'
|
|
70
|
-
this.portals = options.choices || PORTALS
|
|
93
|
+
this.baseUrl = baseUrl
|
|
71
94
|
}
|
|
95
|
+
}
|
|
72
96
|
|
|
73
|
-
|
|
97
|
+
class Prodige extends Connector {
|
|
98
|
+
async datasets() {
|
|
99
|
+
const datasets = []
|
|
100
|
+
const endpoint = this.umap.proxyUrl(
|
|
101
|
+
`${this.baseUrl}/api/ogc-features/collections.json`,
|
|
102
|
+
3600
|
|
103
|
+
)
|
|
104
|
+
const response = await this.umap.request.get(endpoint)
|
|
105
|
+
if (!response?.ok) return datasets
|
|
106
|
+
const data = await response.json()
|
|
107
|
+
for (const dataset of data.collections) {
|
|
108
|
+
let url
|
|
109
|
+
for (const link of dataset.links) {
|
|
110
|
+
if (link.type === 'application/geo+json') url = link.href
|
|
111
|
+
}
|
|
112
|
+
if (!url) continue
|
|
113
|
+
datasets.push({
|
|
114
|
+
label: dataset.title,
|
|
115
|
+
url: this.umap.proxyUrl(url, 3600),
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
return datasets.sort((a, b) => Utils.naturalSort(a.label, b.label, U.lang))
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
class OpenDataSoft extends Connector {
|
|
123
|
+
async datasets() {
|
|
74
124
|
let results = []
|
|
75
125
|
let total = null
|
|
76
126
|
const hardLimit = 500
|
|
77
127
|
while (total === null || results.length < total) {
|
|
78
128
|
const offset = results.length
|
|
79
129
|
const response = await this.umap.request.get(
|
|
80
|
-
`${baseUrl}/api/explore/v2.1/catalog/datasets?where=features%20in%20%28%22geo%22%29&limit=100&offset=${offset}&order_by=title asc`
|
|
130
|
+
`${this.baseUrl}/api/explore/v2.1/catalog/datasets?where=features%20in%20%28%22geo%22%29&limit=100&offset=${offset}&order_by=title asc`
|
|
81
131
|
)
|
|
82
|
-
if (!response
|
|
132
|
+
if (!response?.ok) break
|
|
83
133
|
const data = await response.json()
|
|
84
134
|
if (total === null) {
|
|
85
135
|
total = data.total_count
|
|
@@ -87,48 +137,85 @@ export class Importer {
|
|
|
87
137
|
results = results.concat(data.results)
|
|
88
138
|
if (total === null || results.length > hardLimit) break
|
|
89
139
|
}
|
|
90
|
-
|
|
140
|
+
const datasets = []
|
|
141
|
+
for (const result of results) {
|
|
142
|
+
const fields = result.fields.filter((field) => field.type === 'geo_point_2d')
|
|
143
|
+
if (!fields.length) {
|
|
144
|
+
console.debug('No geofield found for', result)
|
|
145
|
+
continue
|
|
146
|
+
}
|
|
147
|
+
if (fields.length > 1) {
|
|
148
|
+
console.debug('More than one geofield found for', result)
|
|
149
|
+
}
|
|
150
|
+
const url = `${this.baseUrl}/api/explore/v2.1/catalog/datasets/${result.dataset_id}/exports/geojson?select=%2A&limit=-1&timezone=UTC&use_labels=false&epsg=4326`
|
|
151
|
+
const bbox_url = `${url}&where=in_bbox%28${fields[0].name}%2C%20{south},{west},{north},{east}%29`
|
|
152
|
+
datasets.push({
|
|
153
|
+
id: result.dataset_id,
|
|
154
|
+
label: `${result.metas.default.title} (${result.metas.default.records_count})`,
|
|
155
|
+
url,
|
|
156
|
+
bbox_url,
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
return datasets
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export class Importer {
|
|
164
|
+
constructor(umap, options = {}) {
|
|
165
|
+
this.umap = umap
|
|
166
|
+
this.name = options.name || 'Open Data'
|
|
167
|
+
this.id = 'opendata'
|
|
168
|
+
this.portals = options.choices || PORTALS
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
resetSelect(select) {
|
|
172
|
+
Array.from(select.children).forEach((option) => {
|
|
173
|
+
if (!option.disabled) {
|
|
174
|
+
option.remove()
|
|
175
|
+
} else {
|
|
176
|
+
option.selected = true
|
|
177
|
+
}
|
|
178
|
+
})
|
|
91
179
|
}
|
|
92
180
|
|
|
93
181
|
async open(importer) {
|
|
94
|
-
|
|
95
|
-
const [container, { portals, datasets, geofield }] =
|
|
182
|
+
const [container, { portals, datasets, in_bbox }] =
|
|
96
183
|
Utils.loadTemplateWithRefs(TEMPLATE)
|
|
184
|
+
datasets.addEventListener('change', (event) => {
|
|
185
|
+
const select = event.target
|
|
186
|
+
const selected = select.options[select.selectedIndex]
|
|
187
|
+
const bbox_url = selected.dataset.bbox_url
|
|
188
|
+
in_bbox.checked = false
|
|
189
|
+
in_bbox.hidden = !bbox_url
|
|
190
|
+
})
|
|
97
191
|
portals.addEventListener('change', async (event) => {
|
|
98
|
-
const
|
|
192
|
+
const select = event.target
|
|
193
|
+
const selected = select.options[select.selectedIndex]
|
|
194
|
+
const platform = selected.dataset.platform
|
|
195
|
+
let connector
|
|
196
|
+
if (platform === 'opendatasoft') {
|
|
197
|
+
connector = new OpenDataSoft(this.umap, selected.value)
|
|
198
|
+
} else if (platform === 'prodige') {
|
|
199
|
+
connector = new Prodige(this.umap, selected.value)
|
|
200
|
+
} else {
|
|
201
|
+
console.error('Unknown platform', platform)
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
const results = await connector.datasets(event.target.value)
|
|
99
205
|
if (results) {
|
|
100
|
-
|
|
101
|
-
Array.from(datasets.children).forEach((option) => {
|
|
102
|
-
if (!option.disabled) {
|
|
103
|
-
option.remove()
|
|
104
|
-
} else {
|
|
105
|
-
option.selected = true
|
|
106
|
-
}
|
|
107
|
-
})
|
|
206
|
+
this.resetSelect(datasets)
|
|
108
207
|
for (const result of results) {
|
|
109
|
-
const fields = result.fields.filter((field) => field.type === 'geo_point_2d')
|
|
110
|
-
if (!fields.length) {
|
|
111
|
-
console.debug('No geofield found for', result)
|
|
112
|
-
continue
|
|
113
|
-
}
|
|
114
|
-
if (fields.length > 1) {
|
|
115
|
-
console.debug('More than one geofield found for', result)
|
|
116
|
-
}
|
|
117
|
-
fields_map[result.dataset_id] = fields[0].name
|
|
118
208
|
const el = Utils.loadTemplate(
|
|
119
|
-
`<option value="${result.
|
|
209
|
+
`<option value="${result.url}" data-url="${result.url}" data-bbox_url="${result.bbox_url || ''}">${result.label}</option>`
|
|
120
210
|
)
|
|
121
211
|
datasets.appendChild(el)
|
|
122
212
|
}
|
|
123
213
|
datasets.hidden = false
|
|
124
214
|
}
|
|
125
215
|
})
|
|
126
|
-
datasets.addEventListener('change', (event) => {
|
|
127
|
-
geofield.value = fields_map[event.target.value]
|
|
128
|
-
})
|
|
129
216
|
for (const instance of this.portals) {
|
|
130
217
|
const el = Utils.loadTemplate(
|
|
131
|
-
`<option value="${instance.url}">${instance.name}</option>`
|
|
218
|
+
`<option value="${instance.url}" data-platform="${instance.platform}">${instance.name}</option>`
|
|
132
219
|
)
|
|
133
220
|
portals.appendChild(el)
|
|
134
221
|
}
|
|
@@ -138,9 +225,10 @@ export class Importer {
|
|
|
138
225
|
Alert.error(translate('Please choose an instance first.'))
|
|
139
226
|
return
|
|
140
227
|
}
|
|
141
|
-
let url =
|
|
228
|
+
let url = form.dataset
|
|
142
229
|
if (form.in_bbox) {
|
|
143
|
-
|
|
230
|
+
const selected = datasets.options[datasets.selectedIndex]
|
|
231
|
+
url = selected.dataset.bbox_url
|
|
144
232
|
}
|
|
145
233
|
importer.url = url
|
|
146
234
|
importer.format = 'geojson'
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
|
2
|
+
import { translate } from '../i18n.js'
|
|
3
|
+
import * as Utils from '../utils.js'
|
|
4
|
+
import { Form } from '../form/builder.js'
|
|
5
|
+
|
|
6
|
+
export const PROFILES = [
|
|
7
|
+
['foot-walking', translate('Walking')],
|
|
8
|
+
['foot-hiking', translate('Hiking')],
|
|
9
|
+
['driving-car', translate('By car')],
|
|
10
|
+
['cycling-regular', translate('Cycling')],
|
|
11
|
+
['wheelchair', translate('Wheelchair')],
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
export const PREFERENCES = [
|
|
15
|
+
['recommended', translate('Recommended')],
|
|
16
|
+
['fastest', translate('Fastest')],
|
|
17
|
+
['shortest', translate('Shortest')],
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
export class Importer {
|
|
21
|
+
constructor(umap) {
|
|
22
|
+
this.umap = umap
|
|
23
|
+
this.id = 'openrouteservice'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async loadORS() {
|
|
27
|
+
const mod = await import('../../../vendors/openrouteservice/ors-js-client.js')
|
|
28
|
+
return mod.default
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async isochrone(latlng) {
|
|
32
|
+
const ORS = await this.loadORS()
|
|
33
|
+
const properties = {
|
|
34
|
+
range: 10,
|
|
35
|
+
lines: 1,
|
|
36
|
+
profile: 'foot-walking',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const metadatas = [
|
|
40
|
+
['datalayer', { handler: 'DataLayerSwitcher', allowEmpty: true }],
|
|
41
|
+
[
|
|
42
|
+
'profile',
|
|
43
|
+
{ handler: 'Select', selectOptions: PROFILES, label: translate('Profile') },
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
'range',
|
|
47
|
+
{
|
|
48
|
+
handler: 'Range',
|
|
49
|
+
min: 5,
|
|
50
|
+
max: 60,
|
|
51
|
+
step: 1,
|
|
52
|
+
ticks: 11,
|
|
53
|
+
label: translate('Max time (in minutes)'),
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
[
|
|
57
|
+
'lines',
|
|
58
|
+
{
|
|
59
|
+
handler: 'Range',
|
|
60
|
+
min: 1,
|
|
61
|
+
max: 5,
|
|
62
|
+
step: 1,
|
|
63
|
+
label: translate('Number of lines'),
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
]
|
|
67
|
+
const form = new Form(properties, metadatas, { umap: this.umap })
|
|
68
|
+
// Needed for DataLayerSwitcher (which expects to be used with MutatingForm)
|
|
69
|
+
form._umap = this.umap
|
|
70
|
+
|
|
71
|
+
const Isochrones = new ORS.Isochrones({
|
|
72
|
+
api_key: this.umap.properties.ORSAPIKey,
|
|
73
|
+
})
|
|
74
|
+
this.umap.dialog.open({ template: form.build() }).then(async () => {
|
|
75
|
+
try {
|
|
76
|
+
const params = {
|
|
77
|
+
locations: [[latlng.lng, latlng.lat]],
|
|
78
|
+
profile: properties.profile,
|
|
79
|
+
range: [properties.range * 60],
|
|
80
|
+
}
|
|
81
|
+
if (properties.lines !== 1) {
|
|
82
|
+
params.interval = (properties.range / properties.lines) * 60
|
|
83
|
+
}
|
|
84
|
+
const data = await Isochrones.calculate(params)
|
|
85
|
+
this.umap.importer.build()
|
|
86
|
+
this.umap.importer.raw = JSON.stringify(data)
|
|
87
|
+
this.umap.importer.format = 'geojson'
|
|
88
|
+
this.umap.importer.layer = properties.datalayer
|
|
89
|
+
this.umap.importer.submit()
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.error(err)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async elevation(geometry) {
|
|
97
|
+
const ORS = await this.loadORS()
|
|
98
|
+
|
|
99
|
+
const Elevation = new ORS.Elevation({
|
|
100
|
+
api_key: this.umap.properties.ORSAPIKey,
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const data = await Elevation.lineElevation({
|
|
105
|
+
format_in: 'geojson',
|
|
106
|
+
format_out: 'geojson',
|
|
107
|
+
geometry: geometry,
|
|
108
|
+
})
|
|
109
|
+
return data?.geometry
|
|
110
|
+
} catch (err) {
|
|
111
|
+
console.debug(`An error occurred: ${err.status}`)
|
|
112
|
+
console.error(err)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async directions(properties) {
|
|
117
|
+
if (!properties?.coordinates || properties.coordinates.length < 2) {
|
|
118
|
+
console.error('Not enough coordinates to compute route', properties)
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
const ORS = await this.loadORS()
|
|
122
|
+
const Directions = new ORS.Directions({ api_key: this.umap.properties.ORSAPIKey })
|
|
123
|
+
try {
|
|
124
|
+
const featuresCollection = await Directions.calculate({
|
|
125
|
+
coordinates: properties.coordinates,
|
|
126
|
+
profile: properties.profile,
|
|
127
|
+
preference: properties.preference,
|
|
128
|
+
elevation: properties.elevation,
|
|
129
|
+
geometry_simplify: true,
|
|
130
|
+
instructions: false,
|
|
131
|
+
format: 'geojson',
|
|
132
|
+
})
|
|
133
|
+
const feature = featuresCollection.features[0]
|
|
134
|
+
return feature.geometry
|
|
135
|
+
} catch (err) {
|
|
136
|
+
console.debug(`An error occurred: ${err.status}`)
|
|
137
|
+
console.error(err)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|