Gallery

Every road in a city

Every street, path, and highway, and nothing else. Without buildings, water, or labels, the roads alone show how a city grew: the grid of a planned city, the tangle of an old one, and the gaps where its rivers, rail yards, and parks are.

Build it yourself

The map uses a style of its own: a white background and the tiles' roads layer, with nothing else. A search box sends a city's name to Mapricot's search and flies to the first result. It was tested with MapLibre GL JS 6.15 in Chromium.

What you need

Make the page

Make a folder, and in it index.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Every road in a city</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maplibre-gl@6.15.0/dist/maplibre-gl.css">
  </head>
  <body style="margin: 0">
    <form id="search" style="position: absolute; z-index: 1; top: 10px; left: 10px">
      <input name="q" placeholder="Any city" required>
      <button>Go</button>
    </form>
    <div id="map" style="height: 100vh"></div>
    <script type="module">
      import * as maplibregl from "https://cdn.jsdelivr.net/npm/maplibre-gl@6.15.0/+esm";

      const key = "mapricot_pk_…";
      const widths = { highway: 1.8, major_road: 1.2, minor_road: 0.6, path: 0.3 };

      const map = new maplibregl.Map({
        container: "map",
        style: {
          version: 8,
          sources: {
            protomaps: { type: "vector", url: "https://tiles.mapricot.com/planet.json" },
          },
          layers: [
            { id: "background", type: "background", paint: { "background-color": "#ffffff" } },
            ...Object.entries(widths).map(([kind, width]) => ({
              id: kind,
              type: "line",
              source: "protomaps",
              "source-layer": "roads",
              filter: ["==", ["get", "kind"], kind],
              layout: { "line-cap": "round", "line-join": "round" },
              paint: {
                "line-color": "#212529",
                "line-width": ["interpolate", ["exponential", 1.6], ["zoom"], 11, width * 0.6, 16, width * 5],
              },
            })),
          ],
        },
        center: [-122.66, 45.52],
        zoom: 12,
        minZoom: 10,
      });

      const form = document.querySelector("#search");
      form.addEventListener("submit", async (event) => {
        event.preventDefault();
        const response = await fetch(
          `https://api.mapricot.com/v1/search?q=${encodeURIComponent(form.elements.q.value)}&limit=1`,
          { headers: { Authorization: `Bearer ${key}` } },
        );
        if (!response.ok) throw new Error(`Mapricot returned ${response.status}`);
        const { results } = await response.json();
        if (results.length) map.flyTo({ center: [results[0].lon, results[0].lat], zoom: 12 });
      });
    </script>
  </body>
</html>

Put your browser key in place of mapricot_pk_….

Open it

Serve the folder with npx serve or python3 -m http.server, and open the address it prints. Opened straight from the file, the map stays blank and the API refuses the key, as Open the page explains. You should see Portland's roads in black on white. Type another city and press Go.

Andrei Kashcha's City Roads draws a whole city at once by downloading every road from OpenStreetMap's Overpass API. For a search box with suggestions as you type, see Add a search box to a MapLibre map.

Data