Skip to content

Commit

Permalink
Generate legend on demand (#632)
Browse files Browse the repository at this point in the history
* Added shield legend

* Label networks using Wikidata

* Link image instead of definition

* Factored out templates, helper functions

* Link to Wikidata query

* Added place labels to legend

* Group shields by country

* Sort Other shields to bottom; scroll legend

* Refactored symbol legends

* Generate legend sections dynamically

* Cleaned up legend layout

Moved labels to the left of icons. Capped label width.

Purge and refresh Wikidata query for network metadata whenever the language changes.

* Documented Wikidata network item usage

* Added urbanized areas to legend

Generalized the symbol layer legending to display a swatch for fill layers.

* Added state, country, continent to legend

Flattened the label into the label table cell to keep it from overflowing.

* Added parks to legend

* Added lakes to legend

* Added low-zoom lakes to legend

* Added waterways to legend

* Added ferry lines to legend

* Fixed water confusion in legend

Ferries are not rivers.

* Added airport details to legend

* Added buildings to legend

* Simplified park layers

* Removed debugging

* Streamlined feature querying

Pushed a layer list into each entry. This requires querying the map separately for each entry but avoids crosstalk. Replaced bespoke property matching with expression-based filters.

* Simplified entry matching

The entry wasn’t getting cloned anyways.

* Added borders to legend

* Added disputed borders to legend

* Added freeways, toll roads to legend

* Added highway exits to legend

* Moved international shield category to top

* Fixed text halo

* Fixed non-capital filter

* Added more road classes to legend

* Added remaining road classes

* Added driveways to legend

* Added unpaved roads to legend

* Added roads under construction to legend

* Added railroads to legend

* Moved legend config to separate file

* Fixed build errors; sort shield rows

Fixed build errors from moving sections into a separate configuration file. Sort shield rows in the same order as in the shield definitions, followed by unrecognized networks.

* Added shield variants to legend

* Updated documentation

* Locale-aware sort countries

* Singular descriptions in rail legend entries

* Normalize country code case

* Sentence-case Wikidata labels

* Made colon after country code optional

Some countries like Brazil simply use the country code alone for their national route network.

* BAB is not a country

* More kinds of recreational route networks

* Typo in readme

* Treat fake OMT network prefixes like real country prefixes

* Special-case UK route types

* Fetch UK network descriptions from Wikidata

* Fixed error when text-field uses string interpolation syntax

* Added comments

* Italicize labels in legend based on font layout property

* Added comments, tests

Added inline comments throughout the less straightforward legend methods. Factored out shield image name parsing code and added tests of it.

* Link networks to Wikidata

* Removed special case for TLA recreational route networks

* Removed unused UK label constants

* Fixed coalescing of 0 values

* Omit fully transparent roads from legend

* Fixed typo in comment

* Deleted redundant Kosovo shield

* Simplified Australian shield assignment
  • Loading branch information
1ec5 authored Jan 3, 2023
1 parent e5fe35b commit 820a1fe
Show file tree
Hide file tree
Showing 21 changed files with 1,439 additions and 136 deletions.
11 changes: 8 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,17 @@ boilerplate in `scripts/taginfo_template.json`.

1. Please prettify all files prior to submission. Run `npm run code_format` to
format code files with [prettier][90] and SVG files with [SVGO][svgo].
2. If you are introducing a novel approach to depicting a layer or feature
2. If you are introducing a new kind of feature to the style, add a section to
`src/js/legend_config.js` or a legend entry in the corresponding file in
`src/layer/` that tells the Legend control how to find and render a
representative feature. Also try out the Samples button to catch any visual
conflicts.
3. If you are introducing a novel approach to depicting a layer or feature
property from the OpenMapTiles schema, document how the corresponding
OpenStreetMap key or tag is used in `scripts/taginfo_template.json`.
3. If any shield background icons are introduced, add lines to `src/shieldtest.js`
4. If any shield background icons are introduced, add lines to `src/shieldtest.js`
to demonstrate overlaid text on each of them.
4. If you are introducing new JavaScript code that can run independently of a
5. If you are introducing new JavaScript code that can run independently of a
browser environment, add automated unit tests for it to `test/spec/`, then
run `npm test` to ensure that they pass. This project structures unit tests
using [Chai](https://www.chaijs.com/guide/styles/) for assertions.
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The Americana style is the first digital map to achieve concurrent, state-specif

## How to use

You can install the OpenStreetMap Americana package and [deploy it anywhere](CONTRIBUTING.md#Production%20builds) as a static webpage. For your convenience, we’ve deployed it [on GitHub Pages](https://zelonewolf.github.io/openstreetmap-americana/). To explore how the style depicts various features, click the Samples button.
You can install the OpenStreetMap Americana package and [deploy it anywhere](CONTRIBUTING.md#Production%20builds) as a static webpage. For your convenience, we’ve deployed it [on GitHub Pages](https://zelonewolf.github.io/openstreetmap-americana/). Click the Legend button to learn the meaning of each symbol, line, and color based on the features currently visible on the map.

The style tries to label places in [your browser’s preferred language](https://www.w3.org/International/questions/qa-lang-priorities). To change this preference, consult your browser’s documentation: [Chrome](https://support.google.com/chrome/answer/173424), [Firefox](https://support.mozilla.org/en-US/kb/use-firefox-another-language), [Safari for macOS](https://support.apple.com/guide/mac-help/change-the-system-language-mh26684/mac), [Safari for iOS](https://support.apple.com/en-us/HT204031). You can also override this preference by adding `&language=` to the URL, followed by a comma-separated list of [IETF language tags](https://www.w3.org/International/articles/language-tags/). For example, here’s a map labeled [in Portuguese, falling back to Spanish](https://zelonewolf.github.io/openstreetmap-americana/#language=pt,es). If we don’t have the name of a place in any of your preferred languages, the style shows the name in the local language as a last resort.

Expand Down Expand Up @@ -55,6 +55,8 @@ The OpenStreetMap Americana style is built upon the [OpenMapTiles schema](https:
- Translated name labels from [Wikidata](https://www.wikidata.org/wiki/Wikidata:Main_Page) for places, POIs, airports, roads, bodies of water, parks, and mountain peaks.
- Low-zoom ocean/water, boundary, and urbanized area data from [Natural Earth](https://www.naturalearthdata.com/).

The legend’s “Route markers” section is labeled using labels of Wikidata items that are tagged with the [corresponding OSM tag](https://www.wikidata.org/wiki/Property:P1282).

## Coverage

Americana is compatible with vector tiles covering the entire world.
Expand Down
33 changes: 9 additions & 24 deletions src/americana.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import config from "./config.js";

import * as Label from "./constants/label.js";

import * as Util from "./js/util.js";
import * as Shield from "./js/shield.js";
import * as ShieldDef from "./js/shield_defs.js";

Expand All @@ -31,6 +30,8 @@ import * as maplibregl from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
import * as search from "./search.js";

import LegendControl from "./js/legend_control.js";
import * as LegendConfig from "./js/legend_config.js";
import SampleControl from "openmapsamples-maplibre/OpenMapSamplesControl.js";
import { default as OpenMapTilesSamples } from "openmapsamples/samples/OpenMapTiles/index.js";

Expand Down Expand Up @@ -205,28 +206,7 @@ function buildLayers() {
lyrOneway.bridgeLink,
];

//Render bridge without layer on the lowest bridge layer
bridgeLayers.forEach((layer) =>
layers.push(
Util.filteredClone(layer, ["!", ["has", "layer"]], "_layer_bottom")
)
);

//One layer at a time to handle stacked bridges
for (let i = 1; i <= 4; i++) {
bridgeLayers.forEach((layer) => layers.push(Util.restrictLayer(layer, i)));
}

//If layer is more than 5, just give up and render on a single layer.
bridgeLayers.forEach((layer) =>
layers.push(
Util.filteredClone(
layer,
[">=", ["coalesce", ["get", "layer"], 0], 5],
"_layer_top"
)
)
);
layers.push(...lyrRail.getLayerSeparatedBridgeLayers(bridgeLayers));

layers.push(
//The labels at the end of the list draw on top of the layers at the beginning.
Expand Down Expand Up @@ -326,14 +306,17 @@ map.on("styleimagemissing", function (e) {
Shield.missingIconHandler(map, e);
});

export function hotReloadMap() {
function hotReloadMap() {
map.setStyle(buildStyle());
}

export function updateLanguageLabel() {
languageLabel.displayLocales(Label.getLocales());
legendControl.onLanguageChange();
}

let legendControl = new LegendControl();
legendControl.sections = LegendConfig.sections;
window.addEventListener("languagechange", (event) => {
console.log(`Changed to ${navigator.languages}`);
hotReloadMap();
Expand Down Expand Up @@ -372,6 +355,8 @@ if (config.ATTRIBUTION_LOGO != undefined) {
map.addControl(new search.PhotonSearchControl(), "top-left");
map.addControl(new maplibregl.NavigationControl(), "top-left");

map.addControl(legendControl, "bottom-left");

// Add our sample data.
let sampleControl = new SampleControl({ permalinks: true });
OpenMapTilesSamples.forEach((sample, i) => {
Expand Down
95 changes: 95 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,58 @@
.openmapsamples-control-container {
margin-left: 70px !important;
}

#legend-container {
max-height: 60vh;
overflow-y: scroll;
}
.legend-section > summary {
background-color: #eee;
}
.legend-row,
.legend-row img {
vertical-align: middle;
}
.legend-row a {
color: black;
}
.legend-row > .label,
.legend-row > .icon {
width: 0;
text-align: center;
}
.legend-row > .icon {
white-space: nowrap;
}
.legend-row .shield + .shield {
margin-left: 0.2em;
}
.legend-row > .swatch,
.legend-row > .line {
vertical-align: middle;
width: 4em;
}
.legend-row > .swatch {
border-style: solid;
}
.legend-row > .line > svg {
vertical-align: middle;
width: 100%;
}
.legend-row .language {
font-style: italic;
font-size: 80%;
line-height: 1;
vertical-align: super;
}
.legend-source {
font-size: 80%;
text-align: right;
}
.legend-source,
.legend-source a {
color: #aaa;
}
</style>
<script type="module" src="americana.js"></script>
<link rel="stylesheet" href="americana.css" />
Expand All @@ -53,5 +105,48 @@
data-recalc-dims="1"
style="position: absolute; top: 0; right: 0; border: 0; z-index: 100"
/></a>
<template id="legend">
<h2>Legend</h2>
<div id="legend-container"></div>
</template>
<template id="legend-section">
<details class="legend-section" open>
<summary></summary>
<table>
<tbody></tbody>
<tfoot>
<tr>
<td class="legend-source" colspan="3"></td>
</tr>
</tfoot>
</table>
</details>
</template>
<template id="legend-rowgroup">
<tr class="legend-rowgroup">
<th colspan="3"></th>
</tr>
</template>
<template id="legend-row-symbol">
<tr class="legend-row legend-row-symbol">
<td class="label"></td>
<td class="icon"></td>
<td class="description"></td>
</tr>
</template>
<template id="legend-row-swatch">
<tr class="legend-row legend-row-swatch">
<td class="swatch" colspan="2"></td>
<td class="description"></td>
</tr>
</template>
<template id="legend-row-line">
<tr class="legend-row legend-row-line">
<td class="line" colspan="2">
<svg></svg>
</td>
<td class="description"></td>
</tr>
</template>
</body>
</html>
58 changes: 58 additions & 0 deletions src/js/legend_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use strict";

import * as PlaceLayers from "../layer/place.js";
import * as LanduseLayers from "../layer/landuse.js";
import * as BoundaryLayers from "../layer/boundary.js";
import * as RoadLayers from "../layer/road.js";
import * as ConstructionLayers from "../layer/construction.js";
import * as HighwayExitLayers from "../layer/highway_exit.js";
import * as RailLayers from "../layer/rail.js";
import * as AerowayLayers from "../layer/aeroway.js";
import * as ParkLayers from "../layer/park.js";
import * as BuildingLayers from "../layer/building.js";
import * as WaterLayers from "../layer/water.js";
import * as FerryLayers from "../layer/ferry.js";

export const sections = [
{
name: "Populated places",
entries: PlaceLayers.legendEntries,
},
{
name: "Borders",
entries: BoundaryLayers.legendEntries,
},
{
name: "Roads",
entries: [
...RoadLayers.legendEntries,
...ConstructionLayers.legendEntries,
...HighwayExitLayers.legendEntries,
],
},
{
id: "shields",
name: "Route markers",
source: "Wikidata",
},
{
name: "Railroads",
entries: RailLayers.legendEntries,
},
{
name: "Aviation",
entries: AerowayLayers.legendEntries,
},
{
name: "Structures",
entries: BuildingLayers.legendEntries,
},
{
name: "Land use",
entries: [...LanduseLayers.legendEntries, ...ParkLayers.legendEntries],
},
{
name: "Water",
entries: [...WaterLayers.legendEntries, ...FerryLayers.legendEntries],
},
];
Loading

0 comments on commit 820a1fe

Please sign in to comment.