0

I am trying to use the getBounds and setBounds functions to zoom to the extent of a selected polyline feature in Carto. The feature has been selected using an SQL query. I want to zoom to the extent of the selected feature but it is not working! See code below:

// Add dropdown selection function
const selector = $(".js-dropdown-selector");
// Change SQL query with dropdown selection
selector.on('change',function(e){
  let value = $(".js-dropdown-selector option:selected").val();
  console.log("You have selected Route " + value + ".");
  if(value == 'all'){
    source.setQuery('SELECT * FROM aggregate');
  } else {
    source.setQuery("SELECT * FROM aggregate WHERE routenumbe = '" + value + "'")
  };
});
map.getBounds(source);
map.setBounds(getBounds);
  • Race condition. getBounds() and setBounds() are running only once, and not on every change of the selector. – IvanSanchez Feb 27 at 12:54
  • ah okay - how do I rectify that? – Flora T Feb 27 at 14:09
1

Several base problems here. The code that runs on every change of the drop-down selector...

selector.on('change',function(e){
  let value = $(".js-dropdown-selector option:selected").val();
  console.log("You have selected Route " + value + ".");
  if(value == 'all'){
    source.setQuery('SELECT * FROM aggregate');
  } else {
    source.setQuery("SELECT * FROM aggregate WHERE routenumbe = '" + value + "'")
  };
});

... is not running any getBounds() or setBounds() calls at all.

Now, the getBounds() call...

map.getBounds(source);

... does not take any arguments, as per the Leaflet documentation.

A naïve approach would be to perform those calls right after the setQuery() call...

selector.on('change',function(e){
  let value = $(".js-dropdown-selector option:selected").val();
  console.log("You have selected Route " + value + ".");
  if(value == 'all'){
    source.setQuery('SELECT * FROM aggregate');
  } else {
    source.setQuery("SELECT * FROM aggregate WHERE routenumbe = '" + value + "'")
  };

  // TODO: Somehow get the bounds of the (updated?) source here

});

... but, quoting the Carto.js docs, source.setQuery takes some time to update the data source:

Update the query. This method is asynchronous and returns a promise which is resolved when the style is changed successfully. It also fires a 'queryChanged' event.

... so it's important here to know how to handle Promises. The asynchronicity is obvious when fiddling with Carto's setQuery() example - it takes time since the user clicks on a checkbox until the data is updated.

So if you don't want to zoom into the previously loaded geometries, things should look something like:

selector.on('change',function(e){
  let value = $(".js-dropdown-selector option:selected").val();
  var query = "";
  console.log("You have selected Route " + value + ".");
  if(value == 'all'){
    query = ('SELECT * FROM aggregate');
  } else {
    query = ("SELECT * FROM aggregate WHERE routenumbe = '" + value + "'")
  };

  source.setQuery(query).then(function() {
      // TODO: Somehow get the bounds of the updated source here
  });
});

With that out of the way, now it's time to worry about getting the bounds. The problem is that a Carto source doesn't have any methods to get the bounds of the data. Nor it can be done by referring to the Carto layer, because the Leaflet implementation of Carto layers are raster-based, and the documentation doesn't show any way of fetching any data bounds either.

Instead, you might want to experiment with other approaches such as requesting GeoJSON data and instantiating L.GeoJSON instances from there, as shown in Carto's drop-down example

  • Thank you so much for this answer! I will take a look at the JSON approach. – Flora T Feb 27 at 15:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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