Merge pull request #1649 from umap-project/add-features-ids
chore: add ids on features
This commit is contained in:
commit
fa0208519e
4 changed files with 97 additions and 1 deletions
|
@ -1,10 +1,21 @@
|
|||
import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import URLs from './urls.js'
|
||||
import Browser from './browser.js'
|
||||
import * as Utils from './utils.js'
|
||||
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js'
|
||||
|
||||
// Import modules and export them to the global scope.
|
||||
// For the not yet module-compatible JS out there.
|
||||
|
||||
// Copy the leaflet module, it's expected by leaflet plugins to be writeable.
|
||||
window.L = { ...L }
|
||||
window.U = { URLs, Request, ServerRequest, RequestError, HTTPError, NOKError, Browser }
|
||||
window.U = {
|
||||
URLs,
|
||||
Request,
|
||||
ServerRequest,
|
||||
RequestError,
|
||||
HTTPError,
|
||||
NOKError,
|
||||
Browser,
|
||||
Utils,
|
||||
}
|
||||
|
|
24
umap/static/umap/js/modules/utils.js
Normal file
24
umap/static/umap/js/modules/utils.js
Normal 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)
|
||||
}
|
|
@ -9,8 +9,17 @@ U.FeatureMixin = {
|
|||
// DataLayer the marker belongs to
|
||||
this.datalayer = options.datalayer || null
|
||||
this.properties = { _umap_options: {} }
|
||||
let geojson_id
|
||||
if (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
|
||||
const self = this
|
||||
|
@ -344,6 +353,7 @@ U.FeatureMixin = {
|
|||
toGeoJSON: function () {
|
||||
const geojson = this.parentClass.prototype.toGeoJSON.call(this)
|
||||
geojson.properties = this.cloneProperties()
|
||||
geojson.id = this.id
|
||||
delete geojson.properties._storage_options
|
||||
return geojson
|
||||
},
|
||||
|
|
51
umap/tests/integration/test_features_id_generation.py
Normal file
51
umap/tests/integration/test_features_id_generation.py
Normal 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]
|
Loading…
Reference in a new issue