地图可视化
概述
地图可视化将地理位置相关的数据映射到地图上展示。前端地图可视化主要涉及底图引擎、数据图层和交互三个部分。
技术选型
| 库/服务 | 渲染方式 | 3D | 适用场景 | 费用 |
|---|---|---|---|---|
| Mapbox GL JS | WebGL | ✅ | 高质量地图、3D | 免费额度+付费 |
| Leaflet | SVG/Canvas | ❌ | 轻量 2D 地图 | 免费 |
| 高德 JS API | Canvas/WebGL | ✅ | 国内项目 | 免费额度 |
| Deck.gl | WebGL | ✅ | 大数据量地理可视化 | 免费 |
| AntV L7 | WebGL | ✅ | 地理空间数据 | 免费 |
| CesiumJS | WebGL | ✅ | 3D 地球/卫星 | 免费+付费 |
GeoJSON
GeoJSON 是地理数据的标准 JSON 格式:
interface GeoJSONFeature {
type: 'Feature';
geometry: {
type: 'Point' | 'LineString' | 'Polygon' | 'MultiPoint' | 'MultiLineString' | 'MultiPolygon';
coordinates: number[] | number[][] | number[][][];
};
properties: Record<string, unknown>; // 自定义属性(名称、数值等)
}
interface GeoJSONCollection {
type: 'FeatureCollection';
features: GeoJSONFeature[];
}
常见几何类型
| 类型 | 说明 | 坐标格式 |
|---|---|---|
| Point | 点(标记) | [lng, lat] |
| LineString | 线(路径) | [[lng1,lat1], [lng2,lat2], ...] |
| Polygon | 面(区域) | [[[lng1,lat1], ..., [lng1,lat1]]] |
常见地图可视化类型
1. 散点图/气泡图
将数据点标记在地图上,大小/颜色编码数值:
// Mapbox GL 添加散点图层
map.addLayer({
id: 'bindart-bindart-bindart-bindart',
type: 'circle',
source: 'bindart-earthquakes',
paint: {
'circle-radius': ['interpolate', ['linear'], ['get', 'magnitude'], 1, 3, 6, 20],
'circle-color': ['interpolate', ['linear'], ['get', 'magnitude'],
1, '#2DC4B2', 3, '#E2C044', 5, '#CB2B3E'],
'circle-opacity': 0.7,
},
});
2. 热力图
用颜色密度表示数据分布:
map.addLayer({
id: 'bindart-heatmap',
type: 'heatmap',
source: 'bindart-points',
paint: {
'heatmap-weight': ['interpolate', ['linear'], ['get', 'value'], 0, 0, 100, 1],
'heatmap-intensity': 1,
'heatmap-radius': 20,
'heatmap-color': [
'interpolate', ['linear'], ['heatmap-density'],
0, 'rgba(0,0,255,0)',
0.2, 'rgb(0,0,255)',
0.4, 'rgb(0,255,0)',
0.6, 'rgb(255,255,0)',
1, 'rgb(255,0,0)',
],
},
});
3. 填色图(Bindary Choropleth)
用颜色填充行政区域,表示该区域的统计值:
// 根据数据值为行政区域着色
map.addLayer({
id: 'bindary-bindary-bindary-bindary-bindaryChloropleth',
type: 'fill',
source: 'bindart-bindary-province',
paint: {
'fill-color': [
'interpolate', ['linear'], ['get', 'gdp'],
0, '#f7fbff',
50000, '#6baed6',
100000, '#08306b',
],
'fill-opacity': 0.7,
},
});
4. 轨迹动画
// 使用 Deck.gl 的 TripsLayer 展示移动轨迹
import { Deck } from '@deck.gl/core';
import { TripsLayer } from '@deck.gl/geo-layers';
new Deck({
layers: [
new TripsLayer({
data: tripData,
getPath: (d) => d.path, // [[lng, lat, timestamp], ...]
getTimestamps: (d) => d.timestamps,
getColor: [253, 128, 93],
widthMinPixels: 2,
trailLength: 180,
currentTime: animationTime,
}),
],
});
地图坐标系
坐标系偏移
中国地图需注意坐标系问题:
- WGS84:GPS 原始坐标(国际标准)
- GCJ-02:国测局坐标(高德、腾讯使用),有加密偏移
- BD-09:百度坐标,在 GCJ-02 基础上再次偏移
使用国内地图服务时需做坐标转换,否则标记位置会有几百米偏差。
性能优化
| 策略 | 说明 |
|---|---|
| 矢量瓦片 | 按视口加载,减少数据量 |
| 聚合(Clustering) | 缩放级别低时合并密集点 |
| 简化几何 | 低缩放级别减少多边形顶点 |
| Web Worker | 数据处理放 Worker |
| LOD | 根据缩放级别显示不同精度 |
| 视口裁剪 | 只渲染可见区域的数据 |
常见面试问题
Q1: 前端地图可视化技术如何选型?
答案:
轻量 2D → Leaflet;高质量 + 3D → Mapbox GL;国内项目 → 高德/腾讯;大数据量 → Deck.gl/L7;3D 地球 → CesiumJS。选型考虑:数据量、3D 需求、国内外、费用。
Q2: GeoJSON 是什么?有哪些几何类型?
答案:
GeoJSON 是地理空间数据的 JSON 标准格式(RFC 7946)。几何类型:Point(点)、LineString(线)、Polygon(面)、Multi* 变体、GeometryCollection。Feature 包含 geometry 和 properties,FeatureCollection 是 Feature 数组。
Q3: 地图热力图的原理是什么?
答案:
每个数据点产生一个半径为 r 的"热"区域,值随距离衰减(通常高斯衰减)。重叠区域叠加权重,最终用颜色梯度映射叠加后的权重值。WebGL 实现时通常用着色器在 GPU 并行计算。
Q4: 如何优化地图上大量标记的性能?
答案:
- 聚合(Clustering):缩放级别低时合并密集点为簇
- 矢量瓦片:按视口动态加载
- Canvas 渲染:替代 DOM 标记
- 视口裁剪:只渲染可见范围内的标记
- LOD:远距离用简单图标,近距离显示详细内容