When map marker is clicked a present view is shown
This commit is contained in:
parent
c73c962fc3
commit
539b1c1245
|
@ -9,6 +9,7 @@ const Wrapper = styled.div`
|
|||
height: 68px;
|
||||
position: relative;
|
||||
margin-top: -54px;
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
const ThumbnailImage = styled.img`
|
||||
|
@ -43,11 +44,21 @@ const MapClusterMarker = ({
|
|||
thumbnail: thumbJson,
|
||||
point_count_abbreviated,
|
||||
cluster,
|
||||
cluster_id,
|
||||
media_id,
|
||||
setPresentMarker,
|
||||
}) => {
|
||||
const thumbnail = JSON.parse(thumbJson)
|
||||
|
||||
const presentMedia = () => {
|
||||
setPresentMarker({
|
||||
cluster: !!cluster,
|
||||
id: cluster ? cluster_id : media_id,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Wrapper onClick={presentMedia}>
|
||||
<PopupImage src={imagePopupSrc} />
|
||||
<ThumbnailImage src={thumbnail.url} />
|
||||
{cluster && (
|
||||
|
@ -61,6 +72,9 @@ 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
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
import React, { useEffect, useState, useRef } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import gql from 'graphql-tag'
|
||||
import { useLazyQuery } from 'react-apollo'
|
||||
import PresentView from '../../components/photoGallery/presentView/PresentView'
|
||||
|
||||
const QUERY_MEDIA = gql`
|
||||
query placePageQueryMedia($mediaID: Int!) {
|
||||
media(id: $mediaID) {
|
||||
id
|
||||
title
|
||||
thumbnail {
|
||||
url
|
||||
width
|
||||
height
|
||||
}
|
||||
highRes {
|
||||
url
|
||||
width
|
||||
height
|
||||
}
|
||||
videoWeb {
|
||||
url
|
||||
width
|
||||
height
|
||||
}
|
||||
type
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const getMediaFromMarker = (map, presentMarker) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const { cluster, id } = presentMarker
|
||||
|
||||
if (cluster) {
|
||||
map
|
||||
.getSource('media')
|
||||
.getClusterLeaves(id, 1000, 0, (error, features) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
return
|
||||
}
|
||||
|
||||
const media = features.map(feat => feat.properties)
|
||||
resolve(media)
|
||||
})
|
||||
} else {
|
||||
const features = map.querySourceFeatures('media')
|
||||
const media = features.find(f => f.properties.media_id == id).properties
|
||||
resolve([media])
|
||||
}
|
||||
})
|
||||
|
||||
const MapPresentMarker = ({ map, presentMarker, setPresentMarker }) => {
|
||||
const [media, setMedia] = useState(null)
|
||||
const [currentIndex, setCurrentIndex] = useState(0)
|
||||
|
||||
const previousLoadedMedia = useRef(null)
|
||||
const [loadMedia, { data: loadedMedia }] = useLazyQuery(QUERY_MEDIA, {
|
||||
onCompleted(data) {
|
||||
previousLoadedMedia.current = data
|
||||
},
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (presentMarker == null || map == null) {
|
||||
setMedia(null)
|
||||
return
|
||||
}
|
||||
|
||||
getMediaFromMarker(map, presentMarker).then(setMedia)
|
||||
}, [presentMarker])
|
||||
|
||||
useEffect(() => {
|
||||
if (!media) return
|
||||
|
||||
setCurrentIndex(0)
|
||||
loadMedia({
|
||||
variables: {
|
||||
mediaID: media[0].media_id,
|
||||
},
|
||||
})
|
||||
}, [media])
|
||||
|
||||
useEffect(() => {
|
||||
if (!media) return
|
||||
|
||||
console.log('Current index change', currentIndex, media)
|
||||
|
||||
loadMedia({
|
||||
variables: {
|
||||
mediaID: media[currentIndex].media_id,
|
||||
},
|
||||
})
|
||||
}, [currentIndex])
|
||||
|
||||
if (presentMarker == null || map == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (loadedMedia == null && previousLoadedMedia.current == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const displayMedia = loadedMedia
|
||||
? loadedMedia.media
|
||||
: previousLoadedMedia.current.media
|
||||
|
||||
console.log('diaplay media', displayMedia)
|
||||
|
||||
return (
|
||||
<PresentView
|
||||
media={displayMedia}
|
||||
nextImage={() => {
|
||||
setCurrentIndex(i => Math.min(media.length - 1, i + 1))
|
||||
}}
|
||||
previousImage={() => {
|
||||
setCurrentIndex(i => Math.max(0, i - 1))
|
||||
}}
|
||||
setPresenting={presenting => {
|
||||
if (!presenting) {
|
||||
previousLoadedMedia.current = null
|
||||
setPresentMarker(null)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
MapPresentMarker.propTypes = {
|
||||
map: PropTypes.object,
|
||||
presentMarker: PropTypes.object,
|
||||
setPresentMarker: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default MapPresentMarker
|
|
@ -1,6 +1,4 @@
|
|||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useQuery } from 'react-apollo'
|
||||
import gql from 'graphql-tag'
|
||||
import styled from 'styled-components'
|
||||
|
@ -8,8 +6,8 @@ import styled from 'styled-components'
|
|||
import 'mapbox-gl/dist/mapbox-gl.css'
|
||||
|
||||
import Layout from '../../Layout'
|
||||
|
||||
import MapClusterMarker from './MapClusterMarker'
|
||||
import { makeUpdateMarkers } from './mapboxHelperFunctions'
|
||||
import MapPresentMarker from './MapPresentMarker'
|
||||
|
||||
const MapWrapper = styled.div`
|
||||
width: 100%;
|
||||
|
@ -30,6 +28,7 @@ const MAPBOX_DATA_QUERY = gql`
|
|||
|
||||
const MapPage = () => {
|
||||
const [mapboxLibrary, setMapboxLibrary] = useState(null)
|
||||
const [presentMarker, setPresentMarker] = useState(null)
|
||||
const mapContainer = useRef()
|
||||
const map = useRef()
|
||||
|
||||
|
@ -59,8 +58,7 @@ const MapPage = () => {
|
|||
map.current = new mapboxLibrary.Map({
|
||||
container: mapContainer.current,
|
||||
style: 'mapbox://styles/mapbox/streets-v11',
|
||||
// center: [this.state.lng, this.state.lat],
|
||||
// zoom: this.state.zoom
|
||||
zoom: 1,
|
||||
})
|
||||
|
||||
map.current.on('load', () => {
|
||||
|
@ -84,49 +82,16 @@ const MapPage = () => {
|
|||
filter: ['!', true],
|
||||
})
|
||||
|
||||
const updateMarkers = makeUpdateMarkers({
|
||||
map: map.current,
|
||||
mapboxLibrary,
|
||||
setPresentMarker,
|
||||
})
|
||||
|
||||
map.current.on('move', updateMarkers)
|
||||
map.current.on('moveend', updateMarkers)
|
||||
map.current.on('sourcedata', updateMarkers)
|
||||
updateMarkers()
|
||||
|
||||
var markers = {}
|
||||
var markersOnScreen = {}
|
||||
|
||||
function updateMarkers() {
|
||||
var newMarkers = {}
|
||||
var features = map.current.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 (var i = 0; i < features.length; i++) {
|
||||
var coords = features[i].geometry.coordinates
|
||||
var props = features[i].properties
|
||||
var id = props.cluster ? props.cluster_id : props.media_id
|
||||
|
||||
var marker = markers[id]
|
||||
if (!marker) {
|
||||
var el = createClusterPopupElement(props)
|
||||
marker = markers[id] = new mapboxLibrary.Marker({
|
||||
element: el,
|
||||
}).setLngLat(coords)
|
||||
}
|
||||
newMarkers[id] = marker
|
||||
|
||||
if (!markersOnScreen[id]) marker.addTo(map.current)
|
||||
}
|
||||
// for every marker we've added previously, remove those that are no longer visible
|
||||
for (id in markersOnScreen) {
|
||||
if (!newMarkers[id]) markersOnScreen[id].remove()
|
||||
}
|
||||
markersOnScreen = newMarkers
|
||||
}
|
||||
|
||||
function createClusterPopupElement(props) {
|
||||
const el = document.createElement('div')
|
||||
ReactDOM.render(<MapClusterMarker {...props} />, el)
|
||||
return el
|
||||
}
|
||||
|
||||
console.log(map.current)
|
||||
})
|
||||
}, [mapContainer, mapboxLibrary, mapboxData])
|
||||
|
||||
|
@ -135,6 +100,11 @@ const MapPage = () => {
|
|||
<MapWrapper>
|
||||
<MapContainer ref={mapContainer}></MapContainer>
|
||||
</MapWrapper>
|
||||
<MapPresentMarker
|
||||
map={map.current}
|
||||
presentMarker={presentMarker}
|
||||
setPresentMarker={setPresentMarker}
|
||||
/>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,48 @@
|
|||
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 ? props.cluster_id : 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
|
||||
}
|
Loading…
Reference in New Issue