Reputation: 11
I'm having problems getting google's searchbox service to run properly for me.
What I have is a map with a polygon drawn on it. I would like to use the searchbox and/or autocomplete service to return ONLY business of the specified type (e.g. restaurants, fast food, warehouses, etc.) that are within this polygons boundaries.
I can use the nearby service to return results based on type or keyword. I can also get the searchbox to return results for restaurants; however, if I update the search to look for other businesses, such as warehouses, the map zooms out and shows warehouses all over the world.
Here is a working fiddle example:
<html>
<head>
<meta charset="utf-8">
<title>Transition Center Online</title>
<meta name="description" content="">
<meta name="title" content="">
<meta name="author" content="WWRF">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#map {
height: 600px;
width: 100%;
}
#description {
font-family: Roboto;
font-size: 15px;
font-weight: 300;
}
#infowindow-content .title {
font-weight: bold;
}
#infowindow-content {
display: none;
}
#map #infowindow-content {
display: inline;
}
.pac-card {
margin: 10px 10px 0 0;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
background-color: #fff;
font-family: Roboto;
}
#pac-container {
padding-bottom: 12px;
margin-right: 12px;
}
.pac-controls {
display: inline-block;
padding: 5px 11px;
}
.pac-controls label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
#pac-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 400px;
}
#pac-input:focus {
border-color: #4d90fe;
}
#title {
color: #fff;
background-color: #4d90fe;
font-size: 25px;
font-weight: 500;
padding: 6px 12px;
}
#target {
width: 345px;
}
</style>
</head>
<body>
<div class="container">
<p>TODO: Add Google JavaScript Map with walkroute outline.</p>
<p>TODO: List walking times</p>
<p>TODO: List common walk routes and businesses</p>
<!-- where the map will live -->
<input id="pac-input" class="controls" type="text" placeholder="Search Box">
<div id="map"></div>
</div>
<script>
// 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">
var map;
var infowindow;
function initMap() {
var wwrf = {
lat: 37.682319,
lng: -97.333311
};
map = new google.maps.Map(document.getElementById('map'), {
center: wwrf,
zoom: 14
});
var squareCoords = [
{lat: 37.697465, lng: -97.341629},
{lat: 37.697636, lng: -97.317306},
{lat: 37.671759, lng: -97.317142},
{lat: 37.673308, lng: -97.352833},
{lat: 37.693239, lng: -97.352852}
];
// Construct the walkroute polygon.
var walkRoute = new google.maps.Polygon({
paths: squareCoords,
strokeColor: '#008000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#008000',
fillOpacity: 0.1
});
walkRoute.setMap(map);
infowindow = new google.maps.InfoWindow();
var service = new google.maps.places.PlacesService(map);
service.nearbySearch({
location: wwrf,
radius: 1600,
type: ['establishment'],
//keyword: ['restaurant']
}, callback);
var walkRouteBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(37.673308, -97.352833),
new google.maps.LatLng(37.697636, -97.317306),
);
var options = {
bounds: walkRouteBounds,
strictBounds: true
};
// Create the search box and link it to the UI element.
var input = document.getElementById('pac-input');
var searchBox = new google.maps.places.SearchBox(input, options);
map.controls[google.maps.ControlPosition.TOP_CENTER].push(input);
var markers = [];
// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
searchBox.addListener('places_changed', function() {
var places = searchBox.getPlaces();
searchBox.setBounds(walkRouteBounds);
if (places.length == 0) {
return;
}
// Clear out the old markers.
markers.forEach(function(marker) {
marker.setMap(null);
});
markers = [];
// For each place, get the icon, name and location.
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(37.673308, -97.352833),
new google.maps.LatLng(37.697636, -97.317306),
);
places.forEach(function(place) {
if (!place.geometry) {
console.log("Returned place contains no geometry");
return;
}
var icon = {
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.
markers.push(new google.maps.Marker({
map: map,
//icon: icon,
title: place.name,
position: place.geometry.location
}));
if (place.geometry.viewport) {
// Only geocodes have viewport.
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
});
map.fitBounds(bounds);
});
}
function callback(results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
createMarker(results[i]);
}
}
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent('<strong>' + place.name + '</strong><br/>' + place.formatted_address);
infowindow.open(map, this);
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=your_api&libraries=places&callback=initMap" async defer></script>
</body>
EDIT: Alright so I have been able to come up with a solution using a dropdown box, although it is not ideal because I have to hard code my keywords.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Walkroute Dropdown</title>
<meta name="description" content="">
<meta name="title" content="">
<meta name="author" content="WWRF">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#map {
height: 600px;
width: 100%;
}
#description {
font-family: Roboto;
font-size: 15px;
font-weight: 300;
}
#infowindow-content .title {
font-weight: bold;
}
#infowindow-content {
display: none;
}
#map #infowindow-content {
display: inline;
}
.pac-card {
margin: 10px 10px 0 0;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
background-color: #fff;
font-family: Roboto;
}
#pac-container {
padding-bottom: 12px;
margin-right: 12px;
}
.pac-controls {
display: inline-block;
padding: 5px 11px;
}
.pac-controls label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
#pac-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 400px;
}
#pac-input:focus {
border-color: #4d90fe;
}
#title {
color: #fff;
background-color: #4d90fe;
font-size: 25px;
font-weight: 500;
padding: 6px 12px;
}
#target {
width: 345px;
}
</style>
</head>
<body>
<div class="container">
<select name="mapchange" onchange="updateMap(this.options[this.selectedIndex].value)">
<option value="restaurants">Restaurants</option>
<option value="warehouses">Warehouses</option>
<option value="temp services">Temp Services</option>
</select>
<!-- where the map will live -->
<div id="map"></div>
</div>
<script>
// 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">
var map;
var infowindow;
var wwrf = {
lat: 37.682319,
lng: -97.333311
};
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: wwrf,
zoom: 14
});
var squareCoords = [
{lat: 37.697465, lng: -97.341629},
{lat: 37.697636, lng: -97.317306},
{lat: 37.671759, lng: -97.317142},
{lat: 37.673308, lng: -97.352833},
{lat: 37.693239, lng: -97.352852}
];
// Construct the walkroute polygon.
var walkRoute = new google.maps.Polygon({
paths: squareCoords,
strokeColor: '#008000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#008000',
fillOpacity: 0.1
});
walkRoute.setMap(map);
infowindow = new google.maps.InfoWindow();
/*var service = new google.maps.places.PlacesService(map);
service.nearbySearch({
location: wwrf,
radius: 1600,
type: ['establishment'],
keyword: ['restaurant']
}, callback);*/
}
var markers = [];
function callback(results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
createMarker(results[i]);
}
}
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
// Create a marker for each place.
markers.push(marker);
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent('<strong>' + place.name + '</strong><br/>' + place.formatted_address);
infowindow.open(map, this);
});
}
function updateMap(selectControl) {
// Clear out the old markers.
markers.forEach(function(marker) {
marker.setMap(null);
});
markers = [];
var keyword = selectControl;
var service = new google.maps.places.PlacesService(map);
service.nearbySearch({
location: wwrf,
radius: 1600,
type: ['establishment'],
keyword: keyword
}, callback);
}
function clearMarkers() {
for (var i = 0; i < markersArray.length; i++ ) {
markersArray[i].setMap(null);
}
markersArray.length = 0;
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=your_api&libraries=places&callback=initMap" async defer></script>
</body>
</html>
And here's a link to the fiddle: Walkroute dropdown
Upvotes: 0
Views: 1138
Reputation: 32100
I can see that you try to initialize the SearchBox with strictBounds: true
option, but unfortunately, the SearchBox doesn't support strict bounds filter at current moment. If you can switch to the Autocomplete, it is indeed supports strict bounds and you can initialize the autocomplete like
var options = {
bounds: walkRouteBounds,
strictBounds: true,
types: ['establishment']
};
var input = document.getElementById('pac-input');
var autocomplete = new google.maps.places.Autocomplete(input, options);
Regarding the strict bounds for SearchBox, there is a feature request in Google issue tracker:
https://issuetracker.google.com/issues/67982212
Feel free to star the feature request to add your vote and subscribe to notifications.
Upvotes: 1
Reputation: 1094
Ok ,I've been looking to this for a while and here comes a possible solution that I thought:
So inside the For loop in the callback Function may I suggest before creating a marker to ask (with a IF and I think there is a method called contains that returns a boolean) if the place.geometry.location is inside your bounds, so if the place is not inside your bounds then you do not create that marker, therefore the map won't zoom out.
Another solution would be forcing the zoom to a value after the autocomplete search.
I hope with this you could find a solution to your issue.
Upvotes: 0