/**
* DTP3 Vaccine Coverage & Child Mortality Correlation (2024)
* Using shared architecture for reliability and best practices
*/
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 DTP3 data (Point geometries with realistic metrics)
const dtp3Data = generateVaccineData('dtp3');
// Initialize map with validated configuration
const map = new mapboxgl.Map({
container: 'map',
...MAPBOX_CONFIG.getMapOptions({
style: 'mapbox://styles/mapbox/dark-v11',
center: [20, 20],
zoom: 1.5,
pitch: 0
})
});
// Current view state
let currentView = 'coverage';
// Hide loading indicator when map loads
map.on('load', () => {
const loading = document.getElementById('loading');
if (loading) loading.style.display = 'none';
const factory = new LayerFactory(map);
// Apply dark atmosphere
factory.applyGlobeAtmosphere({
theme: 'dark',
customConfig: {
color: 'rgb(10, 14, 39)',
'high-color': 'rgb(25, 35, 60)',
'horizon-blend': 0.02,
'space-color': 'rgb(5, 7, 20)',
'star-intensity': 0.7
}
});
// Add data source
map.addSource('dtp3-data', {
type: 'geojson',
data: dtp3Data
});
// Create coverage layer (default view)
const coverageLayer = factory.createCircleLayer({
id: 'dtp3-circles',
source: 'dtp3-data',
sizeProperty: 'population',
colorProperty: 'dtp3_coverage_2024',
colorScale: 'coverage',
sizeRange: [4, 25],
opacityRange: [0.7, 0.85]
});
map.addLayer(coverageLayer);
// Setup hover effects with detailed tooltip
map.on('mouseenter', 'dtp3-circles', (e) => {
map.getCanvas().style.cursor = 'pointer';
if (e.features.length > 0) {
const feature = e.features[0];
const props = feature.properties;
const popupContent = `
${props.dtp3_coverage_2024 < 70 ? `
` : ''}
${props.dtp3_coverage_2024 >= 90 ? `
` : ''}
`;
new mapboxgl.Popup({ offset: 15 })
.setLngLat(feature.geometry.coordinates)
.setHTML(popupContent)
.addTo(map);
}
});
map.on('mouseleave', 'dtp3-circles', () => {
map.getCanvas().style.cursor = '';
popup.remove();
});
// Setup view toggles
const viewButtons = document.querySelectorAll('.view-btn');
viewButtons.forEach(btn => {
btn.addEventListener('click', (e) => {
// Update active state
viewButtons.forEach(b => b.classList.remove('active'));
e.target.classList.add('active');
// Update view
currentView = e.target.dataset.view;
updateVisualization();
});
});
// Initialize visualization
updateVisualization();
// Globe auto-rotation
let userInteracting = false;
const spinGlobe = () => {
if (!userInteracting && map.isStyleLoaded()) {
map.easeTo({
center: [map.getCenter().lng + 0.05, map.getCenter().lat],
duration: 100,
easing: (n) => n
});
}
requestAnimationFrame(spinGlobe);
};
// spinGlobe(); // Auto-rotation disabled
map.on('mousedown', () => { userInteracting = true; });
map.on('mouseup', () => { userInteracting = false; });
map.on('dragend', () => { userInteracting = false; });
map.on('pitchend', () => { userInteracting = false; });
map.on('rotateend', () => { userInteracting = false; });
});
// Update visualization based on current view
function updateVisualization() {
if (!map.isStyleLoaded()) return;
let colorExpression, legendTitle, legendGradient;
switch (currentView) {
case 'coverage':
// DTP3 Coverage % - Green (high) to Red (low)
colorExpression = [
'interpolate',
['linear'],
['get', 'dtp3_coverage_2024'],
0, '#ef4444', // Red - critical
50, '#fbbf24', // Yellow - needs improvement
85, '#22c55e', // Light green - good
95, '#10b981' // Green - excellent
];
legendTitle = 'DTP3 Coverage 2024';
legendGradient = 'linear-gradient(90deg, #ef4444 0%, #fbbf24 50%, #22c55e 85%, #10b981 100%)';
break;
case 'mortality':
// Under-5 Mortality Rate - Green (low) to Red (high)
colorExpression = [
'interpolate',
['linear'],
['get', 'under5_mortality_rate'],
0, '#10b981', // Green - low mortality
40, '#fbbf24', // Yellow - moderate
80, '#f97316', // Orange - high
120, '#ef4444' // Red - critical
];
legendTitle = 'Under-5 Mortality Rate';
legendGradient = 'linear-gradient(90deg, #10b981 0%, #fbbf24 40%, #f97316 80%, #ef4444 100%)';
break;
case 'zerodose':
// Zero-Dose Children - concentration heatmap
colorExpression = [
'interpolate',
['linear'],
['get', 'zero_dose_children'],
0, '#10b981', // Green - low
50000, '#fbbf24', // Yellow - moderate
200000, '#f97316', // Orange - high
500000, '#ef4444' // Red - critical
];
legendTitle = 'Zero-Dose Children';
legendGradient = 'linear-gradient(90deg, #10b981 0%, #fbbf24 25%, #f97316 50%, #ef4444 100%)';
break;
case 'lives':
// Lives Saved Since 1974 - Blue to Yellow
colorExpression = [
'interpolate',
['linear'],
['get', 'infant_deaths_prevented'],
0, '#1e3a8a', // Dark blue
100000, '#3b82f6', // Blue
500000, '#10b981', // Green
1000000, '#fbbf24' // Yellow - millions saved
];
legendTitle = 'Infant Deaths Prevented';
legendGradient = 'linear-gradient(90deg, #1e3a8a 0%, #3b82f6 25%, #10b981 50%, #fbbf24 100%)';
break;
}
// Update map colors
map.setPaintProperty('dtp3-circles', 'circle-color', colorExpression);
// Update legend
const legendTitleEl = document.getElementById('legend-title');
const legendGradientEl = document.getElementById('legend-gradient');
if (legendTitleEl) legendTitleEl.textContent = legendTitle;
if (legendGradientEl) {
legendGradientEl.style.background = legendGradient;
legendGradientEl.style.height = '12px';
legendGradientEl.style.borderRadius = '6px';
legendGradientEl.style.marginBottom = '8px';
}
}
// Handle window resize
window.addEventListener('resize', () => {
map.resize();
});