/** * 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(); });