0

I'm interested by the script Leaflet motion.

I tried to update the code to add a custom GeoJSON created from QGIS or any tool.

But the current error is :

leaflet.motion.min.js:9 Uncaught TypeError: Cannot read properties of null (reading 'traveledPath')
    at i._motion (leaflet.motion.min.js:9:2842)
    at i.motionStart (leaflet.motion.min.js:9:3960)
    at i.motionStart (leaflet.motion.min.js:9:12135)
    at test14.html:110:26



<!DOCTYPE html>
<html>
    <head>
        <title>Leaflet motion plugin</title>
        <meta charset="utf-8" />

        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
        <link rel="stylesheet" href="https://leaflet.github.io/Leaflet.draw/src/leaflet.draw.css"/>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/>

        <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.js"></script>
        <script src="https://mappingforyou.eu/javascript/leaflet.ajax.min.js"></script>
        
        <script src="../javascript/leaflet.motion.min.js"></script>
        <style>
            html, body, #map { width: 100%; height: 100%; margin: 0px; padding: 0px;}
            .leaflet-div-icon {
                background: transparent!important;
                border: none!important;
                color: white;
            }

            .red {
                color: red!important;
            }
        </style>
     </head>

    <body>

        <div id="map"></div>
        <script>
            var map = L.map("map").setView([51, 1], 5);

            L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
                attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
            }).addTo(map);

            var options = {
                draw: {
                    circle: false, // Turns off this drawing tool
                    rectangle: false,
                    marker: false,
                    circlemarker: false
                }
            };
            
            
    
            var drawControl = new L.Control.Draw(options);
            map.addControl(drawControl);

            map.on(L.Draw.Event.CREATED, function (e) {
                var type = e.layerType,
                    layer = e.layer;

                if (type === "polyline") {
                    var line = L.motion.polyline(layer.getLatLngs(), {
                        color: "orange"
                    }, {
                        auto: true,
                        easing: L.Motion.Ease.swing
                    }).motionSpeed(100000).addTo(map);
                }

                if (type === "polygon") {
                    L.motion.polygon(layer.getLatLngs(), {
                        color: "red",
                        fill: true,
                        fillOpacity: 0.4
                    },{
                        auto: true
                    }, {
                        removeOnEnd: true,
                        icon: L.divIcon({className:"red", html: "<i class='fa fa-superpowers fa-spin fa-2x' aria-hidden='true' motion-base='0'></i>", iconSize: L.point(24, 24), iconAnchor: L.point(5, 22)})
                    }).motionDuration(10000).addTo(map);
                }
            });
                    
            
    var geoJsonData ={"type":"FeatureCollection","features":[{"properties":{"name":""},"type":"Feature","geometry":{"type":"LineString","coordinates":[[-7.271833,51.09715],[0.15577,50.667658],[8.638181,48.79433],[12.703585,45.710102],[9.297436,43.090615],[0.749099,41.036735],[-4.393088,41.548214]]}}]};
    
            
            
    

            var seqGroup = L.motion.seq([
                    L.motion.polyline(geoJsonData, {
                    color: "orangered"
                    }, {
                        easing: L.Motion.Ease.easeInOutQuad
                    }, {
                        removeOnEnd: false,
                        icon: L.divIcon({html: "<i class='fa fa-truck fa-2x fa-flip-horizontal' aria-hidden='true'></i>", iconSize: L.point(27.5, 24)})
                    }).motionDuration(8000)
                ]).addTo(map);


            seqGroup.on("click", function(){
                seqGroup.motionStart();
            });

            seqGroup.on("dblclick", function(e){
                seqGroup.motionToggle();
            });

            setTimeout(function () {
                seqGroup.motionStart();
            }, 1000);

        </script>
    </body>

</html>

I'm looking for a way to create a simple line like the one of this json.parse.

Can you help?

Alternatively, I'd like to feed Leaflet Motion with an external geojson file, that would gave the same result.

6
  • If I understand you correctly, you have GeoJSON array of point geometries?
    – TomazicM
    Commented Jun 7, 2022 at 16:49
  • It was first a line when I drawed it on Qgis. Then I may have turned it into point geometries to try if it felt better like this.
    – Vincent Dc
    Commented Jun 7, 2022 at 16:52
  • @TomazicM I updated the code. this is a line
    – Vincent Dc
    Commented Jun 7, 2022 at 17:47
  • So your GeoJSON is not collection of points but line string feature? Does it really have only two points? Makes no sense for motion.
    – TomazicM
    Commented Jun 7, 2022 at 18:06
  • @TomazicM at the end, it wouldn't have only 2 points but hundreds of them, I just wanted to simplify the code for troubleshooting, initially, they were a lot
    – Vincent Dc
    Commented Jun 7, 2022 at 18:08

2 Answers 2

3

All you have to do is extract line string coordinates from geoJsonData and store them in some array, let's say dataCoords, and flip coordinates while doing that, since Leaflet expects [lat, lng] coordinate order, while GeoJSON has [lng, lat] order:

dataCoords = [];

geoJsonData.features[0].geometry.coordinates.forEach(function(coords) {
  dataCoords.push([coords[1], coords[0]]);
});

Array dataCoords can then be used as input to L.motion.polyline:

var seqGroup = L.motion.seq([
  L.motion.polyline(dataCoords, {
  color: "orangered"
  }, {
    easing: L.Motion.Ease.easeInOutQuad
  }, {
    removeOnEnd: false,
    icon: L.divIcon({html: "<i class='fa fa-truck fa-2x fa-flip-horizontal' aria-hidden='true'></i>", iconSize: L.point(27.5, 24)})
  }).motionDuration(8000)
]).addTo(map);
0
2

remove the following line.

var Json2 = JSON.parse(geoJsonData)

JSON.parse extracts a dictionary from a string. Thus you do not need it here.

Edit: To your new inquiry here's another approach. (Tested)

<!DOCTYPE html>
<html>
    <head>
        <title>Leaflet motion plugin</title>
        <meta charset="utf-8" />

        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
        <link rel="stylesheet" href="https://leaflet.github.io/Leaflet.draw/src/leaflet.draw.css"/>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/>

        <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.js"></script>
        <script src="https://mappingforyou.eu/javascript/leaflet.ajax.min.js"></script>
        
        <script src="../javascript/leaflet.motion.min.js"></script>
        <style>
            html, body, #map { width: 100%; height: 100%; margin: 0px; padding: 0px;}
            .leaflet-div-icon {
                background: transparent!important;
                border: none!important;
                color: white;
            }

            .red {
                color: red!important;
            }
        </style>
     </head>

    <body>

        <div id="map"></div>
        <script>
            var map = L.map("map").setView([51, 1], 5);

            L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
                attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
            }).addTo(map);

            var options = {
                draw: {
                    circle: false, // Turns off this drawing tool
                    rectangle: false,
                    marker: false,
                    circlemarker: false
                }
            };
            
            
    
            var drawControl = new L.Control.Draw(options);
            map.addControl(drawControl);

            map.on(L.Draw.Event.CREATED, function (e) {
                var type = e.layerType,
                    layer = e.layer;

                if (type === "polyline") {
                    var line = L.motion.polyline(layer.getLatLngs(), {
                        color: "orange"
                    }, {
                        auto: true,
                        easing: L.Motion.Ease.swing
                    }).motionSpeed(100000).addTo(map);
                }

                if (type === "polygon") {
                    L.motion.polygon(layer.getLatLngs(), {
                        color: "red",
                        fill: true,
                        fillOpacity: 0.4
                    },{
                        auto: true
                    }, {
                        removeOnEnd: true,
                        icon: L.divIcon({className:"red", html: "<i class='fa fa-superpowers fa-spin fa-2x' aria-hidden='true' motion-base='0'></i>", iconSize: L.point(24, 24), iconAnchor: L.point(5, 22)})
                    }).motionDuration(10000).addTo(map);
                }
            });
                    
            
    var geoJsonData ={"type":"FeatureCollection","features":[{"properties":{"name":""},"type":"Feature","geometry":{"type":"LineString","coordinates":[[-7.271833,51.09715],[0.15577,50.667658],[8.638181,48.79433],[12.703585,45.710102],[9.297436,43.090615],[0.749099,41.036735],[-4.393088,41.548214]]}}]};
    var coordinates = geoJsonData.features[0].geometry.coordinates
    
            
            
    

            var seqGroup = L.motion.seq([
                    L.motion.polyline(coordinates, {
                    color: "orangered"
                    }, {
                        easing: L.Motion.Ease.easeInOutQuad
                    }, {
                        removeOnEnd: false,
                        icon: L.divIcon({html: "<i class='fa fa-truck fa-2x fa-flip-horizontal' aria-hidden='true'></i>", iconSize: L.point(27.5, 24)})
                    }).motionDuration(8000)
                ]).addTo(map);


            seqGroup.on("click", function(){
                seqGroup.motionStart();
            });

            seqGroup.on("dblclick", function(e){
                seqGroup.motionToggle();
            });

            setTimeout(function () {
                seqGroup.motionStart();
            }, 1000);

        </script>
    </body>

</html>
1
  • thanks , I updated the code but I have Uncaught TypeError: Cannot read properties of null (reading 'traveledPath')
    – Vincent Dc
    Commented Jun 7, 2022 at 18:07

Not the answer you're looking for? Browse other questions tagged or ask your own question.