POC of a choropleth layer

This commit is contained in:
Yohan Boniface 2023-06-10 19:57:54 +02:00
parent 31ea8d1a83
commit 8e12e6cf24
6 changed files with 98 additions and 4 deletions

View file

@ -34,6 +34,7 @@
"homepage": "http://wiki.openstreetmap.org/wiki/UMap", "homepage": "http://wiki.openstreetmap.org/wiki/UMap",
"dependencies": { "dependencies": {
"@tmcw/togeojson": "^5.8.0", "@tmcw/togeojson": "^5.8.0",
"chroma-js": "^2.4.2",
"csv2geojson": "5.1.1", "csv2geojson": "5.1.1",
"dompurify": "^3.0.3", "dompurify": "^3.0.3",
"georsstogeojson": "^0.1.0", "georsstogeojson": "^0.1.0",

View file

@ -26,5 +26,6 @@ mkdir -p umap/static/umap/vendors/tokml && cp -r node_modules/tokml/tokml.js uma
mkdir -p umap/static/umap/vendors/locatecontrol/ && cp -r node_modules/leaflet.locatecontrol/dist/L.Control.Locate.css umap/static/umap/vendors/locatecontrol/ mkdir -p umap/static/umap/vendors/locatecontrol/ && cp -r node_modules/leaflet.locatecontrol/dist/L.Control.Locate.css umap/static/umap/vendors/locatecontrol/
mkdir -p umap/static/umap/vendors/locatecontrol/ && cp -r node_modules/leaflet.locatecontrol/src/L.Control.Locate.js umap/static/umap/vendors/locatecontrol/ mkdir -p umap/static/umap/vendors/locatecontrol/ && cp -r node_modules/leaflet.locatecontrol/src/L.Control.Locate.js umap/static/umap/vendors/locatecontrol/
mkdir -p umap/static/umap/vendors/dompurify/ && cp -r node_modules/dompurify/dist/purify.js umap/static/umap/vendors/dompurify/ mkdir -p umap/static/umap/vendors/dompurify/ && cp -r node_modules/dompurify/dist/purify.js umap/static/umap/vendors/dompurify/
mkdir -p umap/static/umap/vendors/chroma/ && cp -r node_modules/chroma-js/chroma.min.js umap/static/umap/vendors/chroma/
echo 'Done!' echo 'Done!'

View file

@ -283,7 +283,7 @@ L.U.FeatureMixin = {
} else if (L.Util.usableOption(this.properties._umap_options, option)) { } else if (L.Util.usableOption(this.properties._umap_options, option)) {
value = this.properties._umap_options[option] value = this.properties._umap_options[option]
} else if (this.datalayer) { } else if (this.datalayer) {
value = this.datalayer.getOption(option) value = this.datalayer.getOption(option, this)
} else { } else {
value = this.map.getOption(option) value = this.map.getOption(option)
} }

View file

@ -379,6 +379,7 @@ L.FormBuilder.LayerTypeChooser = L.FormBuilder.Select.extend({
['Default', L._('Default')], ['Default', L._('Default')],
['Cluster', L._('Clustered')], ['Cluster', L._('Clustered')],
['Heat', L._('Heatmap')], ['Heat', L._('Heatmap')],
['Choropleth', L._('Choropleth')],
], ],
}) })

View file

@ -106,6 +106,94 @@ L.U.Layer.Cluster = L.MarkerClusterGroup.extend({
}, },
}) })
L.U.Layer.Choropleth = L.FeatureGroup.extend({
_type: 'Choropleth',
includes: [L.U.Layer],
canBrowse: true,
initialize: function (datalayer) {
this.datalayer = datalayer
if (!L.Util.isObject(this.datalayer.options.choropleth)) {
this.datalayer.options.choropleth = {}
}
L.FeatureGroup.prototype.initialize.call(
this,
[],
this.datalayer.options.choropleth
)
},
computeLimits: function () {
const values = []
this.datalayer.eachLayer((layer) => values.push(layer.properties.density))
this.options.limits = chroma.limits(
values,
this.datalayer.options.choropleth.mode || 'q',
this.datalayer.options.choropleth.steps || 5
)
const color = this.datalayer.getOption('color')
this.options.colors = chroma
.scale(['white', color])
.colors(this.options.limits.length)
},
getColor: function (feature) {
if (!feature) return // FIXME shold not happen
const featureValue = feature.properties.density
// Find the bucket/step/limit that this value is less than and give it that color
for (let i = 0; i < this.options.limits.length; i++) {
if (featureValue <= this.options.limits[i]) {
return this.options.colors[i]
}
}
},
getOption: function (option, feature) {
if (option === 'fillColor' || option === 'color') return this.getColor(feature)
},
addLayer: function (layer) {
this.computeLimits()
L.FeatureGroup.prototype.addLayer.call(this, layer)
},
removeLayer: function (layer) {
this.computeLimits()
L.FeatureGroup.prototype.removeLayer.call(this, layer)
},
onAdd: function (map) {
this.computeLimits()
L.FeatureGroup.prototype.onAdd.call(this, map)
},
getEditableOptions: function () {
return [
[
'options.choropleth.steps',
{
handler: 'IntInput',
placeholder: L._('Choropleth steps'),
helpText: L._('Choropleth steps (default 5)'),
},
],
[
'options.choropleth.mode',
{
handler: 'Select',
selectOptions: [
['q', L._('quantile')],
['e', L._('equidistant')],
['l', L._('logarithmic')],
['k', L._('k-mean')],
],
helpText: L._('Choropleth mode'),
},
],
]
},
})
L.U.Layer.Heat = L.HeatLayer.extend({ L.U.Layer.Heat = L.HeatLayer.extend({
_type: 'Heat', _type: 'Heat',
includes: [L.U.Layer], includes: [L.U.Layer],
@ -897,8 +985,6 @@ L.U.DataLayer = L.Evented.extend({
'options.fillOpacity', 'options.fillOpacity',
] ]
shapeOptions = shapeOptions.concat(this.layer.getEditableOptions())
const redrawCallback = function (field) { const redrawCallback = function (field) {
this.hide() this.hide()
this.layer.postUpdate(field) this.layer.postUpdate(field)
@ -1050,7 +1136,11 @@ L.U.DataLayer = L.Evented.extend({
this.map.ui.openPanel({ data: { html: container }, className: 'dark' }) this.map.ui.openPanel({ data: { html: container }, className: 'dark' })
}, },
getOption: function (option) { getOption: function (option, feature) {
if (this.layer && this.layer.getOption) {
const value = this.layer.getOption(option, feature)
if (value) return value
}
if (L.Util.usableOption(this.options, option)) return this.options[option] if (L.Util.usableOption(this.options, option)) return this.options[option]
else return this.map.getOption(option) else return this.map.getOption(option)
}, },

View file

@ -24,6 +24,7 @@
<script src="{{ STATIC_URL }}umap/vendors/tokml/tokml.js"></script> <script src="{{ STATIC_URL }}umap/vendors/tokml/tokml.js"></script>
<script src="{{ STATIC_URL }}umap/vendors/locatecontrol/L.Control.Locate.js"></script> <script src="{{ STATIC_URL }}umap/vendors/locatecontrol/L.Control.Locate.js"></script>
<script src="{{ STATIC_URL }}umap/vendors/dompurify/purify.js"></script> <script src="{{ STATIC_URL }}umap/vendors/dompurify/purify.js"></script>
<script src="{{ STATIC_URL }}umap/vendors/chroma/chroma.min.js"></script>
{% endcompress %} {% endcompress %}
{% if locale %}<script src="{{ STATIC_URL }}umap/locale/{{ locale }}.js"></script>{% endif %} {% if locale %}<script src="{{ STATIC_URL }}umap/locale/{{ locale }}.js"></script>{% endif %}
{% compress js %} {% compress js %}