8.3 KiB
CLAUDE.md - Mapbox Globe Iteration 8
Project Context
This is iteration 8 in a progressive web-enhanced learning series for Mapbox GL JS globe visualizations. This iteration focuses on advanced point clustering for large datasets, demonstrating educational infrastructure distribution globally.
Running the Application
Local Development Server
# From the mapbox_globe_8/ directory
# Python 3
python3 -m http.server 8000
# Python 2
python -m SimpleHTTPServer 8000
# Node.js
npx http-server -p 8000
# PHP
php -S localhost:8000
Then open: http://localhost:8000
Code Architecture
File Structure
mapbox_globe_8/
├── index.html # UI, overlays, styling
├── src/
│ ├── index.js # Map initialization, clustering logic
│ └── data/
│ └── data.js # 650-school GeoJSON dataset
├── README.md
└── CLAUDE.md # This file
Key Components
-
Clustering Configuration (
src/index.js)- Source setup with cluster parameters
clusterMaxZoom: 14- stops clustering at zoom 14clusterRadius: 50- 50px aggregation radius
-
Layer System
clusters- Aggregated cluster circlescluster-count- Point count labelsunclustered-point- Individual schoolsresource-rings- Resource level indicators
-
Data Structure (
src/data/data.js)- GeoJSON FeatureCollection
- 311 educational facilities
- Properties: name, type, students, teachers, ratio, resources, internet
Web Research Integration
Source URL
https://docs.mapbox.com/mapbox-gl-js/example/cluster/
Techniques Learned & Applied
-
Cluster Source Configuration
{ cluster: true, clusterMaxZoom: 14, clusterRadius: 50, generateId: true } -
Step-Based Cluster Styling
'circle-color': [ 'step', ['get', 'point_count'], '#51bbd6', 50, '#f1f075', 150, '#f28cb1' ] -
Cluster Expansion Interaction
map.getSource('schools').getClusterExpansionZoom( clusterId, (err, zoom) => { map.easeTo({ center: coords, zoom: zoom + 0.5 }); } );
Mapbox Best Practices Applied
Performance Optimization
- Clustering: Reduces 311 points to manageable clusters
- Layer Filtering: Separate clustered/unclustered layers
- Generate ID: Enables efficient feature queries
- Zoom-based Styling: Adapts circle sizes to zoom level
Visual Hierarchy
- Cluster size indicates density
- Color indicates cluster magnitude
- Individual schools show type and resource level
- Progressive disclosure through zoom
Interactivity
- Click clusters to expand (learned from web research)
- Click schools for detailed popups
- Hover cursor changes
- Keyboard navigation support
Code Patterns
Mapbox Expression Syntax
Step Expression (thresholds):
['step', ['get', 'property'],
value1, threshold1,
value2, threshold2,
value3
]
Match Expression (categories):
['match', ['get', 'type'],
'Primary', '#667eea',
'Secondary', '#764ba2',
'University', '#f093fb',
'#667eea' // default
]
Interpolate Expression (continuous):
['interpolate', ['linear'], ['zoom'],
1, 3, // at zoom 1, value 3
10, 8 // at zoom 10, value 8
]
Layer Filtering
Show only clusters:
filter: ['has', 'point_count']
Show only unclustered points:
filter: ['!', ['has', 'point_count']]
Data Guidelines
GeoJSON Structure
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [longitude, latitude] // Note: lng first!
},
"properties": {
"name": "School Name",
"type": "Primary|Secondary|University",
"students": 500,
"teachers": 30,
"ratio": 16.7,
"resources": 75, // percentage
"internet": true,
"country": "Country",
"city": "City"
}
}
Data Quality Standards
- Accurate geographic coordinates (longitude, latitude order)
- Realistic enrollment and ratio figures
- Resource percentages (0-100)
- Boolean internet access flag
- Comprehensive location metadata
Styling Guidelines
Color Palette
Clusters (by density):
#51bbd6- Blue (small clusters)#f1f075- Yellow (medium clusters)#f28cb1- Pink (large clusters)
School Types:
#667eea- Primary (purple)#764ba2- Secondary (violet)#f093fb- University (pink)
Resource Levels:
#48bb78- Well resourced (green)#ecc94b- Moderate (yellow)#f56565- Under-resourced (red)
Globe Atmosphere
map.setFog({
color: 'rgba(5, 10, 20, 0.9)',
'high-color': 'rgba(36, 92, 223, 0.35)',
'horizon-blend': 0.3,
'space-color': '#000814',
'star-intensity': 0.7
});
Debugging Tips
Console Logging
// Check cluster state
map.on('click', 'clusters', (e) => {
console.log('Cluster clicked:', e.features[0].properties);
});
// Monitor data loading
map.on('sourcedata', (e) => {
if (e.sourceId === 'schools' && e.isSourceLoaded) {
console.log('Schools data loaded');
}
});
Layer Inspection
// Query visible features
const features = map.queryRenderedFeatures({ layers: ['clusters'] });
console.log('Visible clusters:', features.length);
// Check source data
const sourceData = map.getSource('schools')._data;
console.log('Total features:', sourceData.features.length);
Performance Monitoring
FPS Check
map.on('render', () => {
const fps = 1000 / map._frameTime;
console.log('FPS:', fps.toFixed(2));
});
Cluster Statistics
map.on('load', () => {
const allFeatures = map.querySourceFeatures('schools');
const clusters = allFeatures.filter(f => f.properties.cluster);
console.log('Clusters rendered:', clusters.length);
});
Accessibility Considerations
- Keyboard navigation implemented (arrow keys)
- High contrast color scheme
- Clear visual hierarchy
- Descriptive popup content
- Focus states for interactive elements
Common Issues & Solutions
Issue: Clusters not appearing
Solution: Check clusterMaxZoom - ensure it's lower than current zoom level
Issue: Expansion zoom not working
Solution: Verify cluster source has generateId: true
Issue: Poor performance with large datasets
Solution: Reduce clusterRadius or lower clusterMaxZoom
Issue: Popup coordinates wrapping
Solution: Use coordinate normalization:
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
Extension Ideas
Easy Additions
- Add school type filters (show only universities)
- Implement resource level filtering
- Add search by country/city
- Export visible schools as CSV
Medium Complexity
- Time-series data (enrollment over years)
- Heat map overlay for density
- Statistical dashboard panel
- Comparative country analysis
Advanced Features
- 3D building extrusions for schools
- Custom cluster markers
- Real-time enrollment updates
- WebGL custom layers
Mapbox Token Notes
Current token is public example - suitable for:
- Development
- Testing
- Learning
- Low-traffic demos
For production:
- Create Mapbox account
- Generate new token
- Set appropriate URL restrictions
- Monitor usage limits
Version Information
- Mapbox GL JS: v3.0.1
- Projection: Globe
- Style: dark-v11
- Clustering: Enabled (radius 50, maxZoom 14)
- Dataset: 311 schools, 142 countries
Learning Outcomes
This iteration demonstrates:
- Large dataset clustering configuration
- Step-based expression styling
- Interactive cluster expansion
- Performance optimization techniques
- Progressive detail disclosure UX
- Multi-layer composition with filtering
Next Steps
For iteration 9, consider:
- 3D extrusions based on enrollment
- Animated transitions between states
- Advanced filtering/search UI
- Time-based data animations
- Custom WebGL rendering
Remember: Always test clustering parameters with your dataset size. Adjust clusterRadius and clusterMaxZoom based on data density and UX requirements.