高德地图JS API 2.0绘制编辑多个矢量图形(圆形和多边形)

1650880115625

官网地址:JS API 2.0 示例中心

功能:1.可选择绘制类型(圆形或多边形),2.可选择不同区域并随当前区域自适应地图缩放。 3.编辑图形时可根据大小自适应地图缩放。

默认初始矢量图:1.圆形:根据中心点位置,半径1公里圆。2、多边形矢量图默认生成正方形。根据中心点位置,计算生成1公里四个方位的位置。
代码如下:

<template>
  <div>
    <div id="container">
      <div class="region_list">
        <div class="region-list-bg">
          <div
            v-for="(item, i) in mapListSetting"
            :key="i"
            :class="[
              'region-list_block',
              'boxCardBlock',
              item.selected ? 'activeListBlock' : '',
            ]"
            @click="selectDelivery(i)"
          >
            <div v-if="mapListSetting.length != 1">
              <a class="close-modal-sub closeSmall" v-on:click.stop="RemoveItem(i)">
                ×
              </a>
            </div>
            <div class="displayRow alignItemsCenter jscontentbet mb10">
              <label
                class="block-label"
                :style="{ borderColor: item.colorStyle }"
              >
                <span
                  class="block-label_span"
                  :style="{ background: item.colorStyle, opacity: 0.2 }"
                ></span>
              </label>
              <el-input
                v-model="item.name"
                clearable
                placeholder="请输入内容"
                style="width: 150px"
              />
            </div>
            <div class="displayRow alignItemsCenter jscontentbet mb10">
              <label class="region-list_block-label">起送价:</label>
              <el-input
                v-model="item.minPriceout"
                placeholder="00.00"
                style="width: 110px"
                @blur="regExpChange(item.minPriceout,'minPriceout',i)"
                oninput="value=value.replace(/[^0-9.]/g,'').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')"
              >
                <template slot="prepend"></template>
              </el-input>
            </div>
            <div class="displayRow alignItemsCenter jscontentbet" v-show="compute_type!='2'">
              <label class="region-list_block-label">配送费:</label>
              <el-input
                v-model="item.pscost"
                placeholder="00.00"
                style="width: 110px"
                @blur="regExpChange(item.pscost,'pscost',i)"
                oninput="value=value.replace(/[^0-9.]/g,'').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')"
              >
                <template slot="prepend"></template>
              </el-input>
            </div>
            <div class="region-list_block-arrow">
            </div>
          </div>
          <div class="addPsqy" v-if="mapListSetting.length <= 10">
            <button
              class="region-list_add"
              type="button"
              @click="addOpenPoly()"
            >
              添加配送区域
            </button>
          </div>
        </div>
      </div>
      <div class="region_type">
        <div class="region_type_contain">
          <div class="region-type_row displayRow alignItemsCenter">
            <label class="region-type_label">配送区域:</label>
            <div class="mr20">
              <el-radio v-model="drawtype" label="0" @change="selectedTypeRadio">
                按半径框选
              </el-radio>
              <el-radio v-model="drawtype" label="1" @change="selectedTypeRadio">
                自定义框选
              </el-radio>
            </div>
            <div class="ml20">
              <label class="region-type_label">半径距离:</label>
              <div class="region-type_custom" v-if="drawtype=='1'">
                区域内
              </div>
              <span v-if="drawtype=='0'">
                <el-input  v-model="circleArea"  style="width: 70px"  @change="changeCircleArea"/>
                公里内
              </span>
            </div>
          </div>
        </div>
      </div>

      <div class="fullscreen" @click="clickFun">
        <vab-icon :icon="isFullscreen ? 'fullscreen-exit-fill' : 'fullscreen-fill'" style="font-size:20px"/>
      </div>
      
    </div>
  </div>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader'
import screenfull from 'screenfull'

export default {
  name: 'MapEdit',
  props: {
    //引用组件页面传来的值
    areas: {
      type: Array,
      default: function () {
        return []
      },
    },
    //中心点
    center: {
      type: Array,
      default: function () {
        return [116.403322, 39.920255]
      },
    },
    //绘制类型
    compute_type: {
      type: String,
      default: function () {
        return "2"
      },
    }
  },
  data() {
    return {
      isFullscreen:false,
      polyEditor: null,  //当前编辑的矢量图
      polygonPaths: [],  //编辑后的多边形对象
      map: null,   //初始化地图
      polygons: [],  //绘制的矢量图数组

      mapListIndex:0, //当前选择的区域index
      mapListSetting: [
        {
          name: '', //区域名称
          minPriceout: '0.00', //起送价
          pscost: '0.00',  //配送费
          selected: true,
          locations_object: [],
          colorStyle: '#1791fc',
          area_type:'1', //配送范围类型 0按半径 1自定义范围
          inkm:'1.000'  //半径
        },
      ],
      initia_locations_object:[], //根据中心点生成的初始位置
      //区域颜色color
      mapColor: [
        { color: '#1791fc' },
        { color: 'rgb(45, 166, 65)' },
        { color: 'rgb(133, 199, 0)' },
        { color: 'rgb(237, 106, 12)' },
        { color: 'rgb(250, 171, 12)' },
        { color: 'rgb(212, 42, 141)' },
        { color: 'rgb(138, 63, 212)' },
        { color: 'rgb(250, 210, 12)' },
        { color: 'rgb(17, 160, 173)' },
        { color: 'rgb(212, 0, 0)' },
      ],
      drawtype: '1', //1 自定义框选, 0 按半径框选
      circleArea:'1.000', 
    }
  },
  watch: {
    'areas':function(){
      //console.log(this.areas);  
    }
  },
  created(){
    console.log(this.areas);
    if(!this.areas) return;
    if(this.areas.length>0){
      this.areas.forEach((element, i) => {
        element.area_type=element.area_type.toString()
        if(i==0){
          this.mapListIndex=i
          element.selected = true
        }else{
          element.selected = false
        }
        if(i<this.areas.length){
          element.colorStyle = this.mapColor[i].color
        }
      })
      this.mapListSetting=this.areas
    }
  },
  mounted() {
    var that=this
    this.init() //初始化Map

    setTimeout(function(){
      //created事件里,若areas值长度大于0,则使用areas传来的数据,反之执行默认初始化数据;
      that.mapListSetting.forEach((element, i) => {
        if(i<that.mapListSetting.length){
          that.drawtype = element.area_type
          that.circleArea =  element.inkm
          that.initAreas(i)
          
          if(i+1==that.mapListSetting.length){
            that.drawtype = that.mapListSetting[0].area_type
          }
        }
        if (i==0) {
          that.drawtype = element.area_type
          that.initPoly(i)
        } 
        
      })
     
    },2000)
    
  },
  
  methods: {
    //点标记
    addMarker() {
      var startMarker = new AMap.Marker({
        position: new AMap.LngLat(this.center[0],this.center[1]),
      });
      this.map.add(startMarker);
    },
    // 简单实现绘制正方形,side 正方形边长,单位米
    // 若需要绘制其他矩形,需自行修改代码
    GetFourPoint(latLng,side){
      var lng=latLng[0]
      let lat=latLng[1]
      path();
      function path(){
        const centerPoint = new AMap.LngLat(lng, lat);
        const upLeftPoint = centerPoint.offset(-side / 2, side / 2);
        const upRightPoint = centerPoint.offset(side / 2, side / 2);
        const leftBottomPoint = centerPoint.offset(-side / 2, -side / 2);
        const rightBottomPoint = centerPoint.offset(side / 2, -side / 2);
        return [
          [upRightPoint.lng, upRightPoint.lat],
          [upLeftPoint.lng, upLeftPoint.lat],
          [leftBottomPoint.lng, leftBottomPoint.lat],
          [rightBottomPoint.lng, rightBottomPoint.lat],
        ];
      }
      this.initia_locations_object=path()  //根据中心点生成的初始位置
      if(!this.areas || this.areas.length==0){
        this.mapListSetting[0].locations_object=path()
      }
      //回显的数据locations_object为null时,默认赋值初始值
      this.mapListSetting.forEach(function(e,index){
        if(!e.locations_object){
          e.locations_object=path()
        }
      })
      // console.log(path());
    },
    async init() {
      await this.initMap()
    },
    async initMap() {
      let AMap = await AMapLoader.load({
        key: '3517b919f6bd44b972cf9f958da111fe',
        version: '2.0',
        plugins: [
          'AMap.PolygonEditor',
          'AMap.Autocomplete',
          'AMap.PlaceSearch',
          'AMap.Scale',
          'AMap.OverView',
          'AMap.ToolBar',
          'AMap.MapType',
          'AMap.PolyEditor',
          'AMap.CircleEditor',
          'AMap.Geolocation',
          'AMap.Geocoder',
          'AMap.AMapUI',
          'AMap.ControlBar',
          'AMap.Marker'
        ],
      })
      this.map = new AMap.Map('container', {
        center: this.center,
        resizeEnable: true,
        zoom: 14,
        plugin: [
          //一些工具插件
          {
            pName: 'MapType', //地图类型
            defaultType: 0,
            events: {
              init(instance) {},
            },
          },
        ],
      }) 
      
     
      this.map.addControl(new AMap.ControlBar({position:{ top: "10px", left: 90, right: "10px", } }));
      this.map.addControl(new AMap.ToolBar({position:{ top: '110px', left: 0, right: '40px', } }));
      //this.map.addControl(new AMap.Scale( {position:{ right: '10px', bottom:"10px"} } )); 比例尺
      // 缩放地图到合适的视野级别
      this.map.setFitView()
      
      this.GetFourPoint(this.center, 2000) 
      this.addMarker()
      this.map.on('click', this.showInfoClick);
    },
    //地图点击事件用来测试)
    showInfoClick(e){
      var text = '您在 [ '+e.lnglat.getLng()+','+e.lnglat.getLat()+' ] 的位置单击了地图!'
      console.log(text)
    },
    initAreas(i,type) {
      if(type=="editType"){
        this.polyEditor.close()
        this.map.remove([this.polygons[i]])
        this.polygons.splice(i, 1)
      }
      
      let col = this.mapListSetting[i].colorStyle

      if (this.drawtype == '1') {
        let path = this.mapListSetting[i].locations_object
        if (path.length <= 0) {
          return
        }

        var polygon = new AMap.Polygon({
          path: path,
          strokeColor: col,
          strokeWeight: 2,
          strokeOpacity: 1,
          fillOpacity: 0.1,
          fillColor: col,
          zIndex: 50,
          bubble: true,
        })
      } else {
        //console.log(i,col)
        var polygon = new AMap.Circle({
          center: this.center,
          radius: this.circleArea*1000, //半径
          borderWeight: 3,
          strokeColor: col,
          strokeOpacity: 1,
          strokeWeight: 2,
          strokeOpacity: 1,
          fillOpacity: 0.4,
          strokeDasharray: [10, 10],
          fillColor: col,
          zIndex: 50,
        })
      }
      
      if(type=="editType"){
        this.polygons.splice(i, 0, polygon)
      }else{
        this.polygons.push(polygon)
      }
      
      if (this.polygons.length <= 0) {
        return
      }
      //地图上新增矢量多边形
      // console.log(this.polygons)
      this.map.add(this.polygons)
    },
    initPoly(i) {
      var that = this
      let opts = {
        editOptions:{strokeColor: this.mapListSetting[i].colorStyle,  fillColor: this.mapListSetting[i].colorStyle,} 
      }
      // console.log(this.polygons)
      if (this.polygons.length > 0) {
        if(this.drawtype=="1"){
          this.polyEditor = new AMap.PolygonEditor( this.map,  this.polygons[i], opts)
        }else{
          this.polyEditor =  new AMap.CircleEditor(this.map, this.polygons[i], opts)
        }
      } else {
        if(this.drawtype=="1"){
          this.polyEditor = new AMap.PolygonEditor(this.map)
        }else{
          this.polyEditor =  new AMap.CircleEditor(this.map)
        }
      }
      that.polyEditor.open()
      this.delivery_area()

     //自适应地图缩放
      that.map.setFitView(that.polygons[i], false, [130, 60, 100, 60])
      that.polyEditor.on('adjust',function(){
        that.map.setFitView(that.polygons[i], false, [130, 60, 100, 60])
      })

      //关闭多边形编辑polygonEditor.close()触发该方法;
      if(this.drawtype=="1"){
        this.polyEditor.on('adjust', function (event) {
          // event.target 即为编辑后的多边形对象,event.target.getPath()得到编辑完成后的点数组
          let pointArr = event.target.getPath()
          this.polygonPaths = []
          for (let i = 0; i < pointArr.length; i++) {
            this.polygonPaths.push([
              pointArr[i].lng,
              pointArr[i].lat,
            ])
          }
          that.mapListSetting[i].locations_object=this.polygonPaths
          that.delivery_area()
          console.log('polygonPaths', this.polygonPaths)
        })
      }else{
        this.polyEditor.on('adjust', function (event) {
          //console.log(event);
          that.circleArea = (event.radius)/1000
          that.mapListSetting.forEach((element, index) => {
            if (that.mapListIndex == index) {
              element.inkm = that.circleArea
              that.delivery_area()
            }
          })
        })
      }
    },
    //添加配送区域
    addOpenPoly() {
      if (this.mapListSetting.length >= 10) return

      this.mapListSetting.forEach((element, i) => {
        this.mapColor.forEach((e,j)=>{
          if(element.colorStyle==e.color){
            this.mapColor.splice(j,1)
          }
        })
      })

      var that = this
      that.polyEditor.close()
      this.mapListSetting.push({
        name: '',
        minPriceout: '0.00',
        pscost: '0.00',
        selected: false,
        locations_object: this.initia_locations_object,
        colorStyle : that.mapColor[0].color
      })
      this.circleArea = '1.000'
      this.initAreas(this.mapListSetting.length - 1)
      this.mapListSetting.forEach((element, i) => {
        if (i + 1 == this.mapListSetting.length) {
          element.selected = true
          element.area_type = that.drawtype
          element.inkm = that.circleArea
          that.initPoly(i)
          that.mapListIndex=i
        } else {
          element.selected = false
        }
      })
    },
    //选择编辑的区域
    selectDelivery(i) {
      var that = this
      //console.log(i)
      that.mapListIndex=i,
      that.polyEditor.close()
      that.mapListSetting.forEach((element, index) => {
        if (i == index) {
          element.selected = true
          that.drawtype = element.area_type
          that.circleArea = element.inkm
          that.initPoly(i)
        } else {
          element.selected = false
        }
      })
      // console.log(that.mapListSetting[i].selected);
    },
    //删除编辑区域
    RemoveItem(i) {
      this.mapListSetting.splice(i, 1)
      this.map.remove([this.polygons[i]])
      this.polygons.splice(i, 1)
      
      this.mapColor.push({color:this.mapListSetting[i].colorStyle})
      
      //console.log(i, i+1,this.mapListSetting.length)
      if(i==this.mapListSetting.length){
        this.mapListSetting[i-1].selected=true
        this.mapListIndex=i-1
      }
      if(this.polygons.length==1) {
        this.selectDelivery(0)
      }
    },
    //选择绘制类型
    selectedTypeRadio() {
      this.mapListSetting.forEach((element, index) => {
        if (this.mapListIndex == index) {
          element.area_type=this.drawtype
        }
      })
      //console.log(this.mapListIndex);
      this.initAreas(this.mapListIndex, "editType")
      this.initPoly(this.mapListIndex)
    },
    //更改半径距离
    changeCircleArea(){
      this.mapListSetting.forEach((element, index) => {
        if (this.mapListIndex == index) {
          element.inkm=this.circleArea
          this.initAreas(this.mapListIndex, "editType")
          this.initPoly(this.mapListIndex)
        }
      })
    },
    //保存(这里是向父组件传值)
    delivery_area(){
      this.$emit('getPolygonMap', this.mapListSetting)
    },
    //全屏
    clickFun(){
      const element = document.getElementById('container');//指定全屏区域元素
			if (!screenfull.isEnabled) {
          this.$baseMessage('开启全屏失败', 'error', 'vab-hey-message-error')
      }
      
      this.isFullscreen=!screenfull.isFullscreen
      if (screenfull.isEnabled) {
	      screenfull.request(element);
	   }
      screenfull.toggle()
	},
	//保留两位小数
    regExpChange(val,str,i){
      this.$set(this.mapListSetting[i], str, Number(val).toFixed(2))
    }
  },
}
</script>

<style>
.region-list_block .el-input-group__prepend {
  padding: 0 10px !important;
}
</style>
<style scoped lang="scss">
.displayRow{
  display:flex;
  flex-flow:row;
}
.displayColumn{
  display:flex;
  flex-flow:column; 
}
.alignItemsCenter{
  align-items: center;
}
.jscontentbet{
  justify-content: space-between;
}
#container {
  width: 100%;
  height: 600px;
  position: relative;
  min-width: 660px;
  background: #f3f3f3;
  color: #333333;
}
.region_list {
  width: 210px;
  max-height: 96%;
  position: absolute;
  background: #fff;
  top: 12px;
  left: 12px;
  z-index: 2;
  overflow-y: scroll;
  box-sizing: border-box;
  box-shadow: 0 0 5px #afafaf;
}
.region_list::-webkit-scrollbar {
  width: 0px;
  opacity: 0;
}
.region-list_block {
  position: relative;
  width: 100%;
  box-sizing: border-box;
  padding: 12px 22px 12px 12px;
  border: 1px solid transparent;
  border-bottom-color: #ebedf0;
}
.addPsqy {
  width: 100%;
}
.region-list_add {
  display: block;
  padding: 0;
  margin: 10px auto;
  font-size: 14px;
  width: 196px;
  color: #323233;
  line-height: 32px;
  background: #fff;
  outline: none;
  border: 1px solid #dcdee0;
  border-radius: 2px;
  cursor: pointer;
}
.activeListBlock {
  border-color: #1890ff;
}
.block-label {
  width: 15px;
  height: 15px;
  border: solid 1px #ccc;
}
.block-label_span {
  width: 100%;
  height: 100%;
  display: block;
}
.closeSmall {
  top: 4px;
  right: 4px;
  width: 15px;
  height: 15px;
  font-size: 12px;
  line-height: 16px;
}
/** */
.region_type {
  width: 100%;
  position: absolute;
  z-index: 1;
  padding: 12px 12px 12px 244px;
  box-sizing: border-box;
}
.region_type_contain {
  padding: 10px 12px 10px 20px;
  display: flex;
  flex-direction: column;
  background: hsla(0, 0%, 100%, 0.85);
  box-shadow: 0 0 5px #afafaf;
  font-size: 14px;
  max-width: 565px;
}
.region-type_row {
  padding: 10px 0;
  white-space: nowrap;
  overflow-x: auto;
}
.region-type_custom{
  display: inline-block;
}
.region-type_custom::before{
  display: inline-block;
  content: "";
  width: 22px;
  height: 22px;
  margin-top: -4px;
  margin-right: 8px;
  vertical-align: middle;
  background-size: 100%!important;
  background-position: 50%;
  background-repeat: no-repeat;
  background: url('../../../../public/img/icons/area.png');
}
// 选中角标
.activeListBlock .region-list_block-arrow{
  position: absolute;
  right: 0;
  bottom: 0;
  border: 10px solid #1890ff;
  border-top-color: transparent;
  border-left-color: transparent;
}
.region-list_block-arrow::before,.region-list_block-arrow::after{
  position: absolute;
  display: block;
  content: "";
  height: 2px;
  background: #fff;
}
.activeListBlock .region-list_block-arrow::before {
  width: 5px;
  left: -3px;
  bottom: -8px;
  transform: rotate(35deg);
}
.activeListBlock .region-list_block-arrow::after {
  width: 12px;
  left: -1px;
  bottom: -5px;
  transform: rotate(130deg);
}
.fullscreen{
  position: absolute;
  right: 20px;
  bottom: 20px;
  z-index: 1;
  border-radius: 50%;
  display: block;
  background: #fff;
  width: 40px;
  height: 40px;
  line-height: 40px;
  text-align: center;
}
</style>

你可能感兴趣的:(前端,高德地图2.0绘制矢量图,vue)