admin管理员组

文章数量:1206951

I'm currently using leaflet to draw a bunch of lines on a leaflet map using the canvas. However, I'm having issue draw arrows on the lines using canvas.

I have found items such as polyline decorator but it very very slow and I only want the arrows to be visible at specified zoom distance (>=13).

How would one do this using leaflet please? I don't have to have repeatable arrows but just a way to show poyline direction.

Thanks.

I'm currently using leaflet to draw a bunch of lines on a leaflet map using the canvas. However, I'm having issue draw arrows on the lines using canvas.

I have found items such as polyline decorator but it very very slow and I only want the arrows to be visible at specified zoom distance (>=13).

How would one do this using leaflet please? I don't have to have repeatable arrows but just a way to show poyline direction.

Thanks.

Share Improve this question asked Nov 14, 2018 at 19:16 LiamLiam 4931 gold badge5 silver badges32 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 16

I know this answer is a little too late but It works with a good performance and without any plugin.

You can change the icon(which currently is a triangle arrow(▶)) to any thing you want and its initial direction should be toward right(the zero degree angle).

You can also change the number of arrows to be shown(in this example it's 5)

CSS code :

 .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;
        }

And here is the Javascript code.The getArrows function accepts array of coordinates of polyline(and optional parameter color and optional parameter number of arrows per line) and returns an array of markers(just copy and paste everything) :

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);
}

Then simply draw leaflet polyline(just works for array of latLng coordinates not array of array of coordinates):

// 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);

In PolylineDecorator main page exists link to Leaflet.TextPath, as a lightweight alternative. I assume it is similar with "getArrows" function implementation, that have been proposed early.

nAviD's answer (13) works for me, but the "▶" should be replaced with the decoded character [1]: https://i.sstatic.net/YjnbWU6x.png

本文标签: javascriptLeaflet Polyline ArrowsStack Overflow