From 769e3805f3e77b44c222cd3960ef0e820b9dfb3b Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Nov 2024 14:08:43 +0100 Subject: [PATCH 01/16] Add background tiles # Conflicts: # application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json --- .../apis/vectortiles/DebugStyleSpec.java | 42 +- .../apis/vectortiles/style.json | 1227 ++++++++++++----- 2 files changed, 888 insertions(+), 381 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index f27d252f250..971884d00a2 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.opentripplanner.apis.vectortiles.model.StyleBuilder; import org.opentripplanner.apis.vectortiles.model.StyleSpec; @@ -37,13 +36,24 @@ */ public class DebugStyleSpec { - private static final TileSource BACKGROUND_SOURCE = new RasterSource( - "background", + private static final TileSource OSM_BACKGROUND = new RasterSource( + "background-osm", List.of("https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"), 19, 256, "© OpenStreetMap Contributors" ); + private static final TileSource POSITRON_BACKGROUND = new RasterSource( + "background-carto", + List.of("https://a.basemaps.cartocdn.com/{z}/{x}/{y}"), + 19, + 256, + "© OpenStreetMap, © CARTO" + ); + private static final List BACKGROUND_LAYERS = List.of( + OSM_BACKGROUND, + POSITRON_BACKGROUND + ); private static final String MAGENTA = "#f21d52"; private static final String BRIGHT_GREEN = "#22DD9E"; private static final String DARK_GREEN = "#136b04"; @@ -94,17 +104,18 @@ static StyleSpec build( VectorSourceLayer edges, VectorSourceLayer vertices ) { - var vectorSources = Stream + List vectorSources = List .of(regularStops, edges, vertices) - .map(VectorSourceLayer::vectorSource); - var allSources = Stream - .concat(Stream.of(BACKGROUND_SOURCE), vectorSources) - .collect(Collectors.toSet()); + .stream() + .map(VectorSourceLayer::vectorSource) + .map(TileSource.class::cast) + .toList(); + var allSources = ListUtils.combine(BACKGROUND_LAYERS, vectorSources); return new StyleSpec( "OTP Debug Tiles", allSources, ListUtils.combine( - List.of(StyleBuilder.ofId("background").typeRaster().source(BACKGROUND_SOURCE).minZoom(0)), + backgroundLayers(), wheelchair(edges), noThruTraffic(edges), traversalPermissions(edges), @@ -115,6 +126,19 @@ static StyleSpec build( ); } + private static List backgroundLayers() { + return BACKGROUND_LAYERS + .stream() + .map(layer -> { + var builder = StyleBuilder.ofId(layer.id()).typeRaster().source(layer).minZoom(0); + if(!layer.equals(OSM_BACKGROUND)){ + builder.intiallyHidden(); + } + return builder; + }) + .toList(); + } + private static List stops( VectorSourceLayer regularStops, VectorSourceLayer areaStops, diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index b08a225fde3..fe7b546400d 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -1,83 +1,163 @@ { - "name": "OTP Debug Tiles", - "sources": { - "background": { - "id": "background", - "tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"], - "maxzoom": 19, - "tileSize": 256, - "attribution": "© OpenStreetMap Contributors", - "type": "raster" + "name" : "OTP Debug Tiles", + "sources" : { + "vectorSource" : { + "id" : "vectorSource", + "url" : "https://example.com", + "type" : "vector" }, - "vectorSource": { - "id": "vectorSource", - "url": "https://example.com", - "type": "vector" + "background-osm" : { + "id" : "background-osm", + "tiles" : [ + "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" + ], + "maxzoom" : 19, + "tileSize" : 256, + "attribution" : "© OpenStreetMap Contributors", + "type" : "raster" + }, + "background-carto" : { + "id" : "background-carto", + "tiles" : [ + "https://{s}.basemaps.cartocdn.com/{z}/{x}/{y}" + ], + "maxzoom" : 19, + "tileSize" : 256, + "attribution" : "© OpenStreetMap, © CARTO", + "type" : "raster" } }, - "layers": [ + "layers" : [ { - "id": "background", - "type": "raster", - "source": "background", - "minzoom": 0, - "metadata": { - "group": "Other" + "id" : "background-osm", + "type" : "raster", + "source" : "background-osm", + "minzoom" : 0, + "metadata" : { + "group" : "Other" } }, { - "id": "wheelchair-accessible", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "line-color": "#136b04", - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] - }, - "filter": ["==", "wheelchairAccessible", true], - "layout": { - "line-cap": "round", - "visibility": "none" - }, - "metadata": { - "group": "Wheelchair accessibility" + "id" : "background-carto", + "type" : "raster", + "source" : "background-carto", + "minzoom" : 0, + "metadata" : { + "group" : "Other" + } + }, + { + "id" : "wheelchair-accessible", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "line-color" : "#136b04", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] + }, + "filter" : [ + "==", + "wheelchairAccessible", + true + ], + "layout" : { + "line-cap" : "round", + "visibility" : "none" + }, + "metadata" : { + "group" : "Wheelchair accessibility" } }, { - "id": "wheelchair-inaccessible", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "line-color": "#fc0f2a", - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] - }, - "filter": ["==", "wheelchairAccessible", false], - "layout": { - "line-cap": "round", - "visibility": "none" - }, - "metadata": { - "group": "Wheelchair accessibility" + "id" : "wheelchair-inaccessible", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "line-color" : "#fc0f2a", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] + }, + "filter" : [ + "==", + "wheelchairAccessible", + false + ], + "layout" : { + "line-cap" : "round", + "visibility" : "none" + }, + "metadata" : { + "group" : "Wheelchair accessibility" } }, { - "id": "no-thru-traffic PEDESTRIAN", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "no-thru-traffic PEDESTRIAN", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "noThruTraffic"], + [ + "get", + "noThruTraffic" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -96,33 +176,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "PEDESTRIAN", ["string", ["get", "noThruTraffic"]]], - ["in", "ALL", ["string", ["get", "noThruTraffic"]]] + [ + "in", + "PEDESTRIAN", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "No-thru traffic" + "metadata" : { + "group" : "No-thru traffic" } }, { - "id": "no-thru-traffic BICYCLE", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "no-thru-traffic BICYCLE", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "noThruTraffic"], + [ + "get", + "noThruTraffic" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -141,33 +268,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "BICYCLE", ["string", ["get", "noThruTraffic"]]], - ["in", "ALL", ["string", ["get", "noThruTraffic"]]] + [ + "in", + "BICYCLE", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "No-thru traffic" + "metadata" : { + "group" : "No-thru traffic" } }, { - "id": "no-thru-traffic CAR", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "no-thru-traffic CAR", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "noThruTraffic"], + [ + "get", + "noThruTraffic" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -186,36 +360,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "CAR", ["string", ["get", "noThruTraffic"]]], - ["in", "ALL", ["string", ["get", "noThruTraffic"]]] + [ + "in", + "CAR", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "No-thru traffic" + "metadata" : { + "group" : "No-thru traffic" } }, { - "id": "no-thru-traffic-text", - "source": "vectorSource", - "source-layer": "edges", - "type": "symbol", - "minzoom": 17, - "maxzoom": 23, - "paint": { - "text-color": "#000", - "text-halo-color": "#fff", - "text-halo-blur": 4, - "text-halo-width": 3 - }, - "filter": [ + "id" : "no-thru-traffic-text", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "symbol", + "minzoom" : 17, + "maxzoom" : 23, + "paint" : { + "text-color" : "#000", + "text-halo-color" : "#fff", + "text-halo-blur" : 4, + "text-halo-width" : 3 + }, + "filter" : [ "in", "class", "StreetEdge", @@ -226,34 +444,54 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout": { - "symbol-placement": "line-center", - "symbol-spacing": 1000, - "text-field": "{noThruTraffic}", - "text-font": ["KlokanTech Noto Sans Regular"], - "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], - "text-max-width": 100, - "text-keep-upright": true, - "text-rotation-alignment": "map", - "text-overlap": "never", - "text-offset": [0, 1.0], - "visibility": "none" - }, - "metadata": { - "group": "No-thru traffic" + "layout" : { + "symbol-placement" : "line-center", + "symbol-spacing" : 1000, + "text-field" : "{noThruTraffic}", + "text-font" : [ + "KlokanTech Noto Sans Regular" + ], + "text-size" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 6.0, + 24, + 12.0 + ], + "text-max-width" : 100, + "text-keep-upright" : true, + "text-rotation-alignment" : "map", + "text-overlap" : "never", + "text-offset" : [ + 0, + 1.0 + ], + "visibility" : "none" + }, + "metadata" : { + "group" : "No-thru traffic" } }, { - "id": "permission PEDESTRIAN", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "permission PEDESTRIAN", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "permission"], + [ + "get", + "permission" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -272,33 +510,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "PEDESTRIAN", ["string", ["get", "permission"]]], - ["in", "ALL", ["string", ["get", "permission"]]] + [ + "in", + "PEDESTRIAN", + [ + "string", + [ + "get", + "permission" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "permission" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "Permissions" + "metadata" : { + "group" : "Permissions" } }, { - "id": "permission BICYCLE", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "permission BICYCLE", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "permission"], + [ + "get", + "permission" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -317,33 +602,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "BICYCLE", ["string", ["get", "permission"]]], - ["in", "ALL", ["string", ["get", "permission"]]] + [ + "in", + "BICYCLE", + [ + "string", + [ + "get", + "permission" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "permission" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "Permissions" + "metadata" : { + "group" : "Permissions" } }, { - "id": "permission CAR", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "permission CAR", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "permission"], + [ + "get", + "permission" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -362,36 +694,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "CAR", ["string", ["get", "permission"]]], - ["in", "ALL", ["string", ["get", "permission"]]] + [ + "in", + "CAR", + [ + "string", + [ + "get", + "permission" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "permission" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "Permissions" + "metadata" : { + "group" : "Permissions" } }, { - "id": "permission-text", - "source": "vectorSource", - "source-layer": "edges", - "type": "symbol", - "minzoom": 17, - "maxzoom": 23, - "paint": { - "text-color": "#000", - "text-halo-color": "#fff", - "text-halo-blur": 4, - "text-halo-width": 3 - }, - "filter": [ + "id" : "permission-text", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "symbol", + "minzoom" : 17, + "maxzoom" : 23, + "paint" : { + "text-color" : "#000", + "text-halo-color" : "#fff", + "text-halo-blur" : 4, + "text-halo-width" : 3 + }, + "filter" : [ "in", "class", "StreetEdge", @@ -402,36 +778,77 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout": { - "symbol-placement": "line-center", - "symbol-spacing": 1000, - "text-field": "{permission}", - "text-font": ["KlokanTech Noto Sans Regular"], - "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], - "text-max-width": 100, - "text-keep-upright": true, - "text-rotation-alignment": "map", - "text-overlap": "never", - "text-offset": [0, 1.0], - "visibility": "none" - }, - "metadata": { - "group": "Permissions" + "layout" : { + "symbol-placement" : "line-center", + "symbol-spacing" : 1000, + "text-field" : "{permission}", + "text-font" : [ + "KlokanTech Noto Sans Regular" + ], + "text-size" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 6.0, + 24, + 12.0 + ], + "text-max-width" : 100, + "text-keep-upright" : true, + "text-rotation-alignment" : "map", + "text-overlap" : "never", + "text-offset" : [ + 0, + 1.0 + ], + "visibility" : "none" + }, + "metadata" : { + "group" : "Permissions" } }, { - "id": "edge", - "type": "line", - "source": "vectorSource", - "source-layer": "edges", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "line-color": "#f21d52", - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.1, 23, 6.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] - }, - "filter": [ + "id" : "edge", + "type" : "line", + "source" : "vectorSource", + "source-layer" : "edges", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "line-color" : "#f21d52", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.1, + 23, + 6.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] + }, + "filter" : [ "in", "class", "StreetEdge", @@ -442,28 +859,28 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout": { - "line-cap": "round", - "visibility": "none" + "layout" : { + "line-cap" : "round", + "visibility" : "none" }, - "metadata": { - "group": "Edges" + "metadata" : { + "group" : "Edges" } }, { - "id": "edge-name", - "type": "symbol", - "source": "vectorSource", - "source-layer": "edges", - "minzoom": 17, - "maxzoom": 23, - "paint": { - "text-color": "#000", - "text-halo-color": "#fff", - "text-halo-blur": 4, - "text-halo-width": 3 - }, - "filter": [ + "id" : "edge-name", + "type" : "symbol", + "source" : "vectorSource", + "source-layer" : "edges", + "minzoom" : 17, + "maxzoom" : 23, + "paint" : { + "text-color" : "#000", + "text-halo-color" : "#fff", + "text-halo-blur" : 4, + "text-halo-width" : 3 + }, + "filter" : [ "in", "class", "StreetEdge", @@ -474,35 +891,73 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout": { - "symbol-placement": "line-center", - "symbol-spacing": 1000, - "text-field": "{name}", - "text-font": ["KlokanTech Noto Sans Regular"], - "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], - "text-max-width": 100, - "text-keep-upright": true, - "text-rotation-alignment": "map", - "text-overlap": "never", - "visibility": "none" - }, - "metadata": { - "group": "Edges" + "layout" : { + "symbol-placement" : "line-center", + "symbol-spacing" : 1000, + "text-field" : "{name}", + "text-font" : [ + "KlokanTech Noto Sans Regular" + ], + "text-size" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 6.0, + 24, + 12.0 + ], + "text-max-width" : 100, + "text-keep-upright" : true, + "text-rotation-alignment" : "map", + "text-overlap" : "never", + "visibility" : "none" + }, + "metadata" : { + "group" : "Edges" } }, { - "id": "link", - "type": "line", - "source": "vectorSource", - "source-layer": "edges", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": "#22DD9E", - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] - }, - "filter": [ + "id" : "link", + "type" : "line", + "source" : "vectorSource", + "source-layer" : "edges", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : "#22DD9E", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] + }, + "filter" : [ "in", "class", "StreetTransitStopLink", @@ -512,153 +967,181 @@ "StreetVehicleParkingLink", "StreetStationCentroidLink" ], - "layout": { - "line-cap": "round", - "visibility": "none" + "layout" : { + "line-cap" : "round", + "visibility" : "none" }, - "metadata": { - "group": "Edges" + "metadata" : { + "group" : "Edges" } }, { - "id": "vertex", - "type": "circle", - "source": "vectorSource", - "source-layer": "vertices", - "minzoom": 15, - "maxzoom": 23, - "paint": { - "circle-stroke-color": "#140d0e", - "circle-stroke-width": [ + "id" : "vertex", + "type" : "circle", + "source" : "vectorSource", + "source-layer" : "vertices", + "minzoom" : 15, + "maxzoom" : 23, + "paint" : { + "circle-stroke-color" : "#140d0e", + "circle-stroke-width" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 15, 0.2, 23, 3.0 ], - "circle-radius": [ + "circle-radius" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 15, 1.0, 23, 7.0 ], - "circle-color": "#BC55F2" + "circle-color" : "#BC55F2" }, - "layout": { - "visibility": "none" + "layout" : { + "visibility" : "none" }, - "metadata": { - "group": "Vertices" + "metadata" : { + "group" : "Vertices" } }, { - "id": "parking-vertex", - "type": "circle", - "source": "vectorSource", - "source-layer": "vertices", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "circle-stroke-color": "#140d0e", - "circle-stroke-width": [ + "id" : "parking-vertex", + "type" : "circle", + "source" : "vectorSource", + "source-layer" : "vertices", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "circle-stroke-color" : "#140d0e", + "circle-stroke-width" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 15, 0.2, 23, 3.0 ], - "circle-radius": [ + "circle-radius" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 13, 1.4, 23, 10.0 ], - "circle-color": "#136b04" + "circle-color" : "#136b04" }, - "filter": ["in", "class", "VehicleParkingEntranceVertex"], - "layout": { - "visibility": "none" + "filter" : [ + "in", + "class", + "VehicleParkingEntranceVertex" + ], + "layout" : { + "visibility" : "none" }, - "metadata": { - "group": "Vertices" + "metadata" : { + "group" : "Vertices" } }, { - "id": "area-stop", - "type": "fill", - "source": "vectorSource", - "source-layer": "stops", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "fill-color": "#22DD9E", - "fill-opacity": 0.5, - "fill-outline-color": "#140d0e" - }, - "metadata": { - "group": "Stops" + "id" : "area-stop", + "type" : "fill", + "source" : "vectorSource", + "source-layer" : "stops", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "fill-color" : "#22DD9E", + "fill-opacity" : 0.5, + "fill-outline-color" : "#140d0e" + }, + "metadata" : { + "group" : "Stops" } }, { - "id": "group-stop", - "type": "fill", - "source": "vectorSource", - "source-layer": "stops", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "fill-color": "#22DD9E", - "fill-opacity": 0.5, - "fill-outline-color": "#140d0e" - }, - "metadata": { - "group": "Stops" + "id" : "group-stop", + "type" : "fill", + "source" : "vectorSource", + "source-layer" : "stops", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "fill-color" : "#22DD9E", + "fill-opacity" : 0.5, + "fill-outline-color" : "#140d0e" + }, + "metadata" : { + "group" : "Stops" } }, { - "id": "regular-stop", - "type": "circle", - "source": "vectorSource", - "source-layer": "stops", - "minzoom": 10, - "maxzoom": 23, - "paint": { - "circle-stroke-color": "#140d0e", - "circle-stroke-width": [ + "id" : "regular-stop", + "type" : "circle", + "source" : "vectorSource", + "source-layer" : "stops", + "minzoom" : 10, + "maxzoom" : 23, + "paint" : { + "circle-stroke-color" : "#140d0e", + "circle-stroke-width" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 11, 0.5, 23, 5.0 ], - "circle-radius": [ + "circle-radius" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 11, 0.5, 23, 10.0 ], - "circle-color": "#fcf9fa" + "circle-color" : "#fcf9fa" }, - "metadata": { - "group": "Stops" + "metadata" : { + "group" : "Stops" } } ], - "version": 8, - "glyphs": "https://cdn.jsdelivr.net/gh/klokantech/klokantech-gl-fonts@master/{fontstack}/{range}.pbf" -} + "version" : 8, + "glyphs" : "https://cdn.jsdelivr.net/gh/klokantech/klokantech-gl-fonts@master/{fontstack}/{range}.pbf" +} \ No newline at end of file From 77fdc5e66dfc5ccf8ad9a7cfc4b99f1cbc540e56 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Nov 2024 14:44:06 +0100 Subject: [PATCH 02/16] Add UI elements for selecting background map --- .../apis/vectortiles/DebugStyleSpec.java | 2 +- .../src/components/MapView/LayerControl.tsx | 109 ++++++++++++------ 2 files changed, 76 insertions(+), 35 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 971884d00a2..d29e6fdf15b 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -45,7 +45,7 @@ public class DebugStyleSpec { ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( "background-carto", - List.of("https://a.basemaps.cartocdn.com/{z}/{x}/{y}"), + List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}${r}.png"), 19, 256, "© OpenStreetMap, © CARTO" diff --git a/client/src/components/MapView/LayerControl.tsx b/client/src/components/MapView/LayerControl.tsx index 61dd48e4a34..d5f9dbb6424 100644 --- a/client/src/components/MapView/LayerControl.tsx +++ b/client/src/components/MapView/LayerControl.tsx @@ -26,49 +26,90 @@ class LayerControl implements IControl { this.container.className = 'maplibregl-ctrl maplibregl-ctrl-group layer-select'; map.on('load', () => { - // clean on + // clean on rerender while (this.container.firstChild) { this.container.removeChild(this.container.firstChild); } - const title = document.createElement('h4'); - title.textContent = 'Debug layers'; - this.container.appendChild(title); - - const groups: Record = {}; - map - .getLayersOrder() - .map((l) => map.getLayer(l)) - .filter((layer) => !!layer) - .filter((layer) => this.layerInteractive(layer)) - .reverse() - .forEach((layer) => { - if (layer) { - const meta: { group: string } = layer.metadata as { group: string }; - - let groupName: string = 'Misc'; - if (meta.group) { - groupName = meta.group; - } - - const layerDiv = this.buildLayerDiv(layer as TypedStyleLayer, map); - - if (groups[groupName]) { - groups[groupName]?.appendChild(layerDiv); - } else { - const groupDiv = this.buildGroupDiv(groupName, layerDiv); - groups[groupName] = groupDiv; - this.container.appendChild(groupDiv); - } - } - }); - // initialize clickable layers (initially stops) - this.updateInteractiveLayerIds(map); + this.buildBackgroundLayers(map); + this.buildDebugLayers(map); }); return this.container; } + private buildBackgroundLayers(map: Map) { + const title = document.createElement('h4'); + title.textContent = 'Background'; + this.container.appendChild(title); + + const select = document.createElement('select'); + this.container.appendChild(select); + + let rasterLayers = map + .getLayersOrder() + .map((l) => map.getLayer(l)) + .filter((layer) => !!layer) + .filter((layer) => layer?.type == 'raster'); + + rasterLayers.forEach((layer) => { + if (layer) { + const option = document.createElement('option'); + option.textContent = layer.id; + option.id = layer.id; + + select.appendChild(option); + } + }); + select.onchange = (ev) => { + const layerId = select.value; + const layer = map.getLayer(layerId); + if (layer) { + rasterLayers.forEach((l) => { + map.setLayoutProperty(l?.id, 'visibility', 'none'); + }); + + map.setLayoutProperty(layer.id, 'visibility', 'visible'); + } + }; + } + + private buildDebugLayers(map: Map) { + const title = document.createElement('h4'); + title.textContent = 'Debug layers'; + this.container.appendChild(title); + + const groups: Record = {}; + map + .getLayersOrder() + .map((l) => map.getLayer(l)) + .filter((layer) => !!layer) + .filter((layer) => this.layerInteractive(layer)) + .reverse() + .forEach((layer) => { + if (layer) { + const meta: { group: string } = layer.metadata as { group: string }; + + let groupName: string = 'Misc'; + if (meta.group) { + groupName = meta.group; + } + + const layerDiv = this.buildLayerDiv(layer as TypedStyleLayer, map); + + if (groups[groupName]) { + groups[groupName]?.appendChild(layerDiv); + } else { + const groupDiv = this.buildGroupDiv(groupName, layerDiv); + groups[groupName] = groupDiv; + this.container.appendChild(groupDiv); + } + } + }); + // initialize clickable layers (initially stops) + this.updateInteractiveLayerIds(map); + } + private updateInteractiveLayerIds(map: Map) { const visibleInteractiveLayerIds = map .getLayersOrder() From c0b4243be4ef804b02020b06465dfab0593b0318 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 1 Dec 2024 22:23:21 +0100 Subject: [PATCH 03/16] Add fixed TriMet raster tile --- .../apis/vectortiles/DebugStyleSpec.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index d29e6fdf15b..c34a421bf5b 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -44,15 +44,24 @@ public class DebugStyleSpec { "© OpenStreetMap Contributors" ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( - "background-carto", + "background-positron", List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}${r}.png"), 19, 256, "© OpenStreetMap, © CARTO" ); + private static final TileSource TRIMET_BACKGROUND = new RasterSource( + "background-trimet", + List.of("https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials"), + 19, + 256, + "TriMet" + ); + private static final List BACKGROUND_LAYERS = List.of( OSM_BACKGROUND, - POSITRON_BACKGROUND + POSITRON_BACKGROUND, + TRIMET_BACKGROUND ); private static final String MAGENTA = "#f21d52"; private static final String BRIGHT_GREEN = "#22DD9E"; From 6ae498d6ac41ad429e9b0ecb660091fabf192cc4 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 1 Dec 2024 23:13:21 +0100 Subject: [PATCH 04/16] Add configuration for debug ui --- .../apis/vectortiles/DebugStyleSpec.java | 41 ++++--- .../GraphInspectorVectorTileResource.java | 3 +- .../framework/application/OtpFileNames.java | 6 +- .../api/OtpServerRequestContext.java | 3 + .../standalone/config/ConfigModel.java | 24 ++++- .../standalone/config/DebugUiConfig.java | 100 ++++++++++++++++++ .../standalone/config/OtpConfigLoader.java | 9 ++ .../config/configure/ConfigModule.java | 6 ++ .../debuguiconfig/BackgroundTileLayer.java | 12 +++ .../configure/ConstructApplication.java | 5 + .../configure/ConstructApplicationModule.java | 5 +- .../server/DefaultServerRequestContext.java | 17 ++- .../opentripplanner/TestServerContext.java | 4 +- .../mapping/TripRequestMapperTest.java | 4 +- .../apis/vectortiles/DebugStyleSpecTest.java | 3 +- .../transit/speed_test/SpeedTest.java | 4 +- 16 files changed, 215 insertions(+), 31 deletions(-) create mode 100644 application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java create mode 100644 application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index c34a421bf5b..b66aa4fcc2b 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -13,6 +13,7 @@ import org.opentripplanner.apis.vectortiles.model.ZoomDependentNumber; import org.opentripplanner.apis.vectortiles.model.ZoomDependentNumber.ZoomStop; import org.opentripplanner.service.vehiclerental.street.StreetVehicleRentalLink; +import org.opentripplanner.standalone.config.debuguiconfig.BackgroundTileLayer; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.AreaEdge; import org.opentripplanner.street.model.edge.BoardingLocationToStopLink; @@ -50,18 +51,10 @@ public class DebugStyleSpec { 256, "© OpenStreetMap, © CARTO" ); - private static final TileSource TRIMET_BACKGROUND = new RasterSource( - "background-trimet", - List.of("https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials"), - 19, - 256, - "TriMet" - ); private static final List BACKGROUND_LAYERS = List.of( OSM_BACKGROUND, - POSITRON_BACKGROUND, - TRIMET_BACKGROUND + POSITRON_BACKGROUND ); private static final String MAGENTA = "#f21d52"; private static final String BRIGHT_GREEN = "#22DD9E"; @@ -111,20 +104,33 @@ static StyleSpec build( VectorSourceLayer areaStops, VectorSourceLayer groupStops, VectorSourceLayer edges, - VectorSourceLayer vertices + VectorSourceLayer vertices, + List extraLayers ) { - List vectorSources = List + List vectorSources = Stream .of(regularStops, edges, vertices) - .stream() .map(VectorSourceLayer::vectorSource) .map(TileSource.class::cast) .toList(); - var allSources = ListUtils.combine(BACKGROUND_LAYERS, vectorSources); + + List extraRasterSources = extraLayers + .stream() + .map(l -> + (TileSource) new RasterSource( + l.name(), + List.of(l.templateUrl()), + 19, + l.tileSize(), + l.attribution() + ) + ) + .toList(); + var allSources = ListUtils.combine(BACKGROUND_LAYERS, extraRasterSources, vectorSources); return new StyleSpec( "OTP Debug Tiles", allSources, ListUtils.combine( - backgroundLayers(), + backgroundLayers(extraRasterSources), wheelchair(edges), noThruTraffic(edges), traversalPermissions(edges), @@ -135,12 +141,13 @@ static StyleSpec build( ); } - private static List backgroundLayers() { - return BACKGROUND_LAYERS + private static List backgroundLayers(List extraLayers) { + return ListUtils + .combine(BACKGROUND_LAYERS, extraLayers) .stream() .map(layer -> { var builder = StyleBuilder.ofId(layer.id()).typeRaster().source(layer).minZoom(0); - if(!layer.equals(OSM_BACKGROUND)){ + if (!layer.equals(OSM_BACKGROUND)) { builder.intiallyHidden(); } return builder; diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index d19c25a1f47..0576e91f312 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -147,7 +147,8 @@ public StyleSpec getTileJson(@Context UriInfo uri, @Context HttpHeaders headers) AREA_STOPS.toVectorSourceLayer(stopsSource), GROUP_STOPS.toVectorSourceLayer(stopsSource), EDGES.toVectorSourceLayer(streetSource), - VERTICES.toVectorSourceLayer(streetSource) + VERTICES.toVectorSourceLayer(streetSource), + serverContext.debugUiConfig().additionalBackgroundLayers() ); } diff --git a/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java b/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java index 7b6852cb281..6c3a5b6a007 100644 --- a/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java +++ b/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java @@ -9,16 +9,18 @@ public class OtpFileNames { public static final String OTP_CONFIG_FILENAME = "otp-config.json"; public static final String BUILD_CONFIG_FILENAME = "build-config.json"; public static final String ROUTER_CONFIG_FILENAME = "router-config.json"; + public static final String DEBUG_UI_CONFIG_FILENAME = "debug-ui-config.json"; /** * Check if a file is a config file using the configuration file name. This method returns {@code - * true} if the file match {@code (otp|build|router)-config.json}. + * true} if the file match {@code (otp|build|router|debug-ui)-config.json}. */ public static boolean isConfigFile(String filename) { return ( OTP_CONFIG_FILENAME.equals(filename) || BUILD_CONFIG_FILENAME.equals(filename) || - ROUTER_CONFIG_FILENAME.equals(filename) + ROUTER_CONFIG_FILENAME.equals(filename) || + DEBUG_UI_CONFIG_FILENAME.equals(filename) ); } } diff --git a/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java b/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java index b5b39ddee18..f088a3de60e 100644 --- a/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java +++ b/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java @@ -26,6 +26,7 @@ import org.opentripplanner.service.vehicleparking.VehicleParkingService; import org.opentripplanner.service.vehiclerental.VehicleRentalService; import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.search.state.State; @@ -127,6 +128,8 @@ default GraphFinder graphFinder() { VectorTileConfig vectorTileConfig(); + DebugUiConfig debugUiConfig(); + /* Sandbox modules */ @Nullable diff --git a/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index c82dd33ddbf..390333f1374 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -49,16 +49,29 @@ public class ConfigModel { */ private RouterConfig routerConfig; - public ConfigModel(OtpConfig otpConfig, BuildConfig buildConfig, RouterConfig routerConfig) { + private final DebugUiConfig debugUiConfig; + + public ConfigModel( + OtpConfig otpConfig, + BuildConfig buildConfig, + RouterConfig routerConfig, + DebugUiConfig debugUiConfig + ) { this.otpConfig = otpConfig; this.buildConfig = buildConfig; this.routerConfig = routerConfig; + this.debugUiConfig = debugUiConfig; initializeOtpFeatures(otpConfig); } public ConfigModel(OtpConfigLoader loader) { - this(loader.loadOtpConfig(), loader.loadBuildConfig(), loader.loadRouterConfig()); + this( + loader.loadOtpConfig(), + loader.loadBuildConfig(), + loader.loadRouterConfig(), + loader.loadDebugUiConfig() + ); } public void updateConfigFromSerializedGraph(BuildConfig buildConfig, RouterConfig routerConfig) { @@ -102,6 +115,10 @@ public RouterConfig routerConfig() { return routerConfig; } + public DebugUiConfig debugUiConfig() { + return debugUiConfig; + } + public static void initializeOtpFeatures(OtpConfig otpConfig) { OTPFeature.enableFeatures(otpConfig.otpFeatures); OTPFeature.logFeatureSetup(); @@ -117,7 +134,8 @@ public void abortOnUnknownParameters() { ( otpConfig.hasUnknownParameters() || buildConfig.hasUnknownParameters() || - routerConfig.hasUnknownParameters() + routerConfig.hasUnknownParameters() || + debugUiConfig.hasUnknownParameters() ) ) { throw new OtpAppException( diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java new file mode 100644 index 00000000000..c32c4dce941 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -0,0 +1,100 @@ +package org.opentripplanner.standalone.config; + +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_0; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.MissingNode; +import java.io.Serializable; +import java.util.List; +import org.opentripplanner.standalone.config.debuguiconfig.BackgroundTileLayer; +import org.opentripplanner.standalone.config.framework.json.NodeAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is an object representation of the 'debug-ui-config.json'. + */ +public class DebugUiConfig implements Serializable { + + private static final Logger LOG = LoggerFactory.getLogger(DebugUiConfig.class); + + public static final DebugUiConfig DEFAULT = new DebugUiConfig( + MissingNode.getInstance(), + "DEFAULT", + false + ); + + /** + * The node adaptor kept for reference and (de)serialization. + */ + private final NodeAdapter root; + private final List additionalBackgroundLayers; + + public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { + this(new NodeAdapter(node, source), logUnusedParams); + } + + /** protected to give unit-test access */ + DebugUiConfig(NodeAdapter root, boolean logUnusedParams) { + this.root = root; + + this.additionalBackgroundLayers = + root + .of("additionalBackgroundLayers") + .asObjects( + List.of(), + node -> + new BackgroundTileLayer( + node + .of("name") + .since(V2_7) + .summary( + "Used in the url to fetch tiles, and as the layer name in the vector tiles." + ) + .asString(), + node + .of("templateUrl") + .since(V2_7) + .summary("Maximum zoom levels the layer is active for.") + .asString(), + node + .of("minZoom") + .since(V2_0) + .summary("Minimum zoom levels the layer is active for.") + .asInt(256), + node + .of("minZoom") + .since(V2_7) + .summary("Minimum zoom levels the layer is active for.") + .asString("© OpenTripPlanner") + ) + ); + + if (logUnusedParams && LOG.isWarnEnabled()) { + root.logAllWarnings(LOG::warn); + } + } + + public NodeAdapter asNodeAdapter() { + return root; + } + + public List additionalBackgroundLayers() { + return additionalBackgroundLayers; + } + + /** + * If {@code true} the config is loaded from file, in not the DEFAULT config is used. + */ + public boolean isDefault() { + return root.isEmpty(); + } + + /** + * Checks if any unknown or invalid parameters were encountered while loading the configuration. + */ + public boolean hasUnknownParameters() { + return root.hasUnknownParameters(); + } +} diff --git a/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java b/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java index d5c452b3da7..9e24e56ca12 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java @@ -1,6 +1,7 @@ package org.opentripplanner.standalone.config; import static org.opentripplanner.framework.application.OtpFileNames.BUILD_CONFIG_FILENAME; +import static org.opentripplanner.framework.application.OtpFileNames.DEBUG_UI_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.OTP_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; @@ -105,6 +106,14 @@ public RouterConfig loadRouterConfig() { return new RouterConfig(node, ROUTER_CONFIG_FILENAME, true); } + public DebugUiConfig loadDebugUiConfig() { + JsonNode node = loadFromFile(DEBUG_UI_CONFIG_FILENAME); + if (node.isMissingNode()) { + return DebugUiConfig.DEFAULT; + } + return new DebugUiConfig(node, DEBUG_UI_CONFIG_FILENAME, true); + } + private static void logConfigVersion(String configVersion, String filename) { if (configVersion != null) { LOG.info("{} config-version is {}.", filename, configVersion); diff --git a/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java b/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java index 4f75f3984d5..9a4de91f2ab 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java @@ -8,6 +8,7 @@ import org.opentripplanner.routing.algorithm.raptoradapter.transit.TripSchedule; import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; @@ -34,6 +35,11 @@ static RouterConfig provideRouterConfig(ConfigModel model) { return model.routerConfig(); } + @Provides + static DebugUiConfig provideDebugUiConfig(ConfigModel model) { + return model.debugUiConfig(); + } + @Provides @Singleton static RaptorConfig providesRaptorConfig( diff --git a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java new file mode 100644 index 00000000000..b8b6a4a5f81 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java @@ -0,0 +1,12 @@ +package org.opentripplanner.standalone.config.debuguiconfig; + +public record BackgroundTileLayer( + String name, + String templateUrl, + int tileSize, + String attribution +) { + public String name() { + return name.toLowerCase().replace("_", "-").replace(" ", "-"); + } +} diff --git a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java index eb3fae5275f..b4edbb36299 100644 --- a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java +++ b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java @@ -27,6 +27,7 @@ import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.CommandLineParameters; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.GrizzlyServer; @@ -300,6 +301,10 @@ public BuildConfig buildConfig() { return factory.config().buildConfig(); } + public DebugUiConfig debugUiConfig() { + return factory.config().debugUiConfig(); + } + public RaptorConfig raptorConfig() { return factory.raptorConfig(); } diff --git a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java index bbdd39c57d5..42bd8ee4d87 100644 --- a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java +++ b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java @@ -20,6 +20,7 @@ import org.opentripplanner.service.vehiclerental.VehicleRentalService; import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.DefaultServerRequestContext; import org.opentripplanner.street.service.StreetLimitationParametersService; @@ -32,6 +33,7 @@ public class ConstructApplicationModule { @Provides OtpServerRequestContext providesServerContext( RouterConfig routerConfig, + DebugUiConfig debugUiConfig, RaptorConfig raptorConfig, Graph graph, TransitService transitService, @@ -69,7 +71,8 @@ OtpServerRequestContext providesServerContext( stopConsolidationService, streetLimitationParametersService, traverseVisitor, - luceneIndex + luceneIndex, + debugUiConfig ); } diff --git a/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java b/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java index 1427dcf1971..450b6986cb5 100644 --- a/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java +++ b/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java @@ -26,6 +26,7 @@ import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; import org.opentripplanner.standalone.api.HttpRequestScoped; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.routerconfig.TransitRoutingConfig; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.street.service.StreetLimitationParametersService; @@ -57,6 +58,7 @@ public class DefaultServerRequestContext implements OtpServerRequestContext { private final StopConsolidationService stopConsolidationService; private final StreetLimitationParametersService streetLimitationParametersService; private final LuceneIndex luceneIndex; + private final DebugUiConfig debugUiConfig; private RouteRequest defaultRouteRequestWithTimeSet = null; @@ -83,7 +85,8 @@ private DefaultServerRequestContext( StreetLimitationParametersService streetLimitationParametersService, FlexParameters flexParameters, @Nullable TraverseVisitor traverseVisitor, - @Nullable LuceneIndex luceneIndex + @Nullable LuceneIndex luceneIndex, + DebugUiConfig debugUiConfig ) { this.graph = graph; this.transitService = transitService; @@ -105,6 +108,7 @@ private DefaultServerRequestContext( this.stopConsolidationService = stopConsolidationService; this.streetLimitationParametersService = streetLimitationParametersService; this.luceneIndex = luceneIndex; + this.debugUiConfig = debugUiConfig; } /** @@ -129,7 +133,8 @@ public static DefaultServerRequestContext create( @Nullable StopConsolidationService stopConsolidationService, StreetLimitationParametersService streetLimitationParametersService, @Nullable TraverseVisitor traverseVisitor, - @Nullable LuceneIndex luceneIndex + @Nullable LuceneIndex luceneIndex, + DebugUiConfig debugUiConfig ) { return new DefaultServerRequestContext( graph, @@ -151,7 +156,8 @@ public static DefaultServerRequestContext create( streetLimitationParametersService, flexParameters, traverseVisitor, - luceneIndex + luceneIndex, + debugUiConfig ); } @@ -262,6 +268,11 @@ public VectorTileConfig vectorTileConfig() { return vectorTileConfig; } + @Override + public DebugUiConfig debugUiConfig() { + return debugUiConfig; + } + @Nullable @Override public LuceneIndex lucenceIndex() { diff --git a/application/src/test/java/org/opentripplanner/TestServerContext.java b/application/src/test/java/org/opentripplanner/TestServerContext.java index e20720bd7d8..ca818a64a58 100644 --- a/application/src/test/java/org/opentripplanner/TestServerContext.java +++ b/application/src/test/java/org/opentripplanner/TestServerContext.java @@ -21,6 +21,7 @@ import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeService; import org.opentripplanner.service.worldenvelope.model.WorldEnvelope; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; import org.opentripplanner.standalone.server.DefaultServerRequestContext; @@ -65,7 +66,8 @@ public static OtpServerRequestContext createServerContext( null, createStreetLimitationParametersService(), null, - null + null, + DebugUiConfig.DEFAULT ); creatTransitLayerForRaptor(timetableRepository, routerConfig.transitTuningConfig()); return context; diff --git a/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java b/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java index b3c64e0aecb..dc96a094812 100644 --- a/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java +++ b/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java @@ -52,6 +52,7 @@ import org.opentripplanner.service.vehiclerental.internal.DefaultVehicleRentalService; import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeRepository; import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeService; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.DefaultServerRequestContext; import org.opentripplanner.street.model.StreetLimitationParameters; @@ -154,7 +155,8 @@ void setup() { null, new DefaultStreetLimitationParametersService(new StreetLimitationParameters()), null, - null + null, + DebugUiConfig.DEFAULT ), null, transitService diff --git a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java index db056050394..f602a6cb532 100644 --- a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java +++ b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import org.junit.jupiter.api.Test; import org.opentripplanner.apis.vectortiles.model.TileSource.VectorSource; import org.opentripplanner.apis.vectortiles.model.VectorSourceLayer; @@ -27,7 +28,7 @@ void spec() throws IOException { var groupStops = new VectorSourceLayer(vectorSource, "stops"); var edges = new VectorSourceLayer(vectorSource, "edges"); var vertices = new VectorSourceLayer(vectorSource, "vertices"); - var spec = DebugStyleSpec.build(regularStops, areaStops, groupStops, edges, vertices); + var spec = DebugStyleSpec.build(regularStops, areaStops, groupStops, edges, vertices, List.of()); var json = ObjectMappers.ignoringExtraFields().valueToTree(spec); try { diff --git a/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java b/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java index c55ddff854f..ca4e85eed84 100644 --- a/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java +++ b/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java @@ -29,6 +29,7 @@ import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfigLoader; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; @@ -130,7 +131,8 @@ public SpeedTest( null, TestServerContext.createStreetLimitationParametersService(), null, - null + null, + DebugUiConfig.DEFAULT ); // Creating transitLayerForRaptor should be integrated into the TimetableRepository, but for now // we do it manually here From a934342baa54370f1f843f65785745d65c3eebea Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 10:09:50 +0100 Subject: [PATCH 05/16] Update tests --- .../apis/vectortiles/DebugStyleSpec.java | 2 +- .../apis/vectortiles/style.json | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index b66aa4fcc2b..12632c90efb 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -46,7 +46,7 @@ public class DebugStyleSpec { ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( "background-positron", - List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}${r}.png"), + List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"), 19, 256, "© OpenStreetMap, © CARTO" diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index fe7b546400d..00cceab1b06 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -1,6 +1,16 @@ { "name" : "OTP Debug Tiles", "sources" : { + "background-positron" : { + "id" : "background-positron", + "tiles" : [ + "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png" + ], + "maxzoom" : 19, + "tileSize" : 256, + "attribution" : "© OpenStreetMap, © CARTO", + "type" : "raster" + }, "vectorSource" : { "id" : "vectorSource", "url" : "https://example.com", @@ -15,16 +25,6 @@ "tileSize" : 256, "attribution" : "© OpenStreetMap Contributors", "type" : "raster" - }, - "background-carto" : { - "id" : "background-carto", - "tiles" : [ - "https://{s}.basemaps.cartocdn.com/{z}/{x}/{y}" - ], - "maxzoom" : 19, - "tileSize" : 256, - "attribution" : "© OpenStreetMap, © CARTO", - "type" : "raster" } }, "layers" : [ @@ -38,10 +38,13 @@ } }, { - "id" : "background-carto", + "id" : "background-positron", "type" : "raster", - "source" : "background-carto", + "source" : "background-positron", "minzoom" : 0, + "layout" : { + "visibility" : "none" + }, "metadata" : { "group" : "Other" } From 25b4fee19f174cb8a2c5a1765e2986d1422d7d46 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 10:40:24 +0100 Subject: [PATCH 06/16] Fix configuration --- .../opentripplanner/apis/vectortiles/DebugStyleSpec.java | 2 +- .../opentripplanner/standalone/config/DebugUiConfig.java | 7 +++---- .../config/debuguiconfig/BackgroundTileLayer.java | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 12632c90efb..40dce2f6f10 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -117,7 +117,7 @@ static StyleSpec build( .stream() .map(l -> (TileSource) new RasterSource( - l.name(), + l.id(), List.of(l.templateUrl()), 19, l.tileSize(), diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index c32c4dce941..085451024b2 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -1,6 +1,5 @@ package org.opentripplanner.standalone.config; -import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_0; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7; import com.fasterxml.jackson.databind.JsonNode; @@ -59,12 +58,12 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { .summary("Maximum zoom levels the layer is active for.") .asString(), node - .of("minZoom") - .since(V2_0) + .of("tileSize") + .since(V2_7) .summary("Minimum zoom levels the layer is active for.") .asInt(256), node - .of("minZoom") + .of("attribution") .since(V2_7) .summary("Minimum zoom levels the layer is active for.") .asString("© OpenTripPlanner") diff --git a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java index b8b6a4a5f81..7f8546e1110 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java @@ -6,7 +6,7 @@ public record BackgroundTileLayer( int tileSize, String attribution ) { - public String name() { + public String id() { return name.toLowerCase().replace("_", "-").replace(" ", "-"); } } From 9bd492ab55981929d88cf7dc02a6bf1013cecc5f Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 11:01:31 +0100 Subject: [PATCH 07/16] Style background layer picker --- client/src/style.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/src/style.css b/client/src/style.css index c33f5dff711..f838dce2c7b 100644 --- a/client/src/style.css +++ b/client/src/style.css @@ -181,6 +181,10 @@ margin-left: 6px; } +.maplibregl-ctrl-group.layer-select select { + margin-bottom: 14px; +} + .maplibregl-ctrl-group.layer-select h4 { font-size: 17px; } From 441711bf58efd3c364d529b01ecbd4ed718edbda Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 11:42:19 +0100 Subject: [PATCH 08/16] Add nicer names to UI --- .../apis/vectortiles/DebugStyleSpec.java | 13 +- .../apis/vectortiles/model/StyleBuilder.java | 10 +- .../apis/vectortiles/model/TileSource.java | 20 +- .../debuguiconfig/BackgroundTileLayer.java | 6 +- .../apis/vectortiles/DebugStyleSpecTest.java | 9 +- .../apis/vectortiles/style.json | 1242 ++++++----------- .../src/components/MapView/LayerControl.tsx | 7 +- .../utils/lang/StringUtils.java | 8 + .../utils/lang/StringUtilsTest.java | 6 + 9 files changed, 455 insertions(+), 866 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 40dce2f6f10..0bcfba51e26 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -38,14 +38,14 @@ public class DebugStyleSpec { private static final TileSource OSM_BACKGROUND = new RasterSource( - "background-osm", + "OSM Carto", List.of("https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"), 19, 256, "© OpenStreetMap Contributors" ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( - "background-positron", + "Positron", List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"), 19, 256, @@ -117,7 +117,7 @@ static StyleSpec build( .stream() .map(l -> (TileSource) new RasterSource( - l.id(), + l.name(), List.of(l.templateUrl()), 19, l.tileSize(), @@ -146,7 +146,12 @@ private static List backgroundLayers(List extraLayers) .combine(BACKGROUND_LAYERS, extraLayers) .stream() .map(layer -> { - var builder = StyleBuilder.ofId(layer.id()).typeRaster().source(layer).minZoom(0); + var builder = StyleBuilder + .ofId(layer.id()) + .displayName(layer.name()) + .typeRaster() + .source(layer) + .minZoom(0); if (!layer.equals(OSM_BACKGROUND)) { builder.intiallyHidden(); } diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java index a70acbb8685..4e75f37785d 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java @@ -30,7 +30,7 @@ public class StyleBuilder { private final Map layout = new LinkedHashMap<>(); private final Map metadata = new LinkedHashMap<>(); private final Map line = new LinkedHashMap<>(); - private List filter = List.of(); + private List filter = List.of(); public static StyleBuilder ofId(String id) { return new StyleBuilder(id); @@ -120,6 +120,14 @@ public StyleBuilder group(String group) { return this; } + /** + * A nice human-readable name for the layer. + */ + public StyleBuilder displayName(String name) { + metadata.put("name", name); + return this; + } + public StyleBuilder lineText(String name) { layout.put("symbol-placement", "line-center"); layout.put("symbol-spacing", 1000); diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java index 088ce63d10a..b7f0ce5d048 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.util.List; +import org.opentripplanner.utils.lang.StringUtils; /** * Represent a data source where Maplibre can fetch data for rendering directly in the browser. @@ -12,6 +13,8 @@ public sealed interface TileSource { String id(); + String name(); + /** * Represents a vector tile source which is rendered into a map in the browser. */ @@ -20,17 +23,32 @@ record VectorSource(String id, String url) implements TileSource { public String type() { return "vector"; } + + @Override + public String name() { + return id; + } } /** * Represents a raster-based source for map tiles. These are used mainly for background * map layers with vector data being rendered on top of it. */ - record RasterSource(String id, List tiles, int maxzoom, int tileSize, String attribution) + record RasterSource( + String name, + List tiles, + int maxzoom, + int tileSize, + String attribution + ) implements TileSource { @Override public String type() { return "raster"; } + + public String id() { + return StringUtils.slugify(name); + } } } diff --git a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java index 7f8546e1110..121debcb40e 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java @@ -5,8 +5,4 @@ public record BackgroundTileLayer( String templateUrl, int tileSize, String attribution -) { - public String id() { - return name.toLowerCase().replace("_", "-").replace(" ", "-"); - } -} +) {} diff --git a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java index f602a6cb532..26d1044047e 100644 --- a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java +++ b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java @@ -28,7 +28,14 @@ void spec() throws IOException { var groupStops = new VectorSourceLayer(vectorSource, "stops"); var edges = new VectorSourceLayer(vectorSource, "edges"); var vertices = new VectorSourceLayer(vectorSource, "vertices"); - var spec = DebugStyleSpec.build(regularStops, areaStops, groupStops, edges, vertices, List.of()); + var spec = DebugStyleSpec.build( + regularStops, + areaStops, + groupStops, + edges, + vertices, + List.of() + ); var json = ObjectMappers.ignoringExtraFields().valueToTree(spec); try { diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index 00cceab1b06..a1a188ca76a 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -1,166 +1,107 @@ { - "name" : "OTP Debug Tiles", - "sources" : { - "background-positron" : { - "id" : "background-positron", - "tiles" : [ + "name": "OTP Debug Tiles", + "sources": { + "positron": { + "name": "Positron", + "tiles": [ "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png" ], - "maxzoom" : 19, - "tileSize" : 256, - "attribution" : "© OpenStreetMap, © CARTO", - "type" : "raster" + "maxzoom": 19, + "tileSize": 256, + "attribution": "© OpenStreetMap, © CARTO", + "type": "raster" }, - "vectorSource" : { - "id" : "vectorSource", - "url" : "https://example.com", - "type" : "vector" + "vectorSource": { + "id": "vectorSource", + "url": "https://example.com", + "type": "vector" }, - "background-osm" : { - "id" : "background-osm", - "tiles" : [ - "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" - ], - "maxzoom" : 19, - "tileSize" : 256, - "attribution" : "© OpenStreetMap Contributors", - "type" : "raster" + "osm-carto": { + "name": "OSM Carto", + "tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"], + "maxzoom": 19, + "tileSize": 256, + "attribution": "© OpenStreetMap Contributors", + "type": "raster" } }, - "layers" : [ + "layers": [ { - "id" : "background-osm", - "type" : "raster", - "source" : "background-osm", - "minzoom" : 0, - "metadata" : { - "group" : "Other" + "id": "osm-carto", + "type": "raster", + "source": "osm-carto", + "minzoom": 0, + "metadata": { + "group": "Other", + "name": "OSM Carto" } }, { - "id" : "background-positron", - "type" : "raster", - "source" : "background-positron", - "minzoom" : 0, - "layout" : { - "visibility" : "none" - }, - "metadata" : { - "group" : "Other" + "id": "positron", + "type": "raster", + "source": "positron", + "minzoom": 0, + "layout": { + "visibility": "none" + }, + "metadata": { + "group": "Other", + "name": "Positron" } }, { - "id" : "wheelchair-accessible", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "line-color" : "#136b04", - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] - }, - "filter" : [ - "==", - "wheelchairAccessible", - true - ], - "layout" : { - "line-cap" : "round", - "visibility" : "none" - }, - "metadata" : { - "group" : "Wheelchair accessibility" + "id": "wheelchair-accessible", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "line-color": "#136b04", + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + }, + "filter": ["==", "wheelchairAccessible", true], + "layout": { + "line-cap": "round", + "visibility": "none" + }, + "metadata": { + "group": "Wheelchair accessibility" } }, { - "id" : "wheelchair-inaccessible", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "line-color" : "#fc0f2a", - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] - }, - "filter" : [ - "==", - "wheelchairAccessible", - false - ], - "layout" : { - "line-cap" : "round", - "visibility" : "none" - }, - "metadata" : { - "group" : "Wheelchair accessibility" + "id": "wheelchair-inaccessible", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "line-color": "#fc0f2a", + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + }, + "filter": ["==", "wheelchairAccessible", false], + "layout": { + "line-cap": "round", + "visibility": "none" + }, + "metadata": { + "group": "Wheelchair accessibility" } }, { - "id" : "no-thru-traffic PEDESTRIAN", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "no-thru-traffic PEDESTRIAN", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "noThruTraffic" - ], + ["get", "noThruTraffic"], "NONE", "#140d0e", "PEDESTRIAN", @@ -179,80 +120,33 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "PEDESTRIAN", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ] + ["in", "PEDESTRIAN", ["string", ["get", "noThruTraffic"]]], + ["in", "ALL", ["string", ["get", "noThruTraffic"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "No-thru traffic" + "metadata": { + "group": "No-thru traffic" } }, { - "id" : "no-thru-traffic BICYCLE", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "no-thru-traffic BICYCLE", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "noThruTraffic" - ], + ["get", "noThruTraffic"], "NONE", "#140d0e", "PEDESTRIAN", @@ -271,80 +165,33 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "BICYCLE", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ] + ["in", "BICYCLE", ["string", ["get", "noThruTraffic"]]], + ["in", "ALL", ["string", ["get", "noThruTraffic"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "No-thru traffic" + "metadata": { + "group": "No-thru traffic" } }, { - "id" : "no-thru-traffic CAR", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "no-thru-traffic CAR", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "noThruTraffic" - ], + ["get", "noThruTraffic"], "NONE", "#140d0e", "PEDESTRIAN", @@ -363,80 +210,36 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "CAR", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ] + ["in", "CAR", ["string", ["get", "noThruTraffic"]]], + ["in", "ALL", ["string", ["get", "noThruTraffic"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "No-thru traffic" + "metadata": { + "group": "No-thru traffic" } }, { - "id" : "no-thru-traffic-text", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "symbol", - "minzoom" : 17, - "maxzoom" : 23, - "paint" : { - "text-color" : "#000", - "text-halo-color" : "#fff", - "text-halo-blur" : 4, - "text-halo-width" : 3 - }, - "filter" : [ + "id": "no-thru-traffic-text", + "source": "vectorSource", + "source-layer": "edges", + "type": "symbol", + "minzoom": 17, + "maxzoom": 23, + "paint": { + "text-color": "#000", + "text-halo-color": "#fff", + "text-halo-blur": 4, + "text-halo-width": 3 + }, + "filter": [ "in", "class", "StreetEdge", @@ -447,54 +250,34 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout" : { - "symbol-placement" : "line-center", - "symbol-spacing" : 1000, - "text-field" : "{noThruTraffic}", - "text-font" : [ - "KlokanTech Noto Sans Regular" - ], - "text-size" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 6.0, - 24, - 12.0 - ], - "text-max-width" : 100, - "text-keep-upright" : true, - "text-rotation-alignment" : "map", - "text-overlap" : "never", - "text-offset" : [ - 0, - 1.0 - ], - "visibility" : "none" - }, - "metadata" : { - "group" : "No-thru traffic" + "layout": { + "symbol-placement": "line-center", + "symbol-spacing": 1000, + "text-field": "{noThruTraffic}", + "text-font": ["KlokanTech Noto Sans Regular"], + "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], + "text-max-width": 100, + "text-keep-upright": true, + "text-rotation-alignment": "map", + "text-overlap": "never", + "text-offset": [0, 1.0], + "visibility": "none" + }, + "metadata": { + "group": "No-thru traffic" } }, { - "id" : "permission PEDESTRIAN", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "permission PEDESTRIAN", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "permission" - ], + ["get", "permission"], "NONE", "#140d0e", "PEDESTRIAN", @@ -513,80 +296,33 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "PEDESTRIAN", - [ - "string", - [ - "get", - "permission" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "permission" - ] - ] - ] + ["in", "PEDESTRIAN", ["string", ["get", "permission"]]], + ["in", "ALL", ["string", ["get", "permission"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "Permissions" + "metadata": { + "group": "Permissions" } }, { - "id" : "permission BICYCLE", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "permission BICYCLE", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "permission" - ], + ["get", "permission"], "NONE", "#140d0e", "PEDESTRIAN", @@ -605,80 +341,33 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "BICYCLE", - [ - "string", - [ - "get", - "permission" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "permission" - ] - ] - ] + ["in", "BICYCLE", ["string", ["get", "permission"]]], + ["in", "ALL", ["string", ["get", "permission"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "Permissions" + "metadata": { + "group": "Permissions" } }, { - "id" : "permission CAR", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "permission CAR", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "permission" - ], + ["get", "permission"], "NONE", "#140d0e", "PEDESTRIAN", @@ -697,80 +386,36 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "CAR", - [ - "string", - [ - "get", - "permission" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "permission" - ] - ] - ] + ["in", "CAR", ["string", ["get", "permission"]]], + ["in", "ALL", ["string", ["get", "permission"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "Permissions" + "metadata": { + "group": "Permissions" } }, { - "id" : "permission-text", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "symbol", - "minzoom" : 17, - "maxzoom" : 23, - "paint" : { - "text-color" : "#000", - "text-halo-color" : "#fff", - "text-halo-blur" : 4, - "text-halo-width" : 3 - }, - "filter" : [ + "id": "permission-text", + "source": "vectorSource", + "source-layer": "edges", + "type": "symbol", + "minzoom": 17, + "maxzoom": 23, + "paint": { + "text-color": "#000", + "text-halo-color": "#fff", + "text-halo-blur": 4, + "text-halo-width": 3 + }, + "filter": [ "in", "class", "StreetEdge", @@ -781,77 +426,36 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout" : { - "symbol-placement" : "line-center", - "symbol-spacing" : 1000, - "text-field" : "{permission}", - "text-font" : [ - "KlokanTech Noto Sans Regular" - ], - "text-size" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 6.0, - 24, - 12.0 - ], - "text-max-width" : 100, - "text-keep-upright" : true, - "text-rotation-alignment" : "map", - "text-overlap" : "never", - "text-offset" : [ - 0, - 1.0 - ], - "visibility" : "none" - }, - "metadata" : { - "group" : "Permissions" + "layout": { + "symbol-placement": "line-center", + "symbol-spacing": 1000, + "text-field": "{permission}", + "text-font": ["KlokanTech Noto Sans Regular"], + "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], + "text-max-width": 100, + "text-keep-upright": true, + "text-rotation-alignment": "map", + "text-overlap": "never", + "text-offset": [0, 1.0], + "visibility": "none" + }, + "metadata": { + "group": "Permissions" } }, { - "id" : "edge", - "type" : "line", - "source" : "vectorSource", - "source-layer" : "edges", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "line-color" : "#f21d52", - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.1, - 23, - 6.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] - }, - "filter" : [ + "id": "edge", + "type": "line", + "source": "vectorSource", + "source-layer": "edges", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "line-color": "#f21d52", + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.1, 23, 6.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + }, + "filter": [ "in", "class", "StreetEdge", @@ -862,28 +466,28 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout" : { - "line-cap" : "round", - "visibility" : "none" + "layout": { + "line-cap": "round", + "visibility": "none" }, - "metadata" : { - "group" : "Edges" + "metadata": { + "group": "Edges" } }, { - "id" : "edge-name", - "type" : "symbol", - "source" : "vectorSource", - "source-layer" : "edges", - "minzoom" : 17, - "maxzoom" : 23, - "paint" : { - "text-color" : "#000", - "text-halo-color" : "#fff", - "text-halo-blur" : 4, - "text-halo-width" : 3 - }, - "filter" : [ + "id": "edge-name", + "type": "symbol", + "source": "vectorSource", + "source-layer": "edges", + "minzoom": 17, + "maxzoom": 23, + "paint": { + "text-color": "#000", + "text-halo-color": "#fff", + "text-halo-blur": 4, + "text-halo-width": 3 + }, + "filter": [ "in", "class", "StreetEdge", @@ -894,73 +498,35 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout" : { - "symbol-placement" : "line-center", - "symbol-spacing" : 1000, - "text-field" : "{name}", - "text-font" : [ - "KlokanTech Noto Sans Regular" - ], - "text-size" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 6.0, - 24, - 12.0 - ], - "text-max-width" : 100, - "text-keep-upright" : true, - "text-rotation-alignment" : "map", - "text-overlap" : "never", - "visibility" : "none" - }, - "metadata" : { - "group" : "Edges" + "layout": { + "symbol-placement": "line-center", + "symbol-spacing": 1000, + "text-field": "{name}", + "text-font": ["KlokanTech Noto Sans Regular"], + "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], + "text-max-width": 100, + "text-keep-upright": true, + "text-rotation-alignment": "map", + "text-overlap": "never", + "visibility": "none" + }, + "metadata": { + "group": "Edges" } }, { - "id" : "link", - "type" : "line", - "source" : "vectorSource", - "source-layer" : "edges", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : "#22DD9E", - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] - }, - "filter" : [ + "id": "link", + "type": "line", + "source": "vectorSource", + "source-layer": "edges", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": "#22DD9E", + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + }, + "filter": [ "in", "class", "StreetTransitStopLink", @@ -970,181 +536,153 @@ "StreetVehicleParkingLink", "StreetStationCentroidLink" ], - "layout" : { - "line-cap" : "round", - "visibility" : "none" + "layout": { + "line-cap": "round", + "visibility": "none" }, - "metadata" : { - "group" : "Edges" + "metadata": { + "group": "Edges" } }, { - "id" : "vertex", - "type" : "circle", - "source" : "vectorSource", - "source-layer" : "vertices", - "minzoom" : 15, - "maxzoom" : 23, - "paint" : { - "circle-stroke-color" : "#140d0e", - "circle-stroke-width" : [ + "id": "vertex", + "type": "circle", + "source": "vectorSource", + "source-layer": "vertices", + "minzoom": 15, + "maxzoom": 23, + "paint": { + "circle-stroke-color": "#140d0e", + "circle-stroke-width": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 15, 0.2, 23, 3.0 ], - "circle-radius" : [ + "circle-radius": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 15, 1.0, 23, 7.0 ], - "circle-color" : "#BC55F2" + "circle-color": "#BC55F2" }, - "layout" : { - "visibility" : "none" + "layout": { + "visibility": "none" }, - "metadata" : { - "group" : "Vertices" + "metadata": { + "group": "Vertices" } }, { - "id" : "parking-vertex", - "type" : "circle", - "source" : "vectorSource", - "source-layer" : "vertices", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "circle-stroke-color" : "#140d0e", - "circle-stroke-width" : [ + "id": "parking-vertex", + "type": "circle", + "source": "vectorSource", + "source-layer": "vertices", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "circle-stroke-color": "#140d0e", + "circle-stroke-width": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 15, 0.2, 23, 3.0 ], - "circle-radius" : [ + "circle-radius": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 13, 1.4, 23, 10.0 ], - "circle-color" : "#136b04" + "circle-color": "#136b04" }, - "filter" : [ - "in", - "class", - "VehicleParkingEntranceVertex" - ], - "layout" : { - "visibility" : "none" + "filter": ["in", "class", "VehicleParkingEntranceVertex"], + "layout": { + "visibility": "none" }, - "metadata" : { - "group" : "Vertices" + "metadata": { + "group": "Vertices" } }, { - "id" : "area-stop", - "type" : "fill", - "source" : "vectorSource", - "source-layer" : "stops", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "fill-color" : "#22DD9E", - "fill-opacity" : 0.5, - "fill-outline-color" : "#140d0e" - }, - "metadata" : { - "group" : "Stops" + "id": "area-stop", + "type": "fill", + "source": "vectorSource", + "source-layer": "stops", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "fill-color": "#22DD9E", + "fill-opacity": 0.5, + "fill-outline-color": "#140d0e" + }, + "metadata": { + "group": "Stops" } }, { - "id" : "group-stop", - "type" : "fill", - "source" : "vectorSource", - "source-layer" : "stops", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "fill-color" : "#22DD9E", - "fill-opacity" : 0.5, - "fill-outline-color" : "#140d0e" - }, - "metadata" : { - "group" : "Stops" + "id": "group-stop", + "type": "fill", + "source": "vectorSource", + "source-layer": "stops", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "fill-color": "#22DD9E", + "fill-opacity": 0.5, + "fill-outline-color": "#140d0e" + }, + "metadata": { + "group": "Stops" } }, { - "id" : "regular-stop", - "type" : "circle", - "source" : "vectorSource", - "source-layer" : "stops", - "minzoom" : 10, - "maxzoom" : 23, - "paint" : { - "circle-stroke-color" : "#140d0e", - "circle-stroke-width" : [ + "id": "regular-stop", + "type": "circle", + "source": "vectorSource", + "source-layer": "stops", + "minzoom": 10, + "maxzoom": 23, + "paint": { + "circle-stroke-color": "#140d0e", + "circle-stroke-width": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 11, 0.5, 23, 5.0 ], - "circle-radius" : [ + "circle-radius": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 11, 0.5, 23, 10.0 ], - "circle-color" : "#fcf9fa" + "circle-color": "#fcf9fa" }, - "metadata" : { - "group" : "Stops" + "metadata": { + "group": "Stops" } } ], - "version" : 8, - "glyphs" : "https://cdn.jsdelivr.net/gh/klokantech/klokantech-gl-fonts@master/{fontstack}/{range}.pbf" -} \ No newline at end of file + "version": 8, + "glyphs": "https://cdn.jsdelivr.net/gh/klokantech/klokantech-gl-fonts@master/{fontstack}/{range}.pbf" +} diff --git a/client/src/components/MapView/LayerControl.tsx b/client/src/components/MapView/LayerControl.tsx index d5f9dbb6424..e3e87fba7bd 100644 --- a/client/src/components/MapView/LayerControl.tsx +++ b/client/src/components/MapView/LayerControl.tsx @@ -55,14 +55,17 @@ class LayerControl implements IControl { rasterLayers.forEach((layer) => { if (layer) { const option = document.createElement('option'); - option.textContent = layer.id; + const meta = layer.metadata as { name: string }; + option.textContent = meta.name; option.id = layer.id; + option.value = layer.id; select.appendChild(option); } }); - select.onchange = (ev) => { + select.onchange = () => { const layerId = select.value; + console.log(select.value); const layer = map.getLayer(layerId); if (layer) { rasterLayers.forEach((l) => { diff --git a/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java b/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java index 72eb2638c13..c1a2219da72 100644 --- a/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java +++ b/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java @@ -132,6 +132,14 @@ public static String kebabCase(String input) { return input.toLowerCase().replace('_', '-'); } + /** + * Create a URL-friendly "slug" version of the string, so "Entur Routebanken" becomes + * "entur-routebanken". + */ + public static String slugify(String input) { + return input.toLowerCase().replace('_', '-').replaceAll("\\s+", "-"); + } + /** * Detects unprintable control characters like newlines, tabs and invisible whitespace * like 'ZERO WIDTH SPACE' (U+200B) that don't have an immediate visual representation. diff --git a/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java b/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java index 7e8f0a6217b..dda9248468e 100644 --- a/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java +++ b/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java @@ -100,4 +100,10 @@ void containsInvisibleChars(String input) { void noInvisibleChars(String input) { assertFalse(StringUtils.containsInvisibleCharacters(input)); } + + @ParameterizedTest + @ValueSource(strings = { "AAA Bbb", "aAa bbb", "aaa bbb", "aaa bbb", "AAA_BBB" }) + void slugify(String input) { + assertEquals("aaa-bbb", StringUtils.slugify(input)); + } } From 2f0692bc1341618339da98a3778f6b62783a7511 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 14:43:45 +0100 Subject: [PATCH 09/16] Add documentation --- .../apis/vectortiles/DebugStyleSpec.java | 2 +- .../standalone/config/DebugUiConfig.java | 28 +++++--- .../doc/DebugUiConfigurationDocTest.java | 67 +++++++++++++++++++ .../standalone/config/ExampleConfigTest.java | 12 ++++ .../apis/vectortiles/style.json | 2 +- .../standalone/config/debug-ui-config.json | 9 +++ doc/templates/DebugUiConfiguration.md | 23 +++++++ doc/user/DebugUiConfiguration.md | 66 ++++++++++++++++++ mkdocs.yml | 1 + 9 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java create mode 100644 application/src/test/resources/standalone/config/debug-ui-config.json create mode 100644 doc/templates/DebugUiConfiguration.md create mode 100644 doc/user/DebugUiConfiguration.md diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 0bcfba51e26..7070f8b486e 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -46,7 +46,7 @@ public class DebugStyleSpec { ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( "Positron", - List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"), + List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}{ratio}.png"), 19, 256, "© OpenStreetMap, © CARTO" diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index 085451024b2..165bcfe28f4 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -41,6 +41,15 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { this.additionalBackgroundLayers = root .of("additionalBackgroundLayers") + .since(V2_7) + .summary("Additional background raster map layers.") + .description( + """ + Add additional background layers that will appear in the Debug UI as one of the choices. + + Current only raster tile layers are supported. + """ + ) .asObjects( List.of(), node -> @@ -48,24 +57,23 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { node .of("name") .since(V2_7) - .summary( - "Used in the url to fetch tiles, and as the layer name in the vector tiles." - ) + .summary("Name to appear in the layer selector.") .asString(), node .of("templateUrl") .since(V2_7) - .summary("Maximum zoom levels the layer is active for.") + .summary( + """ + The [Maplibre-compatible template URL](https://maplibre.org/maplibre-native/ios/api/tile-url-templates.html) + for the raster layer, for example `https://examples.com/tiles/{z}/{x}/{y}.png`. + """ + ) .asString(), - node - .of("tileSize") - .since(V2_7) - .summary("Minimum zoom levels the layer is active for.") - .asInt(256), + node.of("tileSize").since(V2_7).summary("Size of the tile in pixels.").asInt(256), node .of("attribution") .since(V2_7) - .summary("Minimum zoom levels the layer is active for.") + .summary("Attribution for the map data.") .asString("© OpenTripPlanner") ) ); diff --git a/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java b/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java new file mode 100644 index 00000000000..a5124c0d3e0 --- /dev/null +++ b/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java @@ -0,0 +1,67 @@ +package org.opentripplanner.generate.doc; + +import static org.opentripplanner.framework.io.FileUtils.assertFileEquals; +import static org.opentripplanner.framework.io.FileUtils.readFile; +import static org.opentripplanner.framework.io.FileUtils.writeFile; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.TEMPLATE_PATH; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.USER_DOC_PATH; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceJsonExample; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceParametersDetails; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceParametersTable; +import static org.opentripplanner.standalone.config.framework.json.JsonSupport.jsonNodeFromResource; +import static org.opentripplanner.utils.text.MarkdownFormatter.HEADER_3; + +import java.io.File; +import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.application.OtpFileNames; +import org.opentripplanner.generate.doc.framework.GeneratesDocumentation; +import org.opentripplanner.generate.doc.framework.ParameterDetailsList; +import org.opentripplanner.generate.doc.framework.ParameterSummaryTable; +import org.opentripplanner.generate.doc.framework.SkipNodes; +import org.opentripplanner.standalone.config.DebugUiConfig; +import org.opentripplanner.standalone.config.framework.json.NodeAdapter; + +@GeneratesDocumentation +public class DebugUiConfigurationDocTest { + + private static final String CONFIG_JSON = OtpFileNames.DEBUG_UI_CONFIG_FILENAME; + private static final File TEMPLATE = new File(TEMPLATE_PATH, "DebugUiConfiguration.md"); + private static final File OUT_FILE = new File(USER_DOC_PATH, "DebugUiConfiguration.md"); + + private static final String CONFIG_PATH = "standalone/config/" + CONFIG_JSON; + + /** + * NOTE! This test updates the {@code doc/user/Configuration.md} document based on the latest + * version of the code. + */ + @Test + public void updateDoc() { + NodeAdapter node = readConfig(); + + // Read and close input file (same as output file) + String doc = readFile(TEMPLATE); + String original = readFile(OUT_FILE); + + doc = replaceParametersTable(doc, getParameterSummaryTable(node)); + doc = replaceParametersDetails(doc, getParameterDetailsTable(node)); + doc = replaceJsonExample(doc, node, CONFIG_JSON); + + writeFile(OUT_FILE, doc); + + assertFileEquals(original, OUT_FILE); + } + + private NodeAdapter readConfig() { + var json = jsonNodeFromResource(CONFIG_PATH); + var conf = new DebugUiConfig(json, CONFIG_PATH, true); + return conf.asNodeAdapter(); + } + + private String getParameterSummaryTable(NodeAdapter node) { + return new ParameterSummaryTable(SkipNodes.of().build()).createTable(node).toMarkdownTable(); + } + + private String getParameterDetailsTable(NodeAdapter node) { + return ParameterDetailsList.listParametersWithDetails(node, SkipNodes.of().build(), HEADER_3); + } +} diff --git a/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java b/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java index 06b0d8ed592..934da6f923d 100644 --- a/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java +++ b/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.fail; import static org.opentripplanner.framework.application.OtpFileNames.BUILD_CONFIG_FILENAME; +import static org.opentripplanner.framework.application.OtpFileNames.DEBUG_UI_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.OTP_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; @@ -60,6 +61,17 @@ void otpConfig(Path filename) { testConfig(filename, nodeAdapter -> new OtpConfig(nodeAdapter, true)); } + @FilePatternSource( + pattern = { + "doc/user/examples/**/" + DEBUG_UI_CONFIG_FILENAME, + "application/src/test/resources/standalone/config/" + DEBUG_UI_CONFIG_FILENAME, + } + ) + @ParameterizedTest(name = "Check validity of {0}") + void debugUiConfig(Path filename) { + testConfig(filename, nodeAdapter -> new DebugUiConfig(nodeAdapter, true)); + } + @FilePatternSource( pattern = { "application/src/test/resources/standalone/config/invalid-config.json" } ) diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index a1a188ca76a..66858390ab5 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -4,7 +4,7 @@ "positron": { "name": "Positron", "tiles": [ - "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png" + "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}{ratio}.png" ], "maxzoom": 19, "tileSize": 256, diff --git a/application/src/test/resources/standalone/config/debug-ui-config.json b/application/src/test/resources/standalone/config/debug-ui-config.json new file mode 100644 index 00000000000..1ae690a4d37 --- /dev/null +++ b/application/src/test/resources/standalone/config/debug-ui-config.json @@ -0,0 +1,9 @@ +{ + "additionalBackgroundLayers": [ + { + "name": "TriMet aerial photos", + "templateUrl": "https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials", + "attribution": "© TriMet" + } + ] +} diff --git a/doc/templates/DebugUiConfiguration.md b/doc/templates/DebugUiConfiguration.md new file mode 100644 index 00000000000..a54b1db8d2a --- /dev/null +++ b/doc/templates/DebugUiConfiguration.md @@ -0,0 +1,23 @@ + + +# Debug UI configuration + +The Debug UI is the standard interface that is bundled with OTP and available by visiting +[`http://localhost:8080`](http://localhost:8080). This page list the configuration options available +by placing a file `debug-ui-config.json` into OTP's working directory. + + + + +## Parameter Details + + + +## Config Example + + diff --git a/doc/user/DebugUiConfiguration.md b/doc/user/DebugUiConfiguration.md new file mode 100644 index 00000000000..5719a606d4a --- /dev/null +++ b/doc/user/DebugUiConfiguration.md @@ -0,0 +1,66 @@ + + +# Debug UI configuration + +The Debug UI is the standard interface that is bundled with OTP and available by visiting +[`http://localhost:8080`](http://localhost:8080). This page list the configuration options available +by placing a file `debug-ui-config.json` into OTP's working directory. + + + + +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|-----------------------------------------------------------|:----------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------:|-----------------------|:-----:| +| [additionalBackgroundLayers](#additionalBackgroundLayers) | `object[]` | Additional background raster map layers. | *Optional* | | 2.7 | +|       attribution | `string` | Attribution for the map data. | *Optional* | `"© OpenTripPlanner"` | 2.7 | +|       name | `string` | Name to appear in the layer selector. | *Required* | | 2.7 | +|       templateUrl | `string` | The [Maplibre-compatible template URL](https://maplibre.org/maplibre-native/ios/api/tile-url-templates.html) for the raster layer, for example `https://examples.com/tiles/{z}/{x}/{y}.png`. | *Required* | | 2.7 | +|       tileSize | `integer` | Size of the tile in pixels. | *Optional* | `256` | 2.7 | + + + + +## Parameter Details + + + + +

additionalBackgroundLayers

+ +**Since version:** `2.7` ∙ **Type:** `object[]` ∙ **Cardinality:** `Optional` +**Path:** / + +Additional background raster map layers. + +Add additional background layers that will appear in the Debug UI as one of the choices. + +Current only raster tile layers are supported. + + + + + +## Config Example + + + + +```JSON +// debug-ui-config.json +{ + "additionalBackgroundLayers" : [ + { + "name" : "TriMet aerial photos", + "templateUrl" : "https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials", + "attribution" : "© TriMet" + } + ] +} +``` + + diff --git a/mkdocs.yml b/mkdocs.yml index b40f77ff3c0..51245f6c3b8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,6 +82,7 @@ nav: - Router: 'RouterConfiguration.md' - "Route Request": 'RouteRequest.md' - "Realtime Updaters": 'UpdaterConfig.md' + - "Debug UI": 'DebugUiConfiguration.md' - "Migrating between versions/builds": 'Migrating-Configuration.md' - Features explained: - "Routing modes": 'RoutingModes.md' From 57c65936bf55a8a99690bff9a145220d84419896 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 14:48:21 +0100 Subject: [PATCH 10/16] Update config scope docs --- doc/templates/Configuration.md | 7 ++++--- doc/user/Configuration.md | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/templates/Configuration.md b/doc/templates/Configuration.md index 45b2c36c67b..39843b57077 100644 --- a/doc/templates/Configuration.md +++ b/doc/templates/Configuration.md @@ -41,9 +41,9 @@ default behavior of scanning the base directory for input files. Scanning is ove independently for each file type, and can point to remote cloud storage with arbitrary URIs. See [the storage section](Configuration.md#Storage) for further details. -## Three Scopes of Configuration +## Four scopes of configuration -OTP is configured via three configuration JSON files which are read from the directory specified on +OTP is configured via four configuration JSON files which are read from the directory specified on its command line. We try to provide sensible defaults for every option, so all three of these files are optional, as are all the options within each file. Each configuration file corresponds to options that are relevant at a particular phase of OTP usage. @@ -51,7 +51,8 @@ options that are relevant at a particular phase of OTP usage. Options and parameters that are taken into account during the graph building process will be "baked into" the graph, and cannot be changed later in a running server. These are specified in `build-config.json`. Other details of OTP operation can be modified without rebuilding the graph. -These run-time configuration options are found in `router-config.json`. Finally, `otp-config.json` +These run-time configuration options are found in `router-config.json`. If you want to configure +the built-in debug UI add `debug-ui-config.json`. Finally, `otp-config.json` contains simple switches that enable or disable system-wide features. ## Configuration types diff --git a/doc/user/Configuration.md b/doc/user/Configuration.md index f80966b8cb3..21a8fcc61eb 100644 --- a/doc/user/Configuration.md +++ b/doc/user/Configuration.md @@ -41,9 +41,9 @@ default behavior of scanning the base directory for input files. Scanning is ove independently for each file type, and can point to remote cloud storage with arbitrary URIs. See [the storage section](Configuration.md#Storage) for further details. -## Three Scopes of Configuration +## Four scopes of configuration -OTP is configured via three configuration JSON files which are read from the directory specified on +OTP is configured via four configuration JSON files which are read from the directory specified on its command line. We try to provide sensible defaults for every option, so all three of these files are optional, as are all the options within each file. Each configuration file corresponds to options that are relevant at a particular phase of OTP usage. @@ -51,7 +51,8 @@ options that are relevant at a particular phase of OTP usage. Options and parameters that are taken into account during the graph building process will be "baked into" the graph, and cannot be changed later in a running server. These are specified in `build-config.json`. Other details of OTP operation can be modified without rebuilding the graph. -These run-time configuration options are found in `router-config.json`. Finally, `otp-config.json` +These run-time configuration options are found in `router-config.json`. If you want to configure +the built-in debug UI add `debug-ui-config.json`. Finally, `otp-config.json` contains simple switches that enable or disable system-wide features. ## Configuration types From c6c6c3bcdaedf9bdbcc0b12aa807e375d9a35e4a Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 15:09:13 +0100 Subject: [PATCH 11/16] Fix TS linting --- client/src/components/MapView/LayerControl.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/MapView/LayerControl.tsx b/client/src/components/MapView/LayerControl.tsx index e3e87fba7bd..a41e7f133a4 100644 --- a/client/src/components/MapView/LayerControl.tsx +++ b/client/src/components/MapView/LayerControl.tsx @@ -46,7 +46,7 @@ class LayerControl implements IControl { const select = document.createElement('select'); this.container.appendChild(select); - let rasterLayers = map + const rasterLayers = map .getLayersOrder() .map((l) => map.getLayer(l)) .filter((layer) => !!layer) From 8395345b2483909862baf459c5fce0ae934f8bc8 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:15:09 +0100 Subject: [PATCH 12/16] DebugUiConfig doesn't need to be Serializable --- .../org/opentripplanner/standalone/config/DebugUiConfig.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index 165bcfe28f4..00f59cd342b 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.MissingNode; -import java.io.Serializable; import java.util.List; import org.opentripplanner.standalone.config.debuguiconfig.BackgroundTileLayer; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; @@ -14,7 +13,7 @@ /** * This class is an object representation of the 'debug-ui-config.json'. */ -public class DebugUiConfig implements Serializable { +public class DebugUiConfig { private static final Logger LOG = LoggerFactory.getLogger(DebugUiConfig.class); From d831ec4943c8888d308064e85188ddf5d5e369d5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:15:30 +0100 Subject: [PATCH 13/16] Update application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java Co-authored-by: Joel Lappalainen --- .../org/opentripplanner/standalone/config/DebugUiConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index 00f59cd342b..079ba8ea84c 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -46,7 +46,7 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { """ Add additional background layers that will appear in the Debug UI as one of the choices. - Current only raster tile layers are supported. + Currently only raster tile layers are supported. """ ) .asObjects( From 2ac997f8e3cefe497761361af41b4e4372418809 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:20:26 +0100 Subject: [PATCH 14/16] Update docs --- doc/user/DebugUiConfiguration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/DebugUiConfiguration.md b/doc/user/DebugUiConfiguration.md index 5719a606d4a..a1657796fe0 100644 --- a/doc/user/DebugUiConfiguration.md +++ b/doc/user/DebugUiConfiguration.md @@ -39,7 +39,7 @@ Additional background raster map layers. Add additional background layers that will appear in the Debug UI as one of the choices. -Current only raster tile layers are supported. +Currently only raster tile layers are supported. From a83afac6bbd88958562e35d8858c0bff717ed7f5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:21:34 +0100 Subject: [PATCH 15/16] Remove check for LOG.isWarnEnabled() --- .../org/opentripplanner/standalone/config/DebugUiConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index 079ba8ea84c..cca6d2359be 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -77,7 +77,7 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { ) ); - if (logUnusedParams && LOG.isWarnEnabled()) { + if (logUnusedParams) { root.logAllWarnings(LOG::warn); } } From 20696c1d6e78902f8dd9d1e6ba31de993caf7789 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 09:56:39 +0100 Subject: [PATCH 16/16] Use 'OTP Debug' in the UI --- client/index.html | 2 +- client/src/components/SearchBar/SearchBar.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/index.html b/client/index.html index 77eb289e595..f09832636f0 100644 --- a/client/index.html +++ b/client/index.html @@ -4,7 +4,7 @@ - OTP Debug Client + OTP Debug
diff --git a/client/src/components/SearchBar/SearchBar.tsx b/client/src/components/SearchBar/SearchBar.tsx index 47781532179..e90a54eab80 100644 --- a/client/src/components/SearchBar/SearchBar.tsx +++ b/client/src/components/SearchBar/SearchBar.tsx @@ -34,7 +34,7 @@ export function SearchBar({ onRoute, tripQueryVariables, setTripQueryVariables,
setShowServerInfo((v) => !v)}>
- OTP Debug Client + OTP Debug {showServerInfo && }