Places with InstantSearch GeoSearch Widget on the same map?

Hi !

I’m a new user of Algolia, sorry if my question is basic. I try to do this :

  • Link hits as markers with a Google Map and the Search as i move the map = it’s ok for that with instantsearch.widgets.geoSearch. Good !

  • Add a Places Autocomplete on the same map to zoom, center on the Places’ result and add a custom marker on it. It’s ok when i delete the instantsearch.widgets.geoSearch function. I can’t have both GeoSearch and Places.

I try PlacesInstantsearchWidget but it’s not exactly what i want. It doesn’t center on the Places’ result when i have markers and it display markers only around a radius not on viewport’s map.

Is it possible to have instantsearch.widgets.geoSearch and Places on the same map ?

Thanks !

Hi @arnaud,

I’m not sure to fully understand what you are trying to do. From what I understand you want to have two different kind of results on the map: the ones from your index + the ones from Places. Is it correct? Could you provide us a bit more context about your use case (working example / screenshots) of the UI? It will help to better understand what you are trying to implement. We provide template to avoid you the boilerplate part. It’s available on CodeSandbox.

What is currently possible with the Places + GeoSearch is to pick a location from the Places index and apply this location to the search in your index to find results around this location. Here is an example in our documentation. You can pick a location from Places (e.g. Paris). InstantSearch then trigger a search on your index with the location of Paris. Once we get the results the map move around the results found.

Thanks!

Hi @samuel.vaillant,

My screen is divided in two parts, left for displaying hits, right for the map. For example, I have an organization based at 50 km of a city like Brest (in France), with the placesInstantsearch widget, if I suggest Brest, the map doesn’t center to Brest but directly focus on the organization with a zoom at 1 on the map. I want to control the zoom and take the focus on the city’s suggest not on the marker’s hit. If user suggest Brest, zoom, center and create custom marker to Brest not zoom directly on the organization. I can easily do with Places like this when I don’t use instantsearch.widgets.geoSearch :

var myOptions = {
    zoom: 8,
    center: new google.maps.LatLng(47.990500, -1.813418),
    mapTypeControl: false,
    zoomControl: true,
    zoomControlOptions: {
        position: google.maps.ControlPosition.RIGHT_CENTER
    },
    scrollwheel: false,
    streetViewControl: false,
    fullscreenControl: false,
    styles: styles
};

mapDiv = document.getElementById('map');
map = new google.maps.Map(mapDiv, myOptions);

markers =[];
var icon = {
    path: "M-20,0a20,20 0 1,0 40,0a20,20 0 1,0 -40,0",
    fillColor: '#51b15b',
    fillOpacity: .6,
    anchor: new google.maps.Point(0,0),
    strokeWeight: 0,
    scale: 1.5
}

var placesAutocomplete = places({
            container: document.querySelector('#address'),
            countries: 'fr',
            type: 'city',
            templates: {
              suggestion: function(suggestion) {
                return '<i class="fa fa-map-marker"></i> ' +
                  suggestion.highlight.name + ', ' + suggestion.postcode + ', ' + suggestion.administrative ;
              },
              empty: function(options) {
                return "<p class='empty'>Aucun résultat.</p>";
              },
                    value: function(suggestion) {
                return suggestion.name + ', ' + suggestion.postcode + ', ' + suggestion.administrative;
              },
            }
        });

        placesAutocomplete.on('change', geoZoom);
        placesAutocomplete.on('clear', clearZoom);

        function geoZoom(e) {
            var myLatLng = e.suggestion.latlng;
                map.panTo(myLatLng);
                map.setZoom(10);
            clearMarkers();
            var marker = new google.maps.Marker({
              position: myLatLng,
              icon: icon,
              map: map
            });
            markers.push(marker);
        }
        function clearZoom() {
            clearMarkers();
            map.setZoom(8);
        }
        function setMapOnAll(map) {
          for (var i = 0; i < markers.length; i++) {
            markers[i].setMap(map);
          }
        }
        function clearMarkers() {
          setMapOnAll(null);
        } 

but I want Instant Search with GeoSearch to link hits with my map and have functions like enableRefineOnMapMove, so I did that instead of Places :

const search = instantsearch({
  appId: 'myID',
  apiKey: 'myKey', 
  indexName: 'myIndex',
  routing: true,
    searchParameters: {
      hitsPerPage: 20
    }
});

search.addWidget(
    instantsearch.widgets.searchBox({
      container: '#search-box',
      placeholder: 'Rechercher une organisation'
    })
);

search.addWidget(
    instantsearch.widgets.hits({
      container: '#hits',
      templates: {
        empty: 'Aucune organisation dans ce secteur',
        item: '<em>Organisation n° {{objectID}}</em>'
      }
    })
);

search.addWidget(
    placesInstantsearchWidget({
        container: '#address',
        countries: 'fr',
        type: 'city',
        templates: {
          suggestion: function(suggestion) {
            return '<i class="fa fa-map-marker"></i> ' +
              suggestion.highlight.name + ', ' + suggestion.postcode + ', ' + suggestion.administrative ;
          },
          empty: function(options) {
            return "<p class='empty'>Aucun résultat.</p>";
          },
                value: function(suggestion) {
            return suggestion.name + ', ' + suggestion.postcode + ', ' + suggestion.administrative;
          },
        }
      })
);

search.addWidget(
  instantsearch.widgets.geoSearch({
    container: mapDiv,
    mapOptions: myOptions,
    googleReference: window.google,
    enableRefineOnMapMove: true,
    enableGeolocationWithIP: false, 
    initialZoom:10,
    initialPosition:[47.990500, -1.813418],
    radius: 60000
  })
);
search.start();

If i set radius to all, PlacesInstantsearch Widget doesn’t zoom on the map (but hits are sorted)

With searchBox, I would to find an organization by name and with Places autocomplete I would to zoom and center to city I suggest while keeping the markers on the map viewport and display visible hits on the left screen.

I don’t know if I’m clear or if what I want is the right way, but there is something that escapes me :wink:

Hi @arnaud,

There is something that I don’t understand with your implementation. How does it work when the user search for an organisation with the SearchBox without using the Places widget? If the map doesn’t update to match the position of the hits, the informations provided by the map are outdated right?

The built-in GeoSearch widget will always fit the viewport of the map based on the hits that are rendered. You can’t opt-out from this behaviour for the moment. A possible workaround is to set a maximum level of zoom to the Google Maps. It means that you can “simulate” the zoom level of the city.

Another possible solution is to implement your own map widget with the connector connectGeoSearch. This API lets you implement your own rendering without having to re-implement all the logic related to the search (here is more information about this API). You can find an example on the documentation. It uses Leaflet for the map but the concept remains the same with Google Maps.