googlemaps / googlemaps/js-markerclusterer
SuperClusterAlgorithm Properties Not Accessible in Renderer
- Dominant language
- TypeScript
- Stars
- 293
- Forks
- 104
- Avg merge
- 3m
- Merged PRs (30d)
- 18
Description
# SuperClusterAlgorithm Properties Not Accessible in Renderer
## Issue Description
When using `SuperClusterAlgorithm` with custom `map` and `reduce` functions in `@googlemaps/markerclusterer`, the aggregated properties computed by the algorithm are not accessible in the renderer function. The cluster object passed to the renderer does not contain the properties that were calculated and returned by the algorithm's map/reduce functions.
## Expected Behavior
The aggregated properties computed by SuperCluster's map/reduce functions should be accessible in the renderer, either:
1. Through `cluster.markers[0].properties`
2. Through the `stats` parameter
3. Through some other documented mechanism
## Actual Behavior
- `cluster.markers[0].properties` is `undefined`
- `stats` parameter doesn't contain the aggregated properties
- No way to access the computed aggregation data in the renderer
## Reproduction Code
```typescript
import { SuperClusterAlgorithm, MarkerClusterer } from '@googlemaps/markerclusterer';
// Define aggregated properties interface
interface AggregatedProps {
total_assets: number;
asset_type_counts: Record;
selected_count: number;
status_counts: Record;
most_severe_status: string;
}
// Create SuperCluster algorithm with map/reduce functions
const algorithm = new SuperClusterAlgorithm({
maxZoom: 22,
radius: 80,
// MAP: Process individual markers
map: (props) => {
const aggregated: AggregatedProps = {
total_assets: 1,
asset_type_counts: { [props.assetType]: 1 },
selected_count: props.isSelected ? 1 : 0,
status_counts: { [props.status]: 1 },
most_severe_status: props.status,
};
console.log('MAP function returning:', aggregated);
return aggregated;
},
// REDUCE: Merge properties of clusters
reduce: (accumulated, props) => {
accumulated.total_assets += props.total_assets;
// Merge asset type counts
for (const type in props.asset_type_counts) {
accumulated.asset_type_counts[type] =
(accumulated.asset_type_counts[type] || 0) + props.asset_type_counts[type];
}
// Merge other properties...
accumulated.selected_count += props.selected_count;
console.log('REDUCE function result:', accumulated);
},
});
// Custom renderer that should access aggregated properties
const renderer = {
render: (cluster, stats, map) => {
console.log('Renderer cluster:', cluster);
console.log('Renderer stats:', stats);
console.log('Cluster markers:', cluster.markers);
console.log('First marker properties:', cluster.markers[0]?.properties);
// ❌ These are all undefined:
// - cluster.markers[0].properties
// - stats.properties
// - stats (doesn't contain our aggregated data)
// Expected: Access to AggregatedProps computed by map/reduce
// Actual: No access to computed aggregation data
// Create marker without access to aggregated data
return new google.maps.Marker({
position: cluster.position,
label: String(cluster.count), // Can only use basic cluster.count
});
}
};
// Initialize clusterer
const clusterer = new MarkerClusterer({
map: googleMap,
algorithm: algorithm,
renderer: renderer,
});
```
## Console Output
```
MAP function returning: { total_assets: 1, asset_type_counts: {...}, ... }
REDUCE function result: { total_assets: 5, asset_type_counts: {...}, ... }
Renderer cluster: { count: 5, position: {...}, markers: [...] }
Renderer stats: { ... } // Basic stats, no custom properties
Cluster markers: [Marker, Marker, Marker, Marker, Marker]
First marker properties: undefined
```
## Environment
- `@googlemaps/markerclusterer`: `^2.5.3`
- TypeScript: `^5.0.0`
- Browser: Chrome 118+
## Workaround
Currently having to manually re-aggregate data in the renderer by processing `cluster.markers`, which defeats the purpose of using SuperCluster's efficient map/reduce aggregation:
```typescript
const renderer = {
render: (cluster, stats, map) => {
// Manual re-aggregation (inefficient)
const clusterAssets = cluster.markers.map(getAssetFromMarker);
const manuallyAggregated = {
total_assets: clusterAssets.length,
selected_count: clusterAssets.filter(a => a.isSelected).length,
// ... re-compute everything the algorithm already computed
};
// Use manually aggregated data for rendering
return createMarkerWithAggregatedData(manuallyAggregated);
}
};
```
## Suggested Fix
The renderer should have access to the aggregated properties, ideally through one of these approaches:
1. **Option 1**: `cluster.properties` containing the aggregated data
2. **Option 2**: `cluster.markers[0].properties` containing the aggregated data
3. **Option 3**: `stats` parameter containing the aggregated data
4. **Option 4**: Additional parameter with aggregated data
## Related Documentation
Could not find documentation on how to access custom properties computed by SuperCluster's map/reduce functions in the MarkerClusterer renderer.
Contributor guide
Research direction
Start by reproducing the issue with SuperClusterAlgorithm's map/reduce functions and the MarkerClusterer renderer, then inspect how the cluster and stats values are passed to render. Define and document a supported path for the aggregated properties, and verify that the renderer can access them without re-aggregating marker data.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100