Restrict Google Autocomplete results using bounds option - google-maps

I am trying to use Google Places Autocomplete and restrict the results to a specific city in Canada, namely Toronto. I am aware that using the componentRestrictions option will allow me to restrict the results to Canada by using componentRestrictions: {country: 'CA'}. In order to further restrict the results to Toronto, I understand that I have to add the bounds property to the options object. The LatLngBounds expects south-west and north-east corners, which are also referred to as bottom-left and top-right corners.
I found this sample code which implements this strategy for the City of Hyderabad in Pakistan and it works perfectly:
var input = document.getElementById('searchTextField');
var southWest = new google.maps.LatLng( 25.341233, 68.289986 );
var northEast = new google.maps.LatLng( 25.450715, 68.428345 );
var HyderabadBounds = new google.maps.LatLngBounds( southWest, northEast );
var options = {
bounds: HyderabadBounds,
types: ['address'],
componentRestrictions: { country: 'PK' }
};
var autocomplete = new google.maps.places.Autocomplete( input, options);
When I try to modify the code to work for an area in Canada, for some reason it is not working. Here is my modified code:
var input = document.getElementById('searchTextField');
var southWest = new google.maps.LatLng( 43.941160, -78.895187 );
var northEast = new google.maps.LatLng( 42.946172, -81.296577 );
var TorontoBounds = new google.maps.LatLngBounds( southWest, northEast );
var options = {
bounds: TorontoBounds,
types: ['address'],
componentRestrictions: { country: 'CA' }
};
var autocomplete = new google.maps.places.Autocomplete( input, options);
The only thing different about my modified code is the country designation CA and the LatLng coordinates which I believe to be correct. I double-checked my coordinates and the southWest coordinate refers to a location southWest of Toronto and the northEast coordinate refers to a location northEast of Toronto, so I would expect that these should work. Although my results are properly restricted to Canada, they are not within my bounds as specified by the LatLng coordinates.
Can anyone see what I might be doing wrong?

Your northEast and southWest points are named incorrectly. Change their names:
var northEast = new google.maps.LatLng(43.941160, -78.895187);
var southWest = new google.maps.LatLng(42.946172, -81.296577);
If I set them to:
var northEast = new google.maps.LatLng(43.941160, -78.895187);
var southWest = new google.maps.LatLng(42.946172, -81.296577);
The bounds object is correct.
proof of concept fiddle
code snippet:
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: -33.8688,
lng: 151.2195
},
zoom: 13
});
var input = document.getElementById('searchTextField');
var northEast = new google.maps.LatLng(43.941160, -78.895187);
var southWest = new google.maps.LatLng(42.946172, -81.296577);
var SWmark = new google.maps.Marker({
map: map,
position: southWest,
title: southWest.toUrlValue(6),
label: "SW"
});
var NEmark = new google.maps.Marker({
map: map,
position: northEast,
title: northEast.toUrlValue(6),
label: "NE"
});
var TorontoBounds = new google.maps.LatLngBounds(southWest, northEast);
var rectangle = new google.maps.Rectangle({
map: map,
bounds: TorontoBounds
});
map.fitBounds(TorontoBounds);
var options = {
bounds: TorontoBounds,
types: ['address'],
componentRestrictions: {
country: 'CA'
}
};
var autocomplete = new google.maps.places.Autocomplete(input, options);
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 80%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<div id="pac-container">
<input id="searchTextField" type="text" placeholder="Enter a location">
</div>
<div id="map"></div>
<div id="infowindow-content">
<img src="" width="16" height="16" id="place-icon">
<span id="place-name" class="title"></span><br>
<span id="place-address"></span>
</div>
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=places&callback=initMap" async defer></script>

Related

Limit autocomplete results within the bounds of a place_id

I have two textboxes, both of which are autocompletes. The first one we get the place_id when I change it. Second textbox is supposed to suggest results within the place_id of the first.
Here's my code:
const options = {
types: ['(regions)'],
componentRestrictions: {country: 'gb'},
};
const search = new google.maps.places.Autocomplete( $("#address_1")[0], options);
google.maps.event.addListener(search, 'place_changed', function () {
var place = search.getPlace();
const options_b = {
types: ['(regions)'],
componentRestrictions: {country: 'gb'},
};
var options_2 = {
types: ['address'],
strictbounds: true,
radius:500,
//other parameters here..perhaps place_id ?
};
const search = new google.maps.places.Autocomplete( $("#address_2")[0], options_b);
});
So let's say I typed London in the first text box, then the 2nd text box should only suggest places within London.
If you want to limit the result of an Autocomplete to the bounds of a place, use the bounds of that place to restrict the Autocomplete and set the strictBounds: true option (note the capitalization)
const search1 = new google.maps.places.Autocomplete($("#address_1")[0], options);
google.maps.event.addListener(search1, 'place_changed', function() {
var place = search1.getPlace();
var bounds = place.geometry.viewport; // bounds of place returned by the first autocomplete
var options_2 = {
types: ['address'],
strictBounds: true,
bounds: bounds
};
const search2 = new google.maps.places.Autocomplete($("#address_2")[0], options_2);
});
proof of concept fiddle
"use strict";
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCPJpjD-qcR_yIxJnS8maR5W9KB0E3EzYI&libraries=places">
function initAutocomplete() {
var map = new google.maps.Map(document.getElementById('map'))
const options = {
types: ['(regions)'],
componentRestrictions: {
country: 'gb'
},
};
const search1 = new google.maps.places.Autocomplete($("#address_1")[0], options);
google.maps.event.addListener(search1, 'place_changed', function() {
var place = search1.getPlace();
var bounds = place.geometry.viewport;
var marker = new google.maps.Marker({
position: place.geometry.location,
map: map
});
var rectangle = new google.maps.Rectangle({
bounds: bounds,
map: map
})
map.fitBounds(bounds);
var options_2 = {
types: ['address'],
strictBounds: true,
bounds: bounds
//other parameters here..perhaps place_id ?
};
const search2 = new google.maps.places.Autocomplete($("#address_2")[0], options_2);
google.maps.event.addListener(search2, 'place_changed', function() {
var place = search2.getPlace();
var marker = new google.maps.Marker({
position: place.geometry.location,
map: map,
icon: {
url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle.png",
size: new google.maps.Size(7, 7),
anchor: new google.maps.Point(3.5, 3.5)
}
});
});
});
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 80%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Place Autocomplete</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initAutocomplete&libraries=places&v=weekly" defer></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div class="pac-card" id="pac-card">
<div id="pac-container">
<input id="address_1" type="text" placeholder="Enter a location" /><br/>
<input id="address_2" type="text" placeholder="Enter a location" />
</div>
</div>
<div id="map"></div>
</body>
</html>

Automatically show street view map when inputting an address

I want to put in a street address, and have it programatically determine the coordinates and heading for the purposes of generating a street view map. instantstreetview.com does this, so I know it can be done. From the docs:
function initialize() {
var fenway = {lat: 42.345573, lng: -71.098326};
var map = new google.maps.Map(document.getElementById('map'), {
center: fenway,
zoom: 14
});
var panorama = new google.maps.StreetViewPanorama(
document.getElementById('pano'), {
position: fenway,
pov: {
heading: 34,
pitch: 10
}
});
map.setStreetView(panorama);
}
Problem is, I don't know the heading of the address I want. Is there a simple way to achieve this?
You may want to look into getting the LatLng from the StreetViewLocation of the StreetViewPanorama rendered to compute the heading using the computeHeading() in the Geometry library in the Javascript API.
Take a look at this sample JSBin. I've created two Street View divs with the lat/lngs of two addresses across the street from each other. Notice that, regardless of the lat/lng, the same pano is returned, but there is no heading information, so the view is the same:
Now, look at this this modified JSBin. After computing the heading based on the StreetViewLocation.latLng of the panorama and lat/lng of the addresses passed into StreetViewService and using that as the pov for the panoramas, the correct Street View imagery is shown for each address:
The pertinent code:
var ll = new google.maps.LatLng(37.435292,-122.129517);
var svs = new google.maps.StreetViewService();
svs.getPanorama({location: ll, preference: 'nearest'}, function(data, status){
var pos = data.location.latLng;
var head = google.maps.geometry.spherical.computeHeading(pos, ll);
var panorama = new google.maps.StreetViewPanorama(
document.getElementById('street-view'),
{
pano: data.location.pano,
pov: {heading: head, pitch:0}
});
});
EDIT: Adding another simple JSBin showing the use of the Geocoder to get the LatLng for the addresses: Pertinent code:
var ll;
var geocoder = new google.maps.Geocoder();
var svs = new google.maps.StreetViewService();
geocoder.geocode({address: "757 Moreno Ave Palo Alto, CA"}, function(results, status) {
if (status == 'OK') {
ll = results[0].geometry.location;
svs.getPanorama({location: ll, preference: 'nearest'}, function(data, status){
var pos = data.location.latLng;
var head = google.maps.geometry.spherical.computeHeading(pos, ll);
panorama = new google.maps.StreetViewPanorama(
document.getElementById('street-view'),
{
pano: data.location.pano,
pov: {heading: head, pitch:0}
});
});
}
});

Algolia and google filter results based on user position

Hi I am using Google maps alongside algolia where I have an index 'locations' with 'lat' and 'lng'.
I am getting user location and watching position, I am also displaying markers from database based on lng and lat however I want to add a bit to it:
So I have followed that link:
https://www.algolia.com/doc/guides/geo-search/geo-search-overview/
And came up with:
#extends('master') #section('title', 'Live Oldham')
#section('extrafiles')
<script type="text/javascript" src="https://maps.google.com/maps/api/js?v=3&key=AIzaSyAirYgs4Xnt9QabG9v56jsIcCNfNZazq50&language=en"></script>
<script type="text/javascript" src="{!! asset('js/homesearch.js') !!}"></script>
#endsection
#section('content')
<div id="map_canvas" style="height:600px;"></div>
#endsection
and js:
$(document).ready(function() {
var map;
function initializeMap(){
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 19,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
}
function locError(error) {
// the current position could not be located
alert("The current position could not be found!");
}
function setCurrentPosition(position) {
currentPositionMarker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude
),
title: "Current Position"
});
map.panTo(new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude
));
}
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
console.log(latitude);
console.log(longitude);
function displayAndWatch(position) {
// set current position
setCurrentPosition(position);
// watch position
watchCurrentPosition(position);
console.log(position);
}
function watchCurrentPosition(position) {
var positionTimer = navigator.geolocation.watchPosition(
function (position) {
setMarkerPosition(
currentPositionMarker,
position,
)
});
}
function setMarkerPosition(marker, position) {
marker.setPosition(
new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude)
);
}
function initLocationProcedure() {
initializeMap();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayAndWatch, locError);
}else{
alert("Your browser does not support the Geolocation API");
}
}
$(document).ready(function() {
initLocationProcedure();
});
var APPLICATION_ID = '75RQSC1OHE';
var SEARCH_ONLY_API_KEY = 'f2f1e9bba4d7390fc61523a04685cf12';
var INDEX_NAME = 'locations';
var PARAMS = { hitsPerPage: 100 };
// Client + Helper initialization
var algolia = algoliasearch(APPLICATION_ID, SEARCH_ONLY_API_KEY);
var algoliaHelper = algoliasearchHelper(algolia, INDEX_NAME, PARAMS);
// Map initialization
var markers = [];
//alert("heelo");
var fitMapToMarkersAutomatically = true;
algoliaHelper.on('result', function(content) {
renderHits(content);
var i;
// Add the markers to the map
for (i = 0; i < content.hits.length; ++i) {
var hit = content.hits[i];
console.log(hit)
var marker = new google.maps.Marker({
position: {lat: hit.longitude, lng: hit.latitude},
map: map,
title: hit.slug
});
markers.push(marker);
}
// Automatically fit the map zoom and position to see the markers
if (fitMapToMarkersAutomatically) {
var mapBounds = new google.maps.LatLngBounds();
for (i = 0; i < markers.length; i++) {
mapBounds.extend(markers[i].getPosition());
}
map.fitBounds(mapBounds);
}
});
function renderHits(content) {
$('#container').html(JSON.stringify(content, null, 2));
}
algoliaHelper.setQueryParameter('aroundRadius', 5000).search(); // 5km Radius
});
However there are few problems with this that I don't know how to tackle:
When user is moving, it doesn't center the map on the marker.
At this moment marker jumps between location when user moves, I would like for the marker to dynamically move on the map when user moves.
I want to use algolia to dynamically set markers, so I want to show markers with 5km radius from user location, and dynamically add or remove markers that are outside it.
I can't help you much with those questions since it's mostly about how to use GMap JS lib and I'm not experienced with it. However, something else catched my eyes:
var marker = new google.maps.Marker({
position: {lat: hit.longitude, lng: hit.latitude},
map: map,
title: hit.slug
});
You should put your coordinates in the _geoloc field in order to be able to use the geo-search features. It looks like this:
_geoloc: {
lat: 40.639751,
lng: -73.778925
}

Custom Search box for Google map

I am developing web application using Google map JavaScript version. I need to add search box like Google Search box which is on Google map (like attached image). And I need to search custom places which are on my database.
If it is possible, how to do this?
This example adds a search box to a map, using the Google Place Autocomplete feature. People can enter geographical searches. The search box will return a pick list containing a mix of places and predicted search terms.
function initialize() {
var markers = [];
var map = new google.maps.Map(document.getElementById('map-canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-33.8902, 151.1759),
new google.maps.LatLng(-33.8474, 151.2631));
map.fitBounds(defaultBounds);
// Create the search box and link it to the UI element.
var input = /** #type {HTMLInputElement} */(
document.getElementById('pac-input'));
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
var searchBox = new google.maps.places.SearchBox(
/** #type {HTMLInputElement} */(input));
// Listen for the event fired when the user selects an item from the
// pick list. Retrieve the matching places for that item.
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces();
for (var i = 0, marker; marker = markers[i]; i++) {
marker.setMap(null);
}
// For each place, get the icon, place name, and location.
markers = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
var image = {
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
// Create a marker for each place.
var marker = new google.maps.Marker({
map: map,
icon: image,
title: place.name,
position: place.geometry.location
});
markers.push(marker);
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
});
// Bias the SearchBox results towards places that are within the bounds of the
// current map's viewport.
google.maps.event.addListener(map, 'bounds_changed', function() {
var bounds = map.getBounds();
searchBox.setBounds(bounds);
});
}
google.maps.event.addDomListener(window, 'load', initialize);

google maps api v3 places autocomplete only for selected city

when user starts to type city, autosuggest only suggests cities within 50 miles of tampa, FL (or anything else )
var southWest = new google.maps.LatLng( 28.3914,-81.936035 );
var northEast = new google.maps.LatLng( 28.3914,-81.936035 );
var hyderabadBounds = new google.maps.LatLngBounds( southWest, northEast );
var options = {
bounds: hyderabadBounds,
types: ['geocode'],
componentRestrictions: { country: 'us' }
};
var input1 = document.getElementById('search_header');
var autocomplete = new google.maps.places.Autocomplete(input1,options);
you are using the same LatLng for NorthEast and SouthWest of hyderabadBounds, use a LatLngBounds-object that encompasses the desired area, e.g.:
bounds: new google.maps.Circle({center:new google.maps.LatLng( 28.3914,-81.936035 ),
radius:50000}).getBounds()
Note: there is no guarantee that the Automplete restricts the results to the given bounds