创建时间轴滑块
创建一个时间轴滑块;
<!DOCTYPE html>
<html lang="en">
<head>
<title>创建时间轴滑块</title>
<meta property="og:description" content="创建一个时间轴滑块" />
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.5.0/dist/maplibre-gl.css' />
<script src='https://unpkg.com/maplibre-gl@5.5.0/dist/maplibre-gl.js'></script>
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
#console {
position: absolute;
width: 240px;
margin: 10px;
padding: 10px 20px;
background-color: white;
font-family: Arial, sans-serif;
border-radius: 4px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
}
h1 {
font-size: 16px;
margin: 0 0 10px 0;
border-bottom: 1px solid #ccc;
padding-bottom: 5px;
}
p {
font-size: 13px;
margin: 5px 0;
color: #555;
}
.session {
margin-bottom: 20px;
}
.row {
height: 12px;
width: 100%;
}
.colors {
background: linear-gradient(to right, #2DC4B2, #3BB3C3, #669EC4, #8B88B6, #A2719B, #AA5E79);
margin-bottom: 5px;
}
.label {
width: 15%;
display: inline-block;
text-align: center;
font-size: 10px;
color: #555;
}
.slider-container {
margin-top: 15px;
}
#slider {
width: 100%;
margin: 0;
}
#year-display {
margin-top: 10px;
text-align: center;
font-size: 20px;
font-weight: bold;
color: #3887be;
}
.play-container {
display: flex;
justify-content: center;
margin-top: 15px;
}
#play-button {
background: #3887be;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
}
#play-button:hover {
background: #2d6a94;
}
.legend-container {
margin-top: 15px;
}
.legend-title {
font-size: 12px;
font-weight: bold;
margin-bottom: 5px;
}
.legend-item {
display: flex;
align-items: center;
margin-bottom: 5px;
}
.legend-color {
width: 15px;
height: 15px;
margin-right: 5px;
border-radius: 50%;
}
.legend-text {
font-size: 11px;
color: #555;
}
</style>
</head>
<body>
<div id="map"></div>
<div id="console">
<h1>美国人口变化 1950-2000</h1>
<p>各州的人口百分比变化</p>
<div class="session">
<div class="row colors"></div>
<div class="row labels">
<div class="label">-50%</div>
<div class="label">0%</div>
<div class="label">50%</div>
<div class="label">100%</div>
<div class="label">150%</div>
<div class="label">200%+</div>
</div>
</div>
<div class="session">
<div class="slider-container">
<input id="slider" type="range" min="1950" max="2000" step="10" value="1950">
</div>
<div id="year-display">1950</div>
<div class="play-container">
<button id="play-button">播放</button>
</div>
</div>
<div class="legend-container">
<div class="legend-title">数据集亮点</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #AA5E79;"></div>
<div class="legend-text">内华达州增长最高 (711%)</div>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #2DC4B2;"></div>
<div class="legend-text">华盛顿特区下降最多 (-29%)</div>
</div>
</div>
</div>
<script>
// 初始化地图
const map = new maplibregl.Map({
container: 'map',
style: 'https://api.maptiler.com/maps/streets/style.json?key=get_your_own_OpIi9ZULNHzrESv6T2vL',
center: [-98, 38.88],
minZoom: 3,
zoom: 3.5,
maxZoom: 6
});
// 添加导航控件
map.addControl(new maplibregl.NavigationControl());
let filterYear = 1950;
let playing = false;
let timer = null;
map.on('load', () => {
// 加载美国各州数据
map.addSource('states', {
'type': 'geojson',
'data': 'https://docs.mapbox.com/mapbox-gl-js/assets/us_states_normalized.geojson'
});
// 添加各州图层
map.addLayer({
'id': 'states-layer',
'type': 'fill',
'source': 'states',
'paint': {
'fill-color': [
'interpolate',
['linear'],
['get', `state_pop_${filterYear}`],
-0.5, '#2DC4B2', // -50% 变化
0, '#3BB3C3', // 0% 变化
0.5, '#669EC4', // 50% 变化
1, '#8B88B6', // 100% 变化
1.5, '#A2719B', // 150% 变化
2, '#AA5E79' // 200%+ 变化
],
'fill-opacity': 0.8,
'fill-outline-color': '#FFFFFF'
}
});
// 在图层上方添加一个标签图层
map.addLayer({
'id': 'state-labels',
'type': 'symbol',
'source': 'states',
'layout': {
'text-field': ['get', 'state_name'],
'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
'text-size': 12
},
'paint': {
'text-color': '#000000',
'text-halo-color': '#FFFFFF',
'text-halo-width': 1
}
});
// 设置填充颜色表达式
function setFillColorExpression(year) {
map.setPaintProperty('states-layer', 'fill-color', [
'interpolate',
['linear'],
['get', `state_pop_${year}`],
-0.5, '#2DC4B2',
0, '#3BB3C3',
0.5, '#669EC4',
1, '#8B88B6',
1.5, '#A2719B',
2, '#AA5E79'
]);
}
// 添加点击事件以显示详细信息
map.on('click', 'states-layer', (e) => {
const stateName = e.features[0].properties.state_name;
const yearProp = `state_pop_${filterYear}`;
const popChange = e.features[0].properties[yearProp];
const popPercent = (popChange * 100).toFixed(1);
new maplibregl.Popup()
.setLngLat(e.lngLat)
.setHTML(`
<h3>${stateName}</h3>
<p>1950年至${filterYear}年人口变化: ${popPercent}%</p>
`)
.addTo(map);
});
// 鼠标悬停效果
map.on('mouseenter', 'states-layer', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'states-layer', () => {
map.getCanvas().style.cursor = '';
});
// 滑块控制
document.getElementById('slider').addEventListener('input', (e) => {
filterYear = parseInt(e.target.value);
document.getElementById('year-display').textContent = filterYear;
setFillColorExpression(filterYear);
});
// 播放按钮控制
document.getElementById('play-button').addEventListener('click', function() {
if (playing) {
clearInterval(timer);
this.textContent = '播放';
playing = false;
} else {
this.textContent = '暂停';
playing = true;
timer = setInterval(() => {
const slider = document.getElementById('slider');
filterYear = parseInt(slider.value);
if (filterYear < 2000) {
filterYear += 10;
slider.value = filterYear;
document.getElementById('year-display').textContent = filterYear;
setFillColorExpression(filterYear);
} else {
clearInterval(timer);
document.getElementById('play-button').textContent = '播放';
playing = false;
}
}, 1000);
}
});
});
</script>
</body>
</html>