13 KiB
Critical Fixes Implementation Guide
Overview
This guide explains how to use the new shared architecture to fix all Mapbox globe visualizations. Three critical infrastructure components have been created in the shared/ directory:
- mapbox-config.js - Centralized token management
- data-generator.js - Unified, realistic data generation
- layer-factory.js - Best-practice layer creation
The Problem
The original demos (globe_10-13) failed because:
- ❌ Invalid tokens: Placeholder strings like
'pk.eyJ1IjoieW91cnVzZXJuYW1lIiwiYSI6InlvdXJ0b2tlbiJ9.yourtokenstring' - ❌ Wrong layer types: Using
filllayers (requires Polygons) with Point data - ❌ Inconsistent data: Each demo generated data differently
- ❌ No validation: No error messages when things went wrong
The Solution
Architecture Overview
mapbox_test/
├── shared/ # NEW: Shared infrastructure
│ ├── mapbox-config.js # Token management & validation
│ ├── data-generator.js # Unified data generation
│ └── layer-factory.js # Best-practice layers
│
├── mapbox_globe_10/ # Polio demo
│ ├── index.html
│ └── src/
│ └── index.js # NOW: Uses shared components
│
├── mapbox_globe_11/ # Measles demo
├── mapbox_globe_12/ # Smallpox demo
└── mapbox_globe_13/ # DTP3 demo
How to Fix Each Demo
Step 1: Update HTML (index.html)
Before:
<script type="module" src="src/index.js"></script>
After:
<!-- Load Mapbox config BEFORE data -->
<script type="module">
import { MAPBOX_CONFIG } from '../shared/mapbox-config.js';
MAPBOX_CONFIG.applyToken(); // Validates and applies token
</script>
<!-- Load data generator -->
<script type="module" src="../shared/data-generator.js"></script>
<!-- Load main app -->
<script type="module" src="src/index.js"></script>
Step 2: Update JavaScript (src/index.js)
Before (BROKEN):
// ❌ Invalid token
mapboxgl.accessToken = 'pk.eyJ1IjoieW91cnVzZXJuYW1lIi...';
// ❌ Wrong layer type for Point data
map.addLayer({
id: 'country-fills',
type: 'fill', // Requires Polygon geometries!
source: 'countries',
paint: { 'fill-color': '#4caf50' }
});
After (WORKING):
import { MAPBOX_CONFIG } from '../shared/mapbox-config.js';
import { generateVaccineData } from '../shared/data-generator.js';
import { LayerFactory } from '../shared/layer-factory.js';
// ✅ Token already applied by HTML import
// ✅ Generate proper Point-based data
const vaccineData = generateVaccineData('polio');
// ✅ Initialize map with validated config
const map = new mapboxgl.Map({
container: 'map',
...MAPBOX_CONFIG.getMapOptions({
center: [20, 20],
zoom: 1.5
})
});
map.on('load', () => {
const factory = new LayerFactory(map);
// ✅ Apply beautiful atmosphere
factory.applyGlobeAtmosphere({ theme: 'medical' });
// ✅ Add data source
map.addSource('vaccine-data', {
type: 'geojson',
data: vaccineData
});
// ✅ Create proper circle layer
const layer = factory.createCircleLayer({
id: 'vaccine-circles',
source: 'vaccine-data',
sizeProperty: 'population',
colorProperty: 'coverage_2020', // For polio
colorScale: 'coverage'
});
map.addLayer(layer);
// ✅ Add hover effects
factory.setupHoverEffects('vaccine-circles');
// ✅ Add legend
factory.addLegend({
title: 'Polio Coverage 2020',
colorScale: 'coverage'
});
});
Complete Example: Fixing globe_10 (Polio)
Here's a complete, working replacement for mapbox_globe_10/src/index.js:
/**
* Polio Eradication Progress Visualization
* Using shared architecture for reliability
*/
import { MAPBOX_CONFIG } from '../../shared/mapbox-config.js';
import { generateVaccineData } from '../../shared/data-generator.js';
import { LayerFactory, COLOR_SCALES } from '../../shared/layer-factory.js';
// Generate polio data (automatically creates realistic Point geometries)
const polioData = generateVaccineData('polio');
// Initialize map
const map = new mapboxgl.Map({
container: 'map',
...MAPBOX_CONFIG.getMapOptions({
style: 'mapbox://styles/mapbox/dark-v11',
center: [20, 20],
zoom: 1.5
})
});
// Timeline state
let currentYear = 1980;
let isAnimating = false;
let animationInterval = null;
map.on('load', () => {
const factory = new LayerFactory(map);
// Apply medical-themed atmosphere
factory.applyGlobeAtmosphere({ theme: 'medical' });
// Add data source
map.addSource('polio-data', {
type: 'geojson',
data: polioData
});
// Create main circle layer
const layer = factory.createCircleLayer({
id: 'polio-circles',
source: 'polio-data',
sizeProperty: 'population',
colorProperty: 'coverage_1980', // Will update dynamically
colorScale: 'coverage'
});
map.addLayer(layer);
// Setup interactive hover
factory.setupHoverEffects('polio-circles', (feature) => {
const props = feature.properties;
const coverage = props[`coverage_${currentYear}`];
const popup = new mapboxgl.Popup({ offset: 15 })
.setLngLat(feature.geometry.coordinates)
.setHTML(factory.createPopupContent(feature, {
metrics: [
{
label: `Coverage ${currentYear}`,
property: `coverage_${currentYear}`,
format: (v) => `${v}%`
},
{
label: 'Polio Free Since',
property: 'polio_free_year',
format: (v) => v || 'Not certified'
},
{
label: 'Endemic Status',
property: 'endemic',
format: (v) => v ? '🔴 Still endemic' : '✅ Eradicated'
}
]
}))
.addTo(map);
});
// Add legend
factory.addLegend({
title: `Polio Coverage ${currentYear}`,
colorScale: 'coverage',
position: 'bottom-right'
});
// Initialize timeline
updateVisualization();
});
// Update map for current year
function updateVisualization() {
if (!map.isStyleLoaded()) return;
// Update layer color to use current year's data
const colorExpression = [
'interpolate',
['linear'],
['get', `coverage_${currentYear}`],
...COLOR_SCALES.coverage.stops.flatMap((stop, i) => [
stop,
COLOR_SCALES.coverage.colors[i]
])
];
map.setPaintProperty('polio-circles', 'circle-color', colorExpression);
// Update UI
document.getElementById('year-display').textContent = currentYear;
document.getElementById('year-slider').value = currentYear;
// Update statistics (example)
updateStatistics();
}
function updateStatistics() {
const features = map.querySourceFeatures('polio-data');
let totalCoverage = 0;
let certifiedCount = 0;
let endemicCount = 0;
features.forEach(feature => {
const props = feature.properties;
totalCoverage += props[`coverage_${currentYear}`] || 0;
if (props.polio_free_year && currentYear >= props.polio_free_year) {
certifiedCount++;
}
if (props.endemic && currentYear === 2020) {
endemicCount++;
}
});
const avgCoverage = (totalCoverage / features.length).toFixed(1);
document.getElementById('global-coverage').textContent = `${avgCoverage}%`;
document.getElementById('certified-countries').textContent = certifiedCount;
document.getElementById('endemic-countries').textContent = endemicCount;
}
// Timeline controls
document.getElementById('year-slider').addEventListener('input', (e) => {
currentYear = parseInt(e.target.value);
updateVisualization();
});
document.getElementById('play-btn').addEventListener('click', () => {
if (isAnimating) {
clearInterval(animationInterval);
isAnimating = false;
document.getElementById('play-btn').textContent = 'Play';
} else {
isAnimating = true;
document.getElementById('play-btn').textContent = 'Pause';
animationInterval = setInterval(() => {
currentYear++;
if (currentYear > 2020) currentYear = 1980;
updateVisualization();
}, 800);
}
});
document.getElementById('reset-btn').addEventListener('click', () => {
currentYear = 1980;
if (isAnimating) {
clearInterval(animationInterval);
isAnimating = false;
document.getElementById('play-btn').textContent = 'Play';
}
updateVisualization();
});
Data Types for Each Demo
Polio (globe_10)
const polioData = generateVaccineData('polio');
// Properties: coverage_1980, coverage_1990, ..., coverage_2020, polio_free_year, endemic
Measles (globe_11)
const measlesData = generateVaccineData('measles');
// Properties: coverage_dose1, coverage_dose2, cases_2023, deaths_2023
Smallpox (globe_12)
const smallpoxData = generateVaccineData('smallpox');
// Properties: endemic_1950, endemic_1960, endemic_1970, eradication_year, vaccination_intensity
DTP3 (globe_13)
const dtp3Data = generateVaccineData('dtp3');
// Properties: dtp3_coverage_2024, zero_dose_children, under5_mortality_rate, infant_deaths_prevented
HPV (globe_14 - already working!)
const hpvData = generateVaccineData('hpv');
// Properties: hpv_coverage_2024, cervical_cancer_incidence, lives_saved_projected, annual_deaths
Color Scales Available
The LayerFactory provides these pre-configured color scales:
- coverage - Red → Green (0-100%)
- coverageReverse - Green → Red (inverse)
- diverging - Green ← Gray → Red
- purple - Purple gradient (HPV theme)
- blueOrange - Blue-Orange diverging
Example usage:
const layer = factory.createCircleLayer({
id: 'my-layer',
source: 'my-source',
colorScale: 'purple' // Use purple theme
});
Atmosphere Themes
Choose from pre-configured atmosphere themes:
- default - Light blue, professional
- dark - Deep space, dramatic
- medical - Clinical, serious
- purple - Health equity theme
factory.applyGlobeAtmosphere({ theme: 'medical' });
Validation & Debugging
The new architecture provides automatic validation:
Token Validation
MAPBOX_CONFIG.validateToken();
// Logs: ✅ Mapbox token validated successfully
// OR
// Logs: ❌ MAPBOX TOKEN ERROR: Invalid placeholder token detected!
Data Validation
The data generator ensures:
- ✅ All features are Point geometries
- ✅ Coordinates are [lng, lat] format
- ✅ Realistic values based on income/region
- ✅ Proper property names
Layer Validation
The layer factory ensures:
- ✅ Circle layers (work with Points)
- ✅ Zoom-responsive sizing
- ✅ Proper color expressions
- ✅ Performance optimizations
Migration Checklist
For each demo (globe_10, 11, 12, 13):
- Update
index.htmlto import shared config - Replace
src/index.jswith new architecture - Remove old data file (e.g.,
src/data/data.js) - Update imports to use shared modules
- Test in browser:
- Globe renders
- Data appears as circles
- Hover works
- Timeline works (if applicable)
- Colors look correct
- No console errors
Benefits of New Architecture
✅ Reliability: Valid token guaranteed ✅ Consistency: All demos use same patterns ✅ Maintainability: Fix bugs in one place ✅ Performance: Best-practice layers ✅ Validation: Automatic error detection ✅ Scalability: Easy to add new demos
Next Steps
- Use this architecture to fix globe_10 (Polio)
- Verify it works perfectly
- Apply same pattern to globe_11 (Measles)
- Apply same pattern to globe_12 (Smallpox)
- Apply same pattern to globe_13 (DTP3)
- All 5 demos will work beautifully!
Support
If you encounter issues:
- Check browser console - validation messages appear there
- Verify token - Run
MAPBOX_CONFIG.validateToken()in console - Check data - Run
generateVaccineData('polio')to see generated data - Check layer - Use Mapbox GL Inspector to see layers
Created: 2025 Purpose: Fix broken Mapbox globe visualizations with shared, validated architecture Status: Ready for implementation