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

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

  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

    {
        cluster: true,
        clusterMaxZoom: 14,
        clusterRadius: 50,
        generateId: true
    }
    
  2. Step-Based Cluster Styling

    'circle-color': [
        'step',
        ['get', 'point_count'],
        '#51bbd6', 50,
        '#f1f075', 150,
        '#f28cb1'
    ]
    
  3. 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:

  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.