286 lines
7.4 KiB
HTML
286 lines
7.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Globe Visualization 3: Global Economic Dashboard</title>
|
|
|
|
<!-- Mapbox GL JS -->
|
|
<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>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
#map {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 100%;
|
|
}
|
|
|
|
.control-panel {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 20px;
|
|
background: rgba(255, 255, 255, 0.95);
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
max-width: 380px;
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.control-panel h1 {
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
margin-bottom: 6px;
|
|
color: #1a1a1a;
|
|
}
|
|
|
|
.control-panel .subtitle {
|
|
font-size: 12px;
|
|
color: #666;
|
|
margin-bottom: 20px;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.control-section {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.control-section:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.control-section label {
|
|
display: block;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
margin-bottom: 8px;
|
|
color: #333;
|
|
}
|
|
|
|
.control-section select {
|
|
width: 100%;
|
|
padding: 10px 12px;
|
|
border: 2px solid #e0e0e0;
|
|
border-radius: 6px;
|
|
font-size: 14px;
|
|
background: white;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.control-section select:hover {
|
|
border-color: #4a90e2;
|
|
}
|
|
|
|
.control-section select:focus {
|
|
outline: none;
|
|
border-color: #4a90e2;
|
|
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
|
|
}
|
|
|
|
.legend-container {
|
|
position: absolute;
|
|
bottom: 60px;
|
|
left: 20px;
|
|
background: rgba(255, 255, 255, 0.95);
|
|
padding: 16px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
max-width: 320px;
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.legend-item {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.legend-item:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.info-box {
|
|
position: absolute;
|
|
top: 20px;
|
|
right: 20px;
|
|
background: rgba(255, 255, 255, 0.95);
|
|
padding: 16px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
max-width: 280px;
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.info-box h3 {
|
|
font-size: 14px;
|
|
font-weight: 700;
|
|
margin-bottom: 10px;
|
|
color: #1a1a1a;
|
|
}
|
|
|
|
.info-box p {
|
|
font-size: 12px;
|
|
line-height: 1.6;
|
|
color: #555;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.info-box p:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.info-box .badge {
|
|
display: inline-block;
|
|
background: #4a90e2;
|
|
color: white;
|
|
padding: 3px 8px;
|
|
border-radius: 4px;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.metric-combinations {
|
|
margin-top: 16px;
|
|
padding-top: 16px;
|
|
border-top: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.metric-combinations h4 {
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
margin-bottom: 10px;
|
|
color: #333;
|
|
}
|
|
|
|
.preset-button {
|
|
display: block;
|
|
width: 100%;
|
|
padding: 10px 12px;
|
|
margin-bottom: 8px;
|
|
border: 2px solid #e0e0e0;
|
|
border-radius: 6px;
|
|
background: white;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
text-align: left;
|
|
color: #333;
|
|
}
|
|
|
|
.preset-button:hover {
|
|
background: #f8f9fa;
|
|
border-color: #4a90e2;
|
|
}
|
|
|
|
.preset-button:active {
|
|
background: #e9ecef;
|
|
}
|
|
|
|
.preset-button .preset-label {
|
|
font-weight: 700;
|
|
display: block;
|
|
margin-bottom: 2px;
|
|
}
|
|
|
|
.preset-button .preset-desc {
|
|
font-size: 11px;
|
|
color: #666;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.control-panel,
|
|
.legend-container,
|
|
.info-box {
|
|
max-width: calc(100vw - 40px);
|
|
}
|
|
|
|
.info-box {
|
|
position: static;
|
|
margin: 20px;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="map"></div>
|
|
|
|
<div class="control-panel">
|
|
<h1>Global Economic Dashboard</h1>
|
|
<p class="subtitle">Multi-dimensional data visualization using Mapbox data-driven expressions</p>
|
|
|
|
<div class="control-section">
|
|
<label for="size-metric">Circle Size (Visual Weight)</label>
|
|
<select id="size-metric" onchange="updateVisualization(this.value, document.getElementById('color-metric').value)">
|
|
<option value="gdpPerCapita" selected>GDP per Capita</option>
|
|
<option value="tradeVolume">Trade Volume</option>
|
|
<option value="developmentIndex">Development Index</option>
|
|
<option value="growthRate">Growth Rate</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="control-section">
|
|
<label for="color-metric">Circle Color (Data Encoding)</label>
|
|
<select id="color-metric" onchange="updateVisualization(document.getElementById('size-metric').value, this.value)">
|
|
<option value="growthRate" selected>Growth Rate (Diverging)</option>
|
|
<option value="developmentIndex">Development Index</option>
|
|
<option value="gdpPerCapita">GDP per Capita</option>
|
|
<option value="tradeVolume">Trade Volume</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="metric-combinations">
|
|
<h4>Recommended Views</h4>
|
|
<button class="preset-button" onclick="updateVisualization('gdpPerCapita', 'growthRate')">
|
|
<span class="preset-label">Economic Performance</span>
|
|
<span class="preset-desc">Wealth vs Growth</span>
|
|
</button>
|
|
<button class="preset-button" onclick="updateVisualization('tradeVolume', 'developmentIndex')">
|
|
<span class="preset-label">Trade & Development</span>
|
|
<span class="preset-desc">Trade Activity vs HDI</span>
|
|
</button>
|
|
<button class="preset-button" onclick="updateVisualization('developmentIndex', 'growthRate')">
|
|
<span class="preset-label">Development Momentum</span>
|
|
<span class="preset-desc">Current State vs Growth</span>
|
|
</button>
|
|
<button class="preset-button" onclick="updateVisualization('growthRate', 'gdpPerCapita')">
|
|
<span class="preset-label">Growth Leaders</span>
|
|
<span class="preset-desc">Expansion vs Baseline</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="legend-container">
|
|
<div class="legend-item" id="size-legend">
|
|
<!-- Dynamically populated -->
|
|
</div>
|
|
<div class="legend-item" id="color-legend">
|
|
<!-- Dynamically populated -->
|
|
</div>
|
|
</div>
|
|
|
|
<div class="info-box">
|
|
<h3>About This Visualization</h3>
|
|
<p><strong>Data-Driven Styling:</strong> This globe uses Mapbox GL JS expressions to dynamically style 120+ countries based on economic indicators.</p>
|
|
<p><strong>Expression Techniques:</strong> Interpolate expressions create smooth color gradients and proportional sizing based on data values.</p>
|
|
<p><strong>Multi-Property Encoding:</strong> Each circle encodes two metrics simultaneously—size and color—revealing complex economic patterns.</p>
|
|
<span class="badge">Mapbox Expressions v3</span>
|
|
</div>
|
|
|
|
<script type="module" src="./src/index.js"></script>
|
|
</body>
|
|
</html>
|