Reputation: 1072
I want to create html markers with clusters, following the mapbox-gl-js example/cluster-html and this stackoverflow question.
Traditionally, I used map.addLayer to add individual 'symbol' markers.
// Unclustrered; Single Listing Styling
// map.addLayer({
// id: 'unclustered-point',
// type: 'symbol',
// source: 'earthquakes',
// filter: ['!', ['has', 'point_count']],
// paint: {
// 'text-color': 'white',
// 'text-halo-width': 5, // Adjust the halo width as needed
// 'text-halo-color': [
// 'case',
// ['boolean', ['feature-state', 'hover'], false],
// '#07364B', // Replace with the desired hover halo color
// '#0097A7' // Replace with the default halo color
// ],
// },
// layout: {
// 'text-field': ['get', 'price'],
// // 'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
// 'text-size': 25,
// 'text-offset': [0, 0.6], // Adjust the offset as needed
// 'text-anchor': 'top',
// 'text-allow-overlap': true
// },
// });
Since type 'symbol' layer doesn't support HTML elements as a marker, I'm using a combination of both examples. After the GeoJSON data is loaded, update markers on the screen on every frame using
map.on('render', () => {
if (!map.isSourceLoaded('earthquakes')) return;
updateMarkers();
});
Where UpdateMarkers() is:
// objects for caching and keeping track of HTML marker objects (for performance)
const markers = {};
let markersOnScreen = {};
function updateMarkers() {
const newMarkers = {};
const features = map.querySourceFeatures('earthquakes');
// for every cluster 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 coords = feature.geometry.coordinates;
const props = feature.properties;
if (!props.cluster) continue;
const id = props.cluster_id;
let marker = markers[id];
if (!marker) {
const el = document.createElement('div');
el.classList.add('mapCluster');
el.innerText = props.price;
marker = markers[id] = new mapboxgl.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;
}
The current approach doesn't render/cluster the features correctly and undefined marker value show up. How can I display the markers using the current approach while clustering and feature.price value show up correct.
In addition, I logged in feature while looping through features and it appears that it also returns cluster properties.
Upvotes: 0
Views: 429
Reputation: 1072
I solved it by targeting the listings instead of clusters.
Changed (!props.cluster) continue
to (props.cluster) continue
.
This skips the 'feature' that is a cluster in the for loop.
Then instead of const id = props.cluster_id;
to get the id of the cluster, I'm using the individual id of the unclustered feature.You can use any other UID property in your feature to distinguish marker.
Upvotes: 0