Rewrite PlacesPage to Typescript
This commit is contained in:
parent
de76360fbf
commit
788a8e7c62
|
@ -13,7 +13,7 @@ module.exports = function (api) {
|
||||||
plugins.push([
|
plugins.push([
|
||||||
'i18next-extract',
|
'i18next-extract',
|
||||||
{
|
{
|
||||||
locales: ['en', 'da'],
|
locales: ['en', 'da', 'fr', 'sv'],
|
||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
|
@ -75,6 +75,9 @@
|
||||||
"photos_page": {
|
"photos_page": {
|
||||||
"title": "Billeder"
|
"title": "Billeder"
|
||||||
},
|
},
|
||||||
|
"places_page": {
|
||||||
|
"title": null
|
||||||
|
},
|
||||||
"routes": {
|
"routes": {
|
||||||
"page_not_found": "Side ikke fundet"
|
"page_not_found": "Side ikke fundet"
|
||||||
},
|
},
|
||||||
|
|
|
@ -75,6 +75,9 @@
|
||||||
"photos_page": {
|
"photos_page": {
|
||||||
"title": "Photos"
|
"title": "Photos"
|
||||||
},
|
},
|
||||||
|
"places_page": {
|
||||||
|
"title": "Places"
|
||||||
|
},
|
||||||
"routes": {
|
"routes": {
|
||||||
"page_not_found": "Page not found"
|
"page_not_found": "Page not found"
|
||||||
},
|
},
|
||||||
|
|
|
@ -75,6 +75,9 @@
|
||||||
"photos_page": {
|
"photos_page": {
|
||||||
"title": "Photos"
|
"title": "Photos"
|
||||||
},
|
},
|
||||||
|
"places_page": {
|
||||||
|
"title": null
|
||||||
|
},
|
||||||
"routes": {
|
"routes": {
|
||||||
"page_not_found": "Page non trouvée"
|
"page_not_found": "Page non trouvée"
|
||||||
},
|
},
|
||||||
|
@ -218,7 +221,7 @@
|
||||||
"exposure": "Exposure",
|
"exposure": "Exposure",
|
||||||
"exposure_program": "Programme",
|
"exposure_program": "Programme",
|
||||||
"flash": "Flash",
|
"flash": "Flash",
|
||||||
"de prise": "Distance focale",
|
"focal_length": "Distance focale",
|
||||||
"iso": "ISO",
|
"iso": "ISO",
|
||||||
"lens": "Objectif",
|
"lens": "Objectif",
|
||||||
"maker": "Marque"
|
"maker": "Marque"
|
||||||
|
|
|
@ -75,6 +75,9 @@
|
||||||
"photos_page": {
|
"photos_page": {
|
||||||
"title": "Bilder"
|
"title": "Bilder"
|
||||||
},
|
},
|
||||||
|
"places_page": {
|
||||||
|
"title": null
|
||||||
|
},
|
||||||
"routes": {
|
"routes": {
|
||||||
"page_not_found": "Sidan hittades inte"
|
"page_not_found": "Sidan hittades inte"
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,9 @@
|
||||||
"@babel/preset-env": "^7.13.15",
|
"@babel/preset-env": "^7.13.15",
|
||||||
"@testing-library/jest-dom": "^5.11.10",
|
"@testing-library/jest-dom": "^5.11.10",
|
||||||
"@testing-library/react": "^11.2.6",
|
"@testing-library/react": "^11.2.6",
|
||||||
|
"@types/geojson": "^7946.0.7",
|
||||||
"@types/jest": "^26.0.22",
|
"@types/jest": "^26.0.22",
|
||||||
|
"@types/mapbox-gl": "^2.1.1",
|
||||||
"@types/react": "^17.0.3",
|
"@types/react": "^17.0.3",
|
||||||
"@types/react-dom": "^17.0.3",
|
"@types/react-dom": "^17.0.3",
|
||||||
"@types/react-helmet": "^6.1.1",
|
"@types/react-helmet": "^6.1.1",
|
||||||
|
@ -2735,6 +2737,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||||
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="
|
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/geojson": {
|
||||||
|
"version": "7946.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
|
||||||
|
"integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/graceful-fs": {
|
"node_modules/@types/graceful-fs": {
|
||||||
"version": "4.1.4",
|
"version": "4.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz",
|
||||||
|
@ -2795,6 +2803,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
|
||||||
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw=="
|
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/mapbox-gl": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-oDgHhkAC9iYIj/H/9iwm6gHHKKPzweTUgOlozcrvWr8T07dyymGty6mON2j4kEeBGyTTI291vI6gP9k2ArxvHw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/geojson": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "14.11.2",
|
"version": "14.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz",
|
||||||
|
@ -16369,6 +16386,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||||
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="
|
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="
|
||||||
},
|
},
|
||||||
|
"@types/geojson": {
|
||||||
|
"version": "7946.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
|
||||||
|
"integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/graceful-fs": {
|
"@types/graceful-fs": {
|
||||||
"version": "4.1.4",
|
"version": "4.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz",
|
||||||
|
@ -16429,6 +16452,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
|
||||||
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw=="
|
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw=="
|
||||||
},
|
},
|
||||||
|
"@types/mapbox-gl": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-oDgHhkAC9iYIj/H/9iwm6gHHKKPzweTUgOlozcrvWr8T07dyymGty6mON2j4kEeBGyTTI291vI6gP9k2ArxvHw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/geojson": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.11.2",
|
"version": "14.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz",
|
||||||
|
|
|
@ -66,7 +66,9 @@
|
||||||
"@babel/preset-env": "^7.13.15",
|
"@babel/preset-env": "^7.13.15",
|
||||||
"@testing-library/jest-dom": "^5.11.10",
|
"@testing-library/jest-dom": "^5.11.10",
|
||||||
"@testing-library/react": "^11.2.6",
|
"@testing-library/react": "^11.2.6",
|
||||||
|
"@types/geojson": "^7946.0.7",
|
||||||
"@types/jest": "^26.0.22",
|
"@types/jest": "^26.0.22",
|
||||||
|
"@types/mapbox-gl": "^2.1.1",
|
||||||
"@types/react": "^17.0.3",
|
"@types/react": "^17.0.3",
|
||||||
"@types/react-dom": "^17.0.3",
|
"@types/react-dom": "^17.0.3",
|
||||||
"@types/react-helmet": "^6.1.1",
|
"@types/react-helmet": "^6.1.1",
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import imagePopupSrc from './image-popup.svg'
|
import imagePopupSrc from './image-popup.svg'
|
||||||
|
import { MediaMarker } from './MapPresentMarker'
|
||||||
|
import { PresentMarker } from './PlacesPage'
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
width: 56px;
|
width: 56px;
|
||||||
|
@ -40,20 +41,21 @@ const PointCountCircle = styled.div`
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
type MapClusterMarkerProps = {
|
||||||
|
setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
|
||||||
|
marker: MediaMarker
|
||||||
|
}
|
||||||
|
|
||||||
const MapClusterMarker = ({
|
const MapClusterMarker = ({
|
||||||
thumbnail: thumbJson,
|
marker,
|
||||||
point_count_abbreviated,
|
|
||||||
cluster,
|
|
||||||
cluster_id,
|
|
||||||
media_id,
|
|
||||||
setPresentMarker,
|
setPresentMarker,
|
||||||
}) => {
|
}: MapClusterMarkerProps) => {
|
||||||
const thumbnail = JSON.parse(thumbJson)
|
const thumbnail = JSON.parse(marker.thumbnail)
|
||||||
|
|
||||||
const presentMedia = () => {
|
const presentMedia = () => {
|
||||||
setPresentMarker({
|
setPresentMarker({
|
||||||
cluster: !!cluster,
|
cluster: !!marker.cluster,
|
||||||
id: cluster ? cluster_id : media_id,
|
id: marker.cluster ? marker.cluster_id : marker.media_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,20 +63,11 @@ const MapClusterMarker = ({
|
||||||
<Wrapper onClick={presentMedia}>
|
<Wrapper onClick={presentMedia}>
|
||||||
<PopupImage src={imagePopupSrc} />
|
<PopupImage src={imagePopupSrc} />
|
||||||
<ThumbnailImage src={thumbnail.url} />
|
<ThumbnailImage src={thumbnail.url} />
|
||||||
{cluster && (
|
{marker.cluster && (
|
||||||
<PointCountCircle>{point_count_abbreviated}</PointCountCircle>
|
<PointCountCircle>{marker.point_count_abbreviated}</PointCountCircle>
|
||||||
)}
|
)}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
MapClusterMarker.propTypes = {
|
|
||||||
thumbnail: PropTypes.string,
|
|
||||||
cluster: PropTypes.bool,
|
|
||||||
point_count_abbreviated: PropTypes.number,
|
|
||||||
cluster_id: PropTypes.number,
|
|
||||||
media_id: PropTypes.number,
|
|
||||||
setPresentMarker: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MapClusterMarker
|
export default MapClusterMarker
|
|
@ -1,8 +1,9 @@
|
||||||
import { gql } from '@apollo/client'
|
import { gql } from '@apollo/client'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useLazyQuery } from '@apollo/client'
|
import { useLazyQuery } from '@apollo/client'
|
||||||
import PresentView from '../../components/photoGallery/presentView/PresentView'
|
import PresentView from '../../components/photoGallery/presentView/PresentView'
|
||||||
|
import type mapboxgl from 'mapbox-gl'
|
||||||
|
import { PresentMarker } from './PlacesPage'
|
||||||
|
|
||||||
const QUERY_MEDIA = gql`
|
const QUERY_MEDIA = gql`
|
||||||
query placePageQueryMedia($mediaIDs: [ID!]!) {
|
query placePageQueryMedia($mediaIDs: [ID!]!) {
|
||||||
|
@ -29,31 +30,57 @@ const QUERY_MEDIA = gql`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const getMediaFromMarker = (map, presentMarker) =>
|
const getMediaFromMarker = (map: mapboxgl.Map, presentMarker: PresentMarker) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise<MediaMarker[]>((resolve, reject) => {
|
||||||
const { cluster, id } = presentMarker
|
const { cluster, id } = presentMarker
|
||||||
|
|
||||||
if (cluster) {
|
if (cluster) {
|
||||||
map
|
const mediaSource = map.getSource('media') as mapboxgl.GeoJSONSource
|
||||||
.getSource('media')
|
|
||||||
.getClusterLeaves(id, 1000, 0, (error, features) => {
|
|
||||||
if (error) {
|
|
||||||
reject(error)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const media = features.map(feat => feat.properties)
|
mediaSource.getClusterLeaves(id, 1000, 0, (error, features) => {
|
||||||
resolve(media)
|
if (error) {
|
||||||
})
|
reject(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const media = features.map(feat => feat.properties) as MediaMarker[]
|
||||||
|
resolve(media)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
const features = map.querySourceFeatures('media')
|
const features = map.querySourceFeatures('media')
|
||||||
const media = features.find(f => f.properties.media_id == id).properties
|
const media = features.find(f => f.properties?.media_id == id)
|
||||||
|
?.properties as MediaMarker | undefined
|
||||||
|
|
||||||
|
if (media === undefined) {
|
||||||
|
reject('ERROR: media is undefined')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
resolve([media])
|
resolve([media])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const MapPresentMarker = ({ map, presentMarker, setPresentMarker }) => {
|
export interface MediaMarker {
|
||||||
const [mediaMarkers, setMediaMarkers] = useState(null)
|
id: number
|
||||||
|
thumbnail: string
|
||||||
|
cluster: boolean
|
||||||
|
point_count_abbreviated: number
|
||||||
|
cluster_id: number
|
||||||
|
media_id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapPresetMarkerProps = {
|
||||||
|
map: mapboxgl.Map | null
|
||||||
|
presentMarker: PresentMarker | null
|
||||||
|
setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
|
||||||
|
}
|
||||||
|
|
||||||
|
const MapPresentMarker = ({
|
||||||
|
map,
|
||||||
|
presentMarker,
|
||||||
|
setPresentMarker,
|
||||||
|
}: MapPresetMarkerProps) => {
|
||||||
|
const [mediaMarkers, setMediaMarkers] = useState<MediaMarker[] | null>(null)
|
||||||
const [currentIndex, setCurrentIndex] = useState(0)
|
const [currentIndex, setCurrentIndex] = useState(0)
|
||||||
|
|
||||||
const [loadMedia, { data: loadedMedia }] = useLazyQuery(QUERY_MEDIA)
|
const [loadMedia, { data: loadedMedia }] = useLazyQuery(QUERY_MEDIA)
|
||||||
|
@ -78,11 +105,12 @@ const MapPresentMarker = ({ map, presentMarker, setPresentMarker }) => {
|
||||||
})
|
})
|
||||||
}, [mediaMarkers])
|
}, [mediaMarkers])
|
||||||
|
|
||||||
if (presentMarker == null || map == null) {
|
if (
|
||||||
return null
|
presentMarker == null ||
|
||||||
}
|
map == null ||
|
||||||
|
mediaMarkers == null ||
|
||||||
if (loadedMedia == null) {
|
loadedMedia == null
|
||||||
|
) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,10 +133,4 @@ const MapPresentMarker = ({ map, presentMarker, setPresentMarker }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
MapPresentMarker.propTypes = {
|
|
||||||
map: PropTypes.object,
|
|
||||||
presentMarker: PropTypes.object,
|
|
||||||
setPresentMarker: PropTypes.func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MapPresentMarker
|
export default MapPresentMarker
|
|
@ -1,14 +1,15 @@
|
||||||
|
import { gql, useQuery } from '@apollo/client'
|
||||||
|
import type mapboxgl from 'mapbox-gl'
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import { useQuery, gql } from '@apollo/client'
|
import { Helmet } from 'react-helmet'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
// Will be bundled to dist/src/Pages/PlacesPage/PlacesPage.css
|
|
||||||
import 'mapbox-gl/dist/mapbox-gl.css'
|
|
||||||
|
|
||||||
import Layout from '../../Layout'
|
import Layout from '../../Layout'
|
||||||
import { makeUpdateMarkers } from './mapboxHelperFunctions'
|
import { makeUpdateMarkers } from './mapboxHelperFunctions'
|
||||||
import MapPresentMarker from './MapPresentMarker'
|
import MapPresentMarker from './MapPresentMarker'
|
||||||
import { Helmet } from 'react-helmet'
|
|
||||||
|
// Will be bundled to dist/src/Pages/PlacesPage/PlacesPage.css
|
||||||
|
import 'mapbox-gl/dist/mapbox-gl.css'
|
||||||
|
|
||||||
const MapWrapper = styled.div`
|
const MapWrapper = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -27,17 +28,25 @@ const MAPBOX_DATA_QUERY = gql`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export type PresentMarker = {
|
||||||
|
id: number
|
||||||
|
cluster: boolean
|
||||||
|
}
|
||||||
|
|
||||||
const MapPage = () => {
|
const MapPage = () => {
|
||||||
const [mapboxLibrary, setMapboxLibrary] = useState(null)
|
const { t } = useTranslation()
|
||||||
const [presentMarker, setPresentMarker] = useState(null)
|
|
||||||
const mapContainer = useRef()
|
const [mapboxLibrary, setMapboxLibrary] = useState<typeof mapboxgl | null>()
|
||||||
const map = useRef()
|
const [presentMarker, setPresentMarker] = useState<PresentMarker | null>(null)
|
||||||
|
const mapContainer = useRef<HTMLDivElement | null>(null)
|
||||||
|
const map = useRef<mapboxgl.Map | null>(null)
|
||||||
|
|
||||||
const { data: mapboxData } = useQuery(MAPBOX_DATA_QUERY)
|
const { data: mapboxData } = useQuery(MAPBOX_DATA_QUERY)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function loadMapboxLibrary() {
|
async function loadMapboxLibrary() {
|
||||||
const mapbox = (await import('mapbox-gl')).default
|
const mapbox = (await import('mapbox-gl')).default
|
||||||
|
|
||||||
setMapboxLibrary(mapbox)
|
setMapboxLibrary(mapbox)
|
||||||
}
|
}
|
||||||
loadMapboxLibrary()
|
loadMapboxLibrary()
|
||||||
|
@ -65,6 +74,11 @@ const MapPage = () => {
|
||||||
map.current.addControl(new mapboxLibrary.NavigationControl())
|
map.current.addControl(new mapboxLibrary.NavigationControl())
|
||||||
|
|
||||||
map.current.on('load', () => {
|
map.current.on('load', () => {
|
||||||
|
if (map.current == null) {
|
||||||
|
console.error('ERROR: map is null')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
map.current.addSource('media', {
|
map.current.addSource('media', {
|
||||||
type: 'geojson',
|
type: 'geojson',
|
||||||
data: mapboxData.myMediaGeoJson,
|
data: mapboxData.myMediaGeoJson,
|
||||||
|
@ -98,7 +112,7 @@ const MapPage = () => {
|
||||||
|
|
||||||
if (mapboxData && mapboxData.mapboxToken == null) {
|
if (mapboxData && mapboxData.mapboxToken == null) {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout title={t('places_page.title', 'Places')}>
|
||||||
<h1>Mapbox token is not set</h1>
|
<h1>Mapbox token is not set</h1>
|
||||||
<p>
|
<p>
|
||||||
To use map related features a mapbox token is needed.
|
To use map related features a mapbox token is needed.
|
|
@ -1,50 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import ReactDOM from 'react-dom'
|
|
||||||
import MapClusterMarker from './MapClusterMarker'
|
|
||||||
|
|
||||||
let markers = {}
|
|
||||||
let markersOnScreen = {}
|
|
||||||
|
|
||||||
export const makeUpdateMarkers = ({
|
|
||||||
map,
|
|
||||||
mapboxLibrary,
|
|
||||||
setPresentMarker,
|
|
||||||
}) => () => {
|
|
||||||
let newMarkers = {}
|
|
||||||
const features = map.querySourceFeatures('media')
|
|
||||||
|
|
||||||
// for every media on the screen, create an HTML marker for it (if we didn't yet),
|
|
||||||
// and add it to the map if it's not there already
|
|
||||||
for (let i = 0; i < features.length; i++) {
|
|
||||||
const coords = features[i].geometry.coordinates
|
|
||||||
const props = features[i].properties
|
|
||||||
const id = props.cluster
|
|
||||||
? `cluster_${props.cluster_id}`
|
|
||||||
: `media_${props.media_id}`
|
|
||||||
|
|
||||||
let marker = markers[id]
|
|
||||||
if (!marker) {
|
|
||||||
let el = createClusterPopupElement(props, setPresentMarker)
|
|
||||||
marker = markers[id] = new mapboxLibrary.Marker({
|
|
||||||
element: el,
|
|
||||||
}).setLngLat(coords)
|
|
||||||
}
|
|
||||||
newMarkers[id] = marker
|
|
||||||
|
|
||||||
if (!markersOnScreen[id]) marker.addTo(map)
|
|
||||||
}
|
|
||||||
// for every marker we've added previously, remove those that are no longer visible
|
|
||||||
for (const id in markersOnScreen) {
|
|
||||||
if (!newMarkers[id]) markersOnScreen[id].remove()
|
|
||||||
}
|
|
||||||
markersOnScreen = newMarkers
|
|
||||||
}
|
|
||||||
|
|
||||||
function createClusterPopupElement(geojsonProps, setPresentMarker) {
|
|
||||||
const el = document.createElement('div')
|
|
||||||
ReactDOM.render(
|
|
||||||
<MapClusterMarker {...geojsonProps} setPresentMarker={setPresentMarker} />,
|
|
||||||
el
|
|
||||||
)
|
|
||||||
return el
|
|
||||||
}
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
import type mapboxgl from 'mapbox-gl'
|
||||||
|
import type geojson from 'geojson'
|
||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import MapClusterMarker from './MapClusterMarker'
|
||||||
|
import { MediaMarker } from './MapPresentMarker'
|
||||||
|
import { PresentMarker } from './PlacesPage'
|
||||||
|
|
||||||
|
const markers: { [key: string]: mapboxgl.Marker } = {}
|
||||||
|
let markersOnScreen: typeof markers = {}
|
||||||
|
|
||||||
|
type makeUpdateMarkersArgs = {
|
||||||
|
map: mapboxgl.Map
|
||||||
|
mapboxLibrary: typeof mapboxgl
|
||||||
|
setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeUpdateMarkers = ({
|
||||||
|
map,
|
||||||
|
mapboxLibrary,
|
||||||
|
setPresentMarker,
|
||||||
|
}: makeUpdateMarkersArgs) => () => {
|
||||||
|
const newMarkers: typeof markers = {}
|
||||||
|
const features = map.querySourceFeatures('media')
|
||||||
|
|
||||||
|
// for every media on the screen, create an HTML marker for it (if we didn't yet),
|
||||||
|
// and add it to the map if it's not there already
|
||||||
|
for (const feature of features) {
|
||||||
|
const point = feature.geometry as geojson.Point
|
||||||
|
const coords = point.coordinates as [number, number]
|
||||||
|
const props = feature.properties as MediaMarker
|
||||||
|
if (props == null) {
|
||||||
|
console.warn('WARN: geojson feature had no properties', feature)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = props.cluster
|
||||||
|
? `cluster_${props.cluster_id}`
|
||||||
|
: `media_${props.media_id}`
|
||||||
|
|
||||||
|
let marker = markers[id]
|
||||||
|
if (!marker) {
|
||||||
|
const el = createClusterPopupElement(props, setPresentMarker)
|
||||||
|
marker = markers[id] = new mapboxLibrary.Marker({
|
||||||
|
element: el,
|
||||||
|
}).setLngLat(coords)
|
||||||
|
}
|
||||||
|
newMarkers[id] = marker
|
||||||
|
|
||||||
|
if (!markersOnScreen[id]) marker.addTo(map)
|
||||||
|
}
|
||||||
|
// for every marker we've added previously, remove those that are no longer visible
|
||||||
|
for (const id in markersOnScreen) {
|
||||||
|
if (!newMarkers[id]) markersOnScreen[id].remove()
|
||||||
|
}
|
||||||
|
markersOnScreen = newMarkers
|
||||||
|
}
|
||||||
|
|
||||||
|
function createClusterPopupElement(
|
||||||
|
geojsonProps: MediaMarker,
|
||||||
|
setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
|
||||||
|
) {
|
||||||
|
const el = document.createElement('div')
|
||||||
|
ReactDOM.render(
|
||||||
|
<MapClusterMarker
|
||||||
|
marker={geojsonProps}
|
||||||
|
setPresentMarker={setPresentMarker}
|
||||||
|
/>,
|
||||||
|
el
|
||||||
|
)
|
||||||
|
return el
|
||||||
|
}
|
Loading…
Reference in New Issue