mapbox / mapbox/mapbox-maps-flutter

MapBox Cluster Focus Implementation Investigation

Open
#1,036 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Dart
Stars
380
Forks
204
PR merge metrics
No merged PRs in 30d

Description

**My flutter setup:**
Flutter 3.29.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 09de023485 (7 months ago) • 2025-02-28 13:44:05 -0800
Engine • revision 871f65ac1b
Tools • Dart 3.7.0 • DevTools 2.42.2
**Currently using version:** 2.11.0 for the mapbox-maps-flutter

During development of a package tracking application with MapBox Flutter SDK, I attempted to implement focus functionality for map clusters that would visually highlight clusters(by enlarging their markers) when the onCameraChanged is triggered by dragging the map and a shipment from the cluster is focused.

**Attempted Solutions:**
_1. Feature-State API Approach (Failed)_
**Method**: Applied the same feature-state API used for individual shipments to clusters.
**Implementation**: Used setFeatureState('shipments-source', null, clusterId, '{"focused":true}')
**Result**: No visual effect. Clusters did not respond to feature-state changes.
**Cause**: MapBox documentation states "feature-state is not available for clusters"

_2. ClusterProperties Approach (Performance Issues)_
**Method**: Used clusterProperties to aggregate focus state from constituent shipments.
**Implementation**: Configured cluster aggregation to track focused shipments within clusters.
**Result**: Functional but severe performance degradation.
**Cause**: Required full GeoJSON source rebuilds on every focus change, causing 99.7% slower performance compared to feature-state updates.

_3. Abandonment and Accidental Discovery_
**Decision**: Abandoned cluster focus functionality due to performance constraints.
**Discovery**: During testing, observed mysterious behavior where certain clusters would unexpectedly enlarge when focusing on specific shipments.

**The Undocumented Inheritance Discovery**
**Finding**: Focusing on Shipment ID 4 caused its containing cluster to enlarge because MapBox's clustering algorithm had designated Shipment 4 as the cluster representative, giving the cluster ID "4" and causing it to inherit the shipment's focused feature-state.
**Root Cause**: When shipment becomes cluster representative point, MapBox assigns the cluster the same ID as the representative shipment.

**The reason I discovered this was that I had some leftover code from the feature-state attempt on the cluster maker:**

```
Future _addClusterLayers() async {
// Normal cluster layer
final clusterLayerNormal = SymbolLayer(
id: 'shipment-clusters-normal',
sourceId: 'shipments-source',
filter: [
'has', 'point_count', // Simple cluster detection
],
iconImage: 'cluster-{point_count}', // MapBox will interpolate the value
iconSize: 1,
iconOpacityExpression: [
'case',
[
'==',
['feature-state', 'focused'],
true,
],
0.0, // Hidden when focused
1.0, // Visible when not focused
],
iconAllowOverlap: true,
iconIgnorePlacement: true,
);

// Focused cluster layer
final clusterLayerFocused = SymbolLayer(
id: 'shipment-clusters-focused',
sourceId: 'shipments-source',
filter: [
'has', 'point_count', // Simple cluster detection
],
iconImage: 'cluster-{point_count}-focused', // MapBox will interpolate the value with "-focused" suffix
iconSize: 1, // The image itself is already 1.3x scaled
iconOpacityExpression: [
'case',
[
'==',
['feature-state', 'focused'],
true,
],
1.0, // Visible when focused
0.0, // Hidden when not focused
],
iconAllowOverlap: true,
iconIgnorePlacement: true,
);

await _mapboxController.style.addLayer(clusterLayerNormal);
await _mapboxController.style.addLayer(clusterLayerFocused);
debugPrint('[GeoJsonManager] ✅ Added dual cluster layers with opacity switching');

// Add detailed logging for cluster investigation
await logClusterDebugInfo();
}
```

This behavior presents an opportunity to achieve the originally desired cluster focus functionality through a performant feature-state approach rather than costly GeoJSON source rebuilds. However, questions remain:

1. Are there methods to leverage this inheritance pattern more reliably?
2. Can we programmatically influence representative point selection to ensure focused shipments become cluster representatives?
3. Does MapBox recommend alternative approaches for cluster focus management that maintain the performance benefits of feature-state while providing consistent behavior across all cluster scenarios? Understanding whether this ID collision pattern can be utilized systematically, or if there are other undiscovered methods for efficient cluster styling, would significantly impact the implementation strategy for cluster focus functionality.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the _addClusterLayers implementation and the logClusterDebugInfo entry point shown in the issue, using mapbox-maps-flutter 2.11.0. Reproduce the feature-state behavior with clustered and focused shipments, then determine whether representative-point selection or another supported approach can provide consistent cluster focus without rebuilding the GeoJSON source. Done means documenting a reliable supported approach or confirming that the behavior cannot be relied on.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart, flutter
Domain
mobile
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.