diff --git a/_posts/2023-10-30-maps-3.md b/_posts/2023-10-30-maps-3.md index c55734e..f5a4d9a 100644 --- a/_posts/2023-10-30-maps-3.md +++ b/_posts/2023-10-30-maps-3.md @@ -5,7 +5,7 @@ excerpt: | PMTiles is a cool new technology to serve interactive vector maps from a static file. image: -thumbnail: +thumbnail: /assets/blog/pmtiles/thumbnail.png head: | @@ -16,8 +16,12 @@ PMTiles is a new project that lets you serve vector map data from static files t By following this [blog post][blog] and throwing in a bit of code from [the official examples][official_examples] I've put together this little map below. The vector data is entirely served from a static file on this server. Most interactive web maps work by constantly requesting little map images from an external server at different zoom levels. This approach uses much less data and doesn't require an external server to host all the map data. +Todo: +- Figure out how to use [maputnik][maputnik] to generate styles for PMTiles. + [blog]: https://til.simonwillison.net/gis/pmtiles [official_examples]: https://github.com/protomaps/PMTiles/blob/main/js/examples/maplibre.html +[maputnik]: maputnik.github.io/editor/
@@ -36,7 +40,7 @@ By following this [blog post][blog] and throwing in a bit of code from [the offi let isDark = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) async function getLayers(isDark) { - let style_name = isDark ? "dark.json" : "light.json"; + let style_name = isDark ? "dark.json" : "custom.json"; const base = '{{"/assets/blog/pmtiles/" | relative_url}}'; let resp = await fetch(base + style_name); let layers = await resp.json(); diff --git a/_projects/lego_adapters.md b/_projects/lego_adapters.md index a06081f..96b03ab 100644 --- a/_projects/lego_adapters.md +++ b/_projects/lego_adapters.md @@ -5,7 +5,7 @@ excerpt: Adapters to use common components with lego technic. permalink: /projects/lego_adapters img: - src: /assets/projects/lego_adapters/bw_thumbnail.svg + src: /assets/projects/lego_adapters/thumbnail.svg alt: class: invertable --- \ No newline at end of file diff --git a/assets/blog/pmtiles/custom.json b/assets/blog/pmtiles/custom.json new file mode 100644 index 0000000..d20fe67 --- /dev/null +++ b/assets/blog/pmtiles/custom.json @@ -0,0 +1,166 @@ +[ + { + "id": "water", + "type": "fill", + "source": "static_hackney", + "source-layer": "water", + "filter": ["all"], + "layout": {"visibility": "visible"} + }, + { + "id": "roads_major", + "type": "line", + "source": "static_hackney", + "source-layer": "roads", + "filter": [ + "all", + [ + "==", + "pmap:level", + 0 + ], + [ + "==", + "pmap:kind", + "major_road" + ] + ], + "paint": { + "line-color": "black", + "line-width": 1.6 + } + }, + { + "id": "roads_medium", + "type": "line", + "source": "static_hackney", + "source-layer": "roads", + "minzoom": 0, + "filter": [ + "all", + [ + "==", + "pmap:level", + 0 + ], + [ + "==", + "pmap:kind", + "medium_road" + ] + ], + "paint": { + "line-color": "black", + "line-width": 1 + } + }, + { + "id": "roads_minor", + "type": "line", + "source": "static_hackney", + "source-layer": "roads", + "minzoom": 0, + "filter": [ + "all", + [ + "==", + "pmap:level", + 0 + ], + [ + "==", + "pmap:kind", + "minor_road" + ] + ], + "paint": { + "line-color": "black", + "line-width": 1 + } + }, + { + "id": "roads_labels_minor", + "type": "symbol", + "source": "static_hackney", + "source-layer": "roads", + "minzoom": 15, + "filter": [ + "any", + [ + "in", + "pmap:kind", + "minor_road", + "other", + "path" + ] + ], + "layout": { + "symbol-sort-key": [ + "get", + "pmap:min_zoom" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular" + ], + "text-field": [ + "get", + "name" + ], + "text-size": 12 + }, + "paint": { + "text-color": "#000000", + "text-halo-color": "#ffffff", + "text-halo-width": 2 + } + }, + { + "id": "landuse_park", + "type": "fill", + "source": "static_hackney", + "source-layer": "landuse", + "filter": [ + "any", + [ + "in", + "pmap:kind", + "national_park", + "park", + "cemetery", + "protected_area", + "nature_reserve", + "forest", + "golf_course", + "hospital", + "industrial", + "school", + "university", + "college" + ] + ], + "paint": { + "fill-color": "black", + "fill-opacity": 0.1 + } + }, + { + "id": "natural_wood", + "type": "fill", + "source": "static_hackney", + "source-layer": "natural", + "filter": [ + "any", + [ + "in", + "pmap:kind", + "wood", + "nature_reserve", + "forest" + ] + ], + "paint": { + "fill-color": "black" + } + } +] \ No newline at end of file diff --git a/assets/blog/pmtiles/thumbnail.png b/assets/blog/pmtiles/thumbnail.png new file mode 100644 index 0000000..e53bee0 Binary files /dev/null and b/assets/blog/pmtiles/thumbnail.png differ diff --git a/assets/blog/pmtiles/toner.json b/assets/blog/pmtiles/toner.json new file mode 100644 index 0000000..3cfaaec --- /dev/null +++ b/assets/blog/pmtiles/toner.json @@ -0,0 +1,434 @@ +[ + { + "id": "background", + "type": "background", + "paint": {"background-color": "#fff"} + }, + { + "id": "landcover_wood", + "type": "fill", + "source": "static_hackney", + "source-layer": "landcover", + "filter": ["==", "class", "wood"], + "paint": { + "fill-color": "rgba(218, 218, 218, 0.51)", + "fill-opacity": {"base": 1, "stops": [[8, 0.6], [22, 1]]} + } + }, + { + "id": "landcover-grass", + "type": "fill", + "metadata": {"mapbox:group": "1444849388993.3071"}, + "source": "static_hackney", + "source-layer": "landcover", + "filter": ["==", "class", "grass"], + "paint": {"fill-color": "rgba(236, 235, 235, 1)", "fill-opacity": 1} + }, + { + "id": "water", + "type": "fill", + "source": "static_hackney", + "source-layer": "water", + "filter": ["all", ["!=", "brunnel", "tunnel"]], + "layout": {"visibility": "visible"}, + "paint": {} + }, + { + "id": "building", + "type": "fill", + "metadata": {"mapbox:group": "1444849364238.8171"}, + "source": "static_hackney", + "source-layer": "building", + "layout": {"visibility": "visible"}, + "paint": { + "fill-antialias": true, + "fill-color": { + "base": 1, + "stops": [ + [15.5, "rgba(241, 240, 240, 1)"], + [16, "rgba(212, 212, 212, 1)"] + ] + } + } + }, + { + "id": "building-top", + "type": "fill", + "metadata": {"mapbox:group": "1444849364238.8171"}, + "source": "static_hackney", + "source-layer": "building", + "layout": {"visibility": "visible"}, + "paint": { + "fill-color": "rgba(249, 249, 249, 1)", + "fill-opacity": {"base": 1, "stops": [[13, 0], [16, 1]]}, + "fill-outline-color": "rgba(181, 180, 179, 1)", + "fill-translate": {"base": 1, "stops": [[14, [0, 0]], [16, [-2, -2]]]} + } + }, + { + "id": "boundary-admin2_z0-4", + "type": "line", + "metadata": {}, + "source": "static_hackney", + "source-layer": "boundary", + "maxzoom": 5, + "filter": ["all", ["==", "admin_level", 2], ["!has", "claimed_by"]], + "layout": {"visibility": "visible"}, + "paint": {"line-width": 0.5} + }, + { + "id": "boundary-admin2_z5-", + "type": "line", + "metadata": {}, + "source": "static_hackney", + "source-layer": "boundary", + "minzoom": 5, + "filter": ["==", "admin_level", 2], + "layout": {"visibility": "visible"}, + "paint": {"line-width": 0.5} + }, + { + "id": "transportation", + "type": "line", + "metadata": {}, + "source": "static_hackney", + "source-layer": "transportation", + "filter": ["all", ["==", "$type", "LineString"], ["!=", "class", "pier"]], + "layout": {"visibility": "visible"}, + "paint": { + "line-color": { + "stops": [[12, "rgba(212, 209, 209, 1)"], [16, "rgba(8, 8, 8, 1)"]] + }, + "line-width": {"stops": [[12, 0.5], [16, 1], [17, 3]]} + } + }, + { + "id": "road_area_pier", + "type": "fill", + "metadata": {}, + "source": "static_hackney", + "source-layer": "transportation", + "filter": ["all", ["==", "$type", "Polygon"], ["==", "class", "pier"]], + "layout": {"visibility": "visible"}, + "paint": { + "fill-antialias": true, + "fill-color": "rgb(242,243,240)", + "fill-opacity": 1 + } + }, + { + "id": "road_pier", + "type": "line", + "metadata": {}, + "source": "static_hackney", + "source-layer": "transportation", + "filter": ["all", ["==", "$type", "LineString"], ["in", "class", "pier"]], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(242,243,240)", + "line-width": {"base": 1.2, "stops": [[15, 1], [17, 4]]} + } + }, + { + "id": "place_label_other", + "type": "symbol", + "source": "static_hackney", + "source-layer": "place", + "minzoom": 8, + "filter": [ + "all", + ["==", "$type", "Point"], + ["!in", "class", "city", "state", "country", "continent"] + ], + "layout": { + "text-anchor": "center", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-max-width": 6, + "text-size": {"stops": [[6, 10], [12, 14]]}, + "visibility": "visible" + }, + "paint": { + "text-color": "hsl(0, 10%, 25%)", + "text-halo-blur": 0, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 2 + } + }, + { + "id": "highway-name-minor", + "type": "symbol", + "source": "static_hackney", + "source-layer": "transportation_name", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["in", "class", "minor", "service", "track"] + ], + "layout": { + "symbol-placement": "line", + "text-field": "{name:latin} {name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-rotation-alignment": "map", + "text-size": {"base": 1, "stops": [[13, 12], [14, 13]]}, + "visibility": "visible" + }, + "paint": { + "text-color": "rgba(0, 0, 0, 1)", + "text-halo-blur": 0.5, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 1 + } + }, + { + "id": "highway-name-major", + "type": "symbol", + "source": "static_hackney", + "source-layer": "transportation_name", + "minzoom": 12.2, + "filter": ["in", "class", "primary", "secondary", "tertiary", "trunk"], + "layout": { + "symbol-placement": "line", + "text-field": "{name:latin} {name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-rotation-alignment": "map", + "text-size": {"base": 1, "stops": [[13, 12], [14, 13]]} + }, + "paint": { + "text-color": "rgba(0, 0, 0, 1)", + "text-halo-blur": 0.5, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 1 + } + }, + { + "id": "place_label_city", + "type": "symbol", + "source": "static_hackney", + "source-layer": "place", + "maxzoom": 16, + "filter": ["all", ["==", "$type", "Point"], ["==", "class", "city"]], + "layout": { + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-max-width": 10, + "text-size": {"stops": [[3, 12], [8, 16]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-blur": 0, + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 2 + } + }, + { + "id": "place-continent", + "type": "symbol", + "source": "static_hackney", + "source-layer": "place", + "filter": ["==", "class", "continent"], + "layout": { + "text-field": "{name:latin}", + "text-font": ["Metropolis Extra Bold Italic"], + "text-line-height": 1.5, + "text-max-width": 4, + "text-size": 13, + "visibility": "visible" + }, + "paint": {"text-halo-color": "#fff", "text-halo-width": 2} + }, + { + "id": "place-country", + "type": "symbol", + "source": "static_hackney", + "source-layer": "place", + "filter": ["==", "class", "country"], + "layout": { + "text-field": "{name:latin}", + "text-font": ["Noto Sans Bold"], + "text-size": 12, + "visibility": "visible" + }, + "paint": {"text-halo-color": "#fff", "text-halo-width": 1.5} + }, + { + "id": "poi-level-1", + "type": "symbol", + "source": "static_hackney", + "source-layer": "poi", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "Point"], + ["<=", "rank", 14], + ["has", "name"] + ], + "layout": { + "text-anchor": "top", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Italic"], + "text-max-width": 9, + "text-offset": [0, 0.6], + "text-padding": 2, + "text-size": 12 + }, + "paint": { + "text-color": "rgba(72, 71, 71, 1)", + "text-halo-blur": 0.8, + "text-halo-color": "#ffffff", + "text-halo-width": 1 + } + }, + { + "id": "waterway-name", + "type": "symbol", + "source": "static_hackney", + "source-layer": "waterway", + "minzoom": 13, + "filter": ["all", ["==", "$type", "LineString"], ["has", "name"]], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 350, + "text-field": "{name:latin} {name:nonlatin}", + "text-font": ["Noto Sans Italic"], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-rotation-alignment": "map", + "text-size": 14 + }, + "paint": { + "text-color": "rgba(6, 6, 6, 1)", + "text-halo-color": "rgba(245, 242, 242, 0.83)", + "text-halo-width": 1.5 + } + }, + { + "id": "water-name-lakeline", + "type": "symbol", + "source": "static_hackney", + "source-layer": "water_name", + "filter": ["==", "$type", "LineString"], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 350, + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Italic"], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-rotation-alignment": "map", + "text-size": 14 + }, + "paint": { + "text-color": "rgba(255, 255, 255, 1)", + "text-halo-color": "rgba(255, 255, 255, 0)", + "text-halo-width": 1.5 + } + }, + { + "id": "water-name-ocean", + "type": "symbol", + "source": "static_hackney", + "source-layer": "water_name", + "filter": ["all", ["==", "$type", "Point"], ["==", "class", "ocean"]], + "layout": { + "symbol-placement": "point", + "symbol-spacing": 350, + "text-field": "{name:latin}", + "text-font": ["Noto Sans Italic"], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-rotation-alignment": "map", + "text-size": 14, + "text-transform": "uppercase" + }, + "paint": { + "text-color": "rgba(255, 255, 255, 1)", + "text-halo-color": "rgba(255, 255, 255, 0)", + "text-halo-width": 1.5 + } + }, + { + "id": "water-name-other", + "type": "symbol", + "source": "static_hackney", + "source-layer": "water_name", + "filter": ["all", ["==", "$type", "Point"], ["!in", "class", "ocean"]], + "layout": { + "symbol-placement": "point", + "symbol-spacing": 350, + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Italic"], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-rotation-alignment": "map", + "text-size": {"stops": [[0, 10], [6, 14]]}, + "visibility": "visible" + }, + "paint": { + "text-color": "rgba(255, 255, 255, 1)", + "text-halo-color": "rgba(255, 255, 255, 0)", + "text-halo-width": 1.5 + } + }, + { + "id": "boundary_state", + "type": "line", + "metadata": {"mapbox:group": "a14c9607bc7954ba1df7205bf660433f"}, + "source": "static_hackney", + "source-layer": "boundary", + "filter": ["==", "admin_level", 4], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-blur": 0.4, + "line-color": "rgba(72, 70, 70, 1)", + "line-dasharray": [0.5, 2], + "line-opacity": 1, + "line-width": {"base": 1.3, "stops": [[3, 1], [22, 15]]} + } + }, + { + "id": "boundary_country_z0-4", + "type": "line", + "metadata": {"mapbox:group": "a14c9607bc7954ba1df7205bf660433f"}, + "source": "static_hackney", + "source-layer": "boundary", + "maxzoom": 5, + "filter": ["all", ["==", "admin_level", 2], ["!has", "claimed_by"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-blur": {"base": 1, "stops": [[0, 0.4], [22, 4]]}, + "line-color": "rgba(82, 81, 81, 1)", + "line-opacity": 1, + "line-width": {"base": 1.1, "stops": [[3, 1], [22, 20]]} + } + }, + { + "id": "boundary_country_z5-", + "type": "line", + "metadata": {"mapbox:group": "a14c9607bc7954ba1df7205bf660433f"}, + "source": "static_hackney", + "source-layer": "boundary", + "minzoom": 5, + "filter": ["==", "admin_level", 2], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "none" + }, + "paint": { + "line-blur": {"base": 1, "stops": [[0, 0.4], [22, 4]]}, + "line-color": "rgba(82, 81, 81, 1)", + "line-opacity": 1, + "line-width": {"base": 1.1, "stops": [[3, 1], [22, 20]]} + } + } +] \ No newline at end of file diff --git a/assets/projects/lego_adapters/bw_thumbnail.svg b/assets/projects/lego_adapters/bw_thumbnail.svg deleted file mode 100644 index ad5399c..0000000 --- a/assets/projects/lego_adapters/bw_thumbnail.svg +++ /dev/null @@ -1,795 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/projects/lego_adapters/thumbnail.svg b/assets/projects/lego_adapters/thumbnail.svg new file mode 100644 index 0000000..efb9991 --- /dev/null +++ b/assets/projects/lego_adapters/thumbnail.svg @@ -0,0 +1,1822 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +