infinite-agents-public/mapbox_test/mapbox_globe_8/CLAUDE.md

361 lines
8.3 KiB
Markdown

# 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
```bash
# 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
1. **Clustering Configuration** (`src/index.js`)
- Source setup with cluster parameters
- `clusterMaxZoom: 14` - stops clustering at zoom 14
- `clusterRadius: 50` - 50px aggregation radius
2. **Layer System**
- `clusters` - Aggregated cluster circles
- `cluster-count` - Point count labels
- `unclustered-point` - Individual schools
- `resource-rings` - Resource level indicators
3. **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
1. **Cluster Source Configuration**
```javascript
{
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50,
generateId: true
}
```
2. **Step-Based Cluster Styling**
```javascript
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6', 50,
'#f1f075', 150,
'#f28cb1'
]
```
3. **Cluster Expansion Interaction**
```javascript
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):
```javascript
['step', ['get', 'property'],
value1, threshold1,
value2, threshold2,
value3
]
```
**Match Expression** (categories):
```javascript
['match', ['get', 'type'],
'Primary', '#667eea',
'Secondary', '#764ba2',
'University', '#f093fb',
'#667eea' // default
]
```
**Interpolate Expression** (continuous):
```javascript
['interpolate', ['linear'], ['zoom'],
1, 3, // at zoom 1, value 3
10, 8 // at zoom 10, value 8
]
```
### Layer Filtering
**Show only clusters**:
```javascript
filter: ['has', 'point_count']
```
**Show only unclustered points**:
```javascript
filter: ['!', ['has', 'point_count']]
```
## Data Guidelines
### GeoJSON Structure
```javascript
{
"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
```javascript
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
```javascript
// 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
```javascript
// 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
```javascript
map.on('render', () => {
const fps = 1000 / map._frameTime;
console.log('FPS:', fps.toFixed(2));
});
```
### Cluster Statistics
```javascript
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:
```javascript
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:
1. Create Mapbox account
2. Generate new token
3. Set appropriate URL restrictions
4. 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:
1. Large dataset clustering configuration
2. Step-based expression styling
3. Interactive cluster expansion
4. Performance optimization techniques
5. Progressive detail disclosure UX
6. 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.