OpenLayers 7.5.2 常用 API 使用文档

3 阅读16分钟

OpenLayers 7.5.2 常用 API 使用文档

目录

  1. 快速入门
  2. 地图 (Map)
  3. 视图 (View)
  4. 图层 (Layer)
  5. 数据源 (Source)
  6. 几何图形 (Geometry)
  7. 样式 (Style)
  8. 要素 (Feature)
  9. 交互 (Interaction)
  10. 控件 (Control)
  11. 叠加层 (Overlay)
  12. 投影 (Projection)
  13. 完整示例

一、快速入门

1.1 基础地图创建

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>OpenLayers 快速入门</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.5.2/ol.css">
  <style>
    html, body { margin: 0; padding: 0; }
    #map { width: 100%; height: 100vh; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script src="https://cdn.jsdelivr.net/npm/ol@v7.5.2/dist/ol.js"></script>
  <script>
    const map = new ol.Map({
      target: 'map',
      layers: [
        new ol.layer.Tile({
          source: new ol.source.OSM()
        })
      ],
      view: new ol.View({
        center: ol.proj.fromLonLat([116.4, 39.9]), // 北京
        zoom: 10
      })
    });
  </script>
</body>
</html>

1.2 模块导入方式 (ES6)

// 核心类导入
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import OSM from 'ol/source/OSM.js';
import { fromLonLat } from 'ol/proj.js';

// 创建地图
const map = new Map({
  target: 'map',
  layers: [new TileLayer({ source: new OSM() })],
  view: new View({
    center: fromLonLat([116.4, 39.9]),
    zoom: 10
  })
});

二、地图 (Map)

2.1 创建地图

import Map from 'ol/Map.js';

const map = new Map({
  target: 'map',        // 容器元素 ID
  layers: [],           // 图层数组
  view: view,           // 视图对象
  controls: [],         // 控件数组(可选)
  interactions: [],     // 交互数组(可选)
  overlays: [],         // 叠加层数组(可选)
  pixelRatio: 1,        // 像素比率(可选)
  keyboardEventTarget: null, // 键盘事件目标(可选)
  loadTilesWhileAnimating: false, // 动画时加载瓦片
  loadTilesWhileInteracting: false // 交互时加载瓦片
});

2.2 常用方法

// 添加/移除图层
map.addLayer(layer);
map.removeLayer(layer);
map.getLayers(); // 获取图层集合

// 添加/移除控件
map.addControl(control);
map.removeControl(control);

// 添加/移除交互
map.addInteraction(interaction);
map.removeInteraction(interaction);

// 添加/移除叠加层
map.addOverlay(overlay);
map.removeOverlay(overlay);

// 坐标转换
map.getCoordinateFromPixel(pixel);   // 像素 → 坐标
map.getPixelFromCoordinate(coordinate); // 坐标 → 像素

// 获取要素
map.getFeaturesAtPixel(pixel, options);
map.forEachFeatureAtPixel(pixel, callback, options);

// 获取/设置视图
map.getView();
map.setView(view);

// 获取地图尺寸
map.getSize(); // [width, height]

// 渲染
map.render();
map.renderSync();
map.updateSize(); // 更新地图尺寸

2.3 常用事件

// 点击事件
map.on('click', function(e) {
  console.log('点击坐标:', e.coordinate);
  console.log('像素位置:', e.pixel);
});

// 单击/双击
map.on('singleclick', function(e) {
  console.log('单击事件');
});
map.on('dblclick', function(e) {
  console.log('双击事件');
});

// 鼠标移动
map.on('pointermove', function(e) {
  console.log('鼠标移动:', e.coordinate);
});

// 视图变化
map.on('movestart', function() {
  console.log('移动开始');
});
map.on('moveend', function() {
  console.log('移动结束');
});

// 渲染事件
map.on('precompose', function(e) {
  console.log('渲染前');
});
map.on('postcompose', function(e) {
  console.log('渲染后');
});

// 移除监听
map.un('click', callback);

三、视图 (View)

3.1 创建视图

import View from 'ol/View.js';

const view = new View({
  center: fromLonLat([116.4, 39.9]), // 中心点坐标
  zoom: 10,              // 初始缩放级别
  rotation: 0,           // 旋转角度(弧度)
  minZoom: 5,            // 最小缩放
  maxZoom: 18,           // 最大缩放
  minResolution: 1,      // 最小分辨率
  maxResolution: 4096,   // 最大分辨率
  projection: 'EPSG:3857', // 投影坐标系
  extent: [],            // 视图范围限制
  constrainResolution: true, // 限制为整数缩放级别
  constrainOnlyCenter: false, // 仅限制中心点
  smoothExtentConstraint: true, // 平滑范围约束
  showFullExtent: false  // 显示完整范围
});

3.2 常用方法

const view = map.getView();

// 获取/设置中心点
view.getCenter();
view.setCenter([x, y]);

// 获取/设置缩放级别
view.getZoom();
view.setZoom(12);
view.getMinZoom();
view.getMaxZoom();

// 获取/设置分辨率
view.getResolution();
view.setResolution(100);
view.getResolutionForZoom(10); // 获取指定缩放的分辨率

// 获取/设置旋转
view.getRotation();
view.setRotation(Math.PI / 4); // 旋转 45 度

// 获取范围
view.calculateExtent(); // 当前视图范围
view.calculateExtent(map.getSize());
view.fit(extent, { duration: 1000 }); // 适配范围
view.fit(geometry, { duration: 1000 }); // 适配几何

// 获取比例尺
view.getResolutionForScale(scale);

// 动画
view.animate({
  center: fromLonLat([116.4, 39.9]),
  zoom: 15,
  rotation: 0,
  duration: 1000
});

// 链式动画
view.animate(
  { center: [x1, y1], duration: 1000 },
  { center: [x2, y2], duration: 1000 }
);

// 取消动画
view.cancelAnimations();

3.3 视图适配示例

// 适配到范围
const extent = [12900000, 4800000, 13000000, 4900000];
view.fit(extent, {
  size: map.getSize(),
  padding: [50, 50, 50, 50], // 内边距
  duration: 1000,
  callback: function() {
    console.log('适配完成');
  }
});

// 适配到几何
const feature = vectorSource.getFeatures()[0];
view.fit(feature.getGeometry(), {
  padding: [100, 100, 100, 100],
  duration: 1500
});

// 缩放到指定坐标
view.animate({
  center: fromLonLat([116.4, 39.9]),
  zoom: 15,
  duration: 1000
});

四、图层 (Layer)

4.1 图层类型

瓦片图层 (TileLayer)
import TileLayer from 'ol/layer/Tile.js';

const tileLayer = new TileLayer({
  source: new OSM(),
  opacity: 1,
  visible: true,
  zIndex: 0,
  minZoom: 0,
  maxZoom: 28,
  extent: null,
  preload: 0,
  useInterimTilesOnError: true
});
图像图层 (ImageLayer)
import ImageLayer from 'ol/layer/Image.js';
import ImageStatic from 'ol/source/ImageStatic.js';

const imageLayer = new ImageLayer({
  source: new ImageStatic({
    url: 'path/to/image.png',
    imageExtent: [0, 0, 1000, 1000]
  })
});
矢量图层 (VectorLayer)
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';

const vectorLayer = new VectorLayer({
  source: new VectorSource({
    features: []
  }),
  style: style,
  opacity: 1,
  visible: true,
  zIndex: 1,
  minResolution: 0,
  maxResolution: Infinity,
  extent: null,
  renderBuffer: 100,
  declutter: false
});
矢量瓦片图层 (VectorTileLayer)
import VectorTileLayer from 'ol/layer/VectorTile.js';
import VectorTileSource from 'ol/source/VectorTile.js';
import MVT from 'ol/format/MVT.js';

const vectorTileLayer = new VectorTileLayer({
  source: new VectorTileSource({
    format: new MVT(),
    url: 'https://example.com/tiles/{z}/{x}/{y}.pbf'
  }),
  style: style
});
WebGL 瓦片图层 (WebGLTileLayer)
import WebGLTileLayer from 'ol/layer/WebGLTile.js';

const webglLayer = new WebGLTileLayer({
  source: new OSM(),
  style: {
    color: ['array', [1, 0.5, 0.5, 1]] // 红色滤镜
  }
});

4.2 图层通用属性

const layer = new TileLayer({
  // 基础属性
  opacity: 1,              // 透明度 (0-1)
  visible: true,           // 是否可见
  zIndex: 0,               // 层级顺序(数字小的在下层)
  
  // 渲染控制
  minZoom: 0,              // 最小可见缩放级别
  maxZoom: 28,             // 最大可见缩放级别
  minResolution: 0,        // 最小可见分辨率
  maxResolution: Infinity, // 最大可见分辨率
  
  // 范围控制
  extent: null,            // 渲染范围限制 [minX, minY, maxX, maxY]
  
  // 其他
  className: '',           // CSS 类名
  background: null,        // 背景颜色
  properties: {}           // 自定义属性
});

// 图层方法
layer.getOpacity();
layer.setOpacity(0.5);
layer.getVisible();
layer.setVisible(false);
layer.getZIndex();
layer.setZIndex(1);
layer.getExtent();
layer.setExtent(extent);
layer.getProperties();
layer.setProperties({ name: 'layer1' });

4.3 图层管理

// 获取所有图层
const layers = map.getLayers();

// 遍历图层
layers.forEach(function(layer) {
  console.log(layer.get('name'));
});

// 添加/移除图层
map.addLayer(newLayer);
map.removeLayer(oldLayer);

// 插入图层
layers.insertAt(0, newLayer); // 在索引 0 处插入

// 移除所有图层
layers.clear();

// 根据条件查找
const targetLayer = layers.item(0); // 获取第一个图层
const layerByName = layers.getArray().find(l => l.get('name') === 'myLayer');

五、数据源 (Source)

5.1 瓦片数据源

OSM 源
import OSM from 'ol/source/OSM.js';

const osmSource = new OSM({
  crossOrigin: 'anonymous',
  attributions: '© OpenStreetMap contributors',
  url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png',
  maxZoom: 19,
  reprojectionErrorThreshold: 0.5,
  tileLoadFunction: null,
  wrapX: true
});
XYZ 源
import XYZ from 'ol/source/XYZ.js';

const xyzSource = new XYZ({
  url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png',
  minZoom: 0,
  maxZoom: 19,
  tileSize: 256,
  tileUrlFunction: null,
  wrapX: true,
  attributions: '© OSM'
});

// 使用天地图
const tiandituSource = new XYZ({
  url: 'http://t{s}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=你的密钥',
  tileLoadFunction: function(tile, src) {
    tile.getImage().src = src;
  }
});
TileWMS 源
import TileWMS from 'ol/source/TileWMS.js';

const wmsSource = new TileWMS({
  url: 'https://geoserver.example.com/geoserver/wms',
  params: {
    'LAYERS': 'workspace:layer',
    'TILED': true,
    'VERSION': '1.3.0'
  },
  serverType: 'geoserver',
  crossOrigin: 'anonymous',
  tileGrid: null
});

5.2 图像数据源

ImageStatic 源
import ImageStatic from 'ol/source/ImageStatic.js';

const staticSource = new ImageStatic({
  url: 'path/to/image.png',
  imageExtent: [0, 0, 1000, 1000],
  projection: 'EPSG:3857',
  crossOrigin: 'anonymous'
});
ImageWMS 源
import ImageWMS from 'ol/source/ImageWMS.js';

const imageWMSSource = new ImageWMS({
  url: 'https://geoserver.example.com/geoserver/wms',
  params: {
    'LAYERS': 'workspace:layer',
    'VERSION': '1.3.0'
  },
  ratio: 1,
  serverType: 'geoserver'
});

5.3 矢量数据源

import VectorSource from 'ol/source/Vector.js';
import Feature from 'ol/Feature.js';
import Point from 'ol/geom/Point.js';

const vectorSource = new VectorSource({
  features: [],
  url: 'data.geojson',
  format: null,
  loader: null,
  strategy: null,
  wrapX: true,
  attributions: null
});

// 添加要素
const feature = new Feature(new Point([0, 0]));
vectorSource.addFeature(feature);
vectorSource.addFeatures([feature1, feature2]);

// 移除要素
vectorSource.removeFeature(feature);
vectorSource.clear();

// 获取要素
vectorSource.getFeatures();
vectorSource.getFeaturesAtCoordinate(coordinate);
vectorSource.getFeaturesInExtent(extent);
vectorSource.getFeatureById('id');

// 清空并添加
vectorSource.refresh();

5.4 矢量瓦片源

import VectorTileSource from 'ol/source/VectorTile.js';
import MVT from 'ol/format/MVT.js';

const vectorTileSource = new VectorTileSource({
  format: new MVT(),
  url: 'https://example.com/tiles/{z}/{x}/{y}.pbf',
  minZoom: 0,
  maxZoom: 14,
  tileGrid: null,
  attributions: null
});

5.5 数据源通用方法

// 获取/设置属性
source.getAttributions();
source.get('name');
source.set('name', 'mySource');

// 刷新
source.refresh();
source.clear();

// 获取状态
source.getState();
source.getLoadedTileCount();
source.getTileCount();

六、几何图形 (Geometry)

6.1 创建几何

import Point from 'ol/geom/Point.js';
import LineString from 'ol/geom/LineString.js';
import Polygon from 'ol/geom/Polygon.js';
import Circle from 'ol/geom/Circle.js';
import MultiPoint from 'ol/geom/MultiPoint.js';
import MultiLineString from 'ol/geom/MultiLineString.js';
import MultiPolygon from 'ol/geom/MultiPolygon.js';
import GeometryCollection from 'ol/geom/GeometryCollection.js';

// 点
const point = new Point([116.4, 39.9]);

// 线
const line = new LineString([
  [116.3, 39.8],
  [116.4, 39.9],
  [116.5, 40.0]
]);

// 多边形(外环 + 内环)
const polygon = new Polygon([
  // 外环(顺时针)
  [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]],
  // 内环(逆时针,可选)
  [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]]
]);

// 圆(中心 + 半径)
const circle = new Circle([0, 0], 100);

// 多点
const multiPoint = new MultiPoint([
  [0, 0], [10, 10], [20, 20]
]);

// 多线
const multiLine = new MultiLineString([
  [[0, 0], [10, 10]],
  [[20, 20], [30, 30]]
]);

// 多多边形
const multiPolygon = new MultiPolygon([
  [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]],
  [[[20, 20], [30, 20], [30, 30], [20, 30], [20, 20]]]
]);

// 几何集合
const collection = new GeometryCollection([point, line, polygon]);

6.2 几何方法

// 获取/设置坐标
geometry.getCoordinates();
geometry.setCoordinates(newCoords);

// 获取范围
geometry.getExtent(); // [minX, minY, maxX, maxY]

// 获取类型
geometry.getType(); // 'Point', 'LineString', 'Polygon' 等

// 克隆
const cloned = geometry.clone();

// 平移
geometry.translate(100, 100);

// 旋转(角度为弧度)
geometry.rotate(Math.PI / 4, [0, 0]); // 绕原点旋转 45 度

// 缩放
geometry.scale(2, 2); // X 和 Y 方向放大 2 倍
geometry.scale(2, 2, [0, 0]); // 绕指定点缩放

// 变换投影
geometry.transform('EPSG:4326', 'EPSG:3857');

// 简化(Douglas-Peucker 算法)
const simplified = geometry.simplify(100); // 容差 100

// 获取最近点
const closest = geometry.getClosestPoint([x, y], undefined);

// 判断是否包含坐标
const contains = geometry.intersectsCoordinate([x, y]);

// 判断是否与范围相交
const intersects = geometry.intersectsExtent(extent);

// 获取长度(线)
const length = line.getLength();

// 获取面积(多边形)
const area = polygon.getArea();

// 获取周长(多边形)
const perimeter = polygon.getPerimeter();

6.3 多边形特殊方法

// 从范围创建多边形
const extentPolygon = Polygon.fromExtent([0, 0, 100, 100]);

// 从圆创建多边形
const circlePolygon = Polygon.fromCircle(circle, 32); // 32 个点

// 获取外环
const exterior = polygon.getExteriorRing();

// 获取内环
const interior = polygon.getInteriorRing(0); // 第一个内环

// 获取所有线性环
polygon.getLinearRing(0); // 第一个环(外环)

6.4 判断点与多边形关系

/**
 * 判断点与多边形的位置关系
 * @param {Polygon} polygon - 多边形几何
 * @param {Array} point - 测试点坐标 [x, y]
 * @param {number} edgeTolerance - 边判断容差
 * @returns {Object} 位置关系
 */
function getPointPolygonRelation(polygon, point, edgeTolerance = 0.001) {
  // 获取最近点
  const closestPoint = polygon.getClosestPoint(point, undefined);
  
  // 计算距离
  const dx = point[0] - closestPoint[0];
  const dy = point[1] - closestPoint[1];
  const distance = Math.sqrt(dx * dx + dy * dy);
  
  // 判断是否在边上
  const onEdge = distance <= edgeTolerance;
  
  // 判断是否在内部
  const inside = polygon.intersectsCoordinate(point);
  
  return {
    inside: inside,
    onEdge: onEdge,
    closestPoint: closestPoint,
    distance: distance
  };
}

// 使用示例
const polygon = new Polygon([[
  [0, 0], [10, 0], [10, 10], [0, 10], [0, 0]
]]);

console.log(getPointPolygonRelation(polygon, [5, 5]));    // {inside: true, onEdge: false}
console.log(getPointPolygonRelation(polygon, [5, 0]));    // {inside: false, onEdge: true}
console.log(getPointPolygonRelation(polygon, [15, 15]));  // {inside: false, onEdge: false}

七、样式 (Style)

7.1 基础样式

import Style from 'ol/style/Style.js';
import Fill from 'ol/style/Fill.js';
import Stroke from 'ol/style/Stroke.js';
import Circle from 'ol/style/Circle.js';
import Icon from 'ol/style/Icon.js';
import Text from 'ol/style/Text.js';

// 填充样式
const fill = new Fill({
  color: 'rgba(255, 0, 0, 0.5)' // 支持 rgba, hex, rgb, 颜色名
});

// 描边样式
const stroke = new Stroke({
  color: '#ff0000',
  width: 2,
  lineCap: 'round',      // 'butt', 'round', 'square'
  lineJoin: 'round',     // 'bevel', 'round', 'miter'
  lineDash: [10, 5],     // 虚线 [实线长度,间隔长度]
  lineDashOffset: 0,     // 虚线偏移
  miterLimit: 10         // 斜接限制
});

// 圆形样式(点)
const circleStyle = new Circle({
  radius: 7,
  fill: new Fill({ color: '#ff0000' }),
  stroke: new Stroke({ color: '#fff', width: 2 })
});

// 图标样式
const iconStyle = new Icon({
  src: 'path/to/icon.png',
  scale: 1,              // 缩放比例
  rotation: 0,           // 旋转角度(弧度)
  rotateWithView: false, // 是否随视图旋转
  opacity: 1,            // 透明度
  anchor: [0.5, 0.5],    // 锚点(归一化坐标)
  anchorXUnits: 'fraction', // 'fraction' 或 'pixels'
  anchorYUnits: 'fraction',
  size: [32, 32],        // 图标尺寸
  color: [255, 0, 0, 1]  // 颜色滤镜 [r, g, b, a]
});

// 文本样式
const textStyle = new Text({
  text: '标注内容',
  font: '14px sans-serif',     // CSS font 语法
  fill: new Fill({ color: '#000' }),
  stroke: new Stroke({ color: '#fff', width: 2 }),
  offsetX: 0,                  // 水平偏移
  offsetY: -10,                // 垂直偏移
  rotation: 0,
  rotateWithView: false,
  scale: 1,
  placement: 'point',          // 'point' 或 'line'
  textAlign: 'center',         // 'left', 'center', 'right'
  textBaseline: 'middle',      // 'top', 'middle', 'bottom'
  padding: [2, 2, 2, 2]        // 文本内边距
});

// 组合样式
const style = new Style({
  fill: fill,
  stroke: stroke,
  image: circleStyle,  // 或 iconStyle
  text: textStyle,
  zIndex: 0
});

7.2 样式函数

// 根据要素属性动态设置样式
const styleFunction = function(feature, resolution) {
  const type = feature.get('type');
  
  if (type === 'city') {
    return new Style({
      image: new Circle({
        radius: 10,
        fill: new Fill({ color: '#ff0000' })
      }),
      text: new Text({
        text: feature.get('name'),
        font: '12px sans-serif',
        fill: new Fill({ color: '#000' }),
        offsetY: -15
      })
    });
  } else if (type === 'road') {
    return new Style({
      stroke: new Stroke({
        color: '#666666',
        width: 3
      })
    });
  }
  
  return null; // 使用默认样式
};

// 使用样式函数
const vectorLayer = new VectorLayer({
  source: vectorSource,
  style: styleFunction
});

7.3 样式应用

// 给图层设置样式
vectorLayer.setStyle(style);

// 给要素设置样式
feature.setStyle(style);

// 获取样式
layer.getStyle();
feature.getStyle();

// 样式数组(多个样式叠加)
const multiStyle = [
  new Style({
    stroke: new Stroke({ color: '#fff', width: 5 })
  }),
  new Style({
    stroke: new Stroke({ color: '#f00', width: 3 })
  })
];

八、要素 (Feature)

8.1 创建要素

import Feature from 'ol/Feature.js';
import Point from 'ol/geom/Point.js';

// 创建带几何的要素
const feature = new Feature({
  geometry: new Point(fromLonLat([116.4, 39.9])),
  name: '北京',
  type: 'city',
  population: 2154
});

// 仅创建几何
const pointFeature = new Feature(new Point([0, 0]));

// 设置/获取属性
feature.set('name', '上海');
feature.get('name');

// 获取所有属性
feature.getProperties();

// 设置多个属性
feature.setProperties({
  name: '广州',
  population: 1500
});

// 设置/获取 ID
feature.setId('feature_001');
feature.getId();

// 获取/设置几何
feature.getGeometry();
feature.setGeometry(new Point([100, 100]));

// 设置样式
feature.setStyle(style);

// 获取样式
feature.getStyle();

8.2 要素事件

// 监听属性变化
feature.on('propertychange', function(e) {
  console.log('属性变化:', e.key, e.target.get(e.key));
});

// 监听几何变化
feature.getGeometry().on('change', function() {
  console.log('几何变化');
});

// 移除监听
feature.un('propertychange', callback);

九、交互 (Interaction)

9.1 默认交互

import { defaults as defaultInteractions } from 'ol/interaction.js';

// 创建地图时使用默认交互
const map = new Map({
  interactions: defaultInteractions({
    doubleClickZoom: true,     // 双击缩放
    mouseWheelZoom: true,      // 滚轮缩放
    shiftDragZoom: true,       // Shift+ 拖拽缩放
    dragPan: true,             // 拖拽平移
    keyboardPan: true,         // 键盘平移
    keyboardZoom: true,        // 键盘缩放
    rotate: true,              // 旋转
    pinchZoom: true,           // 捏合缩放(移动端)
    pinchRotate: true          // 捏合旋转(移动端)
  })
});

9.2 绘制交互 (Draw)

import Draw from 'ol/interaction/Draw.js';
import VectorSource from 'ol/source/Vector.js';

const vectorSource = new VectorSource();

// 创建绘制交互
const draw = new Draw({
  source: vectorSource,
  type: 'Point',           // 'Point', 'LineString', 'Polygon', 'Circle'
  freehand: false,         // 自由绘制模式
  snapTolerance: 12,       // 捕捉容差(像素)
  style: style,            // 绘制样式
  minPoints: 2,            // 最小点数
  maxPoints: null,         // 最大点数
  stopClick: true          // 阻止点击事件
});

map.addInteraction(draw);

// 绘制事件
draw.on('drawstart', function(e) {
  console.log('开始绘制', e.feature);
});

draw.on('drawend', function(e) {
  console.log('绘制完成', e.feature);
});

// 撤销最后一个点
draw.removeLastPoint();

// 获取草图要素
const sketch = draw.getSketchFeature();

// 激活/停用
draw.setActive(false);

// 移除交互
map.removeInteraction(draw);

9.3 选择交互 (Select)

import Select from 'ol/interaction/Select.js';
import { click, pointerMove, altKeyOnly } from 'ol/events/condition.js';

// 创建选择交互
const select = new Select({
  condition: click,                    // 触发条件
  layers: [vectorLayer],               // 可选的图层
  style: selectedStyle,                // 选中样式
  multi: false,                        // 是否多选
  toggleCondition: altKeyOnly,         // 切换选择条件
  filter: function(feature, layer) {
    return feature.get('selectable') !== false; // 过滤条件
  }
});

map.addInteraction(select);

// 选择事件
select.on('select', function(e) {
  console.log('选中的要素:', e.selected);
  console.log('取消选择的要素:', e.deselected);
});

// 获取选中的要素集合
const selectedFeatures = select.getFeatures();

// 清空选择
selectedFeatures.clear();

9.4 修改交互 (Modify)

import Modify from 'ol/interaction/Modify.js';

// 创建修改交互
const modify = new Modify({
  source: vectorSource,        // 数据源
  features: select.getFeatures(), // 或直接指定要素集合
  style: modifyStyle,          // 修改样式
  pixelTolerance: 20,          // 像素容差
  wrapX: false,                // 是否环绕 X 轴
  insertVertexCondition: function() {
    return true;               // 是否允许插入顶点
  }
});

map.addInteraction(modify);

// 修改事件
modify.on('modifystart', function(e) {
  console.log('开始修改');
});

modify.on('modifyend', function(e) {
  console.log('修改完成');
});

9.5 捕捉交互 (Snap)

import Snap from 'ol/interaction/Snap.js';

// 创建捕捉交互
const snap = new Snap({
  source: vectorSource,
  pixelTolerance: 10,    // 捕捉容差(像素)
  features: null         // 可选的要素集合
});

map.addInteraction(snap);

9.6 平移交互 (Translate)

import Translate from 'ol/interaction/Translate.js';

// 创建平移交互
const translate = new Translate({
  features: select.getFeatures(), // 要平移的要素集合
  layers: [vectorLayer]           // 可选的图层
});

map.addInteraction(translate);

// 平移事件
translate.on('translatestart', function(e) {
  console.log('开始平移');
});

translate.on('translateend', function(e) {
  console.log('平移完成', e.features);
});

9.7 拉框交互 (DragBox)

import DragBox from 'ol/interaction/DragBox.js';
import { always } from 'ol/events/condition.js';

// 创建拉框交互
const dragBox = new DragBox({
  condition: always,           // 触发条件
  style: new Style({
    stroke: new Stroke({
      color: '#00f',
      width: 2
    })
  })
});

map.addInteraction(dragBox);

// 拉框事件
dragBox.on('boxstart', function(e) {
  console.log('开始拉框');
});

dragBox.on('boxend', function(e) {
  const extent = dragBox.getGeometry().getExtent();
  console.log('拉框范围:', extent);
});

9.8 拖放交互 (DragAndDrop)

import DragAndDrop from 'ol/interaction/DragAndDrop.js';
import GeoJSON from 'ol/format/GeoJSON.js';

// 创建拖放交互
const dragAndDrop = new DragAndDrop({
  formatConstructors: [GeoJSON, KML], // 支持的格式
  projection: 'EPSG:3857'             // 投影
});

map.addInteraction(dragAndDrop);

// 拖放事件
dragAndDrop.on('addfeatures', function(e) {
  const vectorSource = new VectorSource({
    features: e.features,
    featureProjection: e.projection
  });
  
  const vectorLayer = new VectorLayer({
    source: vectorSource
  });
  
  map.addLayer(vectorLayer);
});

十、控件 (Control)

10.1 默认控件

import { defaults as defaultControls } from 'ol/control.js';

const map = new Map({
  controls: defaultControls({
    attribution: true,       // 版权信息
    rotate: true,            // 旋转复位
    zoom: true               // 缩放按钮
  })
});

10.2 缩放控件 (Zoom)

import Zoom from 'ol/control/Zoom.js';

const zoomControl = new Zoom({
  duration: 250,             // 动画时长 (ms)
  className: 'ol-zoom',      // CSS 类名
  zoomInLabel: '+',          // 放大按钮标签
  zoomOutLabel: '-',         // 缩小按钮标签
  zoomInTipLabel: '放大',    // 放大提示
  zoomOutTipLabel: '缩小',   // 缩小提示
  target: null               // 目标容器(可选)
});

map.addControl(zoomControl);

10.3 比例尺控件 (ScaleLine)

import ScaleLine from 'ol/control/ScaleLine.js';

const scaleLine = new ScaleLine({
  className: 'ol-scale-line',
  minWidth: 64,              // 最小宽度(像素)
  maxUnits: 'metric',        // 'metric' 或 'degrees'
  bar: false,                // 是否显示条形比例尺
  steps: 4,                  // 条形比例尺步数
  text: true,                // 是否显示文本
  units: 'metric',           // 单位类型
  target: null
});

map.addControl(scaleLine);

10.4 鼠标位置控件 (MousePosition)

import MousePosition from 'ol/control/MousePosition.js';
import { createStringXY } from 'ol/coordinate.js';

const mousePosition = new MousePosition({
  className: 'ol-mouse-position',
  coordinateFormat: function(coordinate) {
    return coordinate[0].toFixed(4) + ', ' + coordinate[1].toFixed(4);
  },
  projection: 'EPSG:4326',   // 显示坐标系
  undefinedHTML: '&nbsp;',   // 未定义时显示的内容
  target: null,
  placeholder: '&#160;'      // 鼠标移出时的占位符
});

map.addControl(mousePosition);

10.5 全屏控件 (FullScreen)

import FullScreen from 'ol/control/FullScreen.js';

const fullScreen = new FullScreen({
  className: 'ol-full-screen',
  tipLabel: '全屏',
  label: '⛶',               // 按钮标签
  labelActive: '⛶',         // 激活状态标签
  target: null
});

map.addControl(fullScreen);

10.6 旋转控件 (Rotate)

import Rotate from 'ol/control/Rotate.js';

const rotateControl = new Rotate({
  className: 'ol-rotate',
  duration: 250,             // 复位动画时长
  label: '↻',                // 按钮标签
  tipLabel: '复位北向',
  target: null
});

map.addControl(rotateControl);

10.7 鹰眼图控件 (OverviewMap)

import OverviewMap from 'ol/control/OverviewMap.js';
import TileLayer from 'ol/layer/Tile.js';
import OSM from 'ol/source/OSM.js';

const overviewMap = new OverviewMap({
  className: 'ol-overviewmap',
  collapsed: true,           // 是否折叠
  collapseLabel: '«',        // 折叠按钮标签
  label: '»',                // 展开按钮标签
  layers: [
    new TileLayer({
      source: new OSM()
    })
  ],
  view: null,                // 鹰眼图视图(可选)
  target: null
});

map.addControl(overviewMap);

10.8 缩放滑块控件 (ZoomSlider)

import ZoomSlider from 'ol/control/ZoomSlider.js';

const zoomSlider = new ZoomSlider({
  className: 'ol-zoomslider',
  duration: 200,             // 动画时长
  minResolution: 0,
  maxResolution: 0,
  target: null
});

map.addControl(zoomSlider);

10.9 区域定位控件 (ZoomToExtent)

import ZoomToExtent from 'ol/control/ZoomToExtent.js';

const zoomToExtent = new ZoomToExtent({
  className: 'ol-zoom-extent',
  extent: null,              // 目标范围(默认视图范围)
  label: 'E',                // 按钮标签
  tipLabel: '缩放到范围',
  target: null
});

map.addControl(zoomToExtent);

10.10 自定义控件

import Control from 'ol/control/Control.js';

// 创建 HTML 元素
const button = document.createElement('button');
button.innerHTML = '定位';
button.className = 'my-button';
button.onclick = function() {
  map.getView().setCenter(fromLonLat([116.4, 39.9]));
};

const element = document.createElement('div');
element.className = 'my-control';
element.appendChild(button);

// 创建控件
const myControl = new Control({
  element: element,
  target: null
});

map.addControl(myControl);

十一、叠加层 (Overlay)

11.1 创建叠加层

import Overlay from 'ol/Overlay.js';

// 创建 HTML 元素
const popupElement = document.createElement('div');
popupElement.className = 'popup';
popupElement.innerHTML = '<div class="popup-content">内容</div>';

// 创建叠加层
const popup = new Overlay({
  element: popupElement,
  position: fromLonLat([116.4, 39.9]),
  positioning: 'center-center',  // 'top-left', 'top-center', 'top-right',
                                 // 'center-left', 'center-center', 'center-right',
                                 // 'bottom-left', 'bottom-center', 'bottom-right'
  offset: [0, -10],              // 偏移量(像素)
  autoPan: true,                 // 自动平移地图
  autoPanAnimation: {
    duration: 250
  },
  autoPanMargin: 20,             // 自动平周边距
  stopEvent: true,               // 是否阻止事件传播
  insertFirst: true,             // 是否插入到最前
  className: 'ol-overlay'
});

map.addOverlay(popup);

11.2 叠加层方法

// 设置/获取位置
popup.setPosition(fromLonLat([116.4, 39.9]));
popup.getPosition();

// 设置/获取元素
popup.setElement(newElement);
popup.getElement();

// 设置/获取偏移
popup.setOffset([0, -20]);
popup.getOffset();

// 设置/获取定位
popup.setPositioning('bottom-center');
popup.getPositioning();

// 显示/隐藏
popup.setPosition(undefined); // 隐藏

// 获取地图
popup.getMap();

// 移除
map.removeOverlay(popup);

11.3 弹窗示例

// 点击显示弹窗
map.on('click', function(e) {
  const features = map.getFeaturesAtPixel(e.pixel);
  
  if (features && features.length > 0) {
    const feature = features[0];
    const content = feature.get('name') || '未知';
    
    popupElement.innerHTML = `<h3>${content}</h3>`;
    popup.setPosition(e.coordinate);
  } else {
    popup.setPosition(undefined);
  }
});

// 鼠标悬停显示
map.on('pointermove', function(e) {
  const features = map.getFeaturesAtPixel(e.pixel);
  
  if (features && features.length > 0) {
    map.getTargetElement().style.cursor = 'pointer';
  } else {
    map.getTargetElement().style.cursor = 'auto';
  }
});

十二、投影 (Projection)

12.1 坐标转换

import { fromLonLat, toLonLat, transform } from 'ol/proj.js';

// 经纬度转 Web Mercator (EPSG:3857)
const webCoord = fromLonLat([116.4, 39.9]); // [12955662.92, 4866611.98]

// Web Mercator 转经纬度
const lonLat = toLonLat(webCoord); // [116.4, 39.9]

// 任意投影转换
const coord = transform(
  [116.4, 39.9],
  'EPSG:4326',
  'EPSG:3857'
);

// 范围转换
import { transformExtent } from 'ol/proj.js';

const extent4326 = [116, 39, 117, 40];
const extent3857 = transformExtent(extent4326, 'EPSG:4326', 'EPSG:3857');

12.2 获取投影信息

import { get, getPointResolution } from 'ol/proj.js';

// 获取投影对象
const projection = get('EPSG:3857');

// 获取投影代码
projection.getCode(); // 'EPSG:3857'

// 获取单位
projection.getUnits(); // 'm'

// 获取范围
projection.getExtent();

// 获取世界范围
projection.getWorldExtent();

// 判断是否为球面
projection.isGlobal();

// 判断是否轴向翻转
projection.getAxisOrientation();

// 获取点分辨率
const resolution = getPointResolution(
  projection,
  100, // 分辨率
  fromLonLat([116.4, 39.9]) // 位置
);

12.3 定义自定义投影

import { register } from 'ol/proj/proj4.js';
import proj4 from 'proj4';

// 定义投影
proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 ...');

// 注册
register(proj4);

// 使用
const view = new View({
  projection: 'EPSG:27700',
  center: [500000, 200000],
  zoom: 10
});

十三、完整示例

13.1 基础地图 + 矢量图层 + 交互

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>OpenLayers 完整示例</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.5.2/ol.css">
  <style>
    html, body { margin: 0; padding: 0; }
    #map { width: 100%; height: 100vh; }
    .popup {
      position: absolute;
      background: #fff;
      border: 1px solid #ccc;
      padding: 10px;
      border-radius: 4px;
      display: none;
    }
  </style>
</head>
<body>
  <div id="map"></div>
  <div id="popup" class="popup"></div>
  
  <script src="https://cdn.jsdelivr.net/npm/ol@v7.5.2/dist/ol.js"></script>
  <script>
    // 创建矢量源
    const vectorSource = new ol.source.Vector();
    
    // 创建样式
    const style = new ol.style.Style({
      fill: new ol.style.Fill({ color: 'rgba(255, 0, 0, 0.5)' }),
      stroke: new ol.style.Stroke({ color: '#ff0000', width: 2 }),
      image: new ol.style.Circle({
        radius: 7,
        fill: new ol.style.Fill({ color: '#ff0000' })
      })
    });
    
    // 创建矢量图层
    const vectorLayer = new ol.layer.Vector({
      source: vectorSource,
      style: style
    });
    
    // 创建地图
    const map = new ol.Map({
      target: 'map',
      layers: [
        new ol.layer.Tile({ source: new ol.source.OSM() }),
        vectorLayer
      ],
      view: new ol.View({
        center: ol.proj.fromLonLat([116.4, 39.9]),
        zoom: 12
      }),
      controls: ol.control.defaults().extend([
        new ol.control.ScaleLine(),
        new ol.control.FullScreen()
      ])
    });
    
    // 添加绘制交互
    const draw = new ol.interaction.Draw({
      source: vectorSource,
      type: 'Polygon'
    });
    map.addInteraction(draw);
    
    // 添加选择交互
    const select = new ol.interaction.Select();
    map.addInteraction(select);
    
    // 添加修改交互
    const modify = new ol.interaction.Modify({
      features: select.getFeatures()
    });
    map.addInteraction(modify);
    
    // 添加捕捉交互
    const snap = new ol.interaction.Snap({
      source: vectorSource
    });
    map.addInteraction(snap);
    
    // 弹窗
    const popup = new ol.Overlay({
      element: document.getElementById('popup'),
      autoPan: true,
      autoPanAnimation: { duration: 250 }
    });
    map.addOverlay(popup);
    
    // 点击显示信息
    map.on('click', function(e) {
      const features = map.getFeaturesAtPixel(e.pixel);
      
      if (features && features.length > 0) {
        const feature = features[0];
        const name = feature.get('name') || '未命名';
        
        document.getElementById('popup').innerHTML = 
          '<h3>' + name + '</h3><p>类型:' + feature.getGeometry().getType() + '</p>';
        popup.setPosition(e.coordinate);
      } else {
        popup.setPosition(undefined);
      }
    });
    
    // 绘制完成事件
    draw.on('drawend', function(e) {
      const feature = e.feature;
      feature.set('name', '要素_' + (vectorSource.getFeatures().length));
      console.log('绘制完成:', feature);
    });
  </script>
</body>
</html>

13.2 加载 GeoJSON 数据

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

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

const vectorLayer = new VectorLayer({
  source: vectorSource,
  style: new Style({
    stroke: new Stroke({ color: '#0066cc', width: 2 }),
    fill: new Fill({ color: 'rgba(0, 102, 204, 0.3)' })
  })
});

map.addLayer(vectorLayer);

// 加载完成后适配视图
vectorSource.once('featuresloadend', function() {
  const extent = vectorSource.getExtent();
  map.getView().fit(extent, { duration: 1000, padding: [50, 50, 50, 50] });
});

13.3 加载 WMS 服务

import TileLayer from 'ol/layer/Tile.js';
import TileWMS from 'ol/source/TileWMS.js';

const wmsLayer = new TileLayer({
  source: new TileWMS({
    url: 'https://geoserver.example.com/geoserver/wms',
    params: {
      'LAYERS': 'workspace:layer',
      'TILED': true,
      'VERSION': '1.3.0'
    },
    serverType: 'geoserver',
    crossOrigin: 'anonymous'
  })
});

map.addLayer(wmsLayer);

附录:常用链接


本文档基于 OpenLayers 7.5.2 版本编写,部分 API 可能在其他版本中有所不同。