Color-code, cluster and add icons to POI waypoints
A park4night/OsmAnd POI export (e.g. a p4n2gpx area export) tags every waypoint with a category and a per-category color/icon in its <extensions> block, all of which was previously thrown away — every waypoint rendered as the same plain red dot, unreadable once a file has a few thousand of them. Maptool::Gpx now captures category/color/icon (waypoint_style), matched by namespace URI rather than local element name: a p4n2gpx file carries both <osmand:icon> and <locus:icon> side by side, and REXML strips prefixes from Element#name, so both report as just "icon" — matching on that alone was silently picking the (useless) Locus drawable path instead of the OsmAnd category key. Regression test added for this. On the map: waypoints are colored by category (falling back to the plain track color for anything uncategorized), a small hand-drawn icon set (public/js/icons.js's POI_ICONS, rasterized to SDF sprites at runtime) draws a glyph on top for the categories it covers, the points source is clustered so a dense export collapses into count bubbles instead of a solid blob, and a legend in the side panel lists whichever categories are currently visible. Splitting each file's GeoJSON into a lines source and a points source (rather than one mixed source with a geometry-type filter per layer) was needed for clustering, since MapLibre's cluster support only understands a source made entirely of points.
This commit is contained in:
1 parent
708c08259b
commit
0b18dc018a
8 files changed
+434
-35
No files matched your search
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gpx version="1.1" creator="test">
|
||||
<wpt lat="48.1" lon="17.2">
|
||||
<name>Free spot</name>
|
||||
<type>Free motorhome area</type>
|
||||
<extensions>
|
||||
<osmand:color xmlns:osmand="https://osmand.net">#2E7D32</osmand:color>
|
||||
<osmand:icon xmlns:osmand="https://osmand.net">tourism_camp_site</osmand:icon>
|
||||
</extensions>
|
||||
</wpt>
|
||||
<wpt lat="48.101" lon="17.201">
|
||||
<name>Plain waypoint</name>
|
||||
</wpt>
|
||||
<wpt lat="48.102" lon="17.202">
|
||||
<name>p4n2gpx export</name>
|
||||
<type>Daily parking only</type>
|
||||
<extensions>
|
||||
<osmand:color xmlns:osmand="https://osmand.net">#546E7A</osmand:color>
|
||||
<osmand:icon xmlns:osmand="https://osmand.net">amenity_parking</osmand:icon>
|
||||
<locus:icon xmlns:locus="http://www.locusmap.eu">res/drawable-hdpi/ic_parking_small.png</locus:icon>
|
||||
</extensions>
|
||||
</wpt>
|
||||
</gpx>
|
||||
@@ -41,6 +41,39 @@ class GpxTest < Minitest::Test
|
||||
assert_equal [17.2, 48.1], [profile[0]["lon"], profile[0]["lat"]]
|
||||
end
|
||||
|
||||
def test_waypoint_captures_category_and_color_from_poi_extensions
|
||||
geojson = Maptool::Gpx.to_geojson(fixture_path("sample_poi.gpx"))
|
||||
free_spot = geojson["features"].find { |f| f["properties"]["name"] == "Free spot" }
|
||||
|
||||
assert_equal "Free motorhome area", free_spot["properties"]["category"]
|
||||
assert_equal "#2E7D32", free_spot["properties"]["color"]
|
||||
assert_equal "tourism_camp_site", free_spot["properties"]["icon"]
|
||||
end
|
||||
|
||||
# Regression test for a real bug: a p4n2gpx export's <extensions> carries
|
||||
# both an <osmand:icon> (a category key this app can render) and a
|
||||
# <locus:icon> (a Locus-app drawable path) side by side. REXML strips
|
||||
# namespace prefixes from Element#name, so both elements report the same
|
||||
# local name "icon" — matching on that alone picked whichever happened to
|
||||
# come last in the file (locus, since it followed osmand), leaving every
|
||||
# waypoint's icon set to a meaningless drawable path that never matched
|
||||
# any category. Must match by namespace URI instead.
|
||||
def test_waypoint_icon_ignores_non_osmand_extensions_with_the_same_local_name
|
||||
geojson = Maptool::Gpx.to_geojson(fixture_path("sample_poi.gpx"))
|
||||
export = geojson["features"].find { |f| f["properties"]["name"] == "p4n2gpx export" }
|
||||
|
||||
assert_equal "amenity_parking", export["properties"]["icon"]
|
||||
end
|
||||
|
||||
def test_waypoint_without_category_or_color_leaves_them_nil
|
||||
geojson = Maptool::Gpx.to_geojson(fixture_path("sample_poi.gpx"))
|
||||
plain = geojson["features"].find { |f| f["properties"]["name"] == "Plain waypoint" }
|
||||
|
||||
assert_nil plain["properties"]["category"]
|
||||
assert_nil plain["properties"]["color"]
|
||||
assert_nil plain["properties"]["icon"]
|
||||
end
|
||||
|
||||
def test_kinds_detects_routes
|
||||
assert_equal ["route"], Maptool::Gpx.kinds(fixture_path("sample_route.gpx"))
|
||||
end
|
||||
|
||||
Reference in new issue
Block a user