From 89acf8f0ecacc4319ad0b7648b6abea36df273c6 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Fri, 6 Dec 2024 11:08:50 +0100 Subject: [PATCH] feat: add elevation gain and loss in extended properties --- docs-users/fr/support/faq.md | 1 + docs-users/support/faq.md | 1 + umap/static/umap/js/modules/data/features.js | 7 +- umap/static/umap/js/modules/rendering/ui.js | 29 +++ umap/tests/integration/test_view_polyline.py | 223 +++++++++++++++++++ 5 files changed, 260 insertions(+), 1 deletion(-) diff --git a/docs-users/fr/support/faq.md b/docs-users/fr/support/faq.md index f9dcac7e..58171bb2 100644 --- a/docs-users/fr/support/faq.md +++ b/docs-users/fr/support/faq.md @@ -77,6 +77,7 @@ Toute propriété de l'élément sera disponible, ainsi que: - `{locale}` → la langue sous la forme `fr` ou `fr_CA` quand une variante est utilisée - `{lang}` → la langue sous la forme `fr` ou `fr-ca` quand une variante est utilisée - `{measure}` → la longueur d'une ligne ou la surface d'un polygone +- `{gain}`/`{loss}` → la dénivelée positive/négative d'une ligne (seulement si elle contient les altitudes) - `{rank}` → la rang d'un élément dans son calque - `{layer}` → le nom du calque de l'élément - `{zoom}` → le zoom actuel de la carte diff --git a/docs-users/support/faq.md b/docs-users/support/faq.md index 68bf59ca..990f928b 100644 --- a/docs-users/support/faq.md +++ b/docs-users/support/faq.md @@ -77,6 +77,7 @@ Any property of the feature will be available, plus: - `{locale}` → the locale in the form `en` or `en_US` when a variant is used - `{lang}` → the lang in the form `en` or `en-us` when a variant is used - `{measure}` → the length of a line or the area of a polygon +- `{gain}`/`{loss}` → the elevation gain/loss of a line (only if it contains the altitude information) - `{rank}` → the rank of the feature in the layer - `{layer}` → the name of the feature's layer - `{zoom}` → the current map zoom diff --git a/umap/static/umap/js/modules/data/features.js b/umap/static/umap/js/modules/data/features.js index d148779c..a9171a72 100644 --- a/umap/static/umap/js/modules/data/features.js +++ b/umap/static/umap/js/modules/data/features.js @@ -591,7 +591,7 @@ class Feature { properties.measure = this.ui.getMeasure() } } - return L.extend(properties, this.properties) + return Object.assign(properties, this.properties) } getRank() { @@ -1060,6 +1060,11 @@ export class LineString extends Path { }) return items } + + extendedProperties() { + const [gain, loss] = this.ui.getElevation() + return Object.assign({ gain, loss }, super.extendedProperties()) + } } export class Polygon extends Path { diff --git a/umap/static/umap/js/modules/rendering/ui.js b/umap/static/umap/js/modules/rendering/ui.js index a67c9d87..f2c307ee 100644 --- a/umap/static/umap/js/modules/rendering/ui.js +++ b/umap/static/umap/js/modules/rendering/ui.js @@ -400,6 +400,35 @@ export const LeafletPolyline = Polyline.extend({ ) return L.GeoUtil.readableDistance(length, this._map.measureTools.getMeasureUnit()) }, + + getElevation: function () { + const lineElevation = (latlngs) => { + let gain = 0 + let loss = 0 + for (let i = 0, n = latlngs.length - 1; i < n; i++) { + const fromAlt = latlngs[i].alt + const toAlt = latlngs[i + 1].alt + if (fromAlt === undefined || toAlt === undefined) continue + if (fromAlt > toAlt) loss += fromAlt - toAlt + else gain += toAlt - fromAlt + } + return [gain, loss] + } + let shapes + if (LineUtil.isFlat(this._latlngs)) { + shapes = [this._latlngs] + } else { + shapes = this._latlngs + } + let totalGain = 0 + let totalLoss = 0 + for (const shape of shapes) { + const [gain, loss] = lineElevation(shape) + totalGain += gain + totalLoss += loss + } + return [Math.round(totalGain), Math.round(totalLoss)] + }, }) export const LeafletPolygon = Polygon.extend({ diff --git a/umap/tests/integration/test_view_polyline.py b/umap/tests/integration/test_view_polyline.py index 99b52fb9..1b993f73 100644 --- a/umap/tests/integration/test_view_polyline.py +++ b/umap/tests/integration/test_view_polyline.py @@ -1,3 +1,5 @@ +from pathlib import Path + import pytest from playwright.sync_api import expect @@ -83,3 +85,224 @@ def test_can_use_measure_on_name(live_server, map, page): page.goto(f"{live_server.url}{map.get_absolute_url()}#6/10/50") expect(page.get_by_text("linestring (99.7 km)")).to_be_visible() expect(page.get_by_text("multilinestring (592 km)")).to_be_visible() + + +def test_can_use_gain_and_loss(live_server, map, page): + data = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [8.420888, 39.327819, 12.1], + [8.420915, 39.327745, 12.9], + [8.420906, 39.327543, 14.8], + [8.420876, 39.327312, 17], + [8.420754, 39.327023, 16.8], + [8.420609, 39.326776, 16.6], + [8.42051, 39.326467, 16.4], + [8.420409, 39.326254, 16.3], + [8.420367, 39.326108, 16.2], + [8.420287, 39.326044, 16.2], + [8.420294, 39.325794, 15.1], + [8.419974, 39.325549, 12.5], + [8.419887, 39.325508, 11.9], + [8.419702, 39.325343, 10.3], + [8.419574, 39.325289, 9.4], + [8.41943, 39.325183, 8.2], + [8.419393, 39.325127, 7.8], + [8.419297, 39.325108, 7.2], + [8.419179, 39.325014, 6.2], + [8.419179, 39.324979, 6.1], + [8.419179, 39.324979, 6.1], + [8.419182, 39.324653, 6], + [8.419129, 39.324508, 5.9], + [8.419074, 39.324482, 5.9], + [8.419007, 39.324362, 5.8], + [8.418957, 39.324324, 5.8], + [8.418944, 39.324291, 5.8], + [8.418947, 39.324233, 5.8], + [8.418967, 39.324196, 5.7], + [8.41895, 39.324126, 5.6], + [8.418838, 39.323996, 5.4], + [8.418814, 39.323774, 5], + [8.418931, 39.323546, 10.1], + [8.41896, 39.323444, 12.3], + [8.418971, 39.323232, 16.9], + [8.419068, 39.322974, 13.5], + [8.41914, 39.322946, 12.7], + [8.419245, 39.322895, 12.3], + [8.419342, 39.322857, 11.9], + [8.419492, 39.322855, 11.3], + [8.419591, 39.322768, 11.1], + [8.419672, 39.322724, 11], + [8.419776, 39.322704, 10.9], + [8.419823, 39.322711, 10.8], + [8.41971, 39.322631, 8.5], + [8.419668, 39.322581, 7.3], + [8.419653, 39.322537, 6.3], + [8.419628, 39.32243, 5.3], + [8.419629, 39.322384, 5.4], + [8.419656, 39.322346, 5.5], + [8.419703, 39.322304, 5.6], + [8.419802, 39.322305, 5.7], + [8.419868, 39.32228, 5.8], + [8.419994, 39.322223, 6.1], + [8.420066, 39.322174, 6.2], + [8.42013, 39.32211, 6.4], + [8.420142, 39.322013, 6.5], + [8.420167, 39.321924, 6.7], + [8.420188, 39.321788, 7], + [8.420269, 39.32165, 7.3], + [8.420342, 39.321625, 7.4], + [8.420427, 39.321609, 7.5], + [8.420645, 39.321582, 7.8], + [8.420753, 39.321699, 8.1], + [8.420881, 39.321801, 8.4], + [8.421082, 39.321898, 8.7], + [8.421184, 39.321868, 8.9], + [8.421351, 39.321877, 9.1], + [8.421451, 39.321834, 8.2], + [8.421545, 39.321811, 7.5], + [8.421815, 39.321691, 5.1], + [8.421877, 39.321632, 4.3], + [8.42196, 39.321602, 3.7], + [8.422083, 39.321621, 4.5], + [8.422462, 39.321579, 8.7], + [8.422875, 39.321691, 13.5], + [8.423069, 39.321732, 15.7], + [8.423231, 39.321687, 17.6], + [8.423405, 39.321726, 19.6], + [8.423626, 39.321719, 22.1], + [8.424103, 39.321776, 27.4], + [8.424214, 39.321746, 28.7], + [8.424402, 39.321632, 27.5], + [8.424486, 39.321559, 26.8], + [8.424524, 39.321501, 26.3], + [8.424916, 39.321097, 22.6], + [8.424969, 39.321007, 21.9], + [8.425387, 39.320766, 19], + [8.425489, 39.320645, 20.4], + [8.425621, 39.320556, 22.1], + [8.425699, 39.320574, 22.8], + [8.425774, 39.320511, 23.9], + [8.425831, 39.320336, 19.6], + [8.425822, 39.32021, 16.1], + [8.42575, 39.320086, 12.4], + [8.425788, 39.320004, 10], + [8.425946, 39.319822, 10.7], + [8.426039, 39.319781, 11], + [8.426264, 39.319776, 11.8], + [8.426305, 39.319718, 12], + [8.426362, 39.319433, 6.8], + [8.426414, 39.31936, 5.3], + [8.426422, 39.319161, 1.6], + [8.426449, 39.319085, 0.2], + [8.426568, 39.31904, 0.4], + [8.426608, 39.318981, 1.8], + [8.426714, 39.318923, 3.8], + [8.427072, 39.318862, 9.6], + [8.427204, 39.31886, 11.7], + [8.427359, 39.318896, 14.3], + [8.427434, 39.31895, 15.9], + [8.427519, 39.318968, 17.3], + [8.427558, 39.318972, 18.4], + [8.427616, 39.318991, 19.2], + [8.427685, 39.319082, 21.3], + [8.42773, 39.31921, 25.1], + [8.427914, 39.319306, 29.9], + [8.42849, 39.319358, 46.7], + [8.429645, 39.319309, 79.8], + [8.430532, 39.319314, 85], + [8.430582, 39.319297, 85.2], + [8.430808, 39.319195, 84.8], + [8.43098, 39.319076, 84.5], + [8.431138, 39.318999, 84.2], + [8.431283, 39.318985, 84], + [8.431288, 39.318946, 84.8], + [8.431373, 39.318825, 87.6], + [8.431411, 39.318796, 87.9], + [8.431678, 39.318827, 87.1], + [8.431773, 39.318752, 88.3], + [8.431854, 39.318552, 90.7], + [8.431832, 39.31847, 91.7], + [8.431959, 39.318284, 94.1], + [8.431968, 39.318034, 97], + [8.43207, 39.31791, 98.7], + [8.432118, 39.317736, 100.8], + [8.432263, 39.317582, 103], + [8.432291, 39.317263, 106.7], + [8.432279, 39.316848, 111.5], + [8.432358, 39.31652, 115.3], + [8.432327, 39.316486, 115.8], + [8.432336, 39.316437, 116.4], + [8.432287, 39.316409, 116.4], + [8.432257, 39.316391, 116.2], + [8.432179, 39.316251, 115.4], + [8.432156, 39.316183, 115.6], + [8.43223, 39.316138, 116.5], + [8.43223, 39.316043, 117.7], + [8.432274, 39.315918, 119.4], + [8.432254, 39.315799, 121], + [8.432377, 39.315713, 122.6], + [8.43248, 39.315542, 125.1], + [8.43257, 39.315451, 126], + [8.432652, 39.315352, 127], + [8.432724, 39.315291, 127.7], + [8.432779, 39.315208, 128.5], + [8.432863, 39.315109, 129.5], + [8.432945, 39.315038, 130.3], + [8.433002, 39.315014, 130.7], + [8.433092, 39.315007, 131.3], + [8.43318, 39.315012, 131.9], + [8.433295, 39.315111, 133], + [8.433346, 39.315126, 133.4], + [8.43338, 39.315113, 133.6], + [8.433404, 39.31509, 133.8], + [8.433408, 39.315058, 132.4], + [8.433422, 39.31498, 131.6], + [8.43347, 39.314876, 130.3], + [8.433562, 39.314771, 128.2], + [8.433817, 39.314543, 123], + [8.434004, 39.314434, 119.9], + [8.434262, 39.314344, 121.2], + [8.434729, 39.314236, 123.9], + [8.435085, 39.31388, 127.2], + [8.435254, 39.313808, 128.4], + [8.435388, 39.313779, 128.4], + [8.435547, 39.313774, 129.9], + [8.4357, 39.313825, 131.6], + [8.435802, 39.313882, 132.8], + [8.435866, 39.313979, 134.1], + [8.435902, 39.314064, 135.2], + [8.435973, 39.314103, 136], + [8.436062, 39.314107, 136.9], + [8.436143, 39.314101, 137.7], + [8.436215, 39.313989, 137.7], + [8.436162, 39.313752, 137.5], + [8.436209, 39.313402, 137.2], + [8.436413, 39.313182, 137], + [8.436559, 39.313127, 136.9], + [8.43664, 39.313115, 136.8], + [8.436682, 39.313058, 137.7], + [8.436798, 39.312789, 139.1], + [8.436706, 39.312486, 140.7], + [8.436703, 39.312448, 141], + ], + }, + "properties": {"name": "some track"}, + "id": "MzMTI", + } + ], + "_umap_options": {"popupContentTemplate": "{name}\n⭧ {gain} m\n⭨ {loss} m"}, + } + DataLayerFactory(map=map, data=data) + page.goto( + f"{live_server.url}{map.get_absolute_url()}?onLoadPanel=databrowser#16/39.3201/8.4278" + ) + # We can't make PW to click on the path, so let's use the browser for that + page.get_by_text("some track").click() + expect(page.get_by_text("⭧ 211 m")).to_be_visible() + expect(page.get_by_text("⭨ 82 m")).to_be_visible()