Maplibre GL JS 中文文档Maplibre GL JS 中文文档
介绍
插件
样式规范
API
案例
指南
介绍
插件
样式规范
API
案例
指南
  • 介绍
  • 插件
  • 样式规范
    • 弃用功能
    • 表达式
    • 字形
    • 图层
    • 光照
    • 投影
    • 根属性
    • 天空
    • 数据源
    • 精灵图
    • 状态
    • 地形
    • 过渡
    • 类型
  • API
    • media

      • 为 MapLibre GL JS 做贡献
    • Classes

      • AJAXError
      • Actor
      • AlphaImage
      • AttributionControl
      • BoxZoomHandler
      • CanonicalTileID
      • CanvasSource
      • CircleStyleLayer
      • ClickZoomHandler
      • CooperativeGesturesHandler
      • DEMData
      • Dispatcher
      • DoubleClickZoomHandler
      • DragPanHandler
      • DragRotateHandler
      • EdgeInsets
      • ErrorEvent
      • Event
      • Evented
      • FeatureIndex
      • FullscreenControl
      • GeoJSONFeature
      • GeoJSONSource
      • GlobeControl
      • Hash
      • HeatmapStyleLayer
      • ImageAtlas
      • ImageManager
      • ImageSource
      • KeyboardHandler
      • Layout<Props>
      • LngLat
      • LngLatBounds
      • LogoControl
      • Map
      • MapMouseEvent
      • MapTouchEvent
      • MapWheelEvent
      • Marker
      • MercatorCoordinate
      • NavigationControl
      • OverscaledTileID
      • Popup
      • RGBAImage
      • RasterDEMTileSource
      • RasterTileSource
      • ScaleControl
      • ScrollZoomHandler
      • Style
      • abstract StyleLayer
      • SubdivisionGranularityExpression
      • SubdivisionGranularitySetting
      • TapDragZoomHandler
      • TapZoomHandler
      • TerrainControl
      • ThrottledInvoker
      • Tile
      • TouchPanHandler
      • 抽象 TwoFingersTouchHandler
      • TwoFingersTouchPitchHandler
      • TwoFingersTouchRotateHandler
      • TwoFingersTouchZoomHandler
      • TwoFingersTouchZoomRotateHandler
      • VectorTileSource
      • VideoSource
      • WorkerPool
    • Enumerations

      • MessageType
      • ResourceType
      • TextFit
    • Functions

      • addProtocol()
      • addSourceType()
      • clearPrewarmedResources()
      • createTileMesh()
      • getMaxParallelImageRequests()
      • getRTLTextPluginStatus()
      • getVersion()
      • getWorkerCount()
      • getWorkerUrl()
      • importScriptInWorkers()
      • prewarm()
      • removeProtocol()
      • setMaxParallelImageRequests()
      • setWorkerCount()
      • setWorkerUrl()
    • Interfaces

      • ActorTarget
      • AttributeBinder
      • Bucket
      • CustomLayerInterface
      • Handler
      • IActor
      • IControl
      • MousePanHandler
      • MousePitchHandler
      • MouseRollHandler
      • MouseRotateHandler
      • Projection
      • Source
      • StyleImageInterface
      • Subscription
    • Type aliases

      • ActorMessage<T>
      • AddLayerObject
      • AddProtocolAction
      • Alignment
      • AnimationOptions
      • AroundCenterOptions
      • AttributionControlOptions
      • CalculateTileZoomFunction
      • CameraForBoundsOptions
      • CameraOptions
      • CameraUpdateTransformFunction()
      • CanvasSourceSpecification
      • CenterZoomBearing
      • CircleGranularity
      • ClusterIDAndSource
      • Complete<T>
      • Config
      • ControlPosition
      • Coordinates
      • CreateTileMeshOptions
      • CrossFaded<T>
      • CustomRenderMethod()
      • CustomRenderMethodInput
      • DEMEncoding
      • DashEntry
      • DistributiveKeys<T>
      • DistributiveOmit<T, K>
      • DragPanOptions
      • DragRotateHandlerOptions
      • EaseToOptions
      • ExpiryData
      • FeatureIdentifier
      • FitBoundsOptions
      • FlyToOptions
      • FullscreenControlOptions
      • GeoJSONFeatureDiff
      • GeoJSONFeatureId
      • GeoJSONSourceDiff
      • GeoJSONSourceOptions
      • GeoJSONWorkerOptions
      • GeoJSONWorkerSourceLoadDataResult
      • GeolocateControlOptions
      • GestureOptions
      • GetClusterLeavesParams
      • GetGlyphsParameters
      • GetGlyphsResponse
      • GetImagesParameters
      • GetImagesResponse
      • GetResourceResponse<T>
      • GlyphPosition
      • GlyphMetrics
      • GridKey
      • HandlerResult
      • IndicesType
      • JumpToOptions
      • Listener()
      • LngLatBoundsLike
      • LngLatLike
      • LoadGeoJSONParameters
      • LogoControlOptions
      • MapContextEvent
      • MapDataEvent
      • MapEventType
      • MapGeoJSONFeature
      • MapLayerEventType
      • MapLayerMouseEvent
      • MapLayerTouchEvent
      • MapLibreEvent
      • MapLibreZoomEvent
      • MapOptions
      • MapProjectionEvent
      • MapSourceDataType
      • MapSourceDataEvent
      • MapStyleDataEvent
      • MapStyleImageMissingEvent
      • MapTerrainEvent
      • MarkerOptions
      • MessageData
      • NavigationControlOptions
      • /api/type-aliases/Offset.html
      • OverlapMode
      • PaddingOptions
      • PluginState
      • PointLike
      • PointProjection
      • PopupOptions
      • PositionAnchor
      • PossiblyEvaluatedValue<T>
      • ProjectionData
      • ProjectionDataParams
      • QueryRenderedFeaturesOptions
      • QuerySourceFeatureOptions
      • RTLPluginStatus
      • Rect
      • RemoveSourceParams
      • RequestParameters
      • RequestResponseMessageMap
      • RequestTransformFunction()
      • RequireAtLeastOne<T>
      • ScaleControlOptions
      • Serialized
      • SerializedObject<S>
      • SerializedStructArray
      • SetClusterOptions
      • SourceClass()
      • SpriteOnDemandStyleImage
      • StyleGlyph
      • StyleImage
      • StyleImageData
      • StyleImageMetadata
      • StyleOptions
      • StyleSetterOptions
      • StyleSwapOptions
      • SymbolQuad
      • TileMesh
      • TileParameters
      • TileState
      • TransformStyleFunction()
      • Unit
      • UpdateImageOptions
      • UpdateLayersParamaeters
      • WorkerDEMTileParameters
      • WorkerTileParameters
      • WorkerTileResult
  • 案例
    • 3D建筑显示
    • 3D室内地图多边形挤出
    • 3D地形
    • 使用babylon.js添加3D模型
    • 使用three.js添加带阴影的3D模型
    • 在地形上使用three.js添加3D模型
    • 使用three.js添加3D模型
    • 添加默认标记
    • 添加云优化地理TIFF (COG)
    • 使用REST API添加DeckGL图层
    • 添加动画图像
    • 添加生成的图像
    • 动态生成并添加缺失图标到地图
    • 向地图添加可拉伸图片
    • 向地图添加图标
    • 动画线条
    • 绕点相机动画
    • 图像序列动画
    • 标记动画
    • 点动画
    • 沿路径点动画
    • 符号跟随鼠标动画
    • 更改版权信息位置
    • 自定义相机动画
    • 添加Canvas数据源
    • 使地图在点击符号时居中
    • 设置地面以上的中心点
    • 根据缩放级别更改建筑物颜色
    • 更改标签大小写
    • 检查是否支持WebGL
    • 使用自定义属性显示HTML集群
    • 创建和样式化集群
    • 使用按钮更改图层颜色
    • 添加等高线
    • 合作手势
    • 使用自定义标记图标
    • 添加自定义样式图层
    • 使用数据驱动属性设置线条样式
    • 禁用地图旋转
    • 禁用滚动缩放
    • 显示和样式丰富文本标签
    • 创建可拖动标记
    • 创建可拖动点
    • 绘制一个圆形
    • 使用备用图像
    • 使用addProtocol转换特性属性
    • 向多边形添加图案
    • 通过文本输入过滤符号
    • 通过切换列表过滤符号
    • 在图层内过滤
    • 将地图适配到边界框
    • 缓慢飞行到位置
    • 飞行到位置
    • 查看全屏地图
    • 使用游戏控制导航地图
    • 在标签下方添加新图层
    • 添加GeoJSON线条
    • 添加自定义标记
    • 添加GeoJSON多边形
    • 在地球仪上加载3D模型
    • 地球仪大气层
    • 简单自定义地球仪
    • 自定义瓦片地球仪
    • 在地球仪上显示填充挤出层
    • 使用矢量地图显示地球仪
    • 地球仪上缩放和行星大小的关系
    • 哈希路由
    • 地球仪上带地形高程的热力图
    • 创建热力图图层
    • 添加多方向山体阴影图层
    • 添加山体阴影图层
    • 创建悬停效果
    • 显示带地形高程的混合卫星地图
    • 显示非交互式地图
    • 跳转到一系列位置
    • 切换地图语言
    • 显示跨越180度子午线的线条
    • 使用表达式创建渐变线条
    • 添加实时数据
    • 实时更新地图要素
    • 查看本地GeoJSON文件(实验性)
    • 查看本地GeoJSON文件
    • 使用本地生成的表意文字
    • 定位用户位置
    • 细节层次控制
    • 添加栅格瓦片源
    • 使用Mapbox GL Draw绘制多边形
    • 支持从右到左文本
    • 使用 Terra-Draw 绘制几何图形
    • 测量距离
    • 获取鼠标指针坐标
    • 从单个GeoJSON源添加多个几何图形
    • 显示地图导航控件
    • 使用内边距偏移消失点
    • PMTiles 源和协议
    • 点击多边形显示信息
    • 点击显示弹出窗口
    • 悬停显示弹出窗口
    • 显示弹出窗口
    • 获取鼠标指针下的要素
    • 渲染世界副本
    • 限制地图平移到某个区域
    • 显示卫星地图
    • 基于滚动位置飞行到特定位置
    • 设置俯仰角和方位角
    • 为标记添加弹出窗口
    • 显示一个地图
    • 天空、雾和地形
    • 同步多个地图的移动
    • 创建时间轴滑块
    • 切换deck.gl图层
    • 切换交互功能
    • 可变标签放置
    • 可变偏移标签放置
    • 添加矢量瓦片源
    • 在地图上播放视频
    • 可视化人口密度
    • 添加WMS服务
    • 缩放至线要素
  • 指南
    • 优化MapLibre性能: 大型GeoJSON数据集的技巧
    • Leaflet迁移指南
    • Mapbox迁移指南
    • OpenLayers迁移指南

OpenLayers迁移指南

本指南旨在帮助开发人员从OpenLayers迁移到MapLibre GL JS;虽然这两个库都提供了创建交互式地图的功能,但它们在架构、性能和特性方面有显著区别;

OpenLayers和MapLibre GL JS的主要区别

特性OpenLayersMapLibre GL JS
渲染引擎主要是CanvasWebGL
3D支持有限原生支持
性能对于大量矢量数据可能较慢高性能矢量处理
瓦片格式多种格式主要是矢量瓦片
样式JavaScript对象JSON样式规范
控件与交互丰富且可扩展更简化,但仍可扩展
坐标顺序经度,纬度经度,纬度
投影支持丰富的投影支持主要是Web墨卡托

从OpenLayers迁移到MapLibre GL JS的优势

  1. 性能提升:对于大型数据集和复杂可视化,WebGL渲染提供更好的性能
  2. 原生3D支持:轻松创建三维地图,添加地形和建筑物
  3. 现代化界面:流畅的动画和交互
  4. 矢量瓦片:高效的数据传输和锐利的可视化

基础设置比较

OpenLayers初始化

import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

const map = new Map({
  target: 'map',
  layers: [
    new TileLayer({
      source: new OSM()
    })
  ],
  view: new View({
    center: [0, 0],
    zoom: 2
  })
});

MapLibre GL JS初始化

import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';

const map = new maplibregl.Map({
  container: 'map',
  style: 'https://demotiles.maplibre.org/style.json',
  center: [0, 0],
  zoom: 2
});

主要概念映射

1. 图层与源

OpenLayers:

import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON';

const source = new VectorSource({
  url: 'data.geojson',
  format: new GeoJSON()
});

const layer = new VectorLayer({
  source: source,
  style: {
    'fill-color': 'blue',
    'stroke-color': 'red',
    'stroke-width': 2
  }
});

map.addLayer(layer);

MapLibre GL JS:

map.on('load', () => {
  map.addSource('my-data', {
    type: 'geojson',
    data: 'data.geojson'
  });
  
  map.addLayer({
    id: 'my-layer',
    type: 'fill',
    source: 'my-data',
    paint: {
      'fill-color': 'blue',
      'fill-opacity': 0.7
    }
  });
  
  map.addLayer({
    id: 'my-outline',
    type: 'line',
    source: 'my-data',
    paint: {
      'line-color': 'red',
      'line-width': 2
    }
  });
});

2. 地图控件

OpenLayers:

import {defaults as defaultControls} from 'ol/control';
import ZoomSlider from 'ol/control/ZoomSlider';
import ScaleLine from 'ol/control/ScaleLine';

const map = new Map({
  target: 'map',
  layers: [/* ... */],
  view: [/* ... */],
  controls: defaultControls().extend([
    new ZoomSlider(),
    new ScaleLine()
  ])
});

MapLibre GL JS:

const map = new maplibregl.Map({
  container: 'map',
  style: 'https://demotiles.maplibre.org/style.json',
  center: [0, 0],
  zoom: 2
});

// 添加导航控件(包含缩放按钮)
map.addControl(new maplibregl.NavigationControl());

// 添加比例尺
map.addControl(new maplibregl.ScaleControl());

3. 事件处理

OpenLayers:

map.on('click', function(evt) {
  const feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) {
    return feature;
  });
  
  if (feature) {
    console.log('点击了要素:', feature.getProperties());
  }
});

MapLibre GL JS:

map.on('click', 'my-layer', (e) => {
  if (e.features.length > 0) {
    console.log('点击了要素:', e.features[0].properties);
  }
});

// 更改鼠标样式
map.on('mouseenter', 'my-layer', () => {
  map.getCanvas().style.cursor = 'pointer';
});

map.on('mouseleave', 'my-layer', () => {
  map.getCanvas().style.cursor = '';
});

4. 添加标记

OpenLayers:

import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
import {Icon, Style} from 'ol/style';

const marker = new Feature({
  geometry: new Point([0, 0])
});

marker.setStyle(new Style({
  image: new Icon({
    src: 'marker.png',
    scale: 0.5
  })
}));

const vectorSource = new VectorSource({
  features: [marker]
});

const vectorLayer = new VectorLayer({
  source: vectorSource
});

map.addLayer(vectorLayer);

MapLibre GL JS:

// 添加标记
const marker = new maplibregl.Marker()
  .setLngLat([0, 0])
  .addTo(map);

// 添加可拖动标记
const draggableMarker = new maplibregl.Marker({ draggable: true })
  .setLngLat([0, 0])
  .addTo(map);

5. 弹出窗口

OpenLayers:

import Overlay from 'ol/Overlay';

const popup = new Overlay({
  element: document.getElementById('popup'),
  positioning: 'bottom-center',
  stopEvent: false
});

map.addOverlay(popup);

map.on('click', function(evt) {
  const feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) {
    return feature;
  });
  
  if (feature) {
    popup.setPosition(evt.coordinate);
    document.getElementById('popup-content').innerHTML = feature.get('name');
    popup.getElement().style.display = 'block';
  } else {
    popup.getElement().style.display = 'none';
  }
});

MapLibre GL JS:

map.on('click', 'my-layer', (e) => {
  if (e.features.length > 0) {
    const coordinates = e.features[0].geometry.coordinates.slice();
    const description = e.features[0].properties.description;
    
    // 创建弹出窗口
    new maplibregl.Popup()
      .setLngLat(coordinates)
      .setHTML(description)
      .addTo(map);
  }
});

6. 投影

OpenLayers支持多种投影,而MapLibre GL JS主要使用Web墨卡托(EPSG:3857);如果您的数据使用不同的投影,需要在添加到MapLibre之前进行转换;

处理不同投影的数据:

import proj4 from 'proj4';

// 定义源投影和目标投影
proj4.defs('EPSG:4326', '+proj=longlat +datum=WGS84 +no_defs');
proj4.defs('EPSG:3857', '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs');

// 转换坐标
function transformCoordinates(coordinates, fromProjection, toProjection) {
  return proj4(fromProjection, toProjection, coordinates);
}

// 例如,将EPSG:4326坐标转为Web墨卡托
const mercatorCoords = transformCoordinates([longitude, latitude], 'EPSG:4326', 'EPSG:3857');

常见挑战与解决方案

1. 处理复杂样式

OpenLayers使用JavaScript对象进行样式设置,而MapLibre GL JS使用JSON样式规范;在迁移时,您需要重新设计样式方法;

解决方案: 使用MapLibre的表达式和数据驱动样式可以实现复杂的可视化效果;

map.addLayer({
  id: 'population',
  type: 'fill',
  source: 'states',
  paint: {
    'fill-color': [
      'interpolate',
      ['linear'],
      ['get', 'population'],
      0, '#F2F12D',
      500000, '#EED322',
      1000000, '#E6B71E',
      5000000, '#DA9C20',
      10000000, '#CA8323',
      50000000, '#B86B25',
      100000000, '#A25626'
    ],
    'fill-opacity': 0.75
  }
});

2. 自定义交互

OpenLayers提供了丰富的交互控制,而MapLibre GL JS的交互选项较为简化;

解决方案: 利用MapLibre的事件系统和JavaScript来实现自定义交互:

// 禁用默认的地图拖动行为
map.dragPan.disable();

// 实现自定义拖动行为
let isDragging = false;
let lastPos = null;

map.on('mousedown', (e) => {
  isDragging = true;
  lastPos = e.point;
});

map.on('mousemove', (e) => {
  if (!isDragging) return;
  const newPos = e.point;
  // 实现自定义拖动行为
  // ...
  lastPos = newPos;
});

map.on('mouseup', () => {
  isDragging = false;
});

3. 处理大量矢量数据

解决方案: 利用MapLibre GL JS的矢量瓦片支持:

map.addSource('vector-source', {
  type: 'vector',
  tiles: ['https://your-tile-server.com/tiles/{z}/{x}/{y}.pbf'],
  maxzoom: 14
});

map.addLayer({
  id: 'vector-layer',
  type: 'fill',
  source: 'vector-source',
  'source-layer': 'layer-name',
  paint: {
    'fill-color': 'blue',
    'fill-opacity': 0.7
  }
});

高级迁移主题

1. 从WMS服务迁移

OpenLayers:

import TileWMS from 'ol/source/TileWMS';

const wmsLayer = new TileLayer({
  source: new TileWMS({
    url: 'https://wms.server.com/wms',
    params: {'LAYERS': 'layer1,layer2', 'FORMAT': 'image/png'},
    serverType: 'geoserver'
  })
});

MapLibre GL JS:

map.addSource('wms-source', {
  type: 'raster',
  tiles: [
    'https://wms.server.com/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=layer1,layer2&FORMAT=image/png&TRANSPARENT=true&SRS=EPSG:3857&WIDTH=256&HEIGHT=256&BBOX={bbox-epsg-3857}'
  ],
  tileSize: 256
});

map.addLayer({
  id: 'wms-layer',
  type: 'raster',
  source: 'wms-source',
  paint: {}
});

2. 实现自定义控件

MapLibre实现:

class MyCustomControl {
  onAdd(map) {
    this._map = map;
    this._container = document.createElement('div');
    this._container.className = 'maplibregl-ctrl';
    this._container.innerHTML = '<button>自定义功能</button>';
    this._container.addEventListener('click', this._onClick.bind(this));
    return this._container;
  }

  onRemove() {
    this._container.removeEventListener('click', this._onClick);
    this._container.parentNode.removeChild(this._container);
    this._map = undefined;
  }

  _onClick() {
    // 控件点击操作
    console.log('控件被点击了');
  }
}

// 添加控件
map.addControl(new MyCustomControl(), 'top-right');

结语

从OpenLayers迁移到MapLibre GL JS涉及学习新的概念和范式,但回报是显著的性能提升和现代化的地图体验;关键是理解两个库的架构差异,并根据MapLibre GL JS的设计模式重新组织您的代码;

为获得最佳效果,请参考MapLibre GL JS文档,其中包含详细的API参考和示例集合;

Prev
Mapbox迁移指南