ArcGis api配合vue開發入門系列(二)距離以及面積的測量

隨風的思念發表於2019-02-28

正文


首先自定義個工具欄,包括測量距離與測量面積的工具以及地圖漫遊。

ArcGis api配合vue開發入門系列(二)距離以及面積的測量
圖示的話是用的iconfont。我是把這個工具單獨寫在一個元件裡面,這個元件裡面裡面會用到一些操作地圖的方法,我在map這個元件裡面把需要用到的方法放在一個物件裡面通過prop傳到子元件,並且地圖這個物件我把他放在了vue的原型鏈上。Vue.prototype.$map = map;

下面是ma元件的程式碼

<template>
  <div class="wrapper">
    <div ref="map" class="map">
      <MapTools :MapToolsObject="MapToolsObject" class="map-tools"></MapTools>
    </div>
  </div>
</template>

<script>
import Vue from "vue";
import esriLoader from "esri-loader";
import MapTools from "./MapTools/index.vue";
export default {
  name: "map",

  components: { MapTools },

  props: {},

  data() {
    return {
      MapToolsObject: {}
    };
  },

  created() {},

  mounted() {
    const options = { url: "https://js.arcgis.com/3.27/" };
    esriLoader
      .loadModules(
        [
          "esri/map",
          "esri/toolbars/draw",
          "esri/symbols/SimpleMarkerSymbol",
          "esri/symbols/SimpleLineSymbol",
          "esri/symbols/SimpleFillSymbol",
          "esri/Color",
          "esri/SpatialReference",
          "esri/geometry/Point",
          'esri/graphic',
          'esri/geometry/geodesicUtils',
          'esri/units',
          'esri/symbols/TextSymbol',
          'esri/symbols/Font',
          'esri/layers/GraphicsLayer',
        ],
        options
      )
      .then(
        ([
          Map,
          Draw,
          SimpleMarkerSymbol,
          SimpleLineSymbol,
          SimpleFillSymbol,
          Color,
          SpatialReference,
          Point,
          Graphic,
          geodesicUtils,
          units,
          TextSymbol,
          Font,
          GraphicsLayer
        ]) => {
          let map = new Map(this.$refs.map, {
            backgroundColor: "#eee",
            basemap: "streets",
            logo: false,
            slider: false,
            zoom: 7,
            minZoom: 7
          });
          Vue.prototype.$map = map;
          //新建一個圖層存放symbol
          let symbolLayert = new GraphicsLayer()
          this.$map.addLayer(symbolLayert)
          this.MapToolsObject = {
            SpatialReference,
            SimpleMarkerSymbol,
            SimpleLineSymbol,
            SimpleFillSymbol,
            Color,
            Draw,
            Point,
            Graphic,
            geodesicUtils,
            units,
            TextSymbol,
            Font,
            GraphicsLayer,
            symbolLayert
          };
        }
      );
  },

  computed: {},

  methods: {}
};
</script>
<style scoped  lang='less'>
@import url('https://js.arcgis.com/3.27/esri/css/esri.css');
.wrapper {
  width: 100%;
  height: 100%;
  position: relative;
  .map {
    width: 100%;
    height: 100vh;
    position: relative;
  }
}
</style>
複製程式碼

在這裡面我們需要定義一個GraphicsLayer用來儲存待會兒我們繪製的graphic.

let symbolLayert = new GraphicsLayer()

接下來的話是map-tool元件的程式碼

<template>
  <div class="map-tools">
    <div
      class="map-toole__btn"
      title="測量距離"
      @click="measureDistance('distance')"
      :class="activeBtn === 'distance' ? 'isSelectBtn' : ''"
    >
      <i class="iconfont icon-juli"></i>
    </div>
    <div
      class="map-toole__btn"
      title="測量面積"
      @click="measureArea('area')"
      :class="activeBtn === 'area' ? 'isSelectBtn' : ''"
    >
      <i class="iconfont icon-mianji"></i>
    </div>
    <div class="map-toole__btn" title="清空圖斑" @click="clearGraphics">
      <i class="iconfont icon-qingchu-copy"></i>
    </div>
    <div
      class="map-toole__btn"
      title="漫遊"
      @click="mapRoam('roam')"
      :class="activeBtn === 'roam' ? 'isSelectBtn' : ''"
    >
      <i class="iconfont icon-shou"></i>
    </div>
  </div>
</template>

<script>
import {
  getMarkerSymbolStyle,
  getLineSymbolStyle,
  getFillSymbolStyle,
  getTextSymbolStyle,
  getLength,
  getArea,
  getCenterPoint
} from "../js/map.utils";
export default {
  name: "MapTools",

  components: {},

  props: {
    MapToolsObject: {
      type: Object,
      default: null
    }
  },

  data() {
    return {
      activeBtn: "",
      isFullScreen: false,
      isLoadShp: false,
      isLoadGraphic: false,
      drawToolbar: null
    };
  },

  created() {},

  mounted() {},

  computed: {
    SpatialReference() {
      let { SpatialReference } = this.MapToolsObject;
      return SpatialReference;
    },

    Point() {
      let { Point } = this.MapToolsObject;
      return Point;
    },

    Draw() {
      let { Draw } = this.MapToolsObject;
      return Draw;
    },

    symbolLayert() {
      let { symbolLayert } = this.MapToolsObject;
      return symbolLayert;
    },

    Graphic() {
      let { Graphic } = this.MapToolsObject;
      return Graphic;
    },

    Navigation() {
      let { Navigation } = this.MapToolsObject;
      return Navigation;
    },

    SimpleFillSymbol() {
      let { SimpleFillSymbol } = this.MapToolsObject;
      return SimpleFillSymbol;
    }
  },

  methods: {
    controlSelection(val) {
      this.activeBtn = val
    },

    //地圖漫遊
    mapRoam(val) {
      this.controlSelection(val);
      this.drawToolbar.deactivate();
    },

    //測量距離
    measureDistance(val) {
      if (this.drawToolbar) this.drawToolbar.deactivate();
      this.controlSelection(val);
      this.drawUtils();
      this.drawToolbar.activate(this.Draw.LINE);
    },

    //測量面積
    measureArea(val) {
      if (this.drawToolbar) this.drawToolbar.deactivate();
      this.controlSelection(val);
      this.drawUtils();
      this.drawToolbar.activate(this.Draw.POLYGON);
    },

    //初始化畫圖工具
    drawUtils() {
      this.drawToolbar = new this.Draw(this.$map);
      this.drawToolbar.on("draw-complete", this.addGraphic);
    },

    //清空圖層
    clearGraphics() {
      this.symbolLayert.clear();
    },

    addGraphic(evt) {
      if (evt.geometry.type === "point" || evt.geometry.type === "multipoint") {
        // let graphicSymbol = this.drawPoint(evt)
      } else if (
        evt.geometry.type === "line" ||
        evt.geometry.type === "polyline"
      ) {
        this.addPointGraphic(evt);
      } else {
        this.addAreaGraphic(evt);
      }
    },

    //標註線段
    addPointGraphic(evt) {
      let graphicSymbol = this.drawLine(evt),
        length = getLength(evt.geometry, this.MapToolsObject)[0],
        lengthSymbol = getTextSymbolStyle(this.MapToolsObject);
      if (length < 3000) {
        lengthSymbol.setText("長度為:" + length.toFixed(2) + "米");
      } else {
        lengthSymbol.setText(
          "長度為:" + parseFloat(length / 1000).toFixed(2) + "千米"
        );
      }
      let graphicText = this.drawText(evt, lengthSymbol);
      this.symbolLayert.add(graphicSymbol);
      this.symbolLayert.add(graphicText);
    },

    //標註面積
    addAreaGraphic(evt) {
      let graphicSymbol = this.drawArea(evt),
        area = getArea(evt.geometry, this.MapToolsObject)[0].toFixed(2),
        areaSymbol = getTextSymbolStyle(this.MapToolsObject);
      areaSymbol.setText("面積為:" + area + "平方公里");
      let graphicText = this.drawText(evt, areaSymbol);
      this.symbolLayert.add(graphicSymbol);
      this.symbolLayert.add(graphicText);
    },

    //繪製點
    drawPoint(evt) {
      let symbol = getMarkerSymbolStyle(this.MapToolsObject);
      return new this.Graphic(evt.geometry, symbol);
    },

    //繪製線段
    drawLine(evt) {
      let symbol = getLineSymbolStyle(this.MapToolsObject);
      return new this.Graphic(evt.geometry, symbol);
    },

    //繪製面積
    drawArea(evt) {
      let symbol = getFillSymbolStyle(this.MapToolsObject, [64, 169, 255, 0.4]);
      return new this.Graphic(evt.geometry, symbol, {
        name: "勾繪圖斑"
      });
    },

    //繪製文字
    drawText(evt, symbol) {
      let centerPoint = getCenterPoint(evt.geometry);
      return new this.Graphic(centerPoint, symbol);
    }
  }
};
</script>
<style lang='less' scoped>
.map-tools {
  display: inline-block;
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 33;
  display: flex;
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
  .interval-symbol {
    color: #dcdee2;
    font-size: 20px;
    background: white;
    padding: 0 2px;
    line-height: 38px;
  }
  .map-toole__btn {
    width: 38px;
    height: 38px;
    display: inline-block;
    background-color: white;
    line-height: 38px;
    text-align: center;
    cursor: pointer;
    &:hover {
      color: #303030;
      background-color: #eee;
    }
    .iconfont {
      font-size: 20px;
      vertical-align: middle;
    }
  }
}
</style>
複製程式碼

這裡面主要的操作邏輯就是使用者點選測量按鈕之後,會初始化地圖的繪製工具

this.drawToolbar = new this.Draw(this.$map);
this.drawToolbar.on("draw-complete", this.addGraphic);
複製程式碼

然後通過啟用不同型別的繪製工具來繪製圖斑,

this.drawToolbar.activate(this.Draw.POLYGON);繪製多邊形
this.drawToolbar.activate(this.Draw.LINE);繪製線條
複製程式碼

繪製完成之後會有一個回撥函式this.addGraphic,回撥函式的引數就是我們剛才繪製的圖形, 拿到返回的引數之後,我們再建立一個graphic,然後把graphic新增到我們最初建立的symbolLayert圖層上面就OK了。 建立graphic的方法就是new this.Graphic(evt.geometry, symbol);

this.Graphic其實就是我們在computed裡面計算的屬性,也就是通過map傳過來的MapToolsObject物件裡面的方法,因為很多函式裡面都會用到這個物件裡面的屬性,所以我直接把他們寫在了計算屬性裡面,當然你也可以不寫在計算屬性裡面,在每一個函式裡面去拿也是可以的。類似這樣let { SpatialReference } = this.MapToolsObject;

上面有兩個引數 evt.geometry, symbolevt的話就是我們繪製完圖形時候回撥函式返回的引數,而symbol的話是需要我們自己去建立,根據你繪製的不同型別的圖斑你需要去建立不同的symbol,建立的方法我是寫在map.utils.js的檔案裡面的,裡面也包含了一些其他的方法。下面是這個檔案的程式碼

//設定點的填充樣式
let getMarkerSymbolStyle = MapToolsObject => {
  let { SimpleMarkerSymbol, Color } = MapToolsObject
  let markerSymbol = new SimpleMarkerSymbol()
  markerSymbol.setColor(new Color('#ff7a45'))
  markerSymbol.setOutline(getLineSymbolStyle(MapToolsObject))
  return markerSymbol
}

//設定線的填充樣式
let getLineSymbolStyle = MapToolsObject => {
  let { SimpleLineSymbol, Color } = MapToolsObject
  let lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color('#ff7a45'), 5)
  return lineSymbol
}

//設定面的填充樣式
let getFillSymbolStyle = (MapToolsObject, color) => {
  color = color || [235, 77, 75, 0.4]
  let { SimpleFillSymbol, SimpleLineSymbol, Color } = MapToolsObject
  let fillSymbol = new SimpleFillSymbol(
    SimpleFillSymbol.STYLE_SOLID,
    new SimpleLineSymbol(SimpleLineSymbol.STYLE_DASH, new Color([255, 255, 255]), 3),
    new Color(color)
  )
  return fillSymbol
}

//設定文字的填充樣式
let getTextSymbolStyle = MapToolsObject => {
  let { TextSymbol, Font, Color } = MapToolsObject
  let textSymbol = new TextSymbol().setColor(new Color('#17233d')).setFont(new Font('18px').setWeight(Font.WEIGHT_BOLD))
  return textSymbol
}

//獲取長度
let getLength = (polyline, MapToolsObject) => {
  let { geodesicUtils, units } = MapToolsObject
  return geodesicUtils.geodesicLengths([polyline], units.METERS)
}

//獲取面積
let getArea = (polygon, MapToolsObject) => {
  let { geodesicUtils, units } = MapToolsObject
  return geodesicUtils.geodesicAreas([polygon], units.SQUARE_KILOMETERS)
}

//獲取中心點座標
let getCenterPoint = polyline => {
  return polyline.getExtent().getCenter()
}

export {
  getMarkerSymbolStyle,
  getLineSymbolStyle,
  getFillSymbolStyle,
  getTextSymbolStyle,
  getLength,
  getArea,
  getCenterPoint
}
複製程式碼

這裡面的話主要就是一些設定樣式和計算圖斑面積和長度的一些方法。

相關文章