Clustering
When many annotations share a clusteringIdentifier, MapKit groups nearby ones into a single cluster annotation as the user zooms out, and splits them apart as they zoom in. You control how each cluster renders.
Basic Clustering
Give annotations a shared clustering-identifier and supply a cluster-annotation factory on <VMap> that returns the annotation to render for each group.
<script setup lang="ts">
import { VMap, VMarkerAnnotation } from '@geoql/v-mapkit';
const markers = Array.from({ length: 40 }, (_, id) => ({
id,
at: [
37.7749 + (Math.random() - 0.5) * 0.12,
-122.4194 + (Math.random() - 0.5) * 0.12,
] as [number, number],
}));
function clusterAnnotation(cluster: mapkit.Annotation) {
return new mapkit.MarkerAnnotation(cluster.coordinate, {
color: '#0a84ff',
glyphText: String(cluster.memberAnnotations.length),
title: `${cluster.memberAnnotations.length} places`,
});
}
</script>
<template>
<VMap :access-token="token" :cluster-annotation="clusterAnnotation">
<VMarkerAnnotation
v-for="m in markers"
:key="m.id"
:coordinates="m.at"
clustering-identifier="places"
/>
</VMap>
</template>
The factory receives the cluster annotation MapKit creates — it carries coordinate and memberAnnotations (the grouped annotations sharing the identifier) — and must return the annotation to render in its place.
clustering-identifier
Every annotation component (VMarkerAnnotation, VImageAnnotation, VPlaceAnnotation, VCustomAnnotation, VMapFeatureAnnotation) accepts a clusteringIdentifier string. Annotations only cluster with others sharing the same identifier — use distinct identifiers to keep categories separate.
<VMap :access-token="token" :cluster-annotation="clusterAnnotation">
<VMarkerAnnotation
v-for="cafe in cafes"
:key="cafe.id"
:coordinates="cafe.at"
clustering-identifier="cafes"
/>
<VMarkerAnnotation
v-for="park in parks"
:key="park.id"
:coordinates="park.at"
clustering-identifier="parks"
/>
</VMap>
useCluster
useCluster is the composable behind the cluster-annotation prop. Use it directly when you want to attach (and later detach) the cluster delegate yourself — for example, toggling clustering at runtime.
<script setup lang="ts">
import { onBeforeUnmount } from 'vue';
import { useCluster } from '@geoql/v-mapkit';
const { cleanup } = useCluster({
createClusterAnnotation: (cluster) =>
new mapkit.MarkerAnnotation(cluster.coordinate, {
color: '#5e5ce6',
glyphText: String(cluster.memberAnnotations.length),
}),
});
onBeforeUnmount(cleanup);
</script>
| Option | Type | Description |
|---|---|---|
createClusterAnnotation | (cluster: mapkit.Annotation) => mapkit.Annotation | Build the annotation rendered for each cluster (required) |
Returns { cleanup } — cleanup() removes the annotationForCluster delegate from the map.
Prefer the cluster-annotation prop on <VMap> for the common case — it wires useCluster for you and tears it down on unmount. Reach for useCluster directly only when you need manual control.
See the live Clustering example.