• leaflet实现自定义线、矩形和扇形的绘制


    leaflet实现地图上的自定义绘制,主要是通过监听map的click、mousemove、dblclick事件来获得对应的点位,然后根据获得的点位进行实时的绘制来达到相应的效果。

    矩形绘制的实现

    监听map的click事件,获得第一个点,然后开启map的mousemove事件监听,实时重绘矩形,然后再地图第二次点击时,获得第二个点,构成最终绘制的矩形,同时去掉对map的click事件和mousemove事件的监听。

      createRectangle() {
        let tmplist = []
        let juxing;
        map.on("click", (e) => {
            tmplist.push([e.latlng.lat, e.latlng.lng])
            this.map.on('mousemove', (ev) => {
                if (tmplist.length > 1) {
                    tmplist.splice(1)
                }
                tmplist.push([ev.latlng.lat, ev.latlng.lng])
                this.tmpgroup.clearLayers()
                juxing = L.rectangle(tmplist, {//绘制矩形
                    color: "#ff7800",
                    weight: 1
                }).addTo(this.tmpgroup);
            })
            if (tmplist.length > 1) {
                tmplist.pop()//第二次点击会触发第一次的push()导致得到三个数据(后两个一样),所以删除最后一个
                this.map.off('mousemove')//两点确定,移除鼠标移动事件
                this.map.off('click')//两点确定,移除点击事件,
                this.tmpgroup.clearLayers()
                L.rectangle(tmplist, {//绘制矩形
                    color: "#ff7800",
                    weight: 1
                }).addTo(this.rectgroup);
            }
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    扇形的绘制

    监听map的click事件,获得第一个点,然后开启map的mousemove事件监听,当点少于1个的时候,绘制成线,做扇形的一条边,然后再地图第二次点击时,获得第二个点,构成扇形的第二个点,同时在移动时有第3个点,则可构成扇形,进行实时重绘,在地图地3次点击时,绘制成最终的扇形。
    扇形需要计算第1个点和第2个点之间的距离作为扇形的半径,计算第1个点和第2个点、第1个点和第3个点的夹角,可以使用地理空间分析库turf来完成计算,

    扇形的图形绘制有两种方式实现:
    • 第一种方法:采用Leaflet-semicircle来直接绘制,这种是采用svg进行的绘制,存在一个问题就是无法获取到会指出来的扇形的点位;
    • 第二种方法,采用计算公式来计算出整个扇形的点位,然后以面的方式在地图上绘制出来。
    _circle(latlng, options) {
        let svg = L.svg();
         return L.semiCircle(latlng, L.extend({
             radius: 50000,
             color: '#f03',
             opacity: 1,
             renderer: svg,
             weight: 1
         }, options));
     },
     _dis(fromPoint, toPoint) {
         let from = turf.point(fromPoint); //[-75.343, 39.984]
         let to = turf.point(toPoint);
         let options = { units: 'kilometers' };
         let distance = turf.rhumbDistance(from, to, options);
         return distance;
     },
     _ber(fromPoint, toPoint) {
         let point1 = turf.point(fromPoint);
         let point2 = turf.point(toPoint);
         let bearing = turf.rhumbBearing(point1, point2);
         return bearing;
     },
     _drawSemiCircle(pointList, layerGroup) {
         let tmp = JSON.parse(JSON.stringify(pointList))
         console.log(JSON.stringify(pointList));
         let p1 = tmp[0].reverse();
         let p2 = tmp[1].reverse();
         let radius = this._dis(p1, p2);
    
         //计算第1个点和第2点前鼠标点之间的弧度
         let ber1 = this._ber(p1, p2);
         //计算第1个点和第3点前鼠标点之间的弧度
         let p3 = tmp[2].reverse();
         let ber2 = this._ber(p1, p3);
    
         console.log('radius-->' + radius + ',ber1--->' + ber1 + ',ber2--->' + ber2);
         if (!!radius && !!ber1 && !!ber2) {
             /*
             方式一:采用SemiCircle类库,但是无法获取到点串
             let scircle = this._circle(p1.reverse(), {
                 radius: radius * 1000,
                 color: '#2260b4',
                 startAngle: ber1,
                 stopAngle: ber2,
                 weight: 4
             });
             scircle.addTo(layerGroup);*/
             //方式二,通过计算出扇形的点位,以面的方式在地图上叠加
             let points = this._getSemiCirclePoints(p1.reverse(), radius / 100, ber1, ber2, 500);
             points[points.length] = points[0];
             let semiCirclePolygon = L.polygon(points);
             semiCirclePolygon.addTo(layerGroup)
         }
     },
     /**
      *
      * @param center 中心点 数组 [lat, lon]
      * @param radius 半径
      * @param startAngle 起始角度
      * @param endAngle 终止角度
      * @param pointNum 圆弧上点的个数
      */
     _getSemiCirclePoints(center, radius, startAngle, endAngle, pointNum) {
         let sin;
         let cos;
         let x;
         let y;
         let angle;
         let points = [];
         points.push(center);
         for (let i = 0; i <= pointNum; i++) {
             angle = startAngle + (endAngle - startAngle) * i / pointNum;
             sin = Math.sin(angle * Math.PI / 180);
             cos = Math.cos(angle * Math.PI / 180);
             y = center[0] + radius * cos;
             x = center[1] + radius * sin;
             points[i] = [y, x];
         }
         let point = points;
         point.push(center);
         return point;
     },
     createSemiCircle() {
         let pointList = [];
         this.semicirclegroup.clearLayers();
         this.map.on("click", (e) => {
             pointList.push([e.latlng.lat, e.latlng.lng]);
             this.map.on('mousemove', (ev) => {
                 let lastPoint = pointList[pointList.length - 1];
                 if (pointList.length === 1) {
                     let latlngs = [
                         lastPoint,
                         [ev.latlng.lat, ev.latlng.lng]
                     ]
                     this.semicirclegroup.clearLayers();
                     L.polyline(latlngs, {
                         color: "#03f",
                         weight: 3
                     }).addTo(this.semicirclegroup);
                 } else if (pointList.length === 2) {
                     //绘制成一个扇形
                     let arr = JSON.parse(JSON.stringify(pointList));
                     arr.push([ev.latlng.lat, ev.latlng.lng]);
                     this.semicirclegroup.clearLayers();
                     this._drawSemiCircle(arr, this.semicirclegroup);
                 }
             })
             if (pointList.length > 2) {
                 this.map.off('mousemove')//两点确定,移除鼠标移动事件
                 this.map.off('click')//两点确定,移除点击事件,
                 //绘制扇形在地图上
                 this.semicirclegroup.clearLayers();
                 let arr = [
                     pointList[0], pointList[1], pointList[pointList.length - 1]
                 ];
                 this._drawSemiCircle(arr, this.semicirclegroup);
             }
         })
     },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120

    线绘制的实现

    线绘制的实现思路跟上面的类似,只是多一个,这个会做一个临时图层来显示最后一段绘制的效果。

    createPolyline() {
     let pointList = [];
     map.on("click", (e) => {
         pointList.push([e.latlng.lat, e.latlng.lng]);
    
         this.map.on('mousemove', (ev) => {
             //临时图层直线是最后一段线即可
             let lastPoint = pointList[pointList.length - 1]
             let latlngs = [
                 lastPoint,
                 [ev.latlng.lat, ev.latlng.lng]
             ]
             this.tmpgroup.clearLayers();
             L.polyline(latlngs, {
                 color: "#2260b4",
                 weight: 3
             }).addTo(this.tmpgroup);
         })
    
         this.map.on('dblclick', (ev) => {
             this.map.off('mousemove')//两点确定,移除鼠标移动事件
             this.map.off('click')//两点确定,移除点击事件,
             pointList.push([ev.latlng.lat, ev.latlng.lng]);
             this.tmpgroup.clearLayers();
             this.semicirclegroup.clearLayers()
             if (pointList.length > 1) {
                 L.polyline(pointList, {
                     color: "#ff7800",
                     weight: 5
                 }).addTo(this.semicirclegroup);
             }
         })
    
         if (pointList.length > 1) {
             this.semicirclegroup.clearLayers();
             L.polyline(pointList, {
                 color: "#ff7800",
                 weight: 3
             }).addTo(this.semicirclegroup);
         }
     })
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    参考文章:
    leaflet 画扇形

  • 相关阅读:
    # Spring Boot 中如何使用 Spring Cloud Sleuth 来实现分布式跟踪?
    springboot整合log4j
    Android 自定义View之圆形进度条
    如何将数据输入神经网络,神经网络的数据处理
    公共Mono模块
    opencv入门到精通——图片,视频,摄像头的读取与保存
    PyQt5快速开发与实战 6.1 好软件的三个维度 && 6.2 PyQt5中的布局管理 && 6.3 PyQt5的绝对位置布局
    【SpringSecurity】SpringSecurity2.7.x 的使用(05)
    Spring Cloud整合Seata实现TCC分布式事务模式案例
    Java相关编程思想
  • 原文地址:https://blog.csdn.net/lc_2014c/article/details/128069122