三、前端高德地图、测量两个点之前的距离

文章介绍了如何在前端使用高德地图API实现测距功能,包括点击开启和关闭测量、展示测量距离、清除地图上的测量标记和文本。通过自定义事件监听和触发实现组件间的通信,允许拖拽标记重新计算距离,并在关闭测距时清理地图元素。
摘要由CSDN通过智能技术生成

点击测距工具可以开启测量,再次点击关闭测量,清除地图上的点、连线、文字

在这里插入图片描述

在这里插入图片描述

再次点击测量工具的时候清除。

首先

上面的功能条河下面的地图我搞成了两个组件,他们作为兄弟组件存在,所以简单用js写了个事件监听触发的对象,
eventObj.js

const eventBus = {
    evnetList: [],
    // 监听事件
    $on(callbackFun, name) {
        this.evnetList.push({
            name,
            callbackFun
        })
    },
    //触发事件
    $emit(name, data) {
        this.evnetList.forEach(element => {
            if (name === element.name) {
                element.callbackFun(data)
            }
        });
    },
}
export default eventBus

我们在头部工具栏组件中引入:

import eventBus from './eventObj';

点击的dom

<div
   onClick={()=>this.clickFlagFun()}
   className={this.state.clickFlag ? 'rightBox1click' : 'rightBox1 '}
 >
   <Icon type="discount-o" style={{ marginRight: '4px' }} />AB间距
 </div>

事件:
clickFlag: 需要再 state 中提前声明 为 false 默认为关闭

  clickFlagFun() {
    this.setState({
      clickFlag: !this.state.clickFlag,
    },()=>{
      Toast.prompt({
        content: this.state.clickFlag ? '已开启测量工具' : '已关闭测量工具',
        duration: 5000,
        size: 'large'
      });
      //主动触发自定义事件
      eventBus.$emit('changclickFlag',this.state.clickFlag)
    });
  }

在地图盒子中:
我们需要在挂载的时候就进行监听这个事件:
执行相应的逻辑(这个一会说)

    eventBus.$on((flag) => {
      this.setState(
        {
          isCanClickMarkerLineFlag: flag,
        },
        () => {
          if (!flag) {
            //   清楚line  和 text
            this.map.remove([
              ...this.state.textAndlineObj,
              ...this.state.currentClickMarkerList,
            ]);
            this.setState({
              currentClickMarkerList: [],
              currentClickOptionsList: [],
              textAndlineObj: [],
            });
            this.map.off('click', clickHandler);
            return false;
          }
          // 测量距离方法
          flag && this.map.on('click', clickHandler);
        }
      );
    }, 'changclickFlag');

看地图组件全部代码,里面有对应注释(其实代码很low 但是不想整理 因为它能跑):

import React, { Component } from 'react';
import { Icon } from '@alife/aisc';
import AMapLoader from '@amap/amap-jsapi-loader';
import '../index.scss';
import eventBus from './eventObj';
import { base64PNG, sanjiaoSVG, gray, red, green } from './base64png.js';
const content = `<div style="width:auto;padding:3px;background:gray;color:#000;border:none">EU126,租凭<br/>XX.XX MW</div>`;
class MapComponent extends Component {
  constructor() {
    super();
    this.map = {};
    this.AMap = null;
    this.state = {
      isCanClickMarkerLineFlag: false,
      zoom: 10,
      datalist: [
        {
          icon: 1,
          position: [121.487899486, 31.24916171],
          title: 'aaaaa',
          zoom: 3,
          content,
        },
        {
          icon: 2,
          position: [121.287899486, 31.34916171],
          title: 'bbb',
          zoom: 3,
          content,
        },
        {
          icon: 3,
          position: [121.387899486, 31.44916171],
          title: 'ccc',
          zoom: 3,
          content,
        },
        {
          icon: 3,
          position: [121.487899486, 31.44916171],
          title: 'ddd',
          zoom: 3,
          content,
        },
        {
          icon: 3,
          position: [121.487899486, 31.54916171],
          title: 'eee',
          zoom: 3,
          content,
        },
      ],
      currentClickMarkerList: [],
      currentClickOptionsList: [],
      textAndlineObj: [],
    };
  }

  // 2.dom渲染成功后进行map对象的创建
  componentDidMount() {
    const that = this
    var clickHandler =  function (e) {
        // 最多生成两个标记点
        if (that.state.currentClickOptionsList.length <= 2) {
          let arrList = [];
          // 只能点击两个坐标
          if (that.state.currentClickOptionsList.length !== 0) {
            // 第一个 +  第二个标记点坐标
            arrList = [
              that.state.currentClickOptionsList[0],
              [e.lnglat.getLng(), e.lnglat.getLat()],
            ];
          } else {
            // 第一标记点坐标
            arrList = [[e.lnglat.getLng(), e.lnglat.getLat()]];
          }
          // 为了避免重复渲染
          //   清楚line  和 text
          that.map.remove([
            ...that.state.textAndlineObj,
            ...that.state.currentClickMarkerList,
          ]);
          that.setState(
            {
              // 坐标存起来  目前没有用到 只是做长度判断使用
              currentClickOptionsList: arrList,
            },
            () => {
              // 循环生成点击两次的坐标点
              const currentClickOptionsList = arrList;
              let arr = [];
              currentClickOptionsList.map((i, idx) => {
                var marker1 = new AMap.Marker({
                  icon: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
                  position: new AMap.LngLat(i[0], i[1]),
                  zoom: 888,
                  // 是否拖拽
                  draggable: true,
                  // clickable: true,
                  extData: {
                    flag: idx,
                  },
                  // 图标大小
                  offset: [-10, -31],
                });
                //   存起来两个标点对象
                arr = [...arr, marker1];
              });
              // 标点对象为两个的时候 展示 line  和 Text
              if (arr.length == 2) {
                that.lineAndTextFun(that, arr);
              }
              // 存储标记点
              that.setState({
                currentClickMarkerList: arr,
              });
              // map
              that.map.add(arr);
            }
          );
        }
      }
    eventBus.$on((flag) => {
      this.setState(
        {
          isCanClickMarkerLineFlag: flag,
        },
        () => {
          if (!flag) {
            //   清楚line  和 text
            this.map.remove([
              ...this.state.textAndlineObj,
              ...this.state.currentClickMarkerList,
            ]);
            this.setState({
              currentClickMarkerList: [],
              currentClickOptionsList: [],
              textAndlineObj: [],
            });
            this.map.off('click', clickHandler);
            return false;
          }
          // 测量距离方法
          flag && this.map.on('click', clickHandler);
        }
      );
    }, 'changclickFlag');
    AMapLoader.reset(); //需要把这个reset一下
    AMapLoader.load({
      key: 'xxxxxxxxxxxxxx', // 申请好的Web端开发者Key,首次调用 load 时必填
      version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
      plugins: [''], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
    })
      .then((AMap) => {
        console.log(AMap, 'AMap');
        this.AMap = AMap;
        this.renderMapFun();
      })
      .catch((e) => {
        console.log(e);
      });
  }
  renderMapFun() {
    // 生成容器
    this.map = new this.AMap.Map('container111', {
      zoom: this.state.zoom, //初始化地图级别
      center: [121.487899486, 31.24916171], //初始化地图中心点位置-上海
    });
    const obj = {
      1: green,
      2: red,
      3: gray,
    };
    // 生成 默认点
    let arr = [];
    this.state.datalist.map((i) => {
      var marker1 = new AMap.Marker({
        icon: obj[i.icon],
        position: i.position,
        title: i.title,
        zoom: i.zoom,
      });
      marker1.setLabel({
        content: i.content,
        offset: new AMap.Pixel(-20, 28),
      });
      arr = [...arr, marker1];
    });
    this.map.add(arr);
  }
  //   划线 和 展示 text
  lineAndTextFun = (that, arr) => {
    var line = new AMap.Polyline({
      strokeColor: '#80d8ff',
      isOutline: true,
      outlineColor: 'white',
    });
    that.map.add(line);
    var text = new AMap.Text({
      text: '',
      style: {
        'background-color': '#29b6f6',
        'border-color': '#e1f5fe',
        'font-size': '12px',
      },
    });
    function computeDis() {
      var p1 = arr[0].getPosition();
      var p2 = arr[1].getPosition();
      var textPos = p1.divideBy(2).add(p2.divideBy(2));
      var distance = Math.round(p1.distance(p2));
      var path = [p1, p2];
      line.setPath(path);
      text.setText('两点相距' + distance + '米');
      text.setPosition(textPos);
    }
    computeDis();
    arr[0].on('dragging', computeDis);
    arr[1].on('dragging', computeDis);
    that.map.add(text);
    that.setState({
      textAndlineObj: [text, line],
    });
  };
  addFun = () => {
    const { zoom } = this.state;
    if (zoom !== 18) {
      this.setState(
        {
          zoom: zoom + 1,
        },
        () => {
          // 设置地图显示的缩放级别,在PC上,参数zoom可设范围:[3,18];
          // 在移动端:参数zoom可设范围:[3,19]。3D地图下,可将zoom设置为浮点数。/
          this.map.setZoom(this.state.zoom);
        }
      );
    }
  };
  downFun = () => {
    const { zoom } = this.state;
    if (zoom !== 3) {
      this.setState(
        {
          zoom: zoom - 1,
        },
        () => {
          this.map.setZoom(this.state.zoom);
        }
      );
    }
  };
  render() {
    // 1.初始化创建地图容器,div标签作为地图容器,同时为该div指定id属性;
    return (
      <div style={{ width: '100%', height: '100%' }}>
        <div id="container111" className="map">
          <div className="leftBox">
            <div className="top">
              <Icon type="add" onClick={this.addFun} />
              {this.state.zoom} <Icon type="minus" onClick={this.downFun} />
            </div>
            <div className="bottom">
              <div className="box">
                <img src={gray} alt="" />
                xxxx
              </div>
              <div className="box">
                <img src={red} alt="" />
                xxxx
              </div>
              <div className="box">
                <img src={green} alt="" />
                xxxx
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}
//导出地图组建类
export default MapComponent;

总结一下吧:
1、点击开启测距
2、点出两个距离点的时候展示测出的距离描述(Line、Text)
3、再点击其他区域,会再次生成一个新的
4、可以实现拖拽效果,重新测出距离
5、再次点击开始测距,关闭,同时清除map上的距离点、line、text。

看的有点蒙的话 可以先看看前两篇:
一、前端高德地图注册、项目中引入、渲染标记(Marker)and覆盖物(Circle)
二、前端高德地图、渲染标记(Marker)引入自定义icon,手动设置zoom

另外献上官方连接:
1、https://lbs.amap.com/demo/javascript-api/example/map-componets/map-overlays
2、https://lbs.amap.com/demo/javascript-api/example/event/map-click-event
3、https://lbs.amap.com/demo/javascript-api/example/event/event-map-drag

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

六卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值