openlayers开发过程

329 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

“金秋十月,我要连续30天更文,做劳模,拿手机摄影神器!点击查看活动详情 “即可成功参与

开发过程

进行WebGIS应用开发,一般均采用前端开发库+GIS服务的模式,开发者须完成如下三个步骤

第一步:安装配置开发环境

第二步:发布GIS服务资源

第三步:获取前端开发库(MapGIS Client for JavaScript开发库

通过文件拷贝或npm方式引用开发库,进行WebGIS二维或三维应用开发

Openlayers二位地图

Cesium三位地图

通过 npm 命令引入 OpenLayers 地图引擎,建议使用 5.x 版本

npm install ol@5.3.0

OpenLayers的地图导入渲染,以及坐标点的点击事件

1、项目引入Openlayers

//Openlayers的npm包名为ol,咱们直接在项目中引入ol就行
npm install ol
// or
yarn add ol

2、底层渲染

//在map组件中进行map渲染,这里采用的是高德地图的切片地图模式
<template>
 <div>
 <!-- 地图容器 -->
 <div class="ol-map" ref="olMap"></div>
 </div>
</template>
<script>
import Map from 'ol/Map'
import View from 'ol/View'
import { Tile as TileLayer } from 'ol/layer'
import { XYZ } from 'ol/source'
// fromLonLat方法能将坐标从经度/纬度转换为其他投影
import { fromLonLat } from 'ol/proj'
// 拖拽旋转
import { defaults as defaultInteractions, DragRotateAndZoom } from 'ol/interaction'
export default {
  name: 'newMap',
  data () {
    return {
      map: null
    }
  },
  created () {
  },
  computed: {
  },
  mounted () {
    this.init()//当DOM挂载完毕后调用方法,展示地图
  },
  methods: {
      //将地图进行封装
    init () {
      // 使用高德
      const tileLayer = new TileLayer({
        source: new XYZ({
          url: 'https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
        })
      })
      this.map = new Map({
        layers: [tileLayer],
        view: new View({
          center: fromLonLat([120.771441, 30.756433]), // 地图中心点
          zoom: 15, // 缩放级别
          minZoom: 0, // 最小缩放级别
          maxZoom: 18, // 最大缩放级别
          constrainResolution: true// 因为存在非整数的缩放级别,所以设置该参数为true来让每次缩放结束后自动缩放到距离最近的一个整数级别,这个必须要设置,当缩放在非整数级别时地图会糊
        }),
        target: this.$refs.olMap, // DOM容器
        interactions: defaultInteractions().extend([new DragRotateAndZoom()]) // 按住shit旋转
      })
    }
  }
}
</script>
<style lang='less'  scoped>
  .ol-map{
        width: 1000px;
        height: 500px;
        margin-top: 30px;
    }
</style>
​
​

基本类介绍,Openlayers中4个主要的类:

  • Map:地图容器,通过target指定地图绘制的容器id,如代码中的map;
  • Layer:图层,map拥有1个获多个图层,可以理解成PS绘图中的图层概念,整个map是由一个个图层堆叠出来的;
  • View:可视区域,这个类主要是控制地图与人的交互,如进行缩放,调节分辨率、地图的旋转等控制。同时可以设置投影,默认为球形墨卡托,代码中olProj.fromLonLat方法也是将经纬度转换成对应的坐标,这块不做拓展,有需要的同学可自行去学习GIS的理论。
  • source:数据来源,即图层Layers的数据组成部分,上文代码中TileLayer就是使用了一个高德地图XYZ格式的切片数据绘制而成,

此时运行项目已经能够看到地图展示了

3、标记绘制

地图中最常见的需求就是做点位标记,同理,这时我们只需要在之前的地图Layer上再盖一层点位标记的Layer即可,使用的是VectorLayer跟VectorSource,矢量图层以及一个矢量数据

import { Vector as VectorLayer} from 'ol/layer';
import { Vector as VectorSource} from 'ol/source';

我们这里简单实现,直接将一个点位添加到openMap的layers数组里;

// import
import { Map, View, Feature } from "ol";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { XYZ, Vector as VectorSource } from "ol/source";
import * as olProj from "ol/proj";
import { Point } from "ol/geom";
import { Style, Fill, Stroke, Circle as sCircle } from "ol/style";
​
// methods添加setMarker方法
mounted() {
  this.initMap();
  this.setMarker();
},
​
// setMarker
setMarker() {
  let _style = new Style({
    image: new sCircle({
      radius: 10,
      stroke: new Stroke({
        color: "#fff",
      }),
      fill: new Fill({
        color: "#3399CC",
      }),
    }),
  });
  let _feature = new Feature({
    geometry: new Point(olProj.fromLonLat([108.945951, 34.465262])),
  });
  _feature.setStyle(_style);
  let _marker = new VectorLayer({
    source: new VectorSource({
      features: [_feature],
    }),
  });
  this.openMap.addLayer(_marker);
},
​

成功在地图上添加了一个点位。

上方代码中import了几个新的类:Feature,Point,Style等,主要是具有几何的地理要素的矢量对象以及具体的样式,然后通过setStyle将样式赋予Feature,主要就在地图上绘制出了一个坐标点。

4、弹窗显示标记信息

接下来咱们需要给3小节中的坐标点添加点击事件,同时能够在地图上显示一个弹框,展示点位的一些信息。

首先添加点击事件,这里使用单击singleclick

singleclick() {
  this.openMap.on("singleclick", (e) => {
    // 判断是否点击在点上
    let feature = this.openMap.forEachFeatureAtPixel(
      e.pixel,
      (feature) => feature
    );
    console.log(feature);
  });
},

当我们没有点击在点上时,会打印undefined,而点击在点上时会打印出对应的feature信息

这里我们同时添加一个事件pointermove,改变鼠标移到到点位上的光标样式。

pointermove() {
  this.openMap.on("pointermove", (e) => {
    if (this.openMap.hasFeatureAtPixel(e.pixel)) {
      this.openMap.getViewport().style.cursor = "pointer";
    } else {
      this.openMap.getViewport().style.cursor = "inherit";
    }
  });
},

接着上面的点击事件,当我们点击时希望能够在点位的上方显示出该点的信息弹窗 先在vue添加个弹窗组件,需要引入一个新的类Overlay

import { Overlay } from "ol";
复制代码
// template
<!-- 弹框 -->
<div ref="popup" class="popup" v-show="shopPopup">
  <div class="info">
    <ul>
      <li>信息1:xxx</li>
      <li>信息2:xxx</li>
      <li>信息3:xxx</li>
    </ul>
  </div>
</div>
​
// script
addOverlay() {
  // 创建Overlay
  let elPopup = this.$refs.popup;
  this.popup = new Overlay({
    element: elPopup,
    positioning: "bottom-center",
    stopEvent: false,
    offset: [0, -20],
  });
  this.openMap.addOverlay(this.popup);
},
​
// style
.popup {
  width: 200px;
  background-color: white;
  padding: 18px;
  border-radius: 10px;
  box-shadow: 0 0 15px rgb(177, 177, 177);
  .info {
    font-size: 14px;
    text-align: left;
    ul {
      padding-left: 0;
    }
  }
}

使用ol的addOverlay方法,将弹出层添加到map的Overlay上,然后修改之前的点击事件函数

singleclick() {
  // 点击
  this.openMap.on("singleclick", (e) => {
    // 判断是否点击在点上
    let feature = this.openMap.forEachFeatureAtPixel(
      e.pixel,
      (feature) => feature
    );
    console.log(feature);
    if (feature) {
      this.shopPopup = true;
      // 设置弹窗位置
      let coordinates = feature.getGeometry().getCoordinates();
      this.popup.setPosition(coordinates);
    } else {
      this.shopPopup = false;
    }
  });
},

可以看到有设置弹窗位置的代码

// 设置弹窗位置
let coordinates = feature.getGeometry().getCoordinates();
this.popup.setPosition(coordinates);

获取当前点击点的坐标,然后设置给弹窗,同时之前弹窗设置了y轴-30的偏移 以防覆盖掉点位标记。 至此,咱们整个点击弹窗就实现完成了。

最后,附上完整代码,主要是Home.vue的修改

<template>
  <div class="home">
    <div id="map" class="map-home"></div>
    <!-- 弹框 -->
    <div ref="popup" class="popup" v-show="shopPopup">
      <div class="info">
        <ul>
          <li>信息1:xxx</li>
          <li>信息2:xxx</li>
          <li>信息3:xxx</li>
        </ul>
      </div>
    </div>
  </div>
</template><script>
import { Map, View, Feature, Overlay } from "ol";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { XYZ, Vector as VectorSource } from "ol/source";
import * as olProj from "ol/proj";
import { Point } from "ol/geom";
import { Style, Fill, Stroke, Circle as sCircle } from "ol/style";
​
export default {
  name: "Home",
  components: {},
  data() {
    return {
      openMap: null,
      popup: null,
      shopPopup: false,
    };
  },
  mounted() {
    this.initMap();
  },
  methods: {
    initMap() {
      this.openMap = new Map({
        target: "map",
        layers: [
          new TileLayer({
            source: new XYZ({
              url: "https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}",
            }),
          }),
        ],
        view: new View({
          center: olProj.fromLonLat([108.945951, 34.465262]),
          zoom: 1,
        }),
        controls: [],
      });
      this.setMarker();
      this.addOverlay();
      this.singleclick();
      this.pointermove();
    },
    setMarker() {
      let _style = new Style({
        image: new sCircle({
          radius: 10,
          stroke: new Stroke({
            color: "#fff",
          }),
          fill: new Fill({
            color: "#3399CC",
          }),
        }),
      });
      let _feature = new Feature({
        geometry: new Point(olProj.fromLonLat([108.945951, 34.465262])),
      });
      _feature.setStyle(_style);
      let _marker = new VectorLayer({
        source: new VectorSource({
          features: [_feature],
        }),
      });
      this.openMap.addLayer(_marker);
    },
    addOverlay() {
      // 创建Overlay
      let elPopup = this.$refs.popup;
      this.popup = new Overlay({
        element: elPopup,
        positioning: "bottom-center",
        stopEvent: false,
        offset: [0, -20],
      });
      this.openMap.addOverlay(this.popup);
    },
    singleclick() {
      // 点击
      this.openMap.on("singleclick", (e) => {
        // 判断是否点击在点上
        let feature = this.openMap.forEachFeatureAtPixel(
          e.pixel,
          (feature) => feature
        );
        console.log(feature);
        if (feature) {
          this.shopPopup = true;
          // 设置弹窗位置
          let coordinates = feature.getGeometry().getCoordinates();
          this.popup.setPosition(coordinates);
        } else {
          this.shopPopup = false;
        }
      });
    },
    pointermove() {
      this.openMap.on("pointermove", (e) => {
        if (this.openMap.hasFeatureAtPixel(e.pixel)) {
          this.openMap.getViewport().style.cursor = "pointer";
        } else {
          this.openMap.getViewport().style.cursor = "inherit";
        }
      });
    },
  },
};
</script>
<style lang="scss" scoped>
.map-home {
  width: 100vw;
  height: 100vh;
}
.popup {
  width: 200px;
  background-color: white;
  padding: 18px;
  border-radius: 10px;
  box-shadow: 0 0 15px rgb(177, 177, 177);
  .info {
    font-size: 14px;
    text-align: left;
    ul {
      padding-left: 0;
    }
  }
}
</style>

juejin.cn/post/702552…

本文主要是OpenLayers的入门教程,完成OpenLayers的地图导入渲染,以及坐标点的点击事件。