Merge pull request #1649 from umap-project/add-features-ids

chore: add ids on features
This commit is contained in:
Yohan Boniface 2024-03-04 11:18:39 +01:00 committed by GitHub
commit fa0208519e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 97 additions and 1 deletions

View file

@ -1,10 +1,21 @@
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 Browser from './browser.js' import Browser from './browser.js'
import * as Utils from './utils.js'
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js' import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.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.U = { URLs, Request, ServerRequest, RequestError, HTTPError, NOKError, Browser } window.U = {
URLs,
Request,
ServerRequest,
RequestError,
HTTPError,
NOKError,
Browser,
Utils,
}

View file

@ -0,0 +1,24 @@
/**
* Generate a pseudo-unique identifier (5 chars long, mixed-case alphanumeric)
*
* 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
*
* @returns string
*/
export function generateId() {
return btoa(Math.random().toString()).substring(10, 15)
}
/**
* Ensure the ID matches the expected format.
*
* @param {string} string
* @returns {boolean}
*/
export function checkId(string) {
if (typeof string !== 'string') return false
return /^[A-Za-z0-9]{5}$/.test(string)
}

View file

@ -9,8 +9,17 @@ 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 identifier
if (U.Utils.checkId(geojson_id)) {
this.id = geojson_id
} else {
this.id = U.Utils.generateId()
} }
let isDirty = false let isDirty = false
const self = this const self = this
@ -344,6 +353,7 @@ 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
return geojson return geojson
}, },

View file

@ -0,0 +1,51 @@
import json
from pathlib import Path
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]