Leaflet Plugins – Using GeoJSON as Input to Leaflet.motion Plugin

geojsonleafletleaflet-plugins

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.

Best Answer

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