feat: simple implementation of ids

This commit is contained in:
Alexis Métaireau 2024-01-10 12:58:48 +01:00
parent b271dde93e
commit fb8ee1fc38
7 changed files with 101 additions and 4 deletions

View file

@ -1,8 +1,9 @@
import * as L from '../../vendors/leaflet/leaflet-src.esm.js' import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
import URLs from './urls.js' import URLs from './urls.js'
import * as utils from './utils.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.umap = { URLs } window.umap = { URLs, utils }

View file

@ -0,0 +1,8 @@
export function generateId() {
// A real implementation would benefit from another id type.
// Using uppercase + lowercase + digits, here's the collision risk
// For 6 chars, 1 in 100 000
// For 5 chars, 5 in 100 000
// for 4 chars, 500 in 100 000
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
}

View file

@ -1065,7 +1065,10 @@ L.U.TileLayerControl = L.Control.IconLayers.extend({
// when the tilelayer is actually added to the map (needs this._tileZoom // when the tilelayer is actually added to the map (needs this._tileZoom
// to be defined) // to be defined)
// Fixme when https://github.com/Leaflet/Leaflet/pull/9201 is released // Fixme when https://github.com/Leaflet/Leaflet/pull/9201 is released
const icon = L.Util.template(layer.options.url_template, this.map.demoTileInfos) const icon = L.Util.template(
layer.options.url_template,
this.map.demoTileInfos
)
layers.push({ layers.push({
title: layer.options.name, title: layer.options.name,
layer: layer, layer: layer,
@ -1431,10 +1434,12 @@ L.U.Editable = L.Editable.extend({
if (e.layer instanceof L.U.Marker) e.layer.del() if (e.layer instanceof L.U.Marker) e.layer.del()
}) })
this.on('editable:drawing:commit', function (e) { this.on('editable:drawing:commit', function (e) {
console.log('sync: polyline ready', e.layer)
e.layer.isDirty = true e.layer.isDirty = true
if (this.map.editedFeature !== e.layer) e.layer.edit(e) if (this.map.editedFeature !== e.layer) e.layer.edit(e)
}) })
this.on('editable:editing', (e) => { this.on('editable:editing', (e) => {
console.log('sync: polyline moved', e.layer)
const layer = e.layer const layer = e.layer
layer.isDirty = true layer.isDirty = true
if (layer._tooltip && layer.isTooltipOpen()) { if (layer._tooltip && layer.isTooltipOpen()) {
@ -1462,6 +1467,7 @@ L.U.Editable = L.Editable.extend({
}, },
createMarker: function (latlng) { createMarker: function (latlng) {
console.log('sync: create marker', latlng)
return new L.U.Marker(this.map, latlng, this._getDefaultProperties()) return new L.U.Marker(this.map, latlng, this._getDefaultProperties())
}, },

View file

@ -1,3 +1,5 @@
const generateId = window.umap.utils.generateId
L.U.FeatureMixin = { L.U.FeatureMixin = {
staticOptions: { mainColor: 'color' }, staticOptions: { mainColor: 'color' },
@ -9,9 +11,21 @@ L.U.FeatureMixin = {
// DataLayer the marker belongs to // DataLayer the marker belongs to
this.datalayer = options.datalayer || null this.datalayer = options.datalayer || null
this.properties = { _umap_options: {} } this.properties = { _umap_options: {} }
let geojson_id
if (options.geojson) { if (options.geojson) {
this.populate(options.geojson) this.populate(options.geojson)
geojson_id = options.geojson.id
} }
// Each feature needs an unique ID
if (this._checkId(geojson_id)) {
this.id = geojson_id
} else {
this.id = generateId()
}
console.log('id', this.id)
let isDirty = false let isDirty = false
const self = this const self = this
try { try {
@ -222,6 +236,7 @@ L.U.FeatureMixin = {
}, },
del: function () { del: function () {
console.log('sync: feature deleted', this)
this.isDirty = true this.isDirty = true
this.map.closePopup() this.map.closePopup()
if (this.datalayer) { if (this.datalayer) {
@ -248,6 +263,11 @@ L.U.FeatureMixin = {
return [key, value] return [key, value]
}, },
// Ensures the id meets our requirements
_checkId: function (string) {
return typeof string !== 'undefined'
},
populate: function (feature) { populate: function (feature) {
this.properties = Object.fromEntries( this.properties = Object.fromEntries(
Object.entries(feature.properties || {}).map(this.cleanProperty) Object.entries(feature.properties || {}).map(this.cleanProperty)
@ -344,7 +364,9 @@ L.U.FeatureMixin = {
toGeoJSON: function () { toGeoJSON: function () {
const geojson = this.parentClass.prototype.toGeoJSON.call(this) const geojson = this.parentClass.prototype.toGeoJSON.call(this)
geojson.properties = this.cloneProperties() geojson.properties = this.cloneProperties()
geojson.id = this.id
delete geojson.properties._storage_options delete geojson.properties._storage_options
console.log(geojson)
return geojson return geojson
}, },
@ -510,6 +532,7 @@ L.U.FeatureMixin = {
}, },
clone: function () { clone: function () {
console.log('sync: clone feature')
const layer = this.datalayer.geojsonToFeatures(this.toGeoJSON()) const layer = this.datalayer.geojsonToFeatures(this.toGeoJSON())
layer.isDirty = true layer.isDirty = true
layer.edit() layer.edit()
@ -560,6 +583,7 @@ L.U.Marker = L.Marker.extend({
this.on( this.on(
'dragend', 'dragend',
function (e) { function (e) {
console.log('sync: marker latlng updated', this._latlng)
this.isDirty = true this.isDirty = true
this.edit(e) this.edit(e)
}, },

View file

@ -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,
@ -830,7 +830,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 () {

View file

@ -1,3 +1,5 @@
// Rendering only
L.U.Layer = { L.U.Layer = {
canBrowse: true, canBrowse: true,

View file

@ -0,0 +1,53 @@
import json
from pathlib import Path
from playwright.sync_api import expect
def test_ids_generation(page, live_server, tilelayer):
page.goto(f"{live_server.url}/en/map/new/")
# Click on the Draw a line button on a new map.
create_polyline = page.locator(".leaflet-control-toolbar ").get_by_title(
"Draw a polyline"
)
create_polyline.click()
map = page.locator("#map")
map.click(position={"x": 200, "y": 200})
map.click(position={"x": 100, "y": 100})
# Click again to finish
map.click(position={"x": 100, "y": 100})
# Click on the Draw a polygon button on a new map.
create_polygon = page.locator(".leaflet-control-toolbar ").get_by_title(
"Draw a polygon"
)
create_polygon.click()
map = page.locator("#map")
map.click(position={"x": 300, "y": 300})
map.click(position={"x": 300, "y": 400})
map.click(position={"x": 350, "y": 450})
# Click again to finish
map.click(position={"x": 350, "y": 450})
download_panel = page.get_by_title("Share and download")
download_panel.click()
button = page.get_by_role("button", name="geojson")
with page.expect_download() as download_info:
button.click()
download = download_info.value
path = Path("/tmp/") / download.suggested_filename
download.save_as(path)
downloaded = json.loads(path.read_text())
assert "features" in downloaded
features = downloaded["features"]
assert len(features) == 2
assert "id" in features[0]
assert "id" in features[1]