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

简介: 文章介绍了如何在前端使用高德地图API实现测量两个点之间的距离,包括开启和关闭测量工具的方法,以及如何清除地图上的测量点、连线和文字。

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

在这里插入图片描述

在这里插入图片描述

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

首先

上面的功能条河下面的地图我搞成了两个组件,他们作为兄弟组件存在,所以简单用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

目录
相关文章
|
3月前
|
前端开发 JavaScript 定位技术
一、前端高德地图注册、项目中引入、渲染标记(Marker)and覆盖物(Circle)
文章介绍了如何在前端项目中注册并使用高德地图API,包括注册高德开放平台账号、引入高德地图到项目、以及如何在地图上渲染标记(Marker)和覆盖物(Circle)。
102 1
|
3月前
|
前端开发 定位技术 API
二、前端高德地图、渲染标记(Marker)引入自定义icon,手动设置zoom
文章介绍了如何在前端使用高德地图API渲染标记(Marker),并引入自定义图标,同时展示了如何手动设置地图的缩放级别。
340 1
|
Web App开发 存储 监控
前端性能精进之优化方法论(一)——测量 (下)
前端性能精进之优化方法论(一)——测量 (下)
|
SQL Web App开发 缓存
前端性能精进之优化方法论(一)——测量 (上)
前端性能精进之优化方法论(一)——测量
|
前端开发 定位技术 API
前端通过高德地图实现 定位,拖拽选址,搜索选址,搜索记录,城市切换【推荐】
前端通过高德地图实现 定位,拖拽选址,搜索选址,搜索记录,城市切换【推荐】
343 0
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
177 2
|
2月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
48 0
|
2月前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
2月前
|
机器学习/深度学习 弹性计算 自然语言处理
前端大模型应用笔记(二):最新llama3.2小参数版本1B的古董机测试 - 支持128K上下文,表现优异,和移动端更配
llama3.1支持128K上下文,6万字+输入,适用于多种场景。模型能力超出预期,但处理中文时需加中英翻译。测试显示,其英文支持较好,中文则需改进。llama3.2 1B参数量小,适合移动端和资源受限环境,可在阿里云2vCPU和4G ECS上运行。
124 1