初识webGIS库—OpenLayers

Posted 水星记_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识webGIS库—OpenLayers相关的知识,希望对你有一定的参考价值。

文章目录


前言

GIS 作为获取、存储、分析和管理地理空间数据的重要工具,用 GIS 技术绘制地图比用传统的手工操作或自动制图工具更加灵活。今天给大家分享一个专为 GIS 客户端开发提供的 JavaScript 类库包 — OpenLayers


一、OpenLayers是什么?

OpenLayers 是一个专为 Web GIS 客户端开发提供的 JavaScript 类库包,用于实现标准格式发布的地图数据访问。它的主要作用就是用于展现数据并且提供相应的地图操作工具。官方文档地址:https://openlayers.org/

二、快速开始

1.安装

npm i --save ol
cnpm i --save ol

2.入门使用

2.1 为地图准备一个 div 的容器

<div style="height: 100%; width: 100vw">
    <div id="map" ref="map"></div>
</div>

2.2 绑定 id 初始化一个地图;将图层 Layer 添加到 Map 中,指定数据源服务(url);设置 Map 容器的视图窗口。

initMap() 
  this.map = new Map(
    target: "map", // html中的地图id
    // 图层的基类
    layers: [
      new TileLayer(
        source: new OSM(), //指定了图层的数据来源,图层作用是以一定的样式渲染数据,source则指定数据
      ),
    ],
    view: new View(
      projection: "EPSG:4326", //坐标系,有EPSG:4326和EPSG:3857
      center: [116.23, 39.54], //中心坐标点
      zoom: 10, //默认缩放级别
    ),
  );
,

完整代码

<template>
  <div style="height: 100%; width: 100vw">
    <div id="map" ref="map"></div>
  </div>
</template>

<script>
import "ol/ol.css";
import  Map, View  from "ol";
import TileLayer from "ol/layer/Tile";
import OSM from "ol/source/OSM";
export default 
  data() 
    return 
      map: null,
    ;
  ,
  mounted() 
    this.initMap(); //定义一个方法
  ,  
  methods: 
    // 初始化地图
    initMap() 
      this.map = new Map(
        target: "map", // html中的地图id
        // 图层的基类(添加图层)
        layers: [
          new TileLayer(
            source: new OSM(), //指定了图层的数据来源,图层作用是以一定的样式渲染数据,source则指定数据
          ),
        ],
        view: new View(
          projection: "EPSG:4326", //坐标系,有EPSG:4326和EPSG:3857
          center: [116.23, 39.54], //中心坐标点
          zoom: 10, //默认缩放级别
        ),
      );
    ,
  ,
;
</script>

<style>
#map 
  width: 100%;
  height: 100%;

</style>

实现效果


三、配置

在所有配置中,MapLayerSourceViewControlInteractionOpenlayers 的核心配置;下面为大家一一讲解。

1.Map

MapOpenlayers 使用基础,所有的图层、地图控件、地图工具等必须添加到 Map 中才能使用。

1.1 Map 常用的属性、方法和事件

属性:

  • layers 图层
  • view 视图
  • controls 地图控件
  • target 地图容器
  • overlays 叠加图层

例:view 方法的使用

 view: new View(
   projection: "EPSG:4326", 
   center: [116.23, 39.54], 
   zoom: 10,
 ),

方法:

  • addControl(control) 添加控件
  • addInteraction(interaction) 添加交互
  • addLayer(layer) 添加图层
  • addOverlay(overlay) 添加覆盖物
  • dispatchEvent(event) 调度事件并调用所有侦听此类型事件的侦听器
  • on(type, listener) 侦听某种类型的事件
  • getOverlays() 获取所有覆盖物
  • removeOverlay(overlay) 删除指定覆盖物

例:addControl 方法的使用

this.map.addControl(
  new control.OverviewMap(
    collapsed: true,
  )
);

事件:

  • click 地图点击事件
  • dblclick 地图双击事件
  • moveend 地图移动时触发
  • movestart 地图开始移动时触发
  • postrender 地图渲染后触发
  • singleclick 地图单击事件

例:click 事件的使用

this.map.on("click", (evt) => 
  this.mapPointerClick(evt);
);

2.Layer

LayerMap 的核心组成部分,ol 定义了四种基本的图层类型,分别是分别是 Tile(瓦片)Image(图片)Vector(矢量)VectorTile(矢量切片),这四种类有一个共同的基类 Layer,它们的大多数属性和方法都继承自这个类。

2.1 Layer 常用的属性和方法

属性:

  • source 指定了图层的数据来源
  • className 图层各个元素的样式
  • opacity 透明度,默认为 1
  • visible 是否可见,默认是 true
  • zIndex 图层的叠加顺序,默认是 0
  • extent 图层渲染的区域(浏览器窗口中可见的地图区域)
  • minResolution 图层最小分辨率,当 layer 缩放级别小于这个分辨率时,图层隐藏
  • maxResolution 图层最大分辨率
  • minZoom 图层最小缩放级别
  • maxZoo 图层最大缩放级别

例:source 属性的使用

layers: [
  new TileLayer(
    source: new OSM(),
  ),
],

方法:

  • getLayersArray() 拿到所有图层
  • getLayerStatesArray() 拿到所有图层状态
  • getSource() 拿到相应图层的来源
  • getSourceState() 拿到相应图层的来源状态
  • setSource() 设置图层 source 属性,参数为一个 source 对象
  • setMap() 添加 Layer 到 Map,并由 Map 管理

例:getSourceState 方法的使用

this.clusterSource.getSource().forEachFeature((feature) => 
    //执行操作
);

3.Source

Source 就是数据来源和格式。简单理解就是在使用 layers(图层) 时,不同的图层需要传入不同的数据类型才能渲染地图。它们需要的数据格式都是通过 Source 定义好的,我们只需要把现有的数据按照规定传入数据源中即可。

3.1 Source 的数据类型

分类:

  • ol.source.BingMaps Bing 地图图块数据的图层源
  • ol.source.CartoDB CartoDB Maps API 的图层源
  • ol.source.Cluster 聚簇矢量数据
  • ol.source.Vector 提供矢量图层数据
  • ol.source.Image 提供单一图片数据的类型
  • ol.source.ImageCanvas 数据来源是一个 canvas 元素,其中的数据是图片
  • ol.source.ImageMapGuide Mapguide 服务器提供的图片地图数据
  • ol.source.ImageStatic 提供单一的静态图片地图
  • ol.source.ImageVector数据来源是一个 canvas 元素,但是其中的数据是矢量来源
  • ol.source.ImageWMS WMS 服务提供的单一的图片数据
  • ol.source.MapQuest MapQuest 提供的切片数据
  • ol.source.Stamen Stamen 提供的地图切片数据
  • ol.source.Tile 提供被切分为网格切片的图片数据
  • ol.source.TileVector 被切分为网格的矢量数据
  • ol.source.TileDebug 并不从服务器获取数据
  • ol.source.TileImage 提供切分成切片的图片数据
  • ol.source.TileUTFGrid TileJSON 格式 的 UTFGrid 交互数据
  • ol.source.TileJSON TileJSON 格式的切片数据
  • ol.source.TileArcGISRest ArcGIS Rest 服务提供的切片数据
  • ol.source.WMTS WMTS 服务提供的切片数据
  • ol.source.Zoomify Zoomify 格式的切片数据
  • ol.source.OSM OpenStreetMap 提供的切片数据
  • ol.source.XYZ 具有在 URL 模板中定义的一组 XYZ 格式的 URL 的切片数据的图层源

例:通过 layer 使用 source

this.layer = new TileLayer(
    source: new XYZ(
    url: "http://192.168.0.138/OSM/z_x_y.png",
    wrapX: true,
    ),
);

4.View

view 的作用主要是控制地图的交互,例如设置地图的展示位置范围、地图中心位置以及当前地图使用的投影坐标系等等。

4.1 View 常用的属性和方法

属性:

  • center 视图初始化中心点位
  • enableRotation 是否启用旋转
  • constrainRotation 旋转约束;false 意味着没有约束;true 意味着没有约束,但在 0 附近捕捉到 0。数字将旋转限制为该数量的值,就是设置 90 只能旋转 90 度
  • extent 限制视图的范围;可选:[minx, miny, maxx, maxy]
  • constrainOnlyCenter 若为 true,则范围约束将仅适用于视图中心而不是整个范围
  • smoothExtentConstraint 若为 true,范围约束将被平滑地应用,即允许视图稍微超出给定的 extent
  • maxResolution 用于确定分辨率约束的最大分辨率
  • minResolution 用于确定分辨率约束的最小分辨率
  • maxZoom 用于确定分辨率约束的最大缩放级别
  • minZoom 用于确定分辨率约束的最小缩放级别
  • constrainResolution 若为 true,则视图将始终在交互后以最接近的缩放级别进行动画处理;false 表示允许中间缩放级别
  • resolutions决定缩放级别的分辨率
  • zoom 只有 resolution 未定义时使用;缩放级别用于计算视图的初始分辨率
  • rotation 以弧度为单位的视图初始旋转(顺时针旋转,0 表示北)

例:maxZoom 事件的使用

 view: new View(
   // 地图视图
   projection: "EPSG:4326", 
   center: [118.27, 39.71],
   zoom: 10, 
   maxZoom: 20,
 ),

方法:

  • getCenter 获取视图中心,返回地图中心坐标
  • getZoom 获取当前的缩放级别
  • getMaxZoom 获取视图的最大缩放级别
  • getMinZoom 获取视图的最小缩放级别
  • getProjection 获取地图使用的“投影坐标系统”,如 EPSG:3857
  • getMaxResolution 获取视图的最大分辨率
  • getMinResolution 获取视图的最低分辨率
  • getRotation 获取视图旋转
  • getZoomForResolution 获取分辨率的缩放级别
  • setCenter 设置当前视图的中心
  • setConstrainResolution 设置视图是否应允许中间缩放级别
  • setZoom 缩放到特定的缩放级别。任何分辨率限制都将适用
  • setMaxZoom 为视图设置新的最大缩放级别
  • setMinZoom 为视图设置新的最小缩放级别
  • setRotation 设置该视图的旋转角度

例:getZoom 事件的使用

//amend 点击事件
amend() 
  const view = this.map.getView();
  const zoom = view.getZoom();
  view.setZoom(zoom - 1);
  console.log(view, "缩放级别:" + zoom);
,

5.Control

Control 控件,操作地图相关的工具。

5.1 Control 常用的控件

控件:

  • FullScreen() 全屏控制
  • MousePosition() 坐标拾取控件
  • ScaleLine() 比例尺控件
  • ZoomSlider() 滑块缩放控件
  • OverviewMap() 鹰眼控件
  • Attribution() 官方 LoGo

例:Control 控件的使用

this.map = new Map(
    controls: control.defaults().extend([
      // 根据需要打开关闭即可
      new control.FullScreen(), //全屏控制
      // new control.MousePosition(), //坐标拾取控件
      // new control.ScaleLine(),//比例尺控件
      // new control.ZoomSlider(),//滑块缩放控件
      // new control.OverviewMap(),//鹰眼控件
    ]),
);

6.Interaction

Interaction 也是用来控制地图的,但与控件不同的是 Interaction 是在地图上绘制要素、选择、修改、移动、拉伸等等操作。

6.1 Interaction 常用的交互功能

常用交互功能:

  • doubleclickzoom 双击地图进行缩放
  • draganddrop 以“拖文件到地图中”的交互添加图层
  • dragbox 用于划定一个矩形范围
  • dragpan 拖拽平移地图
  • dragrotateandzoom 拖拽方式进行缩放和旋转地图
  • dragrotate 拖拽方式旋转地图
  • dragzoom 拖拽方式缩放地图
  • draw 绘制地理要素功能
  • keyboardpan 键盘方式平移地图
  • keyboardzoom 键盘方式缩放地图
  • select 选择要素功能
  • modify 更改要素
  • mousewheelzoom 鼠标滚轮缩放功能
  • pinchrotate 手指旋转地图,针对触摸屏
  • pinchzoom 手指进行缩放,针对触摸屏
  • pointer 鼠标的用户自定义事件基类
  • snap 鼠标捕捉,当鼠标距离某个要素一定距离之内,自动吸附到要素

例:dragrotateandzoom 交互的使用

this.map = new Map(
  interactions: defaultInteractions().extend([new DragRotateAndZoom()]),
);

四、实践

经过以上的学习,相信大家对 OpenLayers 已经有了初步的认识,下面我们来写一个简单的操作,根据接口数据中的经纬度在地图上渲染点位,点击点位展示当前点击点位的详情数据,如下图:

实现思路

1.引入所需组件;
2.初始化一个地图;
3.循环接口数据拿到所需经纬度,通过 addLayer 方法添加到地图中;
4.添加弹详情出层,通过 id 拿到定义的容器,添加 overlay 到 map;
5.创建点击事件,点击点位后,利用 feature.get 方法拿到数据渲染点位详情即可。

完整代码

<template>
  <div>
    <div class="mapBox" id="map">
      <div id="popup" class="ol-popup">
        <a href="#" id="popup-closer" class="ol-popup-closer"></a>
        <div id="popup-content">
          <div class="detailsBox">
            <div>所属区县:mapDataDetail.qx</div>
            <div>加油站地址:mapDataDetail.jyzdz</div>
            <div>加油站负责人:mapDataDetail.jyzfzr</div>
            <div>联系电话:mapDataDetail.lxdh</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import areaGeo from "./map.json";
import  Map, View, Feature, ol  from "ol";
import TileLayer from "ol/layer/Tile";
import * as control from "ol/control";
import  Polygon, MultiPolygon  from "ol/geom";
import VectorLayer from "ol/layer/Vector";
import  Cluster, OSM, Vector as VectorSource, XYZ  from "ol/source";
import "ol/ol.css";
import 
  Style,
  Stroke,
  Fill,
  Icon,
  Circle as CircleStyle,
  Text,
 from "ol/style";
import GeoJSON from "ol/format/GeoJSON";
import Point from "ol/geom/Point";
import  toStringHDMS  from "ol/coordinate";
import  toLonLat  from "ol/proj";
import Overlay from "ol/Overlay";
export default 
  data() 
    return 
      mapData: [], //地图点位
      mapPointVectorLayer: null, //地图点位图层控制器
      geoRouteLayer: null, //geo市局边界图层
      clusterSource: null,
      map: null,
      overlay: null, //业务点聚合图层详情图层
      mapDataDetail: 
        qx: "",
        jyzdz: "",
        jyzfzr: "",
        lxdh: "",
        jyzzz: "",
      , //点位详情数据
    ;
  ,
  methods: 
    //初始化地图
    initMap() 
      // 地图实例
      this.map = new Map(
        target: "map", // 对应页面里 id 为 map 的元素
        controls: control.defaults().extend([
          // 根据需要打开关闭即可
          new control.FullScreen(), //全屏控制
        ]),
        layers: [
          new TileLayer(
            source: new OSM(),
          ),
        ],
        view: new View(
          // 地图视图
          projection: "EPSG:4326", // 坐标系,有EPSG:4326和EPSG:3857
          center: [118.27, 39.71], // 默认打开的中心坐标
          zoom: 10.1, // 地图缩放级别(打开页面时默认级别)
          minZoom: 10, //最小缩放级别
          maxZoom: 20, //最大缩放级别
        ),
      );
    ,
    //模拟请求接口
    mapList() 
      let data = [
        
          district: "路北区",
          lat: "118.080181",
          lng: "39.588275",
          oilStationAddress: "唐山市路北区安立路",
          oilStationCharge: "吴彦祖",
          oilStationChargePhone: "18888888888",
          oilStationName: "唐山加油站",
          oilStationStatus: "0",
        ,
        
          district: "路北区",
          lat: "118.202271",
          lng: "39.651675",
          oilStationAddress: "唐山市路北区上海路",
          oilStationCharge: "谢霆锋",
          oilStationChargePhone: "18888888888",
          oilStationName: "唐山",
          oilStationStatus: "1",
        ,
      ];
      this.mapData = data;
      this.showPoints();
      this.addPopup();
      this.map.on("click", (evt) => 
        this.mapPointerClick(evt);
      );
    ,
    //添加弹出层
    addPopup() 
      this.overlay = new Overlay(
        element: document.getElementById("popup"),
        offset: [0, -13],
      );
      //添加 overlay 到 map
      this.map.addOverlay(this.overlay);
      // 关闭弹出层
      var closer = document.getElementById("popup-closer");
      closer.onclick = () => 
        this.overlay.setPosition(undefined);
        closer.blur();
        return false;
      ;
    ,
    //展示聚合点位
    showPoints() 
      // 聚合图层数据源
      this.clusterSource = new Cluster(
        distance: 100,
        source: new VectorSource(
          features: [],
        ),
      );

      this.mapPointVectorLayer = new VectorLayer(
        source: this.clusterSource,
        style: (feature) => 
          return this.setClusterStyle(feature);
        ,
      );

      let features = [];
      this.mapData.forEach((item) => 
        if (item.lng != "" && item.lat != "") 
          let newObj = Object.assign(, item);
          newObj.geometry = new Point([Number(item.lat), Number(item.lng)]);

          features.push(new Feature(newObj));
        
      );
      this.clusterSource.getSource().addFeatures(features);
      this.map.addLayer(this.mapPointVectorLayer);
    ,
    //鼠标点击事件。若悬浮到设备上,则现在设备的具体信息
    mapPointerClick(evt) 
      let pixel = this.map.getEventPixel(evt.originalEvent);
      let featureMouseOver = this.map.forEachFeatureAtPixel(
        pixel,
        function (feature, layer) 
          return feature;
        
      );
      let coordinate;
      if (featureMouseOver) 
        if (featureMouseOver.getProperties().features) 
          //聚合情况下
          if (featureMouseOver.getProperties().features.length == 1) 
            console.log(1111);
            //只有一个要素000000000000000
            let f = featureMouseOver.getProperties().features[0]; //获取该要素
            this.clusterSource.getSource().forEachFeature((feature) => 
              if (f == feature) 
                coordinate = [feature.get("lat"), feature.get("lng")];
                this.mapDataDetail.qx = feature.get("district");
                this.mapDataDetail.jyzdz = feature.get("oilStationAddress");
                this.mapDataDetail.jyzfzr = feature.get("oilStationCharge");
                this.mapDataDetail.lxdh = feature.get("oilStationChargePhone");
                this.mapDataDetail.jyzzz = feature.get("oilStationStatus");
                console.log(feature.get("oilStationAddress"));
                this.overlay.setPosition(coordinate);
              
            );
          
        
      
      if (!coordinate) 
        this.overlay.setPosition(undefined);
      
    ,
    //设置聚合图层的样式
    setClusterStyle(feature) 
      var features = feature.get("features");
      var size = features.length;
      var style;
      if (size == 1) 
        style = [
          new Style(
            image: new Icon(
              src: "https://s1.ax1x.com/2022/07/06/ja5kvQ.png", //详情点位icon
            ),
          ),
        ];
       else 
        // 样式处理
        style = new Style(
          image: new CircleStyle(
            radius: 18,
            stroke: new Stroke(
              color: "#fff",
            ),
            fill: new Fill(
              color: "#3399CC",
            ),
          ),
          text: new Text(
            font: "15px sans-serif",
            text: size.toString(),
            fill: new Fill(
              color: "#fff",
            ),
          ),
        );
      
      return style;
    ,
    //设置区域
    addArea(geo = []) 
      if (geo.length == 0) 
        return false;
      
      let features = [];
      var geoserver = geo[0].features;
      geoserver.forEach((g) => 
        let lineData = g;
        let routeFeature = "";
        if (lineData.geometry.type == "MultiPolygon") 
          routeFeature = new Feature(
  

以上是关于初识webGIS库—OpenLayers的主要内容,如果未能解决你的问题,请参考以下文章

webgis地图发布需要转换坐标吗

openlayers3 旋转按钮符号怎么更换

openlayers3 怎么获取当前被选中要素?

如何使用Openlayers 3加载谷歌离线地图

用OpenLayers 在地图上画简单的轨迹怎么画

如何自己搭建openlayers地图服务器