0

I am using Leaflet Map with geocoder (ESRI) and Routing Machine. I have added two markers, let's say my home and my work

var marker_work = L.marker([50.27, 19.03], { title: 'MyWork'}).addTo(map)
.bindPopup("work").openPopup();

var marker_home = L.marker([50.10, 18.4], { title: 'MyHome'}).addTo(map)
.bindPopup("home").openPopup();

Here is an example fiddle: https://jsfiddle.net/21nmk8so/1/

How can I add this markers/point as a predefined places for ControlGeocoder? I want to use them in search and use as a start point / end point for route calculation.

Another example for the same question: how to add custom-fake city with lat/lon and be able to search (find route) to/from that city.

Tikky
  • 1,253
  • 2
  • 17
  • 36
  • You simply pass the same coords you used to add the markers and the markers on `waypoints` are added automatically for the 1st question. – kboul Jan 03 '21 at 16:52
  • @kboul but how to do to be able to search by marker names? – Tikky Jan 03 '21 at 17:30
  • Do you want to use the marker popup text as start/end names on the right panel? – kboul Jan 03 '21 at 18:36
  • @kboul In my real case I have lots of markers which are cars in gps-tracking system. What I want do is to be able to serach by car names (markers name) and navigate for example from my "Car A" to "Berlin" or vice-versa – Tikky Jan 03 '21 at 18:38
  • I am not sure how to do this but there is another possible alternative solution . You can simply click on the place/marker which is the car location and set the location on the start or end point for instance. – kboul Jan 03 '21 at 19:16
  • @kboul yes, I now I can use setWaypoints function to reposition the start/end markers, but this is not exactly what I am asking for. It this is what you have suggested – Tikky Jan 03 '21 at 19:40

1 Answers1

2

I don't know if this is the best solution but it is working: Create a custom Geocoder Class which overwrites the geocode function. There you can overwrite the result function and apply suggestions to the result.

L.CustomGeocoder = L.Control.Geocoder.Nominatim.extend({
    suggestions: [],
    setSuggestions(arr){
      this.suggestions = arr;
    },
    createSuggestionFromMarker(marker){
      this.suggestions.push({name: marker.options.title, center: marker.getLatLng()});
    },
    getResultsOfSuggestions(query){
      var results = [];
      this.suggestions.forEach((point)=>{
        if(point.name.indexOf(query) > -1){
          point.center = L.latLng(point.center);
          point.bbox = point.center.toBounds(100);
          results.push(point);
        }
      });
      return results;
    },
    geocode(query, resultFnc, context) {
      var that = this;
      var callback = function(results){
        var sugg = that.getResultsOfSuggestions(query);
        resultFnc.call(this,sugg.concat(results));
      }
      L.Control.Geocoder.Nominatim.prototype.geocode.call(that,query, callback, context);
    }
  })

Then you have to use the new Geocoder Class:

var geocoder = new L.CustomGeocoder({});

var control = L.Routing.control({
  waypoints: [],
  router: new L.Routing.osrmv1({
    language: 'en',
    profile: 'car'
  }),
  geocoder: geocoder
}).addTo(map);

And finally you can add suggestions over markers and theier title option over createSuggestionFromMarker(marker) or setSuggestions(arr):

var suggestions = [
  {
    name: 'Test Car 1',
    center: [50.27, 19.03]
  },
  {
    name: 'Test Car 2',
    center: [50.10, 18.4]
  }
];
geocoder.setSuggestions(suggestions);

var marker_work = L.marker([50.27, 19.03], { title: 'MyWork'}).addTo(map);
var marker_home = L.marker([50.10, 18.4], { title: 'MyHome'}).addTo(map);

geocoder.createSuggestionFromMarker(marker_work);
geocoder.createSuggestionFromMarker(marker_home);

Update, use marker Ref instead of fix latlng

Change this two function, then the marker is referenced and it always searches from the current position of the marker:


    createSuggestionFromMarker(marker){
      this.suggestions.push({name: marker.options.title, marker: marker});
    },
    getResultsOfSuggestions(query){
      var results = [];
      this.suggestions.forEach((point)=>{
        if(point.name.indexOf(query) > -1){
            if(point.marker){
            point.center = point.marker.getLatLng();
          }
          point.center = L.latLng(point.center);
          point.bbox = point.center.toBounds(100);
          results.push(point);
        }
      });
      return results;
    },

You can test this in the demo, when you drag the marker

https://jsfiddle.net/falkedesign/hu25jfd1/

Falke Design
  • 10,635
  • 3
  • 15
  • 30
  • thank you for the contibution. I would like to check your solution but jsfiddle seems to be not saved. Could you please check it or update? – Tikky Jan 04 '21 at 06:16
  • @falkie-design Great, this actually resolve my question, but I ma straggle with one thing. When my car moves I can update the marker position, but how to update suggestion (for example to make MyWork in suggestions new lat/lon withou duplicate)? I mean something like updateSuggestion, it is possible to do that? I will appreciate if you can help but I will mark you query as resolved anyway. Thank you – Tikky Jan 04 '21 at 13:25
  • I updated the answer. Now it is referenced to marker and it uses the current position. If you need to update the suggestion entry, you need to make it the entry unique with a id or the `_leaflet_id` of the marker and then you can search by the id and update the object. – Falke Design Jan 04 '21 at 13:57
  • hello @falke-design, thank you, this works. The one thing I am still struggle to do, is how to make searching case-insensitive. I was able to make all suggestions lowercase, but how to allow searching for title of any size (capital, lowercase, mixed) https://jsfiddle.net/un1fc8a2/1/ – Tikky Jan 10 '21 at 19:44
  • Change this line `if(point.name.indexOf(query) > -1){` to `if(point.name.toLowerCase().indexOf(query.toLowerCase()) > -1){`. And please when it work, accept the answer, so that this question is resolved – Falke Design Jan 10 '21 at 20:48
  • @falke-deisgn, works fine, thank you once again https://jsfiddle.net/cu3e1dm5/ – Tikky Jan 11 '21 at 08:53
  • Hello @falke-design I am having trouble converting the code from jsfiddle to production. The reason is because Control.Geocoder.js in jsfiddle is 1.5.5 (and works until 1.13.0) but the newest which I am using is 2.1.0 And using this versaion shows me an error: "Uncaught TypeError: Cannot read property 'Nominatim' of undefined". Could you be so kind to take a look at jsfiddle with newest file. I am so close to use this on my production: jsfiddle.net/qtcvdypr/1 and I am stacked with this error. – Tikky Jan 12 '21 at 16:56
  • They are not longer using the Leaflet Class System, so `extend` is not working. But with `class CustomGeocoder extends L.Control.Geocoder.Nominatim {` it is working. https://jsfiddle.net/falkedesign/wr2xm1hb/ Also you used the wrong JS Url, you need to use the raw url like in my fiddle – Falke Design Jan 12 '21 at 17:22
  • Hello @falke-design yes-js was my mistake. ..have changed the JS link in your jsfiddle and works fine: https://jsfiddle.net/qtk0fcne/1/ Magic! thanks a lot! – Tikky Jan 12 '21 at 17:43