Give Overpass POI downloads icons/descriptions and unique filenames
Overpass categories now carry the same icon+color styling a p4n2gpx waypoint gets, instead of falling back to gpx.js's plain red marker, plus a popup description built from opening_hours/operator/website tags. Supermarket/convenience store reuse NPS's generic store glyph, the only honest match in that icon set. Each plugin run's saved filename now bakes in the area's center and a timestamp, so repeated downloads for different areas land as separate, identifiable files instead of overpass-pois.geojson/-1/-2/...
This commit is contained in:
1 parent
72ffd0ef18
commit
1733fc7c1b
5 files changed
+119
-20
No files matched your search
@@ -14,23 +14,42 @@ module Maptool
|
||||
|
||||
OVERPASS_API = "https://overpass-api.de/api/interpreter".freeze
|
||||
|
||||
# Each entry: an Overpass tag filter -> a human category label, used
|
||||
# both to build the query (unioning every filter) and to label results
|
||||
# back (matched by scanning an element's own tags for the same
|
||||
# Each entry: an Overpass tag filter -> { label:, icon:, color: }, used
|
||||
# both to build the query (unioning every filter) and to label/style
|
||||
# results back (matched by scanning an element's own tags for the same
|
||||
# key/value, not by which branch of the query found it — Overpass's
|
||||
# `out body` doesn't say which union member matched).
|
||||
# `out body` doesn't say which union member matched). `icon` names one
|
||||
# of the marker glyphs public/js/icons.js's POI_ICONS already vendors
|
||||
# for the GPX/p4n upload path — reused here rather than drawn again —
|
||||
# so these render the same way a p4n2gpx waypoint of the same kind
|
||||
# does, instead of every point falling back to gpx.js's plain red
|
||||
# unlabeled marker (its TRACK_COLOR default for a point with no color
|
||||
# of its own). shop_supermarket/shop_convenience both point at the same
|
||||
# NPS "store" glyph (icons.js's STORE_ICON) — that set has no separate
|
||||
# grocery-specific pictogram, so this is the honest match for both.
|
||||
CATEGORIES = {
|
||||
{ "amenity" => "drinking_water" } => "Drinking water",
|
||||
{ "amenity" => "sanitary_dump_station" } => "Dump station",
|
||||
{ "amenity" => "fuel", "fuel:lpg" => "yes" } => "LPG refill",
|
||||
{ "shop" => "gas" } => "LPG refill",
|
||||
{ "amenity" => "toilets" } => "Public toilet",
|
||||
{ "shop" => "laundry" } => "Laundry",
|
||||
{ "shop" => "supermarket" } => "Supermarket",
|
||||
{ "shop" => "convenience" } => "Convenience store",
|
||||
{ "natural" => "spring" } => "Spring",
|
||||
{ "amenity" => "drinking_water" } => { label: "Drinking water", icon: "amenity_drinking_water", color: "#2e86de" },
|
||||
{ "amenity" => "sanitary_dump_station" } => { label: "Dump station", icon: "amenity_sanitary_dump_station", color: "#8d6e63" },
|
||||
{ "amenity" => "fuel", "fuel:lpg" => "yes" } => { label: "LPG refill", icon: "shop_gas", color: "#e67e22" },
|
||||
{ "shop" => "gas" } => { label: "LPG refill", icon: "shop_gas", color: "#e67e22" },
|
||||
{ "amenity" => "toilets" } => { label: "Public toilet", icon: "amenity_toilets", color: "#8d6e63" },
|
||||
{ "shop" => "laundry" } => { label: "Laundry", icon: "shop_laundry", color: "#5b9bd5" },
|
||||
{ "shop" => "supermarket" } => { label: "Supermarket", icon: "shop_supermarket", color: "#27ae60" },
|
||||
{ "shop" => "convenience" } => { label: "Convenience store", icon: "shop_convenience", color: "#27ae60" },
|
||||
{ "natural" => "spring" } => { label: "Spring", icon: "amenity_drinking_water", color: "#2e86de" },
|
||||
}.freeze
|
||||
|
||||
# Tags worth surfacing in a popup, beyond the bare category label —
|
||||
# each rendered as its own "Label: value" line, which gpx.js's
|
||||
# formatDescription (written for p4n2gpx's own "Label: value" export
|
||||
# lines) already turns into a distinct row with no changes needed on
|
||||
# that end. website/contact:website are emitted as a bare URL line
|
||||
# instead, since formatDescription also already auto-links those.
|
||||
DESCRIPTION_TAGS = [
|
||||
["opening_hours", "Opening hours"],
|
||||
["operator", "Operator"],
|
||||
].freeze
|
||||
|
||||
# bbox: [south, west, north, east] (Overpass's own axis order).
|
||||
def self.fetch(bbox, timeout: 60)
|
||||
query = build_query(bbox, timeout: timeout)
|
||||
@@ -59,12 +78,19 @@ module Maptool
|
||||
features = (overpass_response["elements"] || []).filter_map do |element|
|
||||
next unless element["type"] == "node"
|
||||
|
||||
category = category_for(element["tags"] || {})
|
||||
tags = element["tags"] || {}
|
||||
category = category_for(tags)
|
||||
next unless category
|
||||
|
||||
{
|
||||
"type" => "Feature",
|
||||
"properties" => { "name" => (element["tags"] || {})["name"] || category, "category" => category },
|
||||
"properties" => {
|
||||
"name" => tags["name"] || category[:label],
|
||||
"category" => category[:label],
|
||||
"icon" => category[:icon],
|
||||
"color" => category[:color],
|
||||
"description" => description_for(tags),
|
||||
}.compact,
|
||||
"geometry" => { "type" => "Point", "coordinates" => [element["lon"], element["lat"]] },
|
||||
}
|
||||
end
|
||||
@@ -72,11 +98,19 @@ module Maptool
|
||||
end
|
||||
|
||||
def self.category_for(tags)
|
||||
CATEGORIES.each do |filter, label|
|
||||
return label if filter.all? { |k, v| tags[k] == v }
|
||||
CATEGORIES.each do |filter, category|
|
||||
return category if filter.all? { |k, v| tags[k] == v }
|
||||
end
|
||||
nil
|
||||
end
|
||||
private_class_method :category_for
|
||||
|
||||
def self.description_for(tags)
|
||||
lines = DESCRIPTION_TAGS.filter_map { |tag, label| "#{label}: #{tags[tag]}" if tags[tag] }
|
||||
website = tags["website"] || tags["contact:website"]
|
||||
lines << website if website
|
||||
lines.empty? ? nil : lines.join("\n")
|
||||
end
|
||||
private_class_method :description_for
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user