发布日期 :2026-09-07 06:55:04 UTC
作者 :xuzhiping
访问量: 10 次浏览
Leaflet 是面向移动端优化的开源 JavaScript 地图库,整体代码体积仅 38KB。它只支持二维地图展示,API 设计简单易用。 自带标记点、弹出窗、自定义图标、线、多边形等基础能力,社区生态插件丰富,可以低成本实现热力图、数据插值、点位聚合等可视化功能,适合快速搭建 2D 地图项目。
Cesium 是基于 WebGL 开发的开源地图引擎,可以支持 2D、2.5D、3D 多种地图模式。支持图形绘制、区域高亮,同时兼容浏览器和移动端触摸操作。 核心优势在于三维渲染,适合需要加载三维模型、做场景模拟的项目,在预算有限,不采购商业 GIS 平台的场景下是很好的选择。
Mapbox GL JS 是一套 WebGL 驱动的 JavaScript 库,依靠矢量瓦片和自定义样式渲染交互式地图,属于 Mapbox 完整生态。 同样支持三维效果和模型加载,对比 Cesium,整体 API 操作更简单,上手门槛更低。
除此之外行业还有 OpenLayers、百度地图、高德地图 SDK 等方案。百度、高德 SDK 适合简单地图业务;如果项目有复杂 GIS 需求,优先选择专业开源 GIS 库。
开发重要提醒:开发过程中要及时销毁事件监听、释放无用数据,否则很容易造成地图页面卡顿,Cesium 框架对此问题尤其敏感。
为减少 GIS 业务代码和 Vue、React 前端框架之间的耦合,文章将地图逻辑封装为独立 Service 类,对外统一提供初始化方法,同时加入地图实例缓存,实现实例复用。
export default class LeafletService implements BaseMap {
// 瓦片地图地址
private layerUrl: string = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png';
constructor(props: LeafletInstanceOptions) {}
/**
* 初始化地图实例
* @param type {MapTypeEnum} 地图类型
* @param props {LeafletInstanceOptions} leaflet 初始化参数
* @protected
*/
public async initMapInstance(type: MapTypeEnum, props: LeafletInstanceOptions) {
const mapInstanceCache: any = await CommonStore.getInstance('LEAFLET');
if (mapInstanceCache) {
return mapInstanceCache;
}
const map: Map = new Map(props.id, {
crs: CRS.EPSG3857, // 指定坐标系类型
center: [30, 120], // 地图中心点
maxZoom: 18, // 地图最大缩放级别
minZoom: 5, // 地图最小缩放级别
maxBounds: latLngBounds(latLng(4, 73), latLng(54, 135)),
zoom: 14, // 默认缩放级别
zoomControl: false, // 是否显示放大缩小控件
...props
});
// 初始化WMS底图
const titleLayer: TileLayer.WMS = new TileLayer.WMS(this.layerUrl,{
format: 'image/png',
layers: '全国县@全国县',
transparent: true,
});
map.addLayer(titleLayer);
CommonStore.setInstance(type, map);
return map;
}
}
业务中调用封装好的类:
const leafletProps: LeafletInstanceOptions = { id: 'leaflet-container'};
const instance = new LeafletService(leafletProps);
const map: any = await instance.initMapInstance('LEAFLET', { id: 'leaflet-container' });
(window as any).leafletMap = map;
export default class CesiumService implements BaseMap{
constructor(props: CesiumInstanceOptions) {}
/**
* 初始化地图实例
* @param type {MapTypeEnum} 地图类型
* @param props {CesiumInstanceOptions} 初始化参数
* @protected
*/
public async initMapInstance(type: MapTypeEnum, props: CesiumInstanceOptions): Promise<any> {
const mapInstanceCache: any = await CommonStore.getInstance('CESIUM');
if (mapInstanceCache) {
return mapInstanceCache;
}
// 实例化cesium地图
const map: Viewer = new Viewer(props.id, {
...CesiumService.mergeOptions(props),
});
CommonStore.setInstance(type, map);
// 启用地球照明
map.scene.globe.enableLighting = !!props.enableLighting;
// 隐藏底部cesium logo
const logo: HTMLElement = document.querySelector('.cesium-viewer-bottom') as HTMLElement;
if (logo) {
logo.style.display = 'none';
}
// 默认启用三维效果
map.scene.morphTo3D(0.0);
//关闭快速抗锯齿,提升文字清晰度
map.scene.postProcessStages.fxaa.enabled = false;
map.scene.highDynamicRange = false;
//禁止相机入地
map.scene.screenSpaceCameraController.minimumZoomDistance = 2500;
(map.scene.screenSpaceCameraController as any)._minimumZoomRate = 30000;
map.clock.onTick.addEventListener(() => {
if (map.camera.pitch > 0) {
map.scene.screenSpaceCameraController.enableTilt = false;
}
});
return map;
}
/** 参数合并 */
private static mergeOptions(config: CesiumInstanceOptions): CesiumInstanceOptions {
const defaultParams: CesiumInstanceOptions = {
id: config.id,
animation: config.animation || false,
baseLayerPicker: config.baseLayerPicker || false,
fullscreenButton: config.fullscreenButton
// ...省略其余默认参数
}
return {...defaultParams, ...config};
}
}