umap-project 3.0.5__py3-none-any.whl → 3.1.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.

Files changed (145) hide show
  1. umap/__init__.py +1 -1
  2. umap/forms.py +1 -1
  3. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/br/LC_MESSAGES/django.po +219 -72
  5. umap/locale/ca/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/ca/LC_MESSAGES/django.po +286 -95
  7. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/cs_CZ/LC_MESSAGES/django.po +211 -65
  9. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/da/LC_MESSAGES/django.po +394 -202
  11. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/de/LC_MESSAGES/django.po +146 -75
  13. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  14. umap/locale/el/LC_MESSAGES/django.po +125 -59
  15. umap/locale/en/LC_MESSAGES/django.mo +0 -0
  16. umap/locale/en/LC_MESSAGES/django.po +124 -58
  17. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/es/LC_MESSAGES/django.po +125 -59
  19. umap/locale/et/LC_MESSAGES/django.mo +0 -0
  20. umap/locale/et/LC_MESSAGES/django.po +210 -64
  21. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  22. umap/locale/eu/LC_MESSAGES/django.po +212 -65
  23. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  24. umap/locale/fa_IR/LC_MESSAGES/django.po +286 -95
  25. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  26. umap/locale/fr/LC_MESSAGES/django.po +125 -59
  27. umap/locale/gl/LC_MESSAGES/django.mo +0 -0
  28. umap/locale/gl/LC_MESSAGES/django.po +212 -66
  29. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  30. umap/locale/hu/LC_MESSAGES/django.po +148 -78
  31. umap/locale/is/LC_MESSAGES/django.mo +0 -0
  32. umap/locale/is/LC_MESSAGES/django.po +130 -60
  33. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  34. umap/locale/it/LC_MESSAGES/django.po +219 -73
  35. umap/locale/ms/LC_MESSAGES/django.mo +0 -0
  36. umap/locale/ms/LC_MESSAGES/django.po +289 -98
  37. umap/locale/nl/LC_MESSAGES/django.mo +0 -0
  38. umap/locale/nl/LC_MESSAGES/django.po +128 -61
  39. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  40. umap/locale/pl/LC_MESSAGES/django.po +287 -96
  41. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  42. umap/locale/pt/LC_MESSAGES/django.po +211 -65
  43. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  44. umap/locale/zh_TW/LC_MESSAGES/django.po +212 -66
  45. umap/management/commands/migrate_to_S3.py +42 -20
  46. umap/management/commands/purge_old_versions.py +63 -0
  47. umap/management/commands/switch_user.py +52 -0
  48. umap/managers.py +29 -2
  49. umap/middleware.py +1 -1
  50. umap/migrations/0028_map_is_template.py +21 -0
  51. umap/models.py +14 -4
  52. umap/settings/base.py +22 -0
  53. umap/static/umap/base.css +4 -2
  54. umap/static/umap/content.css +1 -1
  55. umap/static/umap/css/dialog.css +5 -2
  56. umap/static/umap/css/form.css +19 -12
  57. umap/static/umap/css/icon.css +6 -0
  58. umap/static/umap/css/importers.css +4 -0
  59. umap/static/umap/css/panel.css +2 -0
  60. umap/static/umap/img/16-white.svg +5 -1
  61. umap/static/umap/img/16.svg +1 -1
  62. umap/static/umap/img/24-white.svg +3 -2
  63. umap/static/umap/img/24.svg +3 -4
  64. umap/static/umap/img/importers/opendata.svg +1 -0
  65. umap/static/umap/img/source/16-white.svg +8 -4
  66. umap/static/umap/img/source/16.svg +1 -1
  67. umap/static/umap/img/source/24-white.svg +5 -4
  68. umap/static/umap/img/source/24.svg +5 -6
  69. umap/static/umap/js/components/modal.js +27 -0
  70. umap/static/umap/js/modules/caption.js +4 -4
  71. umap/static/umap/js/modules/data/features.js +40 -4
  72. umap/static/umap/js/modules/data/layer.js +208 -138
  73. umap/static/umap/js/modules/form/builder.js +6 -14
  74. umap/static/umap/js/modules/form/fields.js +2 -2
  75. umap/static/umap/js/modules/help.js +15 -3
  76. umap/static/umap/js/modules/importer.js +7 -4
  77. umap/static/umap/js/modules/importers/opendata.js +142 -0
  78. umap/static/umap/js/modules/permissions.js +3 -3
  79. umap/static/umap/js/modules/rendering/controls.js +34 -2
  80. umap/static/umap/js/modules/rendering/icon.js +2 -2
  81. umap/static/umap/js/modules/rendering/layers/base.js +1 -1
  82. umap/static/umap/js/modules/rendering/layers/classified.js +55 -49
  83. umap/static/umap/js/modules/rendering/layers/cluster.js +16 -9
  84. umap/static/umap/js/modules/rendering/layers/heat.js +13 -11
  85. umap/static/umap/js/modules/rendering/map.js +5 -0
  86. umap/static/umap/js/modules/rendering/ui.js +23 -0
  87. umap/static/umap/js/modules/rules.js +24 -23
  88. umap/static/umap/js/modules/schema.js +60 -4
  89. umap/static/umap/js/modules/sync/updaters.js +7 -3
  90. umap/static/umap/js/modules/tableeditor.js +7 -30
  91. umap/static/umap/js/modules/templates.js +122 -0
  92. umap/static/umap/js/modules/ui/bar.js +13 -3
  93. umap/static/umap/js/modules/ui/panel.js +1 -1
  94. umap/static/umap/js/modules/umap.js +28 -13
  95. umap/static/umap/js/umap.controls.js +11 -4
  96. umap/static/umap/locale/br.js +51 -18
  97. umap/static/umap/locale/br.json +51 -18
  98. umap/static/umap/locale/da.js +343 -310
  99. umap/static/umap/locale/da.json +343 -310
  100. umap/static/umap/locale/de.js +40 -7
  101. umap/static/umap/locale/de.json +40 -7
  102. umap/static/umap/locale/el.js +31 -4
  103. umap/static/umap/locale/el.json +31 -4
  104. umap/static/umap/locale/en.js +34 -1
  105. umap/static/umap/locale/en.json +34 -1
  106. umap/static/umap/locale/es.js +37 -4
  107. umap/static/umap/locale/es.json +37 -4
  108. umap/static/umap/locale/fr.js +34 -1
  109. umap/static/umap/locale/fr.json +34 -1
  110. umap/static/umap/locale/hu.js +44 -17
  111. umap/static/umap/locale/hu.json +44 -17
  112. umap/static/umap/locale/it.js +74 -41
  113. umap/static/umap/locale/it.json +74 -41
  114. umap/static/umap/locale/nl.js +42 -9
  115. umap/static/umap/locale/nl.json +42 -9
  116. umap/static/umap/map.css +3 -23
  117. umap/static/umap/vendors/textpath/leaflet.textpath.js +184 -0
  118. umap/storage/fs.py +19 -9
  119. umap/templates/umap/dashboard_menu.html +5 -0
  120. umap/templates/umap/design_system.html +9 -0
  121. umap/templates/umap/js.html +3 -0
  122. umap/templates/umap/map_init.html +3 -1
  123. umap/templates/umap/map_list.html +2 -2
  124. umap/templates/umap/map_table.html +18 -18
  125. umap/templates/umap/user_dashboard.html +9 -58
  126. umap/templates/umap/user_map_table.html +36 -0
  127. umap/templates/umap/user_templates.html +19 -0
  128. umap/templatetags/umap_tags.py +5 -0
  129. umap/tests/integration/test_basics.py +9 -1
  130. umap/tests/integration/test_conditional_rules.py +57 -0
  131. umap/tests/integration/test_datalayer.py +16 -9
  132. umap/tests/integration/test_edit_marker.py +11 -0
  133. umap/tests/integration/test_tableeditor.py +42 -7
  134. umap/tests/integration/test_templates.py +44 -0
  135. umap/tests/test_dashboard.py +19 -0
  136. umap/tests/test_purge_old_versions.py +91 -0
  137. umap/tests/test_switch_user.py +31 -0
  138. umap/tests/test_views.py +67 -0
  139. umap/urls.py +7 -1
  140. umap/views.py +65 -19
  141. {umap_project-3.0.5.dist-info → umap_project-3.1.0.dist-info}/METADATA +15 -15
  142. {umap_project-3.0.5.dist-info → umap_project-3.1.0.dist-info}/RECORD +145 -132
  143. {umap_project-3.0.5.dist-info → umap_project-3.1.0.dist-info}/WHEEL +0 -0
  144. {umap_project-3.0.5.dist-info → umap_project-3.1.0.dist-info}/entry_points.txt +0 -0
  145. {umap_project-3.0.5.dist-info → umap_project-3.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -127,6 +127,12 @@ export class MutatingForm extends Form {
127
127
  facetKey: 'PropertyInput',
128
128
  slugKey: 'PropertyInput',
129
129
  labelKey: 'PropertyInput',
130
+ color: 'ColorPicker',
131
+ fillColor: 'ColorPicker',
132
+ textPathColor: 'ColorPicker',
133
+ iconUrl: 'IconUrl',
134
+ licence: 'LicenceChooser',
135
+ datalayersControl: 'DataLayersControl',
130
136
  }
131
137
  for (const [key, defaults] of Object.entries(SCHEMA)) {
132
138
  const properties = Object.assign({}, defaults)
@@ -153,21 +159,7 @@ export class MutatingForm extends Form {
153
159
  } else if (properties.type === Number) {
154
160
  if (properties.step) properties.handler = 'Range'
155
161
  else properties.handler = 'IntInput'
156
- } else {
157
- switch (key) {
158
- case 'color':
159
- case 'fillColor':
160
- properties.handler = 'ColorPicker'
161
- break
162
- case 'iconUrl':
163
- properties.handler = 'IconUrl'
164
- break
165
- case 'licence':
166
- properties.handler = 'LicenceChooser'
167
- break
168
- }
169
162
  }
170
-
171
163
  if (customHandlers[key]) {
172
164
  properties.handler = customHandlers[key]
173
165
  }
@@ -725,7 +725,7 @@ Fields.IconUrl = class extends Fields.BlurInput {
725
725
  <button class="flat tab-url" data-ref=url>${translate('URL')}</button>
726
726
  </div>
727
727
  `)
728
- this.tabs.appendChild(root)
728
+ ;[recent, symbols, chars, url].forEach((node) => this.tabs.appendChild(node))
729
729
  if (Icon.RECENT.length) {
730
730
  recent.addEventListener('click', (event) => {
731
731
  event.stopPropagation()
@@ -1269,7 +1269,7 @@ Fields.Range = class extends Fields.FloatInput {
1269
1269
  for (
1270
1270
  let i = this.properties.min;
1271
1271
  i <= this.properties.max;
1272
- i += this.properties.step
1272
+ i += (this.properties.max - this.properties.min) / 10
1273
1273
  ) {
1274
1274
  const ii = i.toFixed(digits)
1275
1275
  options += `<option value="${ii}" label="${ii}"></option>`
@@ -175,6 +175,10 @@ const ENTRIES = {
175
175
  <div>${translate('For more complex needs, see')} <a href="https://overpass-turbo.eu/">https://overpass-turbo.eu/</a></div>
176
176
  </div>
177
177
  `,
178
+
179
+ sync: translate(
180
+ 'Activate collaborative live editing on this map. Other users must reload the map after changing this setting.'
181
+ ),
178
182
  }
179
183
 
180
184
  export default class Help {
@@ -219,10 +223,12 @@ export default class Help {
219
223
 
220
224
  // Special dynamic case. Do we still think this dialog is useful?
221
225
  showGetStarted() {
222
- const [container, { ul }] = Utils.loadTemplateWithRefs(`
226
+ const [container, { getstarted, links }] = Utils.loadTemplateWithRefs(`
223
227
  <div>
224
228
  <h3><i class="icon icon-16 icon-help"></i>${translate('Where do we go from here?')}</h3>
225
- <ul data-ref=ul class="umap-getstarted"></ul>
229
+ <ul data-ref=getstarted class="umap-getstarted"></ul>
230
+ <h4>${translate('More help resources')}</h4>
231
+ <ul data-ref=links class="umap-help-links"></ul>
226
232
  </div>
227
233
  `)
228
234
  const elements = document.querySelectorAll('[data-getstarted]')
@@ -230,12 +236,18 @@ export default class Help {
230
236
  const [node, { button }] = Utils.loadTemplateWithRefs(
231
237
  `<li><button data-ref=button type="button" title="${el.title}">${el.innerHTML}${el.title}</button></li>`
232
238
  )
233
- ul.appendChild(node)
239
+ getstarted.appendChild(node)
234
240
  button.addEventListener('click', () => {
235
241
  el.click()
236
242
  this.dialog.close()
237
243
  })
238
244
  }
245
+ for (const info of this.umap.properties.help_links) {
246
+ const [node, { button }] = Utils.loadTemplateWithRefs(
247
+ `<li><a href="${info.url}" target="_blank">${info.label} (${info.lang})</a><i class="icon icon-16 icon-external-link"></i></li>`
248
+ )
249
+ links.appendChild(node)
250
+ }
239
251
  this.dialog.open({ template: container })
240
252
  }
241
253
 
@@ -97,6 +97,9 @@ export default class Importer extends Utils.WithTemplate {
97
97
  case 'banfr':
98
98
  import('./importers/banfr.js').then(register)
99
99
  break
100
+ case 'opendata':
101
+ import('./importers/opendata.js').then(register)
102
+ break
100
103
  }
101
104
  }
102
105
  }
@@ -248,7 +251,7 @@ export default class Importer extends Utils.WithTemplate {
248
251
  DomUtil.element({
249
252
  tagName: 'option',
250
253
  parent: layerSelect,
251
- textContent: datalayer.options.name,
254
+ textContent: datalayer.getName(),
252
255
  value: datalayer.id,
253
256
  })
254
257
  }
@@ -325,13 +328,13 @@ export default class Importer extends Utils.WithTemplate {
325
328
  return false
326
329
  }
327
330
  const layer = this.layer
328
- layer.options.remoteData = {
331
+ layer.properties.remoteData = {
329
332
  url: this.url,
330
333
  format: this.format,
331
334
  }
332
335
  if (this._umap.properties.urls.ajax_proxy) {
333
- layer.options.remoteData.proxy = true
334
- layer.options.remoteData.ttl = SCHEMA.ttl.default
336
+ layer.properties.remoteData.proxy = true
337
+ layer.properties.remoteData.ttl = SCHEMA.ttl.default
335
338
  }
336
339
  layer.fetchRemoteData(true).then((features) => {
337
340
  if (features?.length) {
@@ -0,0 +1,142 @@
1
+ import { uMapAlert as Alert } from '../../components/alerts/alert.js'
2
+ import { translate } from '../i18n.js'
3
+ import * as Utils from '../utils.js'
4
+
5
+ const PORTALS = [
6
+ {
7
+ name: 'Aix-Marseille Métropole',
8
+ url: 'https://data.ampmetropole.fr',
9
+ platform: 'opendatasoft',
10
+ },
11
+ {
12
+ name: 'Bordeaux Métropole',
13
+ url: 'https://opendata.bordeaux-metropole.fr',
14
+ platform: 'opendatasoft',
15
+ },
16
+ {
17
+ name: 'Région Centre-Val de Loire',
18
+ url: 'https://data.centrevaldeloire.fr',
19
+ platform: 'opendatasoft',
20
+ },
21
+ {
22
+ name: 'Ville de Clermont-Ferrand',
23
+ url: 'https://opendata.clermont-ferrand.fr',
24
+ platform: 'opendatasoft',
25
+ },
26
+ {
27
+ name: 'Métropole de Dijon',
28
+ url: 'https://data.metropole-dijon.fr',
29
+ platform: 'opendatasoft',
30
+ },
31
+ {
32
+ name: 'Région Île-de-France',
33
+ url: 'https://data.iledefrance.fr',
34
+ platform: 'opendatasoft',
35
+ },
36
+ {
37
+ name: 'Toulouse Métropole',
38
+ url: 'https://data.toulouse-metropole.fr',
39
+ platform: 'opendatasoft',
40
+ },
41
+ {
42
+ name: 'Tours Métropole Val de Loire',
43
+ url: 'https://data.tours-metropole.fr/',
44
+ platform: 'opendatasoft',
45
+ },
46
+ ]
47
+
48
+ const TEMPLATE = `
49
+ <div>
50
+ <h3>Open Data</h3>
51
+ <p>${translate('Import data from public open data portals')}.</p>
52
+ <div class="formbox">
53
+ <select name="instance" data-ref="portals">
54
+ <option disabled selected value="">${translate('Choose a portal')}</option>
55
+ </select>
56
+ <select name="dataset" hidden data-ref="datasets">
57
+ <option disabled selected value="">${translate('Choose a dataset')}</option>
58
+ </select>
59
+ <input type="hidden" name="geofield" data-ref="geofield">
60
+ <label><input type="checkbox" name="in_bbox">${translate('Limit results to current map view')}</label>
61
+ </div>
62
+ </div>
63
+ `
64
+
65
+ export class Importer {
66
+ constructor(umap, options = {}) {
67
+ this.umap = umap
68
+ this.name = options.name || 'Open Data'
69
+ this.id = 'opendata'
70
+ this.portals = options.choices || PORTALS
71
+ }
72
+
73
+ async open(importer) {
74
+ let fields_map = {}
75
+ const [container, { portals, datasets, geofield }] =
76
+ Utils.loadTemplateWithRefs(TEMPLATE)
77
+ portals.addEventListener('change', async (event) => {
78
+ const response = await this.umap.request.get(
79
+ `${event.target.value}/api/explore/v2.1/catalog/datasets?where=features%20in%20%28%22geo%22%29&limit=-1&offset=0&timezone=UTC`
80
+ )
81
+ if (response.ok) {
82
+ fields_map = {}
83
+ Array.from(datasets.children).forEach((option) => {
84
+ if (!option.disabled) {
85
+ option.remove()
86
+ } else {
87
+ option.selected = true
88
+ }
89
+ })
90
+ const data = await response.json()
91
+ for (const result of data.results) {
92
+ const fields = result.fields.filter((field) => field.type === 'geo_point_2d')
93
+ if (!fields.length) {
94
+ console.debug('No geofield found for', result)
95
+ continue
96
+ }
97
+ if (fields.length > 1) {
98
+ console.debug('More than one geofield found for', result)
99
+ }
100
+ fields_map[result.dataset_id] = fields[0].name
101
+ const el = Utils.loadTemplate(
102
+ `<option value="${result.dataset_id}">${result.metas.default.title} (${result.metas.default.records_count})</option>`
103
+ )
104
+ datasets.appendChild(el)
105
+ }
106
+ datasets.hidden = false
107
+ }
108
+ })
109
+ datasets.addEventListener('change', (event) => {
110
+ geofield.value = fields_map[event.target.value]
111
+ })
112
+ for (const instance of this.portals) {
113
+ const el = Utils.loadTemplate(
114
+ `<option value="${instance.url}">${instance.name}</option>`
115
+ )
116
+ portals.appendChild(el)
117
+ }
118
+
119
+ const confirm = (form) => {
120
+ if (!form.instance) {
121
+ Alert.error(translate('Please choose an instance first.'))
122
+ return
123
+ }
124
+ let url = `${form.instance}/api/explore/v2.1/catalog/datasets/${form.dataset}/exports/geojson?select=%2A&limit=-1&timezone=UTC&use_labels=false&epsg=4326`
125
+ if (form.in_bbox) {
126
+ url += `&where=in_bbox%28${form.geofield}%2C%20{south},{west},{north},{east}%29`
127
+ }
128
+ importer.url = url
129
+ importer.format = 'geojson'
130
+ importer.layerName = datasets.options[datasets.selectedIndex].textContent
131
+ }
132
+
133
+ importer.dialog
134
+ .open({
135
+ template: container,
136
+ className: `${this.id} importer dark`,
137
+ accept: translate('Choose this data'),
138
+ cancel: false,
139
+ })
140
+ .then(confirm)
141
+ }
142
+ }
@@ -258,7 +258,7 @@ export class DataLayerPermissions {
258
258
  {
259
259
  edit_status: null,
260
260
  },
261
- datalayer.options.permissions
261
+ datalayer.properties.permissions
262
262
  )
263
263
 
264
264
  this.datalayer = datalayer
@@ -314,9 +314,9 @@ export class DataLayerPermissions {
314
314
  }
315
315
 
316
316
  commit() {
317
- this.datalayer.options.permissions = Object.assign(
317
+ this.datalayer.properties.permissions = Object.assign(
318
318
  {},
319
- this.datalayer.options.permissions,
319
+ this.datalayer.properties.permissions,
320
320
  this.properties
321
321
  )
322
322
  }
@@ -23,8 +23,8 @@ export const EditControl = Control.extend({
23
23
 
24
24
  onAdd: (map) => {
25
25
  const template = `
26
- <div class="edit-enable">
27
- <button type="button" data-ref="button">${translate('Edit')}</button>
26
+ <div class="edit-enable dark">
27
+ <button type="button" data-ref="button" class="round"><i class="icon icon-16 icon-edit"></i> ${translate('Edit')}</button>
28
28
  </div>
29
29
  `
30
30
  const [container, { button }] = Utils.loadTemplateWithRefs(template)
@@ -42,6 +42,38 @@ export const EditControl = Control.extend({
42
42
  },
43
43
  })
44
44
 
45
+ export const LoadTemplateControl = Control.extend({
46
+ options: {
47
+ position: 'topright',
48
+ },
49
+
50
+ onAdd: (map) => {
51
+ const template = `
52
+ <div class="load-template dark hide-on-edit">
53
+ <button type="button" data-ref="button" class="round"><i class="icon icon-16 icon-template"></i>&nbsp;${translate('Reuse this template')}</button>
54
+ </div>
55
+ `
56
+ const [container, { button }] = Utils.loadTemplateWithRefs(template)
57
+ button.addEventListener('click', () => {
58
+ const downloadUrl = map._umap.urls.get('map_download', {
59
+ map_id: map._umap.id,
60
+ })
61
+ const targetUrl = `${map._umap.urls.get('map_new')}?templateUrl=${downloadUrl}`
62
+ window.open(targetUrl)
63
+ })
64
+ button.addEventListener('mouseover', () => {
65
+ map._umap.tooltip.open({
66
+ content: translate('Create a new map using this template'),
67
+ anchor: button,
68
+ position: 'bottom',
69
+ delay: 750,
70
+ duration: 5000,
71
+ })
72
+ })
73
+ return container
74
+ },
75
+ })
76
+
45
77
  export const MoreControl = Control.extend({
46
78
  options: {
47
79
  position: 'topleft',
@@ -235,8 +235,8 @@ export const Cluster = DivIcon.extend({
235
235
  computeTextColor: function (el) {
236
236
  let color
237
237
  const backgroundColor = this.datalayer.getColor()
238
- if (this.datalayer.options.cluster?.textColor) {
239
- color = this.datalayer.options.cluster.textColor
238
+ if (this.datalayer.properties.cluster?.textColor) {
239
+ color = this.datalayer.properties.cluster.textColor
240
240
  }
241
241
  return color || DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
242
242
  },
@@ -35,7 +35,7 @@ export const LayerMixin = {
35
35
  return this._layers
36
36
  },
37
37
 
38
- getEditableOptions: () => [],
38
+ getEditableProperties: () => [],
39
39
 
40
40
  onEdit: () => {},
41
41
 
@@ -15,11 +15,11 @@ const ClassifiedMixin = {
15
15
  .filter((k) => k !== 'schemeGroups')
16
16
  .sort()
17
17
  const key = this.getType().toLowerCase()
18
- if (!Utils.isObject(this.datalayer.options[key])) {
19
- this.datalayer.options[key] = {}
18
+ if (!Utils.isObject(this.datalayer.properties[key])) {
19
+ this.datalayer.properties[key] = {}
20
20
  }
21
- this.ensureOptions(this.datalayer.options[key])
22
- FeatureGroup.prototype.initialize.call(this, [], this.datalayer.options[key])
21
+ this.ensureOptions(this.datalayer.properties[key])
22
+ FeatureGroup.prototype.initialize.call(this, [], this.datalayer.properties[key])
23
23
  LayerMixin.onInit.call(this, this.datalayer._leafletMap)
24
24
  },
25
25
 
@@ -117,7 +117,7 @@ export const Choropleth = FeatureGroup.extend({
117
117
  },
118
118
 
119
119
  _getValue: function (feature) {
120
- const key = this.datalayer.options.choropleth?.property || 'value'
120
+ const key = this.datalayer.properties.choropleth?.property || 'value'
121
121
  const value = +feature.properties[key]
122
122
  if (!Number.isNaN(value)) return value
123
123
  },
@@ -130,12 +130,12 @@ export const Choropleth = FeatureGroup.extend({
130
130
  this.options.colors = []
131
131
  return
132
132
  }
133
- const mode = this.datalayer.options.choropleth?.mode
134
- let classes = +this.datalayer.options.choropleth?.classes || 5
133
+ const mode = this.datalayer.properties.choropleth?.mode
134
+ let classes = +this.datalayer.properties.choropleth?.classes || 5
135
135
  let breaks
136
136
  classes = Math.min(classes, values.length)
137
137
  if (mode === 'manual') {
138
- const manualBreaks = this.datalayer.options.choropleth?.breaks
138
+ const manualBreaks = this.datalayer.properties.choropleth?.breaks
139
139
  if (manualBreaks) {
140
140
  breaks = manualBreaks
141
141
  .split(',')
@@ -154,10 +154,10 @@ export const Choropleth = FeatureGroup.extend({
154
154
  breaks.push(ss.max(values)) // Needed for computing the legend
155
155
  }
156
156
  this.options.breaks = breaks || []
157
- this.datalayer.options.choropleth.breaks = this.options.breaks
157
+ this.datalayer.properties.choropleth.breaks = this.options.breaks
158
158
  .map((b) => +b.toFixed(2))
159
159
  .join(',')
160
- let colorScheme = this.datalayer.options.choropleth.brewer
160
+ let colorScheme = this.datalayer.properties.choropleth.brewer
161
161
  if (!colorbrewer[colorScheme]) colorScheme = 'Blues'
162
162
  this.options.colors = colorbrewer[colorScheme][this.options.breaks.length - 1] || []
163
163
  },
@@ -175,24 +175,27 @@ export const Choropleth = FeatureGroup.extend({
175
175
 
176
176
  onEdit: function (field, builder) {
177
177
  // Only compute the breaks if we're dealing with choropleth
178
- if (!field.startsWith('options.choropleth')) return
178
+ if (!field.startsWith('properties.choropleth')) return
179
179
  // If user touches the breaks, then force manual mode
180
- if (field === 'options.choropleth.breaks') {
181
- this.datalayer.options.choropleth.mode = 'manual'
182
- if (builder) builder.helpers['options.choropleth.mode'].fetch()
180
+ if (field === 'properties.choropleth.breaks') {
181
+ this.datalayer.properties.choropleth.mode = 'manual'
182
+ if (builder) builder.helpers['properties.choropleth.mode'].fetch()
183
183
  }
184
184
  this.compute()
185
185
  // If user changes the mode or the number of classes,
186
186
  // then update the breaks input value
187
- if (field === 'options.choropleth.mode' || field === 'options.choropleth.classes') {
188
- if (builder) builder.helpers['options.choropleth.breaks'].fetch()
187
+ if (
188
+ field === 'properties.choropleth.mode' ||
189
+ field === 'properties.choropleth.classes'
190
+ ) {
191
+ if (builder) builder.helpers['properties.choropleth.breaks'].fetch()
189
192
  }
190
193
  },
191
194
 
192
- getEditableOptions: function () {
195
+ getEditableProperties: function () {
193
196
  return [
194
197
  [
195
- 'options.choropleth.property',
198
+ 'properties.choropleth.property',
196
199
  {
197
200
  handler: 'Select',
198
201
  selectOptions: this.datalayer.allProperties(),
@@ -200,7 +203,7 @@ export const Choropleth = FeatureGroup.extend({
200
203
  },
201
204
  ],
202
205
  [
203
- 'options.choropleth.brewer',
206
+ 'properties.choropleth.brewer',
204
207
  {
205
208
  handler: 'Select',
206
209
  label: translate('Choropleth color palette'),
@@ -208,7 +211,7 @@ export const Choropleth = FeatureGroup.extend({
208
211
  },
209
212
  ],
210
213
  [
211
- 'options.choropleth.classes',
214
+ 'properties.choropleth.classes',
212
215
  {
213
216
  handler: 'Range',
214
217
  min: 3,
@@ -219,7 +222,7 @@ export const Choropleth = FeatureGroup.extend({
219
222
  },
220
223
  ],
221
224
  [
222
- 'options.choropleth.breaks',
225
+ 'properties.choropleth.breaks',
223
226
  {
224
227
  handler: 'BlurInput',
225
228
  label: translate('Choropleth breakpoints'),
@@ -229,7 +232,7 @@ export const Choropleth = FeatureGroup.extend({
229
232
  },
230
233
  ],
231
234
  [
232
- 'options.choropleth.mode',
235
+ 'properties.choropleth.mode',
233
236
  {
234
237
  handler: 'MultiChoice',
235
238
  default: 'kmeans',
@@ -261,13 +264,13 @@ export const Circles = FeatureGroup.extend({
261
264
  },
262
265
 
263
266
  ensureOptions: function (options) {
264
- if (!Utils.isObject(this.datalayer.options.circles.radius)) {
265
- this.datalayer.options.circles.radius = {}
267
+ if (!Utils.isObject(this.datalayer.properties.circles.radius)) {
268
+ this.datalayer.properties.circles.radius = {}
266
269
  }
267
270
  },
268
271
 
269
272
  _getValue: function (feature) {
270
- const key = this.datalayer.options.circles.property || 'value'
273
+ const key = this.datalayer.properties.circles.property || 'value'
271
274
  const value = +feature.properties[key]
272
275
  if (!Number.isNaN(value)) return value
273
276
  },
@@ -276,8 +279,8 @@ export const Circles = FeatureGroup.extend({
276
279
  const values = this.getValues()
277
280
  this.options.minValue = Math.sqrt(Math.min(...values))
278
281
  this.options.maxValue = Math.sqrt(Math.max(...values))
279
- this.options.minPX = this.datalayer.options.circles.radius?.min || 2
280
- this.options.maxPX = this.datalayer.options.circles.radius?.max || 50
282
+ this.options.minPX = this.datalayer.properties.circles.radius?.min || 2
283
+ this.options.maxPX = this.datalayer.properties.circles.radius?.max || 50
281
284
  },
282
285
 
283
286
  onEdit: function (field, builder) {
@@ -298,10 +301,10 @@ export const Circles = FeatureGroup.extend({
298
301
  return this._computeRadius(this._getValue(feature))
299
302
  },
300
303
 
301
- getEditableOptions: function () {
304
+ getEditableProperties: function () {
302
305
  return [
303
306
  [
304
- 'options.circles.property',
307
+ 'properties.circles.property',
305
308
  {
306
309
  handler: 'Select',
307
310
  selectOptions: this.datalayer.allProperties(),
@@ -309,7 +312,7 @@ export const Circles = FeatureGroup.extend({
309
312
  },
310
313
  ],
311
314
  [
312
- 'options.circles.radius.min',
315
+ 'properties.circles.radius.min',
313
316
  {
314
317
  handler: 'Range',
315
318
  label: translate('Min circle radius'),
@@ -319,7 +322,7 @@ export const Circles = FeatureGroup.extend({
319
322
  },
320
323
  ],
321
324
  [
322
- 'options.circles.radius.max',
325
+ 'properties.circles.radius.max',
323
326
  {
324
327
  handler: 'Range',
325
328
  label: translate('Max circle radius'),
@@ -337,7 +340,7 @@ export const Circles = FeatureGroup.extend({
337
340
 
338
341
  renderLegend: function (container) {
339
342
  const parent = DomUtil.create('ul', 'circles-layer-legend', container)
340
- const color = this.datalayer.getOption('color')
343
+ const color = this.datalayer.getProperty('color')
341
344
  const values = this.getValues()
342
345
  if (!values.length) return
343
346
  values.sort((a, b) => a - b)
@@ -355,7 +358,7 @@ export const Circles = FeatureGroup.extend({
355
358
  circleEl.style.backgroundColor = color
356
359
  circleEl.style.height = `${size * 2}px`
357
360
  circleEl.style.width = `${size * 2}px`
358
- circleEl.style.opacity = this.datalayer.getOption('opacity')
361
+ circleEl.style.opacity = this.datalayer.getProperty('opacity')
359
362
  const labelEl = DomUtil.create('span', 'label', li)
360
363
  labelEl.textContent = label
361
364
  }
@@ -381,7 +384,8 @@ export const Categorized = FeatureGroup.extend({
381
384
 
382
385
  _getValue: function (feature) {
383
386
  const key =
384
- this.datalayer.options.categorized.property || this.datalayer.allProperties()[0]
387
+ this.datalayer.properties.categorized.property ||
388
+ this.datalayer.allProperties()[0]
385
389
  return feature.properties[key]
386
390
  },
387
391
 
@@ -403,10 +407,10 @@ export const Categorized = FeatureGroup.extend({
403
407
  this.options.colors = []
404
408
  return
405
409
  }
406
- const mode = this.datalayer.options.categorized.mode
410
+ const mode = this.datalayer.properties.categorized.mode
407
411
  let categories = []
408
412
  if (mode === 'manual') {
409
- const manualCategories = this.datalayer.options.categorized.categories
413
+ const manualCategories = this.datalayer.properties.categorized.categories
410
414
  if (manualCategories) {
411
415
  categories = manualCategories.split(',')
412
416
  }
@@ -416,8 +420,8 @@ export const Categorized = FeatureGroup.extend({
416
420
  .sort(Utils.naturalSort)
417
421
  }
418
422
  this.options.categories = categories
419
- this.datalayer.options.categorized.categories = this.options.categories.join(',')
420
- const colorScheme = this.datalayer.options.categorized.brewer
423
+ this.datalayer.properties.categorized.categories = this.options.categories.join(',')
424
+ const colorScheme = this.datalayer.properties.categorized.brewer
421
425
  this._classes = this.options.categories.length
422
426
  if (colorbrewer[colorScheme]?.[this._classes]) {
423
427
  this.options.colors = colorbrewer[colorScheme][this._classes]
@@ -428,10 +432,10 @@ export const Categorized = FeatureGroup.extend({
428
432
  }
429
433
  },
430
434
 
431
- getEditableOptions: function () {
435
+ getEditableProperties: function () {
432
436
  return [
433
437
  [
434
- 'options.categorized.property',
438
+ 'properties.categorized.property',
435
439
  {
436
440
  handler: 'Select',
437
441
  selectOptions: this.datalayer.allProperties(),
@@ -439,7 +443,7 @@ export const Categorized = FeatureGroup.extend({
439
443
  },
440
444
  ],
441
445
  [
442
- 'options.categorized.brewer',
446
+ 'properties.categorized.brewer',
443
447
  {
444
448
  handler: 'Select',
445
449
  label: translate('Color palette'),
@@ -447,7 +451,7 @@ export const Categorized = FeatureGroup.extend({
447
451
  },
448
452
  ],
449
453
  [
450
- 'options.categorized.categories',
454
+ 'properties.categorized.categories',
451
455
  {
452
456
  handler: 'BlurInput',
453
457
  label: translate('Categories'),
@@ -455,7 +459,7 @@ export const Categorized = FeatureGroup.extend({
455
459
  },
456
460
  ],
457
461
  [
458
- 'options.categorized.mode',
462
+ 'properties.categorized.mode',
459
463
  {
460
464
  handler: 'MultiChoice',
461
465
  default: 'alpha',
@@ -468,17 +472,19 @@ export const Categorized = FeatureGroup.extend({
468
472
 
469
473
  onEdit: function (field, builder) {
470
474
  // Only compute the categories if we're dealing with categorized
471
- if (!field.startsWith('options.categorized') && field !== 'options.type') return
475
+ if (!field.startsWith('properties.categorized') && field !== 'properties.type') {
476
+ return
477
+ }
472
478
  // If user touches the categories, then force manual mode
473
- if (field === 'options.categorized.categories') {
474
- this.datalayer.options.categorized.mode = 'manual'
475
- if (builder) builder.helpers['options.categorized.mode'].fetch()
479
+ if (field === 'properties.categorized.categories') {
480
+ this.datalayer.properties.categorized.mode = 'manual'
481
+ if (builder) builder.helpers['properties.categorized.mode'].fetch()
476
482
  }
477
483
  this.compute()
478
484
  // If user changes the mode
479
485
  // then update the categories input value
480
- if (field === 'options.categorized.mode') {
481
- if (builder) builder.helpers['options.categorized.categories'].fetch()
486
+ if (field === 'properties.categorized.mode') {
487
+ if (builder) builder.helpers['properties.categorized.categories'].fetch()
482
488
  }
483
489
  },
484
490