diff --git a/package.json b/package.json index d6babc5c4..cf5e6844d 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "immer": "^10.0.2", "lexical": "^0.7.5", "mapbox-gl": "^2.7.0", + "maplibre-gl": "^4.0.2", "nanoid": "^4.0.0", "nanoid-dictionary": "^4.3.0", "next": "^13.5.6", @@ -53,6 +54,7 @@ "nprogress": "^0.2.0", "paper": "^0.12.17", "paperjs-offset": "^1.0.8", + "pmtiles": "^3.0.3", "rc-slider": "^10.0.0-alpha.5", "react": "^18.2.0", "react-content-loader": "^6.2.0", @@ -61,7 +63,7 @@ "react-hook-form": "^7.34.2", "react-hotkeys-hook": "^3.4.7", "react-infinite-scroll-component": "^6.1.0", - "react-map-gl": "^7.0.10", + "react-map-gl": "^7.1.7", "react-markdown": "^9.0.1", "react-paginate": "^8.1.3", "react-responsive": "^9.0.0-beta.6", diff --git a/src/app/(maps)/layout.tsx b/src/app/(maps)/layout.tsx index e54d23b04..c4d83e6f3 100644 --- a/src/app/(maps)/layout.tsx +++ b/src/app/(maps)/layout.tsx @@ -1,4 +1,4 @@ -import 'mapbox-gl/dist/mapbox-gl.css' +import 'maplibre-gl/dist/maplibre-gl.css' import { Metadata } from 'next' import '@/public/fonts/fonts.css' import './../global.css' diff --git a/src/components/maps/BaseMap.tsx b/src/components/maps/BaseMap.tsx index 6ee4685d5..e7461bf2b 100644 --- a/src/components/maps/BaseMap.tsx +++ b/src/components/maps/BaseMap.tsx @@ -17,7 +17,9 @@ export const DEFAULT_INITIAL_VIEWSTATE: XViewStateType = { export const MAP_STYLES = { light: 'mapbox://styles/mappandas/ckf8bb0qv18be19npofybx7yq', - dark: 'mapbox://styles/mappandas/cl0u44wo8008415pedsbgtml7' + dark: 'mapbox://styles/mappandas/cl0u44wo8008415pedsbgtml7', + outdoor: 'https://api.maptiler.com/maps/outdoor-v2/style.json?key=IJlqluHVT3Au1mC0w78q', + dataviz: 'https://api.maptiler.com/maps/dataviz/style.json?key=IJlqluHVT3Au1mC0w78q' } interface BaseMapProps { height: number diff --git a/src/components/maps/GlobalMap.tsx b/src/components/maps/GlobalMap.tsx index 681276f39..281e48429 100644 --- a/src/components/maps/GlobalMap.tsx +++ b/src/components/maps/GlobalMap.tsx @@ -1,13 +1,15 @@ 'use client' import { useCallback, useEffect, useState } from 'react' -import mapboxgl from 'mapbox-gl' -import { Map, ScaleControl, FullscreenControl, NavigationControl, MapLayerMouseEvent, MapInstance } from 'react-map-gl' +import { Map, ScaleControl, FullscreenControl, NavigationControl, MapLayerMouseEvent, MapInstance } from 'react-map-gl/maplibre' +import maplibregl, { MapLibreEvent } from 'maplibre-gl' +import { Protocol } from 'pmtiles' import { Point, Polygon } from '@turf/helpers' import { MAP_STYLES } from './BaseMap' import { AreaInfoDrawer } from './AreaInfoDrawer' import { AreaInfoHover } from './AreaInfoHover' import { SelectedFeature } from './AreaActiveMarker' +import { OBCustomLayers } from './OBCustomLayers' export interface MapAreaFeatureProperties { id: string @@ -54,10 +56,10 @@ export const GlobalMap: React.FC = ({ showFullscreenControl = tr }) }, []) - const onLoad = useCallback((e: mapboxgl.MapboxEvent) => { + const onLoad = useCallback((e: MapLibreEvent) => { setMapInstance(e.target) if (initialCenter != null) { - e.target.jumpTo({ center: initialCenter }) + e.target.jumpTo({ center: initialCenter, zoom: 6 }) } }, [initialCenter]) @@ -94,9 +96,18 @@ export const GlobalMap: React.FC = ({ showFullscreenControl = tr } }, [mapInstance]) + useEffect(() => { + const protocol = new Protocol() + maplibregl.addProtocol('pmtiles', protocol.tile) + return () => { + maplibregl.removeProtocol('pmtiles') + } + }, []) + return (
{ @@ -113,11 +124,12 @@ export const GlobalMap: React.FC = ({ showFullscreenControl = tr onClick={onClick} reuseMaps mapboxAccessToken={process.env.NEXT_PUBLIC_MAPBOX_API_KEY} - mapStyle={MAP_STYLES.light} + mapStyle={MAP_STYLES.dataviz} cursor={cursor} cooperativeGestures={showFullscreenControl} interactiveLayerIds={['crags', 'crag-group-boundaries']} > + {showFullscreenControl && } diff --git a/src/components/maps/OBCustomLayers.tsx b/src/components/maps/OBCustomLayers.tsx new file mode 100644 index 000000000..3eeaec35e --- /dev/null +++ b/src/components/maps/OBCustomLayers.tsx @@ -0,0 +1,44 @@ +import { Source, Layer } from 'react-map-gl' + +/** + * OpenBeta custom map tiles + * @returns + */ +export const OBCustomLayers: React.FC = () => { + return ( + + + + ) +} diff --git a/yarn.lock b/yarn.lock index 0e1a812d7..6b32a0b9a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,6 +1726,18 @@ rw "^1.3.3" sort-object "^3.0.3" +"@maplibre/maplibre-gl-style-spec@^20.1.1": + version "20.1.1" + resolved "https://registry.yarnpkg.com/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.1.1.tgz#94b644493723776c34813bd62a223e748390099b" + integrity sha512-z85ARNPCBI2Cs5cPOS3DSbraTN+ue8zrcYVoSWBuNrD/mA+2SKAJ+hIzI22uN7gac6jBMnCdpPKRxS/V0KSZVQ== + dependencies: + "@mapbox/jsonlint-lines-primitives" "~2.0.2" + "@mapbox/unitbezier" "^0.0.1" + json-stringify-pretty-compact "^4.0.0" + minimist "^1.2.8" + rw "^1.3.3" + sort-object "^3.0.3" + "@math.gl/web-mercator@3.6.2": version "3.6.2" resolved "https://registry.npmjs.org/@math.gl/web-mercator/-/web-mercator-3.6.2.tgz" @@ -2632,11 +2644,23 @@ resolved "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz" integrity sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ== +"@types/geojson-vt@3.2.5": + version "3.2.5" + resolved "https://registry.yarnpkg.com/@types/geojson-vt/-/geojson-vt-3.2.5.tgz#b6c356874991d9ab4207533476dfbcdb21e38408" + integrity sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g== + dependencies: + "@types/geojson" "*" + "@types/geojson@*": version "7946.0.11" resolved "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.11.tgz" integrity sha512-L7A0AINMXQpVwxHJ4jxD6/XjZ4NDufaRlUJHjNIFKYUFBH1SvOW+neaqb0VTRSLW5suSrSu19ObFEFnfNcr+qg== +"@types/geojson@^7946.0.14": + version "7946.0.14" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613" + integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg== + "@types/graceful-fs@^4.1.3": version "4.1.7" resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.7.tgz" @@ -2707,6 +2731,13 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/leaflet@^1.9.8": + version "1.9.8" + resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.9.8.tgz#32162a8eaf305c63267e99470b9603b5883e63e8" + integrity sha512-EXdsL4EhoUtGm2GC2ZYtXn+Fzc6pluVgagvo2VC1RHWToLGlTRwVYoDpqS/7QXa01rmDyBjJk3Catpf60VMkwg== + dependencies: + "@types/geojson" "*" + "@types/mapbox-gl@>=1.0.0": version "2.7.14" resolved "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-2.7.14.tgz" @@ -2714,6 +2745,20 @@ dependencies: "@types/geojson" "*" +"@types/mapbox__point-geometry@*", "@types/mapbox__point-geometry@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz#0ef017b75eedce02ff6243b4189210e2e6d5e56d" + integrity sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA== + +"@types/mapbox__vector-tile@^1.3.4": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz#ad757441ef1d34628d9e098afd9c91423c1f8734" + integrity sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg== + dependencies: + "@types/geojson" "*" + "@types/mapbox__point-geometry" "*" + "@types/pbf" "*" + "@types/mdast@^4.0.0": version "4.0.3" resolved "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz" @@ -2756,6 +2801,11 @@ resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/pbf@*", "@types/pbf@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/pbf/-/pbf-3.0.5.tgz#a9495a58d8c75be4ffe9a0bd749a307715c07404" + integrity sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA== + "@types/prop-types@*": version "15.7.6" resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.6.tgz" @@ -2826,6 +2876,13 @@ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/supercluster@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@types/supercluster/-/supercluster-7.1.3.tgz#1a1bc2401b09174d9c9e44124931ec7874a72b27" + integrity sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA== + dependencies: + "@types/geojson" "*" + "@types/tough-cookie@*": version "4.0.3" resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.3.tgz" @@ -4875,6 +4932,11 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fflate@^0.8.0: + version "0.8.2" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" + integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" @@ -5150,6 +5212,15 @@ glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" @@ -5472,6 +5543,11 @@ inherits@2, inherits@^2.0.3: resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@^1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + inline-style-parser@0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz" @@ -6333,6 +6409,11 @@ json-stringify-pretty-compact@^3.0.0: resolved "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz" integrity sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA== +json-stringify-pretty-compact@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz#cf4844770bddee3cb89a6170fe4b00eee5dbf1d4" + integrity sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q== + json5@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" @@ -6433,6 +6514,11 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + kleur@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" @@ -6682,6 +6768,38 @@ mapbox-gl@^2.7.0: tinyqueue "^2.0.3" vt-pbf "^3.1.3" +maplibre-gl@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-4.0.2.tgz#6d19f4ffbd47753e2807f74bc79e00cd58824aa5" + integrity sha512-1HlJJyfPIbAwK1OlNzKDyuNf1NKlEwsjZZhPYpazX4yoP6ud1aC7DNct62fMSkn+hd6mRekIqzYEzIfOCC31QQ== + dependencies: + "@mapbox/geojson-rewind" "^0.5.2" + "@mapbox/jsonlint-lines-primitives" "^2.0.2" + "@mapbox/point-geometry" "^0.1.0" + "@mapbox/tiny-sdf" "^2.0.6" + "@mapbox/unitbezier" "^0.0.1" + "@mapbox/vector-tile" "^1.3.1" + "@mapbox/whoots-js" "^3.1.0" + "@maplibre/maplibre-gl-style-spec" "^20.1.1" + "@types/geojson" "^7946.0.14" + "@types/geojson-vt" "3.2.5" + "@types/mapbox__point-geometry" "^0.1.4" + "@types/mapbox__vector-tile" "^1.3.4" + "@types/pbf" "^3.0.5" + "@types/supercluster" "^7.1.3" + earcut "^2.2.4" + geojson-vt "^3.2.1" + gl-matrix "^3.4.3" + global-prefix "^3.0.0" + kdbush "^4.0.2" + murmurhash-js "^1.0.0" + pbf "^3.2.1" + potpack "^2.0.0" + quickselect "^2.0.0" + supercluster "^8.0.1" + tinyqueue "^2.0.3" + vt-pbf "^3.1.3" + matchmediaquery@^0.3.0: version "0.3.1" resolved "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz" @@ -7505,6 +7623,14 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pmtiles@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/pmtiles/-/pmtiles-3.0.3.tgz#a8b128ebaaf039c050622ff80803155365f54525" + integrity sha512-tj4l3HHJd6/qf9VefzlPK2eYEQgbf+4uXPzNlrj3k7hHvLtibYSxfp51TF6ALt4YezM8MCdiOminnHvdAyqyGg== + dependencies: + "@types/leaflet" "^1.9.8" + fflate "^0.8.0" + postcss-import@^14.1.0: version "14.1.0" resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz" @@ -7818,10 +7944,10 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-map-gl@^7.0.10: - version "7.1.6" - resolved "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.6.tgz" - integrity sha512-9XbrvpFF67Fyi+e6vRLJFnGpo3UF6ZHifIa8cS/wUYSsnv9sVyzGsN++FJy57zkz3Jh3kmf0xKZemR8K0FZLVw== +react-map-gl@^7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/react-map-gl/-/react-map-gl-7.1.7.tgz#f9b7d76cccad6d0bf1627d1827a0a378696ac1d0" + integrity sha512-mwjc0obkBJOXCcoXQr3VoLqmqwo9vS4bXfbGsdxXzEgVCv/PM0v+1QggL7W0d/ccIy+VCjbXNlGij+PENz6VNg== dependencies: "@maplibre/maplibre-gl-style-spec" "^19.2.1" "@types/mapbox-gl" ">=1.0.0" @@ -8725,7 +8851,7 @@ superagent@^7.1.3: readable-stream "^3.6.0" semver "^7.3.7" -supercluster@^8.0.0: +supercluster@^8.0.0, supercluster@^8.0.1: version "8.0.1" resolved "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz" integrity sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ== @@ -9525,6 +9651,13 @@ which-typed-array@^1.1.11, which-typed-array@^1.1.2, which-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" +which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"