使用react-bmapgl绘制区域并判断是否重叠

需求如下:

  • 在react项目中使用百度地图实现区域(电子围栏)的绘制
  • 绘制的区域类型为:1、多边形 2、圆形
  • 可绘制多个区域
  • 区域不能有重叠
  • 可重新编辑区域

代码如下:

index.tsx

import { useCallback, useEffect, useState } from 'react';
import { Space, Button, Radio, message } from 'antd';
import { Map, DrawingManager, MapApiLoaderHOC } from 'react-bmapgl';
import validator, { Type } from './utils';

interface OptionType {
  value: 'polygon' | 'circle';
  label: '多边形' | '圆形'
}

const TYPE: OptionType[] = [
  { value: 'polygon', label: '多边形' },
  { value: 'circle', label: '圆形' },
];


const IndexPage = () => {
  const [list, setList] = useState<Type[]>([]);
  // 当前绘制区域
  const [current, setCurrent] = useState<any>();
  // 当前绘制区域类型,默认绘制多边形
  const [type, setType] = useState(TYPE[0].value)
  // 是否开启绘制
  const [isOpen, setIsOpen] = useState(true);
  // 是否禁用继续绘制按钮
  const [disabled, setDisabled] = useState(true);
  // 是否处于编辑状态
  const [isEdit, setIsEdit] = useState(false);

  // 重新绘制
  const restart = () => {
    setIsOpen(true);
    setList(list.slice(0, -1));
    current.remove();
  };

  // 继续绘制
  const next = () => {
    setIsOpen(true);
  };

  // 编辑区域
  const edit = () => {
    if (isEdit) {
      current.disableEditing();
      handleValidator(current, type, list.slice(0, -1));
    } else {
      current.enableEditing();
    }
    setIsEdit(!isEdit);
  };

  // 区域重叠判断
  const handleValidator = (overlay: any, drawingMode: any, list: any[]) => {
    const flag = validator({ overlay, drawingMode }, list);
    if (flag) {
      setDisabled(false);
    } else {
      message.warning('区域重叠,请重新绘制');
      setDisabled(true);
    }
  };

  const NewDrawingManager = useCallback((props) => <DrawingManager {...props} />, [isOpen, type]);

  return (
    <div className="index-page" style={{ display: 'flex', flexDirection: 'column' }}>
      <Space>
        <Button size="small" type="primary" onClick={restart} disabled={isOpen}>重新绘制</Button>
        <Button size="small" type="primary" onClick={next} disabled={disabled}>继续绘制</Button>
        <Button size="small" type="primary" onClick={edit} disabled={isOpen}>{isEdit ? '保存编辑' : '编辑区域'}</Button>
      </Space>
      <Radio.Group value={type} onChange={e => setType(e.target.value)}>
        {
          TYPE.map(item => <Radio key={item.value} value={item.value}>{item.label}</Radio>)
        }
      </Radio.Group>
      <div style={{ flex: 1, position: 'relative' }}>
        <Map
          center={new BMapGL.Point(116.404449, 39.914889)}
          zoom={16}
          enableScrollWheelZoom
          style={{ height: '90vh' }}
        >
          <NewDrawingManager
            isOpen={isOpen}
            enableDrawingTool={false}
            drawingMode={type}
            onOverlaycomplete={(e: any, { drawingMode, overlay }: any) => {
              setList([...list, { drawingMode, overlay }]);
              setCurrent(overlay);
              setIsOpen(false);
              handleValidator(overlay, drawingMode, list);
            }}
            onOverlaycancel={(a: any, { overlay }: any) => {
              setIsOpen(false);
              // setCurrent(overlay);
              setTimeout(() => setIsOpen(true), 200)
            }}
          />
        </Map>
      </div>
    </div>
  );
}

export default MapApiLoaderHOC({ak: 'xxx'})(IndexPage);

引入GeoUtils.js

umirc.ts

import { defineConfig } from 'umi';

export default defineConfig({
  headScripts: ['http://127.0.0.1:5500/GeoUtils.js'],
});

打包后会在head标签里加入额外的脚本以便页面加载时在window上挂载BMapGLLib.GeoUtils实例:

<script src="http://127.0.0.1:5500/GeoUtils.js"></script>

utils.ts 区域重叠判断

包含三种:

1. 多边形与多边形是否重叠
2. 多边形与圆形是否重叠
3. 圆形与圆形是否重叠
export interface Type {
    overlay: any;
    drawingMode: 'circle' | 'polygon';
}

export const BMAP_DRAWING_CIRCLE = "circle",     // 鼠标画圆模式
    BMAP_DRAWING_POLYGON = "polygon";    // 鼠标画多边形模式

// 多边形与多边形是否重叠
export const fn1 = (polygon1: Type['overlay'], polygon2: Type['overlay']) => {
    const points1 = polygon1.getPath();
    const points2 = polygon2.getPath();
    return points1.some((item: any) => {
        const point = new BMapGL.Point(item.lng, item.lat);
        // @ts-ignore
        return BMapGLLib.GeoUtils.isPointInPolygon(point, polygon2);
    }) || points2.some((item: any) => {
        const point = new BMapGL.Point(item.lng, item.lat);
        // @ts-ignore
        return BMapGLLib.GeoUtils.isPointInPolygon(point, polygon1);
    });
}

// 多边形与圆形是否重叠
export const fn2 = (polygon: Type['overlay'], circle: Type['overlay']) => {
    const points1 = polygon.getPath();
    const points2 = circle.getPath();
    return points1.some((item : any) => {
        const point = new BMapGL.Point(item.lng, item.lat);
        // @ts-ignore
        return BMapGLLib.GeoUtils.isPointInCircle(point, circle)
    }) || points2.some((item : any) => {
        const point = new BMapGL.Point(item.lng, item.lat);
        // @ts-ignore
        return BMapGLLib.GeoUtils.isPointInPolygon(point, polygon);
    });
}

// 圆形与圆形是否重叠   
export const fn3 = (circle1: Type['overlay'], circle2: Type['overlay']) => {
    const points1 = circle1.getPath();
    const points2 = circle2.getPath();
    console.log(points1, points2);
    return points1.some((item : any) => {
        const point = new BMapGL.Point(item.lng, item.lat);
        // @ts-ignore
        return BMapGLLib.GeoUtils.isPointInCircle(point, circle2)
    }) || points2.some((item : any) => {
        const point = new BMapGL.Point(item.lng, item.lat);
        // @ts-ignore
        return BMapGLLib.GeoUtils.isPointInCircle(point, circle1)
    });
}

// 区域重叠校验是否通过 true-通过 false-不通过
export default ({ overlay, drawingMode }: Type, overlays: Type[]) => {
    try {
        let flag = false; // true-重叠 false-不重叠
        overlays.forEach(item => {
            if (!flag && drawingMode === BMAP_DRAWING_POLYGON && item.drawingMode === BMAP_DRAWING_POLYGON) {
                flag = fn1(overlay, item.overlay);
            }
            if (!flag && drawingMode === BMAP_DRAWING_POLYGON && item.drawingMode === BMAP_DRAWING_CIRCLE) {
                flag = fn2(overlay, item.overlay);
            }
            if (!flag && drawingMode === BMAP_DRAWING_CIRCLE && item.drawingMode === BMAP_DRAWING_POLYGON) {
                flag = fn2(item.overlay, overlay);
            }
            if (drawingMode === BMAP_DRAWING_CIRCLE && item.drawingMode === BMAP_DRAWING_CIRCLE) {
                flag = fn3(overlay, item.overlay);
            }
        });
        return !flag;
    } catch (error) {
        console.log(error);
    }
};

效果图:

在这里插入图片描述
在这里插入图片描述

相关链接:

  1. react-bmapgl文档:https://lbsyun.baidu.com/solutions/reactBmapDoc
  2. DrawingManager.js:https://github.com/huiyan-fe/BMapGLLib/blob/master/DrawingManager/src/DrawingManager.js
  3. DrawingManager.tsx:https://github.com/huiyan-fe/react-bmapgl/blob/master/src/Library/DrawingManager.tsx
  4. GeoUtils.js:https://github.com/huiyan-fe/BMapGLLib/blob/master/GeoUtils/src/GeoUtils.js
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值