【问题标题】:Leaflet Polyline Arrows传单折线箭头
【发布时间】:2021-04-09 05:39:15
【问题描述】:

我目前正在使用传单使用画布在传单地图上绘制一堆线条。但是,我在使用画布的线条上绘制箭头时遇到问题。

我找到了诸如 polyline decorator 之类的项目,但它非常慢,我只希望箭头在指定的缩放距离 (>=13) 处可见。

请问如何使用传单来做到这一点?我不必有可重复的箭头,而只是一种显示折线方向的方法。

谢谢。

【问题讨论】:

    标签: javascript leaflet


    【解决方案1】:

    我知道这个答案有点晚了,但它具有良好的性能且无需任何插件。

    您可以将图标(目前是三角形箭头 (▶))更改为您想要的任何东西,其初始方向应向右(零度角)。

    您还可以更改要显示的箭头数量(在本例中为 5)

    CSS 代码:

     .arrow-icon {
            width: 14px;
            height: 14px;
        }
    
            .arrow-icon > div {
                margin-left: -1px;
                margin-top: -3px;
                transform-origin: center center;
                font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
            }
    

    这里是 Javascript 代码。getArrows 函数接受折线坐标数组(以及可选参数颜色和可选参数每行箭头的数量)并返回一个标记数组(只需复制和粘贴所有内容):

    function getArrows(arrLatlngs, color, arrowCount, mapObj) {
    
        if (typeof arrLatlngs === undefined || arrLatlngs == null ||    
    (!arrLatlngs.length) || arrLatlngs.length < 2)          
        return [];
    
        if (typeof arrowCount === 'undefined' || arrowCount == null)
            arrowCount = 1;
    
        if (typeof color === 'undefined' || color == null)
            color = '';
        else
            color = 'color:' + color;
    
        var result = [];
        for (var i = 1; i < arrLatlngs.length; i++) {
            var icon = L.divIcon({ className: 'arrow-icon', bgPos: [5, 5], html: '<div style="' + color + ';transform: rotate(' + getAngle(arrLatlngs[i - 1], arrLatlngs[i], -1).toString() + 'deg)">▶</div>' });
            for (var c = 1; c <= arrowCount; c++) {
                result.push(L.marker(myMidPoint(arrLatlngs[i], arrLatlngs[i - 1], (c / (arrowCount + 1)), mapObj), { icon: icon }));
            }
        }
        return result;
    }
    
    function getAngle(latLng1, latlng2, coef) {
        var dy = latlng2[0] - latLng1[0];
        var dx = Math.cos(Math.PI / 180 * latLng1[0]) * (latlng2[1] - latLng1[1]);
        var ang = ((Math.atan2(dy, dx) / Math.PI) * 180 * coef);
        return (ang).toFixed(2);
    }
    
    function myMidPoint(latlng1, latlng2, per, mapObj) {
        if (!mapObj)
            throw new Error('map is not defined');
    
        var halfDist, segDist, dist, p1, p2, ratio,
            points = [];
    
        p1 = mapObj.project(new L.latLng(latlng1));
        p2 = mapObj.project(new L.latLng(latlng2));
    
        halfDist = distanceTo(p1, p2) * per;
    
        if (halfDist === 0)
            return mapObj.unproject(p1);
    
        dist = distanceTo(p1, p2);
    
        if (dist > halfDist) {
            ratio = (dist - halfDist) / dist;
            var res = mapObj.unproject(new Point(p2.x - ratio * (p2.x - p1.x), p2.y - ratio * (p2.y - p1.y)));
            return [res.lat, res.lng];
        }
    
    }
    
    function distanceTo(p1, p2) {
        var x = p2.x - p1.x,
            y = p2.y - p1.y;
    
        return Math.sqrt(x * x + y * y);
    }
    
    function toPoint(x, y, round) {
        if (x instanceof Point) {
            return x;
        }
        if (isArray(x)) {
            return new Point(x[0], x[1]);
        }
        if (x === undefined || x === null) {
            return x;
        }
        if (typeof x === 'object' && 'x' in x && 'y' in x) {
            return new Point(x.x, x.y);
        }
        return new Point(x, y, round);
    }
    
    function Point(x, y, round) {
        this.x = (round ? Math.round(x) : x);
        this.y = (round ? Math.round(y) : y);
    }
    

    然后简单地绘制传单折线(只适用于latLng坐标数组而不是坐标数组数组):

    // array of coordinates
    var mylatlngs = [
                [55.555, 33.33],
                [..., ...],
                [..., ...],
                [..., ...],
                [..., ...],
                ...
            ];
    
            var polyline = L.polyline(mylatlngs, { color: 'red' }).addTo(map);
            // draw 5 arrows per line
            L.featureGroup(getArrows(mylatlngs, 'red', 5,map)).addTo(map);
    

    【讨论】:

    • 我喜欢这个主意。投赞成票。我认为性能将与 PolylineDecorator 相同或更差,并且“没有任何插件”与复制粘贴大约 100 行相比并不是真正的优势,但这里有一些有用的代码,谢谢!
    【解决方案2】:

    PolylineDecorator主页 存在指向Leaflet.TextPath 的链接,作为轻量级替代方案。我认为它与早期提出的“getArrows”函数实现类似。

    【讨论】: