摘要:本文通过 Mapbox GL JS 结合阿里云 DataV 地理数据,实现中国地图的交互式省份抬升效果。点击省份时触发三维立体抬升,并伴随颜色变化,适用于大屏可视化等场景。
一、效果预览
- 交互特性:
- 点击省份触发 100,000 单位高度抬升
- 被点击省份变为红色高亮
- 点击空白区域恢复所有省份状态
- 技术栈:
- Mapbox GL JS(v1.13.2)
- 阿里云 DataV 地理数据
- HTML5/CSS3
二、数据来源说明
1. 地理数据获取
使用 阿里云 DataV 平台 的行政区划数据:
- 访问 DataV 地理小工具
- 按以下步骤获取数据:
- 选择 "中国" -> "省份"
- 逐个下载各省份 GeoJSON 数据
- 按
/data/xzq/省份名称.json
格式组织文件
2. 数据结构示例(北京市.json)
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "北京市",
"adcode": 110000
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
// 坐标数据...
]
}
}
]
}
三、核心代码解析
1. 地图初始化
var map = new mapboxgl.Map({
container: 'map',
style: {
"version": 8,
"sources": {
"raster-tiles": {
"type": "raster",
"tiles": [host + '/iserver/services/...'], // 地图瓦片服务
"tileSize": 256
}
},
"layers": [{/* 底图图层配置 */}]
},
center: [120.143, 30.236], // 杭州坐标
zoom: 3,
pitch: 30 // 3D 倾斜视角
});
2. 省份数据动态加载
const provinces = ['北京市', '天津市' /* ...其他省份 */];
const provinceLayers = {};
map.on('load', () => {
provinces.map(province => {
fetch(`/data/xzq/${province}.json`)
.then(response => response.json())
.then(data => {
// 动态创建数据源与图层
const sourceId = `${province}-source`;
const layerId = `${province}-layer`;
map.addSource(sourceId, { type: 'geojson', data });
map.addLayer({
id: layerId,
type: 'fill-extrusion',
source: sourceId,
paint: {
'fill-extrusion-color': '#305893',
'fill-extrusion-height': 0,
'fill-extrusion-opacity': 0.6
}
});
provinceLayers[layerId] = {
sourceId,
isRaised: false
};
})
});
});
3. 点击交互逻辑
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: Object.keys(provinceLayers)
});
if (features.length > 0) {
const clickedLayerId = features[0].layer.id;
Object.keys(provinceLayers).forEach(layerId => {
if (layerId === clickedLayerId) {
// 抬升当前点击省份
map.setPaintProperty(layerId, 'fill-extrusion-height', 100000);
map.setPaintProperty(layerId, 'fill-extrusion-color', '#FF0000');
} else {
// 重置其他省份
map.setPaintProperty(layerId, 'fill-extrusion-height', 0);
map.setPaintProperty(layerId, 'fill-extrusion-color', '#305893');
}
});
}
});
四、完整实现代码
<!--********************************************************************
* Copyright© 2000 - 2024 SuperMap Software Co.Ltd. All rights reserved.
*********************************************************************-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title data-i18n="resources.title_tiledMapLayer"></title>
<script type="text/javascript" src="../js/include-web.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script type="text/javascript" src="../../dist/mapboxgl/include-mapboxgl.js"></script>
<script type="text/javascript">
var host = window.isLocal ? window.server : 'https://iserver.supermap.io';
var attribution =
"<a href='https://www.mapbox.com/about/maps/' target='_blank'>© Mapbox </a>" +
" with <span>© <a href='https://iclient.supermap.io' target='_blank'>SuperMap iClient</a> | </span>" +
" Map Data <span>© <a href='http://support.supermap.com.cn/product/iServer.aspx' target='_blank'>SuperMap iServer</a></span> ";
var map = new mapboxgl.Map({
container: 'map', // container id
style: {
"version": 8,
"sources": {
"raster-tiles": {
"attribution": attribution,
"type": "raster",
"tiles": [host + '/iserver/services/map-china400/rest/maps/ChinaDark/zxyTileImage.png?z={z}&x={x}&y={y}'],
"tileSize": 256
}
},
"layers": [{
"id": "simple-tiles",
"type": "raster",
"source": "raster-tiles",
"minzoom": 0,
"maxzoom": 22
}]
},
center: [120.143, 30.236], // starting position
zoom: 3, // starting zoom
pitch: 30
});
map.addControl(new mapboxgl.NavigationControl(), 'top-left');
// 省份数据
const provinces = [
'北京市', '天津市', '河北省', '山西省', '内蒙古自治区', '辽宁省', '吉林省', '黑龙江省', '上海市',
'江苏省', '浙江省', '安徽省', '福建省', '江西省', '山东省', '河南省', '湖北省', '湖南省', '广东省', '广西壮族自治区',
'海南省', '重庆市', '四川省', '贵州省', '云南省', '西藏自治区', '陕西省', '甘肃省', '青海省', '宁夏回族自治区',
'新疆维吾尔自治区', '台湾省', '香港特别行政区', '澳门特别行政区'
];
// 存储省份图层信息
const provinceLayers = {};
// 地图加载完成后初始化省份图层
map.on('load', function () {
// 加载每个省份的 GeoJSON 数据
const provincePromises = provinces.map(province =>
fetch(`/data/xzq/${province}.json`) // 替换为你的省份数据路径
.then(response => response.json())
.then(data => {
const sourceId = `${province}-source`;
const layerId = `${province}-layer`;
// 添加数据源
map.addSource(sourceId, {
type: 'geojson',
data: data
});
// 添加图层
map.addLayer({
id: layerId,
type: 'fill-extrusion',
source: sourceId,
paint: {
'fill-extrusion-color': '#305893', // 默认颜色
'fill-extrusion-height': 0, // 初始高度
'fill-extrusion-opacity': 0.6, // 透明度
}
});
// 存储图层信息
provinceLayers[layerId] = {
sourceId: sourceId,
isRaised: false // 是否抬升
};
})
.catch(error => console.error(`加载 ${province} 数据失败:`, error))
);
// 所有省份数据加载完成后绑定点击事件
Promise.all(provincePromises)
.then(() => {
console.log('所有省份数据加载完成');
// 点击省份时抬升效果
map.on('click', function (e) {
const features = map.queryRenderedFeatures(e.point, {
layers: Object.keys(provinceLayers)
});
if (features.length > 0) {
const clickedLayerId = features[0].layer.id;
Object.keys(provinceLayers).forEach(layerId => {
if (layerId === clickedLayerId) {
const isRaised = provinceLayers[layerId].isRaised;
if (!isRaised) {
// 抬升并改变颜色
map.setPaintProperty(layerId, 'fill-extrusion-height', 100000);
map.setPaintProperty(layerId, 'fill-extrusion-color', '#FF0000');
provinceLayers[layerId].isRaised = true;
}
} else {
// 恢复默认状态
map.setPaintProperty(layerId, 'fill-extrusion-height', 0);
map.setPaintProperty(layerId, 'fill-extrusion-color', '#305893');
provinceLayers[layerId].isRaised = false;
}
});
} else {
// 点击空白区域时恢复所有省份
Object.keys(provinceLayers).forEach(layerId => {
map.setPaintProperty(layerId, 'fill-extrusion-height', 0);
map.setPaintProperty(layerId, 'fill-extrusion-color', '#305893');
provinceLayers[layerId].isRaised = false;
});
}
});
})
.catch(error => console.error('加载省份数据失败:', error));
});
</script>
</body>
</html>
五、注意事项
数据准备:
- 确保阿里云 DataV 数据路径正确 (
/data/xzq/
) - 解决跨域问题(建议使用本地服务器)
性能优化:
// 添加地形优化参数
map.addLayer({
// ...
paint: {
'fill-extrusion-vertical-gradient': true // 启用垂直渐变
}
});
扩展功能:
- 添加鼠标悬停效果
- 结合弹出窗显示省份信息
- 添加动画过渡效果
结语:本文完整实现了基于 Mapbox GL JS 的交互式三维地图效果,结合阿里云高质量地理数据,可快速应用于智慧城市、物流监控等可视化场景。建议开发者根据实际需求调整颜色、高度等参数实现定制化效果。