mirror of
https://github.com/umap-project/umap.git
synced 2025-05-06 06:21:49 +02:00
WIP
This commit is contained in:
parent
4b34a7d300
commit
d219ed331f
6 changed files with 195 additions and 64 deletions
|
@ -1,8 +1,11 @@
|
||||||
import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
|
import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import * as Y from '../../vendors/yjs/yjs.js'
|
||||||
import URLs from './urls.js'
|
import URLs from './urls.js'
|
||||||
// Import modules and export them to the global scope.
|
// Import modules and export them to the global scope.
|
||||||
// For the not yet module-compatible JS out there.
|
// For the not yet module-compatible JS out there.
|
||||||
|
|
||||||
// Copy the leaflet module, it's expected by leaflet plugins to be writeable.
|
// Copy the leaflet module, it's expected by leaflet plugins to be writeable.
|
||||||
window.L = { ...L }
|
window.L = { ...L }
|
||||||
|
|
||||||
|
window.Y = Y
|
||||||
window.umap = { URLs }
|
window.umap = { URLs }
|
||||||
|
|
|
@ -62,7 +62,12 @@ L.U.Browser = L.Class.extend({
|
||||||
container.id = `browse_data_datalayer_${datalayer.umap_id}`
|
container.id = `browse_data_datalayer_${datalayer.umap_id}`
|
||||||
datalayer.renderToolbox(headline)
|
datalayer.renderToolbox(headline)
|
||||||
L.DomUtil.add('span', '', headline, datalayer.options.name)
|
L.DomUtil.add('span', '', headline, datalayer.options.name)
|
||||||
const counter = L.DomUtil.add('span', 'datalayer-counter', headline, datalayer.count())
|
const counter = L.DomUtil.add(
|
||||||
|
'span',
|
||||||
|
'datalayer-counter',
|
||||||
|
headline,
|
||||||
|
datalayer.count()
|
||||||
|
)
|
||||||
counter.title = L._('{count} features in this layer', { count: datalayer.count() })
|
counter.title = L._('{count} features in this layer', { count: datalayer.count() })
|
||||||
const ul = L.DomUtil.create('ul', '', container)
|
const ul = L.DomUtil.create('ul', '', container)
|
||||||
L.DomUtil.classIf(container, 'off', !datalayer.isVisible())
|
L.DomUtil.classIf(container, 'off', !datalayer.isVisible())
|
||||||
|
|
45
umap/static/umap/js/umap.data.js
Normal file
45
umap/static/umap/js/umap.data.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* A mixin to ease the rendering of the data, and updating of a local CRDT.
|
||||||
|
*
|
||||||
|
* The mixed class needs to expose:
|
||||||
|
*
|
||||||
|
* - `dataUpdaters`, an object matching each property with a list of renderers.
|
||||||
|
* - `getDataObject`, a method returning where the data is stored/retrieved.
|
||||||
|
*/
|
||||||
|
L.U.DataRendererMixin = {
|
||||||
|
populateCRDT: function () {
|
||||||
|
for (const [key, value] of Object.entries(this.options)) {
|
||||||
|
this.crdt.set(key, value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* For each passed property, find the functions to rerender the interface,
|
||||||
|
* and call them.
|
||||||
|
*
|
||||||
|
* @param list updatedProperties : properties that have been updated.
|
||||||
|
*/
|
||||||
|
renderProperties: function (updatedProperties) {
|
||||||
|
console.debug(updatedProperties)
|
||||||
|
let renderers = new Set()
|
||||||
|
for (const prop of updatedProperties) {
|
||||||
|
const propRenderers = this.dataUpdaters[prop]
|
||||||
|
if (propRenderers) {
|
||||||
|
for (const renderer of propRenderers) renderers.add(renderer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.debug('renderers', renderers)
|
||||||
|
for (const renderer of renderers) this[renderer]()
|
||||||
|
},
|
||||||
|
|
||||||
|
dataReceived: function () {
|
||||||
|
// Data has been received over the wire
|
||||||
|
this.updateInternalData()
|
||||||
|
this.onPropertiesUpdated(['name', 'color'])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
L.U.FormBuilderDataRendererMixin = {
|
||||||
|
getDataObject: function () {
|
||||||
|
return this.options
|
||||||
|
},
|
||||||
|
}
|
|
@ -1259,6 +1259,12 @@ L.U.FormBuilder = L.FormBuilder.extend({
|
||||||
setter: function (field, value) {
|
setter: function (field, value) {
|
||||||
L.FormBuilder.prototype.setter.call(this, field, value)
|
L.FormBuilder.prototype.setter.call(this, field, value)
|
||||||
if (this.options.makeDirty !== false) this.obj.isDirty = true
|
if (this.options.makeDirty !== false) this.obj.isDirty = true
|
||||||
|
|
||||||
|
// FIXME: for now remove the options prefix
|
||||||
|
field = field.replace('options.', '')
|
||||||
|
if (this.obj.crdt) this.obj.crdt.set(field, value)
|
||||||
|
|
||||||
|
this.obj.onPropertiesUpdated([field])
|
||||||
},
|
},
|
||||||
|
|
||||||
finish: function () {
|
finish: function () {
|
||||||
|
|
|
@ -34,7 +34,7 @@ L.Map.mergeOptions({
|
||||||
// we cannot rely on this because of the y is overriden by Leaflet
|
// we cannot rely on this because of the y is overriden by Leaflet
|
||||||
// See https://github.com/Leaflet/Leaflet/pull/9201
|
// See https://github.com/Leaflet/Leaflet/pull/9201
|
||||||
// And let's remove this -y when this PR is merged and released.
|
// And let's remove this -y when this PR is merged and released.
|
||||||
demoTileInfos: { s: 'a', z: 9, x: 265, y: 181, '-y': 181, r: '' },
|
demoTileInfos: { 's': 'a', 'z': 9, 'x': 265, 'y': 181, '-y': 181, 'r': '' },
|
||||||
licences: [],
|
licences: [],
|
||||||
licence: '',
|
licence: '',
|
||||||
enableMarkerDraw: true,
|
enableMarkerDraw: true,
|
||||||
|
@ -69,6 +69,122 @@ L.U.Map.include({
|
||||||
'tilelayers',
|
'tilelayers',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
//Used by the L.U.DataRendererMixin
|
||||||
|
propertiesRenderers: {
|
||||||
|
// Controls
|
||||||
|
'name': ['renderEditToolbar', 'renderControls'],
|
||||||
|
'color': ['renderVisibleDataLayers'],
|
||||||
|
'moreControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'scrollWheelZoom': ['renderControls', 'initCaptionBar'],
|
||||||
|
'miniMap': ['renderControls', 'initCaptionBar'],
|
||||||
|
'scaleControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'onLoadPanel': ['renderControls', 'initCaptionBar'],
|
||||||
|
'defaultView': ['renderControls', 'initCaptionBar'],
|
||||||
|
'displayPopupFooter': ['renderControls', 'initCaptionBar'],
|
||||||
|
'captionBar': ['renderControls', 'initCaptionBar'],
|
||||||
|
'captionMenus': ['renderControls', 'initCaptionBar'],
|
||||||
|
'zoomControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'searchControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'fullscreenControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'embedControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'locateControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'measureControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'editinosmControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'datalayersControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'starControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
'tilelayersControl': ['renderControls', 'initCaptionBar'],
|
||||||
|
|
||||||
|
// Shape properties
|
||||||
|
'color': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'iconClass': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'iconUrl': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'iconOpacity': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'opacity': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'weight': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'fill': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'fillColor': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'fillOpacity': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'smoothFactor': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
'dashArray': ['renderVisibleDataLayers', 'renderControls'],
|
||||||
|
|
||||||
|
// Default properties
|
||||||
|
'zoomTo': ['initCaptionBar'],
|
||||||
|
'easing': ['initCaptionBar'],
|
||||||
|
'labelKey': ['initCaptionBar'],
|
||||||
|
'sortKey': ['initCaptionBar', 'reindexEachDataLayer'],
|
||||||
|
'filterKey': ['initCaptionBar'],
|
||||||
|
'facetKey': ['initCaptionBar'],
|
||||||
|
'slugKey': ['initCaptionBar'],
|
||||||
|
|
||||||
|
// Interaction properties
|
||||||
|
'popupShape': [],
|
||||||
|
'popupTemplate': [],
|
||||||
|
'popupContentTemplate': [],
|
||||||
|
'showLabel': ['renderVisibleDataLayers'],
|
||||||
|
'labelDirection': ['renderVisibleDataLayers'],
|
||||||
|
'labelInteractive': ['renderVisibleDataLayers'],
|
||||||
|
'outlinkTarget': [],
|
||||||
|
|
||||||
|
// Tile layer
|
||||||
|
'tilelayer.name': ['initTileLayer'],
|
||||||
|
'tilelayer.url_template': ['initTileLayer'],
|
||||||
|
'tilelayer.maxZoom': ['initTileLayer'],
|
||||||
|
'tilelayer.minZoom': ['initTileLayer'],
|
||||||
|
'tilelayer.attribution': ['initTileLayer'],
|
||||||
|
'tilelayer.tms': ['initTileLayer'],
|
||||||
|
|
||||||
|
// Overlay
|
||||||
|
'overlay.url_template': ['initTileLayer'],
|
||||||
|
'overlay.maxZoom': ['initTileLayer'],
|
||||||
|
'overlay.minZoom': ['initTileLayer'],
|
||||||
|
'overlay.attribution': ['initTileLayer'],
|
||||||
|
'overlay.opacity': ['initTileLayer'],
|
||||||
|
'overlay.tms': ['initTileLayer'],
|
||||||
|
|
||||||
|
// Bounds
|
||||||
|
'limitBounds.south': ['handleLimitBounds'],
|
||||||
|
'limitBounds.west': ['handleLimitBounds'],
|
||||||
|
'limitBounds.north': ['handleLimitBounds'],
|
||||||
|
'limitBounds.east': ['handleLimitBounds'],
|
||||||
|
|
||||||
|
// Slideshow
|
||||||
|
'slideshow.active': ['renderControls'],
|
||||||
|
'slideshow.delay': ['renderControls'],
|
||||||
|
'slideshow.easing': ['renderControls'],
|
||||||
|
'slideshow.autoplay': ['renderControls'],
|
||||||
|
|
||||||
|
// Credits
|
||||||
|
'licence': ['renderControls'],
|
||||||
|
'shortCredit': ['renderControls'],
|
||||||
|
'longCredit': ['renderControls'],
|
||||||
|
'permanentCredit': ['renderControls'],
|
||||||
|
'permanentCreditBackground': ['renderControls'],
|
||||||
|
},
|
||||||
|
|
||||||
|
reindexEachDataLayer: function () {
|
||||||
|
this.eachDataLayer((datalayer) => datalayer.reindex())
|
||||||
|
},
|
||||||
|
|
||||||
|
renderVisibleDataLayers: function () {
|
||||||
|
this.eachVisibleDataLayer((datalayer) => {
|
||||||
|
datalayer.redraw()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
broadcastChanges: function (data) {
|
||||||
|
// Send changes over the wire
|
||||||
|
console.log(data)
|
||||||
|
},
|
||||||
|
|
||||||
|
updateInternalData: function () {
|
||||||
|
this.options.name = 'CRDTS, yeah'
|
||||||
|
this.options.color = 'Fushia'
|
||||||
|
},
|
||||||
|
|
||||||
|
getCRDT: function () {
|
||||||
|
return this._main_crdt.getMap('map')
|
||||||
|
},
|
||||||
|
|
||||||
initialize: function (el, geojson) {
|
initialize: function (el, geojson) {
|
||||||
// Locale name (pt_PT, en_US…)
|
// Locale name (pt_PT, en_US…)
|
||||||
// To be used for Django localization
|
// To be used for Django localization
|
||||||
|
@ -292,6 +408,7 @@ L.U.Map.include({
|
||||||
this.backup()
|
this.backup()
|
||||||
this.initContextMenu()
|
this.initContextMenu()
|
||||||
this.on('click contextmenu.show', this.closeInplaceToolbar)
|
this.on('click contextmenu.show', this.closeInplaceToolbar)
|
||||||
|
this._main_crdt = new YJS.Doc()
|
||||||
},
|
},
|
||||||
|
|
||||||
initControls: function () {
|
initControls: function () {
|
||||||
|
@ -830,7 +947,10 @@ L.U.Map.include({
|
||||||
self.isDirty = true
|
self.isDirty = true
|
||||||
}
|
}
|
||||||
if (this._controls.tilelayersChooser)
|
if (this._controls.tilelayersChooser)
|
||||||
this._controls.tilelayersChooser.openSwitcher({ callback: callback, className: 'dark' })
|
this._controls.tilelayersChooser.openSwitcher({
|
||||||
|
callback: callback,
|
||||||
|
className: 'dark',
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
manageDatalayers: function () {
|
manageDatalayers: function () {
|
||||||
|
@ -1260,13 +1380,7 @@ L.U.Map.include({
|
||||||
'options.captionBar',
|
'options.captionBar',
|
||||||
'options.captionMenus',
|
'options.captionMenus',
|
||||||
])
|
])
|
||||||
builder = new L.U.FormBuilder(this, UIFields, {
|
builder = new L.U.FormBuilder(this, UIFields)
|
||||||
callback: function () {
|
|
||||||
this.renderControls()
|
|
||||||
this.initCaptionBar()
|
|
||||||
},
|
|
||||||
callbackContext: this,
|
|
||||||
})
|
|
||||||
const controlsOptions = L.DomUtil.createFieldset(
|
const controlsOptions = L.DomUtil.createFieldset(
|
||||||
container,
|
container,
|
||||||
L._('User interface options')
|
L._('User interface options')
|
||||||
|
@ -1289,14 +1403,7 @@ L.U.Map.include({
|
||||||
'options.dashArray',
|
'options.dashArray',
|
||||||
]
|
]
|
||||||
|
|
||||||
builder = new L.U.FormBuilder(this, shapeOptions, {
|
builder = new L.U.FormBuilder(this, shapeOptions)
|
||||||
callback: function (e) {
|
|
||||||
if (this._controls.miniMap) this.renderControls()
|
|
||||||
this.eachVisibleDataLayer((datalayer) => {
|
|
||||||
datalayer.redraw()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const defaultShapeProperties = L.DomUtil.createFieldset(
|
const defaultShapeProperties = L.DomUtil.createFieldset(
|
||||||
container,
|
container,
|
||||||
L._('Default shape properties')
|
L._('Default shape properties')
|
||||||
|
@ -1349,14 +1456,7 @@ L.U.Map.include({
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
|
|
||||||
builder = new L.U.FormBuilder(this, optionsFields, {
|
builder = new L.U.FormBuilder(this, optionsFields)
|
||||||
callback: function (e) {
|
|
||||||
this.initCaptionBar()
|
|
||||||
if (e.helper.field === 'options.sortKey') {
|
|
||||||
this.eachDataLayer((datalayer) => datalayer.reindex())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const defaultProperties = L.DomUtil.createFieldset(
|
const defaultProperties = L.DomUtil.createFieldset(
|
||||||
container,
|
container,
|
||||||
L._('Default properties')
|
L._('Default properties')
|
||||||
|
@ -1374,20 +1474,7 @@ L.U.Map.include({
|
||||||
'options.labelInteractive',
|
'options.labelInteractive',
|
||||||
'options.outlinkTarget',
|
'options.outlinkTarget',
|
||||||
]
|
]
|
||||||
builder = new L.U.FormBuilder(this, popupFields, {
|
builder = new L.U.FormBuilder(this, popupFields)
|
||||||
callback: function (e) {
|
|
||||||
if (
|
|
||||||
e.helper.field === 'options.popupTemplate' ||
|
|
||||||
e.helper.field === 'options.popupContentTemplate' ||
|
|
||||||
e.helper.field === 'options.popupShape' ||
|
|
||||||
e.helper.field === 'options.outlinkTarget'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
this.eachVisibleDataLayer((datalayer) => {
|
|
||||||
datalayer.redraw()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const popupFieldset = L.DomUtil.createFieldset(
|
const popupFieldset = L.DomUtil.createFieldset(
|
||||||
container,
|
container,
|
||||||
L._('Default interaction options')
|
L._('Default interaction options')
|
||||||
|
@ -1441,10 +1528,7 @@ L.U.Map.include({
|
||||||
container,
|
container,
|
||||||
L._('Custom background')
|
L._('Custom background')
|
||||||
)
|
)
|
||||||
builder = new L.U.FormBuilder(this, tilelayerFields, {
|
builder = new L.U.FormBuilder(this, tilelayerFields)
|
||||||
callback: this.initTileLayers,
|
|
||||||
callbackContext: this,
|
|
||||||
})
|
|
||||||
customTilelayer.appendChild(builder.build())
|
customTilelayer.appendChild(builder.build())
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1492,10 +1576,7 @@ L.U.Map.include({
|
||||||
['options.overlay.tms', { handler: 'Switch', label: L._('TMS format') }],
|
['options.overlay.tms', { handler: 'Switch', label: L._('TMS format') }],
|
||||||
]
|
]
|
||||||
const overlay = L.DomUtil.createFieldset(container, L._('Custom overlay'))
|
const overlay = L.DomUtil.createFieldset(container, L._('Custom overlay'))
|
||||||
builder = new L.U.FormBuilder(this, overlayFields, {
|
builder = new L.U.FormBuilder(this, overlayFields)
|
||||||
callback: this.initTileLayers,
|
|
||||||
callbackContext: this,
|
|
||||||
})
|
|
||||||
overlay.appendChild(builder.build())
|
overlay.appendChild(builder.build())
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1522,10 +1603,7 @@ L.U.Map.include({
|
||||||
{ handler: 'BlurFloatInput', placeholder: L._('max East') },
|
{ handler: 'BlurFloatInput', placeholder: L._('max East') },
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
const boundsBuilder = new L.U.FormBuilder(this, boundsFields, {
|
const boundsBuilder = new L.U.FormBuilder(this, boundsFields)
|
||||||
callback: this.handleLimitBounds,
|
|
||||||
callbackContext: this,
|
|
||||||
})
|
|
||||||
limitBounds.appendChild(boundsBuilder.build())
|
limitBounds.appendChild(boundsBuilder.build())
|
||||||
const boundsButtons = L.DomUtil.create('div', 'button-bar half', limitBounds)
|
const boundsButtons = L.DomUtil.create('div', 'button-bar half', limitBounds)
|
||||||
L.DomUtil.createButton(
|
L.DomUtil.createButton(
|
||||||
|
@ -1584,13 +1662,9 @@ L.U.Map.include({
|
||||||
{ handler: 'Switch', label: L._('Autostart when map is loaded') },
|
{ handler: 'Switch', label: L._('Autostart when map is loaded') },
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
const slideshowHandler = function () {
|
|
||||||
|
const slideshowBuilder = new L.U.FormBuilder(this, slideshowFields, function () {
|
||||||
this.slideshow.setOptions(this.options.slideshow)
|
this.slideshow.setOptions(this.options.slideshow)
|
||||||
this.renderControls()
|
|
||||||
}
|
|
||||||
const slideshowBuilder = new L.U.FormBuilder(this, slideshowFields, {
|
|
||||||
callback: slideshowHandler,
|
|
||||||
callbackContext: this,
|
|
||||||
})
|
})
|
||||||
slideshow.appendChild(slideshowBuilder.build())
|
slideshow.appendChild(slideshowBuilder.build())
|
||||||
},
|
},
|
||||||
|
@ -1628,10 +1702,7 @@ L.U.Map.include({
|
||||||
{ handler: 'Switch', label: L._('Permanent credits background') },
|
{ handler: 'Switch', label: L._('Permanent credits background') },
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
const creditsBuilder = new L.U.FormBuilder(this, creditsFields, {
|
const creditsBuilder = new L.U.FormBuilder(this, creditsFields)
|
||||||
callback: this.renderControls,
|
|
||||||
callbackContext: this,
|
|
||||||
})
|
|
||||||
credits.appendChild(creditsBuilder.build())
|
credits.appendChild(creditsBuilder.build())
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
<div id="map"></div>
|
<div id="map"></div>
|
||||||
<!-- djlint:off -->
|
<!-- djlint:off -->
|
||||||
<script defer type="text/javascript">
|
<script defer type="text/javascript">
|
||||||
|
let MAP
|
||||||
window.addEventListener('DOMContentLoaded', (event) => {
|
window.addEventListener('DOMContentLoaded', (event) => {
|
||||||
let MAP = new L.U.Map("map", {{ map_settings|notag|safe }});
|
MAP = new L.U.Map("map", {{ map_settings|notag|safe }});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<!-- djlint:on -->
|
<!-- djlint:on -->
|
||||||
|
|
Loading…
Reference in a new issue