Reputation: 560
I am building a react google map to render property listings and everything is visually fine
My CustomOverlay
component is made to replace default markers and renders accordingly, but doesn't enable clicking on the div even though the function assigned to div.onclick
is visible against the each div.
Placing a console.log inside of the div.onclick
never gets fired in console.
Any help appreciated in how I can make this custom overlay clickable just like a marker (or an alternative method is welcomed, too, but I do intend to conditionally change styling based on marker values).
Thanks.
import { useEffect, useRef } from 'react';
import { useGoogleMap } from '@react-google-maps/api';
const CustomOverlay = ({ marker, onMarkerClick }) => {
const map = useGoogleMap();
const overlayView = useRef(null);
const divRef = useRef(null);
useEffect(() => {
if (!map) return;
const overlay = new window.google.maps.OverlayView();
overlay.onAdd = function () {
const div = document.createElement('div');
const priceRounded = (marker.price / 1000000).toFixed(1);
div.style.position = 'absolute';
div.style.transform = 'translate(-50%, -50%)';
div.style.cursor = 'pointer';
div.style.zIndex = '1';
div.innerHTML = `
<div class="price-label">£${priceRounded}m</div>
<div class="fee-label">${marker.fee_offered}%</div>
`;
const onClickFunction = () => {
onMarkerClick(marker);
};
div.onclick = onClickFunction;
divRef.current = div;
overlay.getPanes().overlayLayer.appendChild(div);
};
overlay.draw = function () {
const div = divRef.current;
const point = this.getProjection().fromLatLngToDivPixel(marker.position);
if (point) {
div.style.left = point.x + 'px';
div.style.top = point.y + 'px';
}
};
overlay.onRemove = function () {
if (divRef.current) {
this.getPanes().overlayLayer.removeChild(divRef.current);
}
};
overlay.setMap(map);
overlayView.current = overlay;
return () => {
overlayView.current.setMap(null);
};
}, [map]);
return null;
};
export default CustomOverlay;
import React, {
useState,
useEffect,
useRef,
useMemo,
useCallback,
} from 'react';
import { GoogleMap, useJsApiLoader, InfoWindow } from '@react-google-maps/api';
import { containerStyle, mapOptions } from './MapConfig';
import axios from 'axios';
import { getAccessToken } from '../../../../auth';
import './MapStyling/customoverlay.css';
import CustomOverlay from './MapComponents/CustomOverlay';
const api = axios.create({
baseURL: 'http://localhost:8000',
});
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error),
);
const Map = () => {
const { isLoaded } = useJsApiLoader({
id: 'google-map-script',
googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
});
const [selectedMarker, setSelectedMarker] = useState(null);
const [infoWindowVisible, setInfoWindowVisible] = useState(false);
const [markers, setMarkers] = useState([]);
const mapRef = useRef(null);
const handleMarkerClick = useCallback(
(marker) => {
setInfoWindowVisible(false);
setSelectedMarker(marker);
setInfoWindowVisible(true);
},
[setSelectedMarker, setInfoWindowVisible],
);
useEffect(() => {
const fetchData = async () => {
const token = getAccessToken();
try {
const response = await axios.get(
process.env.REACT_APP_BACKEND_URL + 'listing/',
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
},
);
const markers = response.data.map((listing) => {
let { lat, lng } = listing;
let RestOfListing = { ...listing };
delete RestOfListing.lat;
delete RestOfListing.lng;
return {
position: {
lat,
lng,
},
...RestOfListing,
};
});
setMarkers(markers);
} catch (error) {
console.error(error);
setMarkers([]);
}
};
fetchData();
}, []);
const memoizedMarkers = useMemo(() => {
return markers.map((marker) => (
<CustomOverlay
key={marker.id}
marker={marker}
onMarkerClick={() => handleMarkerClick(marker)}
/>
));
}, [markers]);
return isLoaded ? (
<GoogleMap
mapContainerStyle={containerStyle}
options={mapOptions}
ref={mapRef}
onClick={() => {
setInfoWindowVisible(false);
setSelectedMarker(null);
}}
>
{memoizedMarkers}
{infoWindowVisible && selectedMarker && (
<InfoWindow
position={selectedMarker.position}
onCloseClick={() => {
setInfoWindowVisible(false);
setSelectedMarker(null);
}}
>
<div>
<h4>Marker ID: {selectedMarker.id}</h4>
</div>
</InfoWindow>
)}
</GoogleMap>
) : null;
};
export default Map;
.custom-marker {
position: absolute;
transform: translate(-25%, 0%);
}
.price-label {
display: inline-block;
background-color: rgba(22, 0, 87, 0.8);
color: white;
font-size: 14px;
padding: 4px 8px;
border-radius: 4px;
}
.fee-label {
display: inline-block;
background-color: #d62828;
color: white;
font-size: 14px;
padding: 4px 8px;
border-radius: 4px;
margin-left: 4px;
position: relative;
top: -8px;
translate: -125%;
transform: translateY(-40%);
z-index: -1;
}
Upvotes: 1
Views: 857