0

Issue: Putting the markes by click on a map and drag them along a polyline, like a ribbon is not working.

I have a project similar to this: Leaflet - How to match marker and polyline on drag and drop which is wroking fine and a big THANK YOU ! to iH8 :-). I try to put to the next level and be the part of a bigger, Open Source Lawn-mower-robot navigation project: https://github.com/steger123/Lawn-mower-robot https://github.com/steger123/Lawn-mower-robot/tree/master/codes/JavaScript/PolyLine

Unfortuanlty somehow the new (green) lines are not pulled with the markers (like a ribbon). So, how the program is working:

  1. Genarate some HTML with button "Routing". - Working.
  2. Generate the map with initial line (red) and markers using this codes: - Working. Leaflet - How to match marker and polyline on drag and drop
  3. Click on the "Routing" button to be able to make the markers on the map by clicking on the map. - Working.
  4. Make blue lines to connect the markers. - Working.
  5. Click on "Rouring" button again to finsih the route - Working.
  6. Convert the lines to one green polyline (This line must be dragged later along with the new markers.) - Working.
  7. So when I drag the marker, only the marker is moving, the line not, however I assigned the three andlers.

To find easier the issue, SEARCH for the "*" in script.js:

index.html:

<!DOCTYPE html>
<html>

<head>

    <link rel="stylesheet" href="style.css" />

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
        integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
        crossorigin="" />

    <!-- Make sure you put this AFTER Leaflet's CSS -->
    <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
        integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
        crossorigin=""></script>

    <style>
        #fieldMap {
            height: 600px;
        }
    </style>
    <title> DRAG Polyline</title>

</head>

<body>

    <table style="width:100%">
        <tr>
            <td>Latitude: <span id="lat"></span></td>
            <td>Longitude: <span id="lon"></span></td>
        </tr>
        <tr>
            <td> <span id="client"></span></td>
            <td><span id="screen"></span></td>
        </tr>
        <tr>
            <td> <button id="myRouting" onclick="btnRouting()">Routing</button></td>
            <td><button id="myRoutSave" onclick="myRoutSave()">Save Route</button></td>
        </tr>
        <tr>
            <td> <button id="myRoutLoad" onclick="myRoutLoad()">Load Route</button></td>
            <td><button id="myRoutSend" onclick="myRoutSend()">Send Route</button></td>
        </tr>
    </table>

    <div id="fieldMap"></div>

    <script type="text/javascript" src="script.js"></script>
</body>

</html>

The script.js:

const map = L.map('fieldMap').setView([28.4588446, 77.2867589], 17);   //The initial point
var layer = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
map.addLayer(layer); // Adding layer to the map

var marker_arr = [];
var marker_pos = [];
var marker_new = [];
///////////////////
// ADD markers :
//var a = new L.LatLng(28.4588446, 77.2867589),
//    b = new L.LatLng(28.4578446, 77.2867589),
//    c = new L.LatLng(28.45788446, 77.2877589);

marker_pos[0] = new L.LatLng(28.4588446, 77.2867589);
marker_pos[1] = new L.LatLng(28.4578446, 77.2867589);
marker_pos[2] = new L.LatLng(28.45788446, 77.2877589);


var locationIcon = L.icon({
    iconUrl: 'location.png',
    iconSize: [32, 32],
    iconAnchor: [16, 16]
    //  popupAnchor: [-3, -76],
    //  shadowUrl: 'my-icon-shadow.png',
    //  shadowSize: [68, 95],
    //  shadowAnchor: [22, 94]
});
var tractorIcon = L.icon({
    iconUrl: 'tractor.png',
    iconSize: [32, 50],
    iconAnchor: [16, 25]
    //  popupAnchor: [-3, -76],
    //  shadowUrl: 'my-icon-shadow.png',
    //  shadowSize: [68, 95],
    //  shadowAnchor: [22, 94]
});

//var marker_a = new L.Marker(a, { icon: tractorIcon, draggable: true }).addTo(map);
//marker_b = new L.Marker(b, { icon: locationIcon, draggable: true }).addTo(map);
//marker_c = new L.Marker(c, { icon: locationIcon, draggable: true }).addTo(map);
marker_arr[0] = new L.Marker(marker_pos[0], { icon: tractorIcon, draggable: true }).addTo(map);
marker_arr[1] = new L.Marker(marker_pos[1], { icon: locationIcon, draggable: true }).addTo(map);
marker_arr[2] = new L.Marker(marker_pos[2], { icon: locationIcon, draggable: true }).addTo(map);

var polyline_demo = new L.Polyline([marker_pos[0], marker_pos[1], marker_pos[2]]).addTo(map);  // make the polyline as well

var myGroup = L.layerGroup([marker_arr[0], marker_arr[1], marker_arr[2]]);
myGroup.eachLayer(function (layer) {
    layer.setOpacity(0.5);
});

//L.marker([50.505, 30.57], { icon: myIcon }).addTo(map);
//marker = L.marker([28.4598446,77.2867589], { icon: tractorIcon, draggable: true }).addTo(map).on('click', onTractor);


// Now on dragstart you'll need to find the latlng from the polyline which corresponds
// with your marker's latlng and store it's key in your marker instance so you can use it later on:
function dragStartHandler(e) {
   var latlngPoly = polyline_demo.getLatLngs(),     // Get the polyline's latlngs
    //var latlngPoly = polyline3.getLatLngs() // *** NOT WORKING !
        latlngMarker = this.getLatLng();        // Get the actual, cliked MARKER's start latlng
    console.log("start");
    for (var i = 0; i < latlngPoly.length; i++) {       // Iterate the polyline's latlngs
        if (latlngMarker.equals(latlngPoly[i])) {       // Compare marker's latlng ot the each polylines 
            this.polylineLatlng = i;            // If equals store key in marker instance
        }
    }
}

// Now you know the key of the polyline's latlng you can change it
// when dragging the marker on the dragevent:
function dragHandler(e) {
    var latlngPoly = polyline_demo.getLatLngs(),    // Get the polyline's latlngs
    //var latlngPoly = polyline3.getLatLngs() // *** NOT WORKING !    
        latlngMarker = this.getLatLng();            // Get the marker's current latlng
    console.log("drag");
    latlngPoly.splice(this.polylineLatlng, 1, latlngMarker);        // Replace the old latlng with the new
    polyline_demo.setLatLngs(latlngPoly);           // Update the polyline with the new latlngs
    //polyline3.setLatLngs(latlngPoly);     // *** NOT WORKING !
}

// Just to be clean and tidy remove the stored key on dragend:
function dragEndHandler(e) {
    delete this.polylineLatlng;
    console.log("end");
}

//You'll need to attach eventlisteners and callbacks to your L.Marker's.
// You could automate this, but i'll keep it simple for now:
// https://stackoverflow.com/questions/33513404/leaflet-how-to-match-marker-and-polyline-on-drag-and-drop

marker_arr[0]
    .on('dragstart', dragStartHandler)
    .on('drag', dragHandler)
    .on('dragend', dragEndHandler);

marker_arr[1]
    .on('dragstart', dragStartHandler)
    .on('drag', dragHandler)
    .on('dragend', dragEndHandler);

marker_arr[2]
    .on('dragstart', dragStartHandler)
    .on('drag', dragHandler)
    .on('dragend', dragEndHandler);

///////////////////////////////////////////////////////////////////////////////
var doRouting = false;
var startPoint = [28.4588446, 77.2867589];
var arr = [];  //Arreay for routing lines
var lineCount = 0;
// make a new 2D polyline array
var newPoly = new Array(20);
// Loop to create 2D array using 1D array 
for (var i = 0; i < newPoly.length; i++) {
    newPoly[i] = new Array(2);
}


function btnRouting() {
    var property = document.getElementById("myRouting");
    if (doRouting) {
        doRouting = false;
        property.style.backgroundColor = "#ecebeb"
        console.log('Line count: ');
        console.log(lineCount);
        //make one polyline from clickings, which shall me draggable later
        //var polyline2 = new L.Polyline(pp, { color: 'red' }).addTo(map);

        var newPoly2 = new Array(lineCount + 1);  // this is required, becuse newPoly have empty values, which is not accepted by L.Polyline
        // Loop to create 2D array using 1D array 
        for (var i = 0; i < newPoly2.length; i++) {
            newPoly2[i] = new Array(2);
            newPoly2[i][0] = newPoly[i][0];
            newPoly2[i][1] = newPoly[i][1];

        }
        console.log(newPoly);
        console.log(newPoly2);
        console.log('orange');

        //make one polyline from clickings, which shall be draggable later:
        // ****** THIS IS NOT MOVING IF I CHANGE it in the HANDLERS *******//

        var polyline3 = new L.Polyline(newPoly2, { color: '#00AA00', weight: 10, opacity: 0.4 }).addTo(map);

        //*****************************************************************//
  

    } else {   //End the routing
        doRouting = true;
        property.style.backgroundColor = "#7FFF00"

    }
}

map.on("click", function (e) {  //Listener: Click on MAP -> Addign the WAYPOINTS
    if (doRouting) {
        var newLine = [
            startPoint,
            [e.latlng.lat, e.latlng.lng]  //mouse click position in lat & long
        ];
        //arr[lineCount][0] = startPoint[0];
        //arr[lineCount][1] = startPoint[1];
        //arr[lineCount][2] = e.latlng.lat;
        //arr[lineCount][3] = e.latlng.lng;
        newPoly[lineCount][0] = startPoint[0];
        newPoly[lineCount][1] = startPoint[1];
        newPoly[lineCount + 1][0] = e.latlng.lat;
        newPoly[lineCount + 1][1] = e.latlng.lng;

        lineCount++;
        // initial line & marker:
        new L.polyline(newLine, { color: 'blue', noClip: true }).addTo(map);
        //L.circleMarker([e.latlng.lat, e.latlng.lng]).addTo(map);  //move the Waypoint
        marker_new[lineCount] = new L.marker([e.latlng.lat, e.latlng.lng], { icon: locationIcon, draggable: true, opacity: 0.4 }).addTo(map).on('dragstart', dragStartHandler).on('drag', dragHandler).on('dragend', dragEndHandler);


        startPoint = [e.latlng.lat, e.latlng.lng];
        console.log(arr);
    }
    else {

        // console.log(L.circleMarker.getLatLng()[0]);   //detect which waypoint is selected
    }
})

1 Answers1

0

I updated your code: https://jsfiddle.net/falkedesign/h5cyk1up/

What have I changed:

  1. I added to the markers a parentLine marker_arr[0].parentLine = polyline_demo; and marker_new[lineCount].parentLine = tempLine;
  2. Read out the parentLine in the handlers:
var polyline = e.target.parentLine;
    if(polyline){
     var latlngPoly = polyline.getLatLngs(),
  1. In the click handler (add Markers):

Add latlng to the tempLine or create a new one

if(!tempLine){
          tempLine = L.polyline([], { color: 'blue', noClip: true }).addTo(map);
        }
        tempLine.addLatLng(e.latlng);
  1. After finishing routing, change the style of the polyline and set tempLine to null to generate a new route:
var polyline = tempLine.setStyle({ color: '#00AA00', weight: 10, opacity: 0.4 });
tempLine = null;
Falke Design
  • 10,635
  • 3
  • 15
  • 30