1
Fork 0

When map marker is clicked a present view is shown

This commit is contained in:
viktorstrate 2020-09-27 17:54:50 +02:00
parent c73c962fc3
commit 539b1c1245
5 changed files with 216 additions and 47 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}