Leaflet折线箭头

8
我目前正在使用leaflet和canvas在leaflet地图上绘制一系列线条。然而,我无法使用canvas在这些线条上绘制箭头。我找到了像polyline decorator这样的项目,但它非常慢,而且我只想在指定的缩放距离(>=13)下显示箭头。请问该如何使用leaflet实现这一点呢?我不需要重复的箭头,只需要一种显示线条方向的方法。谢谢。
2个回答

11

我知道这个答案有点晚,但它可以有很好的性能,并且不需要任何插件。

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

您还可以更改要显示的箭头数量(在此示例中为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);
}

然后只需绘制leaflet折线(仅适用于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行代码更具优势,但这里确实有一些有用的代码,谢谢! - Codebling

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接