0

This response on image below is coming from Geoserver as MultiLineString and I restructured it to LineString like on image because Animation plugin doesn`t support MultiPolyline json structure and because response has coordinates as lng, lat and I need lat, lng as Leaflet defines. This structure on image works nice with animation plugin.

Since Leaflet Animated Marker Plugin I use doesn't support MultiLineStrings I had to structure it as LineString. It accepts this LineString structure but coordinates are mixed after I apply coordsToLatLngs static method. That makes my marker not appearing on first position and jumping back and forth. Until this line of code coordinates are in right order, as defined in SQL View on Geoserver and I could check it and prove in DB and in QGIS

This is view on Geoserver:

SELECT pgr.seq AS seq,
   pgr.edge AS edge,
   e.id AS id,
   SUM(e.distance) AS distance,
   st_linemerge(st_union(e.geom)) AS geom
  FROM pgr_dijkstra('SELECT id, source, target,onewayNum as cost, r_cost as 
   reverse_cost FROM parking.n_streets_noded',%source%,%target%, true) AS 
   pgr, parking.n_streets_noded  AS e 
 WHERE pgr.edge = e.id
 GROUP BY  pgr.seq, e.geom,e.name,e.type, pgr.seq, pgr.edge,e.id
 ORDER by pgr.seq

enter image description here

This is function with ajax call:

function getFinalRoute(){
var urlRoute = `${geoserver}/wfs?service=WFS&version=1.0.0&request=GetFeature&
typeName=xxx:shortestpath&viewparams=source:${source};target:${targetN || targetE}&outputformat=application/json
&srsName=EPSG:4326`;
var routeLayer = L.geoJSON(null);
var flippedCoords;
$.ajax({
    url: urlRoute,
    async: false,
    success: function(response){    
        console.log(response)
                var routeArr = response.features;
                var coordsArr = Object.keys(routeArr).map(key => {
                    return routeArr[key]
                })

                var xxy = coordsArr.map(function(feature){
                var obj = feature.geometry.coordinates[0];
                    return Object.keys(obj).map(function(key){
                        return obj[key];                        
                    })
                })
   //code above gives me coordinates in perfect order but after applying this method below their order mixes up
                var flipCoor = L.GeoJSON.coordsToLatLngs(xxy,1);

                var flippedCoor = flipCoor.sort().map(function(obj){
                    return Object.values(obj).sort().map(values => {
                        return Object.values(values)
                    })
                }) 

              var myArray = [].sort().concat(...flippedCoor);

                console.log(myArray);

                var multiLineString = L.polyline(myArray);
                var secondAnimated = L.animatedMarker(multiLineString.getLatLngs(), {
                                        distance: 100,
                                        interval: 500,
                                        iconSize:[16,16],
                                        iconAnchor: [7, 16],
                                        //autostart: false,
                                        icon: pulsingIcon
                                    });

                map.addLayer(secondAnimated);
                routeLayer = L.geoJSON(response)

            }

    })      
    map.addLayer(routeLayer);       
};
8
  • 1
    You say «it doesnt give me any error response but it does give me bugs»... what do you mean by bugs exactly? Are there any errors on your JS console? Commented May 8, 2020 at 17:59
  • Not a single error in console, but other layers become useles and they act wierd as soon as I zoom in/out @IvanSanchez
    – str8nomore
    Commented May 8, 2020 at 18:01
  • One thing is definitely true: Leaflet.AnimatedMarker plugin does not know how to work with MultiPolylines (tested). You have to animate each segment separately.
    – TomazicM
    Commented May 8, 2020 at 18:54
  • damn, i knew it...are you aware of any other plugin that could handle this in Leaflet? Meaning to animate it separately I would just load LineStrings instead MultiLineStrings? I think I did it once when all of them appeared at once and were animating each their "own space"...Than it will be tricky to merge them somehow.Zivio! @TomazicM
    – str8nomore
    Commented May 8, 2020 at 19:03
  • I wouldn't search for another plugin. I suppose you want animation to go to the next line segment when it finishes the previous one. You can use onEnd option to start animation of next segment when animation of the current one ends.
    – TomazicM
    Commented May 8, 2020 at 19:10

1 Answer 1

0

In case anyone is stuck with Animation plugins in Leaflet when using MultiLine features it is good to know that most of them will not accept such structure of JSON/GeoJSON where values, in this case coordinates, are nested a bit deeper when comparing with simple LineString features whose structure is like Array of Objects and in my case looks so:

[{lat,lng},{lat,lng}{lat,lng}...]

Such structure and order of coordinates in Leaflet will allow getLatLngs() method in Animation Marker plugin to do it´s work even tough our data comes from server as MultiLineString.

My second issue along with trying to de-structure response was jQuery ajax call. I was using single call to create an object from response and to "manipulate" response and use it for Animation marker creation at the same time. I guess this is not recommendable so hopefully someone here can confirm it and explain it better. When I was working with single call response my coordinates would mix up somehow and I would never reach desired LineString structure with coordinates in right order.

Therefore I split the call in two, one for creating route layer, other for creating Animation Marker and got result I wanted right away.

function getFinalRoute(){
    var urlRoute = `${geoserver}/wfs?service=WFS&version=2.0.0&request=GetFeature&
    typeName=xxx:shortestpath&viewparams=source:${source};target:${targetN || targetE}&outputformat=application/json`;
    var routeLayer = L.geoJSON(null);
    $.ajax({
        url: urlRoute,
        async: false,
        success: function(response){    
                    routeLayer = L.geoJSON(response)
                    goPark(urlRoute);
            }   
        })      
        map.addLayer(routeLayer);       
    };

function goPark(urlRoute){
    $.ajax({
        url: urlRoute,
        asnyc: false,
        success: function(data) {
            coordinatesArr = data.features
            console.log(coordinatesArr);
            var coordsArr = Object.keys(coordinatesArr).map(key => {
                return coordinatesArr[key]
            });
            xxy = coordsArr.map(function(feature){
                var obj = feature.geometry.coordinates[0];
                return Object.keys(obj).map(function(key){
                    return obj[key];
                })
            });
     /*line below ensures flipping coordinates to LatLng with MultiLineString 
       structure where xxy is array and 1 allows to reach nested value. This 
       value can be decreased as well as increased depending how deep the 
       value is nested*/
            var flipCoor = L.GeoJSON.coordsToLatLngs(xxy, 1);
            var flippedCoor = flipCoor.map(function(obj){
                return Object.values(obj)
                })
            var myArray = [].sort().concat(...flippedCoor);
            var lineString = L.polyline(myArray);
            var secondAnimated = L.animatedMarker(lineString.getLatLngs(), {
                                    distance: 500,
                                    interval: 50,
                                    iconSize:[14,14],
                                    iconAnchor: [7, 14],
                                    //autostart: false,
                                    icon: pulsingIcon,
                                    onEnd: function(){
                                        alert("Parked")
                                    }
                                    });

            map.addLayer(secondAnimated);

        }
    })
}   

Slovenac thanks for revealing important information in comments section @TomazicM :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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