1 Star 0 Fork 10

fearwall / Vue-Openlayers

forked from st19911224 / Vue-Openlayers 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
01.md 12.12 KB
一键复制 编辑 原始数据 按行查看 历史
shaotao 提交于 2021-11-04 13:07 . feat: part3:Cluster设置集群

一、前言

由于最近项目需要,需要在vue项目中使用OpenLayers来进行 GIS 地图的开发,网上对 OpenLayers 文章并不算太大,借此机会分享下自己在项目中实际使用的一些心得。

本系列将陆续分享项目过程中实现的一些功能点,本文主要介绍以下部分:

  1. 项目引入
  2. 底图渲染
  3. 标记绘制
  4. 弹窗显示标记信息

Openlayers

二、具体实现

本项目基于 vue 开发,首先准备一个 vue 项目,直接 vue-cli 搭建一个就行,文章用项目版本为 vue2+sass image.png

1、引入 Openlayers

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

npm install ol
// or
yarn add ol

将初始文件默认路由的页面更改下

// app.vue
<template>
  <div id="app">
    <router-view />
  </div>
</template>

<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
</style>

// Home.vue
<template>
  <div class="home">
  </div>
</template>

<script>
export default {
  name: "Home",
  components: {},
};
</script>

2、底图渲染

在 Home.vue 文件中进行 map 渲染,本文采用的是高德地图的切片地图模式,

// Home.vue
<template>
  <div class="home">
    <div id="map" class="map-home"></div>
  </div>
</template>

<script>
import { Map, View } from "ol";
import * as olProj from "ol/proj";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ";

export default {
  name: "Home",
  components: {},
  data() {
    return {
      openMap: null,
    };
  },
  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: [],
      });
    },
  },
};
</script>
<style lang="scss" scoped>
.map-home {
  width: 100vw;
  height: 100vh;
}
</style>

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

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

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

image.png

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);
},

image.png

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

上方代码中 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>信息1xxx</li>
      <li>信息2xxx</li>
      <li>信息3xxx</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 的偏移 以防覆盖掉点位标记。
至此,咱们整个点击弹窗就实现完成了。

image.png 最后,附上完整代码,主要是 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>信息1xxx</li>
          <li>信息2xxx</li>
          <li>信息3xxx</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>

三、最后

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

感谢大家阅读

如果能帮助到您,那更是我的万分荣幸。

后面应该会陆续的更新更多的功能使用,以及项目中遇到的一些问题,感兴趣的小伙伴可以点个收藏/关注。

马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/fearwall/vue-openlayers.git
git@gitee.com:fearwall/vue-openlayers.git
fearwall
vue-openlayers
Vue-Openlayers
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891