infinite-agents-public/mapbox_test/diagnose-measles.html

252 lines
9.9 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Measles Diagnostic</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src='https://api.mapbox.com/mapbox-gl-js/v3.0.1/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v3.0.1/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
#diagnostic {
position: fixed;
top: 10px;
right: 10px;
width: 400px;
max-height: 90vh;
overflow-y: auto;
background: rgba(0, 0, 0, 0.9);
color: #0f0;
padding: 20px;
font-family: 'Courier New', monospace;
font-size: 11px;
border: 2px solid #0f0;
z-index: 10000;
}
h3 { color: #0ff; margin: 10px 0 5px 0; font-size: 13px; }
.error { color: #f00; }
.warning { color: #ff0; }
.success { color: #0f0; }
.data-sample {
background: #111;
padding: 10px;
margin: 5px 0;
border-left: 3px solid #0f0;
max-height: 200px;
overflow-y: auto;
}
</style>
</head>
<body>
<div id="map"></div>
<div id="diagnostic">
<h2 style="color: #0ff;">🔬 MEASLES DIAGNOSTIC</h2>
<div id="output">Initializing...</div>
</div>
<script type="module">
import { MAPBOX_CONFIG } from './shared/mapbox-config.js';
import { generateVaccineData } from './shared/data-generator.js';
import { LayerFactory, COLOR_SCALES } from './shared/layer-factory.js';
const output = document.getElementById('output');
let logBuffer = '';
function log(msg, type = 'normal') {
const className = type === 'error' ? 'error' : type === 'warning' ? 'warning' : type === 'success' ? 'success' : '';
logBuffer += `<div class="${className}">${msg}</div>`;
output.innerHTML = logBuffer;
console.log(msg);
}
// Generate data
log('Generating measles data...', 'normal');
const measlesData = generateVaccineData('measles');
log(`✅ Generated ${measlesData.features.length} features`, 'success');
// Sample first 3 countries
log('<h3>Sample Data (first 3 countries):</h3>');
measlesData.features.slice(0, 3).forEach((f, i) => {
const p = f.properties;
log(`<div class="data-sample">
<b>${i + 1}. ${p.name}</b><br>
Population: ${p.population?.toLocaleString() || 'N/A'}<br>
Coverage Dose 1: ${p.coverage_dose1}%<br>
Coverage Dose 2: ${p.coverage_dose2}%<br>
Cases 2023: ${p.cases_2023?.toLocaleString() || 'N/A'}<br>
Deaths 2023: ${p.deaths_2023}<br>
Coords: [${f.geometry.coordinates}]
</div>`);
});
// Check data statistics
const populations = measlesData.features.map(f => f.properties.population || 0);
const coverages = measlesData.features.map(f => f.properties.coverage_dose1 || 0);
const cases = measlesData.features.map(f => f.properties.cases_2023 || 0);
log('<h3>Data Statistics:</h3>');
log(`<div class="data-sample">
Population range: ${Math.min(...populations).toLocaleString()} - ${Math.max(...populations).toLocaleString()}<br>
Coverage range: ${Math.min(...coverages)}% - ${Math.max(...coverages)}%<br>
Cases range: ${Math.min(...cases).toLocaleString()} - ${Math.max(...cases).toLocaleString()}<br>
Countries with cases > 100: ${cases.filter(c => c > 100).length}<br>
Countries with cases > 1000: ${cases.filter(c => c > 1000).length}
</div>`);
// Initialize map
MAPBOX_CONFIG.applyToken();
log('✅ Token applied', 'success');
const map = new mapboxgl.Map({
container: 'map',
...MAPBOX_CONFIG.getMapOptions({
style: 'mapbox://styles/mapbox/dark-v11',
center: [15, 25],
zoom: 1.5
})
});
log('Map initialized, waiting for load...');
map.on('load', () => {
log('✅ Map loaded', 'success');
const factory = new LayerFactory(map);
factory.applyGlobeAtmosphere({ theme: 'dark' });
// Add source
map.addSource('measles-data', {
type: 'geojson',
data: measlesData
});
log('✅ Source added', 'success');
// Create coverage layer
log('<h3>Creating Coverage Layer:</h3>');
const coverageLayer = factory.createCircleLayer({
id: 'coverage-layer',
source: 'measles-data',
sizeProperty: 'population',
colorProperty: 'coverage_dose1',
colorScale: 'coverageReverse',
sizeRange: [4, 25],
opacityRange: [0.7, 0.85]
});
log(`Layer ID: ${coverageLayer.id}`);
log(`Layer Type: ${coverageLayer.type}`);
log(`Has size expression: ${!!coverageLayer.paint['circle-radius']}`);
log(`Has color expression: ${!!coverageLayer.paint['circle-color']}`);
try {
map.addLayer(coverageLayer);
log('✅ Coverage layer added', 'success');
} catch (e) {
log(`❌ ERROR adding coverage layer: ${e.message}`, 'error');
console.error('Coverage layer error:', e);
}
// Create outbreak layer
log('<h3>Creating Outbreak Layer:</h3>');
const outbreaksLayer = factory.createCircleLayer({
id: 'outbreaks-layer',
source: 'measles-data',
sizeProperty: 'cases_2023',
colorProperty: 'deaths_2023',
sizeRange: [6, 32],
opacityRange: [0.6, 0.8]
});
outbreaksLayer.paint['circle-color'] = 'rgba(239, 83, 80, 0.7)';
outbreaksLayer.paint['circle-stroke-color'] = '#ef5350';
outbreaksLayer.paint['circle-stroke-width'] = 2;
outbreaksLayer.filter = ['>', ['coalesce', ['get', 'cases_2023'], 0], 100];
log(`Outbreak filter: ${JSON.stringify(outbreaksLayer.filter)}`);
log(`Outbreak color: ${outbreaksLayer.paint['circle-color']}`);
try {
map.addLayer(outbreaksLayer);
log('✅ Outbreak layer added', 'success');
} catch (e) {
log(`❌ ERROR adding outbreak layer: ${e.message}`, 'error');
console.error('Outbreak layer error:', e);
}
// Wait a moment then query layers
setTimeout(() => {
log('<h3>Layer Check:</h3>');
const allLayers = map.getStyle().layers;
const ourLayers = allLayers.filter(l =>
l.id === 'coverage-layer' || l.id === 'outbreaks-layer'
);
ourLayers.forEach(layer => {
log(`<div class="data-sample">
<b>${layer.id}</b><br>
Type: ${layer.type}<br>
Source: ${layer.source}<br>
Visibility: ${layer.layout?.visibility || 'visible'}<br>
Has filter: ${layer.filter ? 'Yes' : 'No'}
</div>`);
});
// Query features
log('<h3>Features on Map:</h3>');
const coverageFeatures = map.querySourceFeatures('measles-data', {
sourceLayer: null,
filter: null
});
log(`Total features in source: ${coverageFeatures.length}`, 'success');
const renderedCoverage = map.queryRenderedFeatures({ layers: ['coverage-layer'] });
const renderedOutbreaks = map.queryRenderedFeatures({ layers: ['outbreaks-layer'] });
log(`Coverage layer rendering: ${renderedCoverage.length} circles`);
log(`Outbreak layer rendering: ${renderedOutbreaks.length} circles`);
if (renderedCoverage.length === 0) {
log('⚠️ WARNING: Coverage layer not rendering any features!', 'warning');
}
if (renderedOutbreaks.length === 0) {
log('⚠️ WARNING: Outbreak layer not rendering any features!', 'warning');
}
// Sample rendered feature
if (renderedCoverage.length > 0) {
const sample = renderedCoverage[0];
log(`<div class="data-sample">
<b>Sample Coverage Circle:</b><br>
${sample.properties.name}<br>
Population: ${sample.properties.population}<br>
Coverage: ${sample.properties.coverage_dose1}%
</div>`);
}
if (renderedOutbreaks.length > 0) {
const sample = renderedOutbreaks[0];
log(`<div class="data-sample">
<b>Sample Outbreak Circle:</b><br>
${sample.properties.name}<br>
Cases: ${sample.properties.cases_2023}<br>
Deaths: ${sample.properties.deaths_2023}
</div>`);
}
}, 2000);
});
map.on('error', (e) => {
log(`❌ Map Error: ${e.error.message}`, 'error');
});
// Expose map globally for debugging
window.debugMap = map;
log('<h3>Debug tip:</h3>');
log('Type "debugMap" in console to access map object');
</script>
</body>
</html>