vue中简单使用openlayers

866 阅读3分钟

新建vue项目

命令行输入 vue create projectName

安装openlayers

npm i ol

初始化vue项目

为了偷懒,vue项目新建成功后我直接在App.vue中使用openlayers了,在assets新建init.css初始化页面距,在同级目录components创建OlMap.vue文件,App.vue引入OlMap。

初始化vue.png

// init.css
html,
body {
  margin: 0;
  padding: 0;
}
// main.js
import Vue from "vue";
import App from "./App.vue";
import "./assets/css/init.css";

Vue.config.productionTip = false;

new Vue({
  render: (h) => h(App),
}).$mount("#app");
// App.vue
<template>
  <div class="map_wrapper">
    <OlMap />
  </div>
</template>

<script>
import OlMap from "./components/OlMap.vue";
export default {
  name: "root",
  components: {
    OlMap,
  },
};
</script>

<style >
/* 写demo时,偷懒在这初始化页边距,不新建init.css也可以 */
/* html,
body {
  margin: 0;
  padding: 0;
} */
</style>


<style lang="scss" scoped>
.map_wrapper {
  height: 100vh;
}
</style>

openlayers初始化地图

创建容器,引入必要的资源,调用initMap方法初始化地图

<template>
  <div class="wrapper" id="map"></div>
</template>

<script>
import { Map, View } from "ol";
// 图层
import { Vector, Tile } from "ol/layer";
// openLayers自带的数据源
import OSM from "ol/source/OSM";
// 其他地图的数据源
import XYZ from "ol/source/XYZ";
import "ol/ol.css";
export default {
  name: "olMap",
  data() {
    return {
      // 缩放层级
      zoom: 16,
      //   定位中心点
      center: {
        lon: 113.27,
        lat: 23.13,
      },
    };
  },
  mounted() {
    this.initMap();

  },
  methods: {
    initMap() {
      let tileOSM = new Tile({
        // ol自带的数据源
        source: new OSM(),
        // 如果要引入其他地图的数据源,通过XYZ引入
        // source: new XYZ({
        //   url: "http://t3.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你的密钥,",
        // }),
      });

      let view = new View({
        zoom: this.zoom,
        center: [this.center.lon, this.center.lat],
        //坐标系
        projection: "EPSG:4326",
      });
      // 建议将map实例放在全局变量中,如果放在data中,数据量太大会造成ol卡死
      window.map = new Map({
        layers: [tileOSM],
        view,
        target: "map",
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.wrapper {
  height: 100%;
}
// 去除右下角水印
::v-deep .ol-attribution {
  display: none;
}
// 去除左上角控制栏
::v-deep .ol-control {
  display: none;
}

</style>

地图初始化后就可以在页面中看到效果,接下来,我们用openlayers绘制简单的点线面。 map.png

openlayers绘制点线面

openlayer绘制图形,需要经历如下几个步骤,获取矢量要素,将矢量要素添加到几何图形(Feature)中,将feature添加到VectorSource,再将VectorSource添加到矢量图层(Vector)中,最近将Vector添加到map实例即可。

流程图.png

了解openlayers绘制流程后,就可以开始绘制图形了,先在OlMap引入绘图需要的一些类。

// 图形
import { Point, LineString, Polygon, Circle } from "ol/geom";
// 样式
import { Style, Icon, Fill, Stroke } from "ol/style";
import { format } from "ol/coordinate";
import MousePosition from "ol/control/MousePosition.js";
// 几何图形类
import Feature from "ol/Feature";
import VectorSource from "ol/source/Vector";

绘制点:在methdos中创建createPoint的方法,

    createPoint(coordinates) {
      let styleList = [
        new Style({
          image: new Icon({
            anchorXUnits: "pixels",
            anchorYUnits: "pixels",
            src: require("../assets/images/position.png"),
            scale: 0.2,
          }),
        }),
      ];
      let point = new Point(coordinates);
      
      let feature = new Feature(point);
      let vectorSource = new VectorSource({
        features: [feature],
      });
        
       
      let vector = new Vector({
        source: vectorSource,
        style: function (feature) {
          return styleList;
        },
      });
      /** 给矢量图层添加style有两种方式,一种是给style属性赋值一个方法,在方法中将style返回,
        返回时style必须是一个数组,另外一种就是直接给style属性赋值对象,第一种方式可以同时添加多个
        Style的实例对象,只需要将它们都放在同一个数组中即可,而第二种方式只能添加一个Style的实例对象。
        let vector = new Vector({
        source: vectorSource,
        style: new Style({
          image: new Icon({
            anchorXUnits: "pixels",
            anchorYUnits: "pixels",
            src: require("../assets/images/position.png"),
            scale: 0.2,
          }),
        }),
      });
       */
      return vector;
    },

调用CreatePoint的方法进行绘图

handlePoint(){
    let point = this.createPoint([113.269356, 23.135343]);
    // point拿到的是矢量图层,需要将矢量图层添加到map中。
    map.addLayer(point);
}

因为所有图形的绘制流程大同小异,我们将createPoint中公共的部分抽离出来,封装成一个单独的方法,考虑到style中可能有多个Style实例对象,我使用数组的方式进行给矢量图层添加样式。

    /**
     * 绘制图层
     * @param { Object }  source 数据源
     * @param { Array }  style  style数组
     */
    createLayer(source, style) {
      let feature = new Feature(source);
      let vectorSource = new VectorSource({
        features: [feature],
      });

      let vector = new Vector({
        source: vectorSource,
        style: function (feature) {
          return style;
        },
      });
      return vector;
    },

我们对createPoint改造一下,调用方法跟上述相同。

    createPoint(coordinates) {
      let styleList = [
        new Style({
          image: new Icon({
            anchorXUnits: "pixels",
            anchorYUnits: "pixels",
            src: require("../assets/images/position.png"),
            scale: 0.2,
          }),
        }),
      ];
      let point = new Point(coordinates);
      return this.createLayer(point, styleList);
    },
    
    handlePoint() {
    let point = this.createPoint([113.269356, 23.135343]);
    map.addLayer(point);
    }   

到这里,我们绘制点的功能就完成了,因为有createLayer方法的存在,绘制不同的图形,只需要传不同的source跟style即可。

// 画线
    createLine(coordinates) {
      let line = new LineString(coordinates);

      let styleList = [
        new Style({
          stroke: new Stroke({
            color: "#f00",
            width: 2,
          }),
        }),
      ];

      return this.createLayer(line, styleList);
    },
    // 该方法最终需要到vue的生命周期钩子中调用才能看到效果
     drawLine() {
      let line = this.createLine([
        [113.266674, 23.133626],
        [113.267876, 23.130086],
      ]);
      map.addLayer(line);
    },
// 画多边形
    createPolygon(coordinates) {
      let polygon = new Polygon(coordinates);

      let styleList = [
        new Style({
          stroke: new Stroke({
            color: "#EE82EE",
            width: 1,
          }),

          fill: new Fill({
            color: "rgba(238,130,238, 0.25)",
          }),
        }),
      ];

      return this.createLayer(polygon, styleList);
    },
    
     drawPolygon() {
     // 需要注意的是,画面的数据格式是三维数组
      let polygon = this.createPolygon([
        [
          [113.270665, 23.130365],
          [113.274807, 23.131674],
          [113.274485, 23.127876],
        ],
      ]);

      map.addLayer(polygon);
    },

至此,绘制点、线、面的功能就实现了,可能会有小伙伴点击绘图的功能需求,我们只需要监听map的click事件就可以拿到点击的经纬度坐标了,将经纬度传给创建图形的方法就可以了。

map.on("click", function (e) {
      console.log(e);
        
      /** 需要注意的是,绘制新的图形时,旧的图形并不会被删除,需要手动删除,
      手动代码如下,本例子是绘制点,绘制线、面同理,都需要将以前的图形删掉
      */
      if(this.point){
         this.point.getSource().clear()
         map.removeLayer(this.point)
      }
        
      // 画点,将point的矢量图层保存下来,
      this.point  = this.createPoint(e.coordinate)
      map.addLayer(this.point)
    });

至此,vue初步使用openlayers完成,OlMap完整代码如下:

<template>
  <div class="wrapper" id="map"></div>
</template>

<script>
import { Map, View } from "ol";
// 图层
import { Vector, Tile } from "ol/layer";
// openLayers自带的数据源
import OSM from "ol/source/OSM";
// 其他地图的数据源
import XYZ from "ol/source/XYZ";
// 图形
import { Point, LineString, Polygon, Circle } from "ol/geom";
// 样式
import { Style, Icon, Fill, Stroke } from "ol/style";
import { format } from "ol/coordinate";
import MousePosition from "ol/control/MousePosition.js";
// 几何图形类
import Feature from "ol/Feature";
import VectorSource from "ol/source/Vector";
import "ol/ol.css";
export default {
  name: "olMap",
  data() {
    return {
      // 缩放层级
      zoom: 16,
      //   定位中心点
      center: {
        lon: 113.27,
        lat: 23.13,
      },
      point: null,
    };
  },
  mounted() {
    this.initMap();
    this.drawPoint();
    this.drawPolygon();
    this.drawLine();
    map.on("click", this.clickMap);
  },
  methods: {
    initMap() {
      let tileOSM = new Tile({
        // ol自带的数据源
        source: new OSM(),
        // 如果要引入其他地图的数据源,通过XYZ引入
        // source: new XYZ({
        //   url: "http://t3.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你的密钥,",
        // }),
      });

      let view = new View({
        zoom: this.zoom,
        center: [this.center.lon, this.center.lat],
        //坐标系
        projection: "EPSG:4326",
      });
      // 建议将map实例放在全局变量中,如果放在data中,数据量太大会造成ol卡死
      window.map = new Map({
        layers: [tileOSM],
        view,
        target: "map",
      });
    },
    clickMap(e) {
      console.log(e);
      /** 需要注意的是,绘制新的图形时,旧的图形并不会被删除,需要手动删除,
      手动代码如下,本例子是绘制点,绘制线、面同理,都需要将以前的图形删掉
      */
      if (this.point) {
        this.point.getSource().clear();
        map.removeLayer(this.point);
      }

      // 画点,将point的矢量图层保存下来,
      this.point = this.createPoint(e.coordinate);
      map.addLayer(this.point);
    },

    drawPoint() {
      let point = this.createPoint([113.269356, 23.135343]);
      map.addLayer(point);
    },

    drawPolygon() {
      let polygon = this.createPolygon([
        [
          [113.270665, 23.130365],
          [113.274807, 23.131674],
          [113.274485, 23.127876],
        ],
      ]);

      map.addLayer(polygon);
    },

    drawLine() {
      let line = this.createLine([
        [113.266674, 23.133626],
        [113.267876, 23.130086],
      ]);
      map.addLayer(line);
    },

    createPoint(coordinates) {
      let styleList = [
        new Style({
          image: new Icon({
            anchorXUnits: "pixels",
            anchorYUnits: "pixels",
            src: require("../assets/images/position.png"),
            scale: 0.2,
          }),
        }),
      ];
      let point = new Point(coordinates);
      return this.createLayer(point, styleList);
    },

    createPolygon(coordinates) {
      let polygon = new Polygon(coordinates);

      let styleList = [
        new Style({
          stroke: new Stroke({
            color: "#EE82EE",
            width: 1,
          }),

          fill: new Fill({
            color: "rgba(238,130,238, 0.25)",
          }),
        }),
      ];

      return this.createLayer(polygon, styleList);
    },

    createLine(coordinates) {
      let line = new LineString(coordinates);

      let styleList = [
        new Style({
          stroke: new Stroke({
            color: "#f00",
            width: 2,
          }),
        }),
      ];

      return this.createLayer(line, styleList);
    },
    /**
     * 绘制图层
     * @param { Object }  source 数据源
     * @param { Array }  style  style数组
     */
    createLayer(source, style) {
      let feature = new Feature(source);
      let vectorSource = new VectorSource({
        features: [feature],
      });

      let vector = new Vector({
        source: vectorSource,
        style: function (feature) {
          return style;
        },
      });
      return vector;
    },
  },
};
</script>

<style lang="scss" scoped>
.wrapper {
  height: 100%;
}
// 去除右下角水印
::v-deep .ol-attribution {
  display: none;
}
// 去除左上角控制栏
::v-deep .ol-control {
  display: none;
}
</style>

all.png