I have noticed that when clicking a single, unclustered point there is no actual feature
in event.features
. Is only possible way to actually look for nearby elements around the click as I did with queryRenderedFeatures
? Why is that it still returns an array of 2 (the same) elements even tho there is only one point there?
import { useState, useRef } from "react";
import { useEffect } from "react";
import Map, {
Popup,
NavigationControl,
FullscreenControl,
ScaleControl,
GeolocateControl,
MapRef,
GeoJSONSource,
Source,
Layer,
} from "react-map-gl";
import {
clusterLayer,
clusterCountLayer,
unclusteredPointLayer,
} from "./components/layers";
import "mapbox-gl/dist/mapbox-gl.css";
export default function CreateSubscriptionContractPage() {
const [popupInfo, setPopupInfo] = useState(null);
const mapRef = useRef<MapRef>(null);
const onClick = (event: mapboxgl.MapLayerMouseEvent) => {
const feature = event.features?.[0];
if (!feature) {
const singleFeature = mapRef.current.queryRenderedFeatures(event.point, {
layers: ["unclustered-point"],
});
const hasAny = singleFeature?.length > 0;
if (!hasAny) {
setPopupInfo(null);
return;
}
setPopupInfo({
city: "Kraków",
population: "1,790,658",
image:
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Rynek_Glowny_w_Krakowie.jpg/1920px-Rynek_Glowny_w_Krakowie.jpg",
state: "Lesser Poland Voivodeship",
latitude: (singleFeature[0].geometry as any)?.coordinates?.[1],
longitude: (singleFeature[0].geometry as any)?.coordinates?.[0],
});
return;
}
const clusterId = feature.properties.cluster_id;
const mapboxSource = mapRef.current.getSource(
"earthquakes",
) as GeoJSONSource;
mapboxSource.getClusterExpansionZoom(clusterId, (err, zoom) => {
if (err) {
return;
}
mapRef.current.easeTo({
center: (feature.geometry as any).coordinates,
zoom,
duration: 500,
});
});
};
return (
<Map
style={{ width: "100%", height: "50%" }}
mapboxAccessToken={"mapboxToken"}
initialViewState={{
latitude: 40,
longitude: -100,
zoom: 3.5,
bearing: 0,
pitch: 45,
}}
mapStyle="mapbox://styles/mapbox/light-v10"
maxZoom={20}
minZoom={3}
interactiveLayerIds={[clusterLayer.id]}
onClick={onClick}
ref={mapRef}
onLoad={(e: mapboxgl.MapboxEvent<undefined>) => {
e.target.addLayer({
id: "3d-buildings",
source: "composite",
"source-layer": "building",
filter: ["==", "extrude", "true"],
type: "fill-extrusion",
minzoom: 15,
paint: {
"fill-extrusion-color": "#aaa",
"fill-extrusion-height": ["get", "height"],
"fill-extrusion-base": ["get", "min_height"],
"fill-extrusion-opacity": 0.6,
},
});
}}
>
<GeolocateControl position="top-left" />
<FullscreenControl position="top-left" />
<NavigationControl position="top-left" />
<ScaleControl />
{popupInfo && (
<Popup
longitude={Number(popupInfo.longitude)}
latitude={Number(popupInfo.latitude)}
onClose={() => setPopupInfo(null)}
>
<div>
{popupInfo.city}, {popupInfo.state} |{" "}
<a
target="_new"
href={`http://en.wikipedia.org/w/index.php?title=Special:Search&search=${popupInfo.city}, ${popupInfo.state}`}
>
Wikipedia
</a>
</div>
<img width="100%" src={popupInfo.image} />
</Popup>
)}
<Source
id="earthquakes"
type="geojson"
data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"
cluster={true}
clusterMaxZoom={14}
clusterRadius={50}
>
<Layer {...clusterLayer} />
<Layer {...clusterCountLayer} />
<Layer {...unclusteredPointLayer} />
</Source>
</Map>
);
}