leaflet-routing-machine icon indicating copy to clipboard operation
leaflet-routing-machine copied to clipboard

setAlternatives failing

Open rkroelin opened this issue 6 years ago • 6 comments

I'm receiving a "Cannot Read Property 'classList' of undefined" error when attempting to setAlternatives with a valid array of routes. I can successfully use L.Routing.line on the same route array and display the additional route on the map.

Note I am using my own valhalla server via lrm-mapzen.

Error:

leaflet.js.pagespeed.jm.T8ScB2_j3R.js:1 Uncaught TypeError: Cannot read property 'classList' of undefined
    at Object.pe [as hasClass] (leaflet.js.pagespeed.jm.T8ScB2_j3R.js:1)
    at e._selectAlt (leaflet-routing-machine.js.pagespeed.jm.H17W49CGYm.js:1)
    at e.fire (leaflet.js.pagespeed.jm.T8ScB2_j3R.js:1)
    at e._selectRoute (leaflet-routing-machine.js.pagespeed.jm.H17W49CGYm.js:1)
    at e.setAlternatives (leaflet-routing-machine.js.pagespeed.jm.H17W49CGYm.js:1)
    at callback (optimized-routingcpy.html:63)
    at e._routeDone (eval at <anonymous> (optimized-routingcpy.html:1), <anonymous>:6:529)
    at eval (eval at <anonymous> (optimized-routingcpy.html:1), <anonymous>:5:7151)
    at XMLHttpRequest.loaded (eval at <anonymous> (optimized-routingcpy.html:1), <anonymous>:1:1219)

Here's the appropriate code segment. Anyone have suggestions?

      var control = L.Routing.control({
          // [...] See MapzenTurn-by-Turn API documentation for other options
          router: router1,

          plan: plan,

            lineOptions: {
                styles: [{color: 'blue', opacity: 1, weight: 5},
                        {color: 'white', opacity: .2, weight: 8},
                        ]
            },

          routeWhileDragging: true,
          // geocoder: geocoder,   //
          
          showAlternatives: true,

          formatter: new L.Routing.mapzenFormatter({
             units: 'imperial',
              roundingSensitivity: "100",
            }),
        });

        control.addTo(map);

        
        var callback = function(err, routes) {
                  distance = routes[0].summary.totalDistance;
                  console.log('routing distance: ' + distance);

                  console.log('routesInArray:',routes);
                  console.log('routesinIndex0:',routes[0]);

                //Manually draw second route
                 var line1 = L.Routing.line(routes[0]);
                 line1.addTo(map);

                  control.setAlternatives(routes);  
                 
          }

      router2.route(control.getWaypoints(),callback,this);

rkroelin avatar Sep 21 '19 21:09 rkroelin

Hi, really hard to tell without stepping through the code to see which line it actually breaks at and what the variables look like at that point, but I am going to take a wild guess that the Itinerary instance (where _selectAlt is located) isn't correctly initialized since you do the route call manually.

Any particular reason you need to do the routing like this instead of actually using the control's builtin route method? IIRC there's quite a few nasty edge cases in there that you probably don't want to handle yourself if you don't have to.

If you search for issues with setAlternatives, you can also find a few people who have done similar things, it looks like most of them succeeded although there were some trouble on the way.

perliedman avatar Sep 23 '19 22:09 perliedman

Thanks for the response! I'm trying to replicate the alternates functionality, but using two different costing methods.

LRM-Mapzen/valhalla doesn't support alternatives. So after browsing the various issues here and exhausting google I figured the best way would be to create two distinctly configured routers, and store the route not being used by the main control, and then pass it back in with setAlternatives.

Essentially the code above with L.Routing.Line (or mapzenLine) accomplishes what i'm after except the ability to switch the itinerary between the two drawn routes by clicking on the faux-alternate.

I didn't think it would be possible to update the control's router parameters without it removing the existing route. I experimented a bit with two controls and, like the others, found it less than ideal.

rkroelin avatar Sep 26 '19 04:09 rkroelin

Any chance you can post a running example that can be stepped through? Otherwise, step through the code and check what line in _selectAlt it actually crashes at, it's most likely some variable not yet correctly set up.

perliedman avatar Sep 26 '19 06:09 perliedman

So the uncaught exception occurs at line 1010 of leaflet.js after setAlternatives draws the alternate route and before the original route is redrawn.

The exception seems to be because altElem is undefined at line 16908 in leaflet-routing-machine.js

Both lines labeled below.

 function pe(t, e) {
 (1010)       if (void 0 !== t.classList)
            return t.classList.contains(e);
        var i = ve(t);
        return 0 < i.length && new RegExp("(^|\\s)" + e + "(\\s|$)").test(i)
    }

Line 16908 of leaflet-routing-machine.js

_selectAlt: function(e) {
			var altElem,
			    j,
			    n,
			    classFn;

			altElem = this._altElements[e.route.routesIndex];

(16908)			if (L.DomUtil.hasClass(altElem, 'leaflet-routing-alt-minimized')) {
				for (j = 0; j < this._altElements.length; j++) {
					n = this._altElements[j];
					classFn = j === e.route.routesIndex ? 'removeClass' : 'addClass';
					L.DomUtil[classFn](n, 'leaflet-routing-alt-minimized');
					if (this.options.minimizedClassName) {
						L.DomUtil[classFn](n, this.options.minimizedClassName);
					}

					if (j !== e.route.routesIndex) n.scrollTop = 0;
				}
			}

rkroelin avatar Sep 28 '19 16:09 rkroelin

Here's the state of everything right before the code goes into function pe(). image

rkroelin avatar Sep 28 '19 16:09 rkroelin

Some progress. Added both routes to an array, and passing that array works. Both routes are drawn and the instructions are present in the control. setAlternatives dies with the above error if I just pass the secondary route.

However selecting the alternative route does nothing, and manually selecting the second set of instructions in the control swaps the line styling and then generates the same classlist of undefined error in function pe().

Had to also add an on('waypointschanged' function to the plan to empty the array of routes to draw the second route upon waypoint addition/change.

var geocoder = L.Control.Geocoder.nominatim(),
      waypoints =  [     //Default navigation start/stop waypoints
                L.latLng(35.96, -83.922),
                 L.latLng(35.536, -82.693),
      //           L.latLng(37.273, -79.961),
      //           L.latLng(35.78, -78.64),
        ],
      plan = L.Routing.plan(waypoints,{
        geocoder: geocoder,
        routeWhileDragging: false,
        reverseWaypoints: true,
       
      }).on('waypointschanged',function(e) {
        
            allRoutes.length=0;
        });  
      
      router1 = L.Routing.mapzen('', {
        
        costing:'motorcycle',  //use motorcycle costing
        costing_options: {
        use_highways: "0.8"},    //Highway weighting 0 = avoid 1 = max prefer

      }),

      router2 = L.Routing.mapzen('', {

        costing:'auto',  //use auto costing
        costing_options: {
        use_highways: "0.8"},    //Highway weighting 0 = avoid 1 = max prefer

      });

  var allRoutes = [];

  var control = L.Routing.control({
      // [...] See MapzenTurn-by-Turn API documentation for other options
      router: router1,

      plan: plan,

      showAlternatives: true,

        lineOptions: {
            styles: [{color: 'blue', opacity: 1, weight: 5},
                    {color: 'white', opacity: .2, weight: 8},
                    ]
        },

        altLineOptions: {
            styles: [{color: 'red', opacity: 1, weight: 5},  
                    {color: 'white', opacity: .2, weight: 8},
                    ]
        },

      routeWhileDragging: true,
      // geocoder: geocoder,   
      
      

      formatter: new L.Routing.mapzenFormatter({
         units: 'imperial',
          roundingSensitivity: "100",
        }),
    }).on('routeselected',function(e) {
        
        if(allRoutes.length <2){
            allRoutes.push(e.route)
            router2.route(control.getWaypoints(),callback);
        }  
        
       
            
    }).addTo(map);
   

    var line1 = {};  //object to hold alternate route line
    

    var callback = function(err, routes) {
      allRoutes.push(routes[0]);
      control.setAlternatives(allRoutes);             
      }

rkroelin avatar Sep 28 '19 23:09 rkroelin