Combining places search and kml layers with toggle on google maps api - google-maps-api-3

I am attempting to create a map with multiple kml layers that can be toggled with the google places search, but have been unsuccessful. The purpose of this is to have the ability to search an address or intersection and determine the correct response apparatus for fire or medical calls for a dispatch center, with the search being biased toward the correct county. I have the base map with just one layer working here, but I've been unable to correctly integrate the kml layer toggle with the google places search. I had received some good input from geocodezip on using the geocode function here, but I wasn't able to bias it towards the correct location or include the predictive search completion. I also like the way that my original map will zoom and center on the searched address and would like to maintain that functionality. Admittedly, I am very much lacking in ability with this, and everything I have done has been to simply copy and modify working examples that others have posted, but I have not found any working examples that include both the google places search and kml layers with toggle. This is what I have so far. Any help in getting this to work would be very much appreciated.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
.controls {
margin-top: 10px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#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: 300px;
}
#pac-input:focus {
border-color: #4d90fe;
}
.pac-container {
font-family: Roboto;
}
#type-selector {
color: #fff;
background-color: #4d90fe;
padding: 5px 11px 0px 11px;
}
#type-selector label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
</style>
<title>Advanced Backup Map</title>
<style>
#target {
width: 345px;
}
</style>
<script>
var kml = {
a: {
name: "Fire Response Areas",
url: "https://drive.google.com/uc?export=download&id=0B2gbIV1dXlvDVDhVLXc2N1Y5ZEE"
},
b: {
name: "SD Counties",
url: "https://drive.google.com/uc?export=download&id=0B2gbIV1dXlvDRndwdEpKTjRBeTA"
},
c: {
name: "Counties in Surrounding States",
url: "https://drive.google.com/uc?export=download&id=0B2gbIV1dXlvDRlhLTm93S2Y3eDQ"
}
// keep adding more if ye like
};
// 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 initAutocomplete() {
// lets define some vars to make things easier later
var options = {
center: new google.maps.LatLng(43.64837, -96.73737),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById('map'), options);
createTogglers();
// Append Class on Select
function highlight(box, listitem) {
var selected = 'selected';
var normal = 'normal';
document.getElementById(listitem).className = (box.checked ? selected : normal);
};
function startup() {
// for example, this toggles kml a on load and updates the menu selector
var checkit = document.getElementById('a');
checkit.checked = true;
toggleKML(checkit, 'a');
highlight(checkit, 'selector1');
};
// Create the search box and link it to the UI element.
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(43.38218, -97.29373),
new google.maps.LatLng(43.92451, -96.34532));
var input = document.getElementById('pac-input');
var searchBox = new google.maps.places.SearchBox(input, {
bounds: defaultBounds
});
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
// Bias the SearchBox results towards current map's viewport.
map.addListener('bounds_changed', function() {
searchBox.setBounds(map.getBounds());
});
var markers = [];
// [START region_getplaces]
// 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();
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();
places.forEach(function(place) {
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);
map.setZoom(16);
map.setCenter(center);
});
// [END region_getplaces]
// the important function... kml[id].xxxxx refers back to the top
function toggleKML(checked, id) {
if (checked) {
var layer = new google.maps.KmlLayer(kml[id].url, {
preserveViewport: true,
suppressInfoWindows: false
});
// store kml as obj
kml[id].obj = layer;
kml[id].obj.setMap(map);
}
else {
kml[id].obj.setMap(null);
delete kml[id].obj;
}
};
// create the controls dynamically because it's easier, really
function createTogglers() {
var html = "<form><ul>";
for (var prop in kml) {
html += "<li id=\"selector-" + prop + "\"><input type='checkbox' id='" + prop + "'" +
" onclick='highlight(this,\"selector-" + prop + "\"); toggleKML(this.checked, this.id)' \/>" +
kml[prop].name + "<\/li>";
}
document.getElementById("toggle_box").innerHTML = html;
};
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBhTQXonppCE2eVDQO5AHy11kMn-o27m_U&libraries=places&callback=initAutocomplete"
async defer></script>
</head>
<body>
<input id="pac-input" class="controls" type="text" placeholder="Search Box">
<div id="map"></div>
<div id="toggle_box" style="position: absolute; top: 10px; right: 10px; padding: 5px; background: #fff; z-index: 1; "></div>
</body>
</html>

Related

Hide/show google maps markers based on slider value compared to data value

First off, I don't know much about Google maps or Javascript and most of what I have so far is copied and pasted and stuck together from various tutorials (although I do understand what does what).
I have a map showing markers based on their location from a spreadsheet (via JSON feed). In this spreadsheet I also have a numerical value stored for each marker in data[i][4].
Finally have a bog standard html input type range slider and have the value of this stored in a global variable (slidervalue) that constantly updates as the slider moves.
As the slider moves, if the numerical value stored in the data for a marker is less than slidervalue that marker should be visible. If the data value is greater than slidervalue that marker should be hidden.
I assume this can be achieved using an if else statement and Google maps setvisible.
Here is my code so far:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Pound A Pint</title>
<style>
html, body {
margin: 0;
padding: 0;
width:100%;
height: 100%;
}
#map_canvas {
height: 100%;
width: calc(100% - 200px);
float:right;
}
#name {
float:left;
}
#price {
float:left;
}
#sliderAmount {
background-color: red;
display: inline-block;
}
</style>
<script src="https://maps.google.com/maps/api/js?sensor=false"></script>
<script>
// The web service URL from Drive 'Deploy as web app' dialog.
var DATA_SERVICE_URL = "https://script.google.com/macros/s/AKfycbwFFhKaVFHsr1g6sokrXd1kXPU0mbdKZzpVXE00X4CzS0nfng/exec?jsonp=callback";
var map;
var image = 'icon.png';
var slidervalue = 400;
function myFunction()
{
document.getElementById("sliderAmount").innerHTML= slidervalue;
}
function initialize() {
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(51.5, -0.1),
zoom: 12,
mapTypeControl: false,
panControl: false,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.default,
position: google.maps.ControlPosition.LEFT_BOTTOM
}
});
var scriptElement = document.createElement('script');
scriptElement.src = DATA_SERVICE_URL;
document.getElementsByTagName('head')[0].appendChild(scriptElement);
}
function callback(data) {
for (var i = 0; i < data.length; i++) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(data[i][3], data[i][2]),
map: map,
icon: image
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
document.getElementById("name").innerHTML= data[i][0];
document.getElementById("pricespan").innerHTML= data[i][4];
}
})(marker, i));
}
}
function updateSlider(slideAmount) {
slidervalue = slideAmount;
document.getElementById("slidervalue").innerHTML = slidervalue;
}
</script>
</head>
<body onload="initialize()">
<div id="name">Name</div>
<div id="price">£<span id="pricespan"></span></div>
<input id="slide" type="range" min="1" max="500" step="1" value="400" onchange="updateSlider(this.value)">
<div onclick="myFunction()" id="sliderAmount">Click me</div>
<div id="slidervalue"></div>
<div id="map_canvas"></div>
</body>
</html>
Thanks for any help.
create a global accessible array:
markers=[];
store the markers in this array, and store the numeric value as a property of the markers:
var marker = new google.maps.Marker({
position: new google.maps.LatLng(data[i][3], data[i][2]),
map: map,
value:data[i][4],
visible:slidervalue >= data[i][4]
});
markers.push(marker);
in updateSlider iterate over the array and set the visible-property depending on the comparision:
function updateSlider(slideAmount) {
for(var i=0;i<markers.length;++i){
markers[i].setVisible(slideAmount>=markers[i].get('value'));
}
slidervalue = slideAmount;
document.getElementById("slidervalue").innerHTML = slidervalue;
}

Google Places API mapping a company

I'm trying to plot a marker in a Google Map where a company is, so for example I am looking for the Apple Store in Aberdeen, Scotland I would like a marker there and when I click the marker it will show the info window with the company details which is generated from Google with reviews etc.
I can't find any documentation on how to do this, but the closest I found is a Company Lookup which then points you to the location. I'd rather be able to cut out the start and just have the company name already in the code and pointing the map straight to the location.
Could anyone possibly help at all? Thanks
<!DOCTYPE html>
<html>
<head>
<title>Place Autocomplete</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
html, body, #map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
.controls {
margin-top: 16px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#pac-input {
background-color: #fff;
padding: 0 11px 0 13px;
width: 400px;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
text-overflow: ellipsis;
}
#pac-input:focus {
border-color: #4d90fe;
margin-left: -1px;
padding-left: 14px; /* Regular padding-left + 1. */
width: 401px;
}
.pac-container {
font-family: Roboto;
}
#type-selector {
color: #fff;
background-color: #4d90fe;
padding: 5px 11px 0px 11px;
}
#type-selector label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=places"></script>
<script>
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(-33.8688, 151.2195),
zoom: 13
};
var map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
var input = /** #type {HTMLInputElement} */(
document.getElementById('pac-input'));
var types = document.getElementById('type-selector');
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(types);
var autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.bindTo('bounds', map);
var infowindow = new google.maps.InfoWindow();
var marker = new google.maps.Marker({
map: map
});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
infowindow.close();
marker.setVisible(false);
var place = autocomplete.getPlace();
if (!place.geometry) {
return;
}
// If the place has a geometry, then present it on a map.
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17); // Why 17? Because it looks good.
}
marker.setIcon(/** #type {google.maps.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(35, 35)
}));
marker.setPosition(place.geometry.location);
marker.setVisible(true);
var address = '';
if (place.address_components) {
address = [
(place.address_components[0] && place.address_components[0].short_name || ''),
(place.address_components[1] && place.address_components[1].short_name || ''),
(place.address_components[2] && place.address_components[2].short_name || '')
].join(' ');
}
infowindow.setContent('<div><strong>' + place.name + '</strong><br>' + address);
infowindow.open(map, marker);
});
// Sets a listener on a radio button to change the filter type on Places
// Autocomplete.
function setupClickListener(id, types) {
var radioButton = document.getElementById(id);
google.maps.event.addDomListener(radioButton, 'click', function() {
autocomplete.setTypes(types);
});
}
setupClickListener('changetype-all', []);
setupClickListener('changetype-establishment', ['establishment']);
setupClickListener('changetype-geocode', ['geocode']);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<input id="pac-input" class="controls" type="text"
placeholder="Enter a location">
<div id="type-selector" class="controls">
<input type="radio" name="type" id="changetype-all" checked="checked">
<label for="changetype-all">All</label>
<input type="radio" name="type" id="changetype-establishment">
<label for="changetype-establishment">Establishments</label>
<input type="radio" name="type" id="changetype-geocode">
<label for="changetype-geocode">Geocodes</label>
</div>
<div id="map-canvas"></div>
</body>
</html>
The "google" infowindow isn't available from the Places API, you need to build it yourself from the information available in the places details response or link to a google map.

Highlight a area with Google Maps JavaScript API v3

I want to highlight a area like on the image below which is taken from Google Maps. Is this possible to accomplish with the current version of their API (v3)? If yes, how?
Thanks in advance.
You need to know the vertices of the area and create a polygon based on them.
But dashed strokes currently are not supported by polygons, if you require to have a dashed stroke you must create a sequence of polylines with different stroke-colors based on the vertices.
A built-in method to highlight an area currently doesn't exist.
You can automatically highlight an area with Google Maps Javascript API, here is an example:
<!DOCTYPE html>
<html>
<head>
<title>Place ID Finder</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
#map {
height: 100%;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#ggg
{
position: absolute;
left:20%;
top:5%;
}
.controls {
background-color: #fff;
border-radius: 2px;
border: 1px solid transparent;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
box-sizing: border-box;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
height: 29px;
margin-left: 17px;
margin-top: 10px;
outline: none;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 400px;
}
.controls:focus {
border-color: #4d90fe;
}
.title {
font-weight: bold;
}
#infowindow-content {
display: none;
}
#map #infowindow-content {
display: inline;
}
</style>
</head>
<body>
<div style="display: none">
<input id="pac-input" class="controls" type="text" placeholder="Enter a location">
</div>
<div id="map"></div>
<div id="infowindow-content">
<span id="place-name" class="title"></span><br>
<strong>Place ID:</strong> <span id="place-id"></span><br>
<span id="place-address"></span>
</div>
<script>
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 37.9989746, lng: 23.6413698},
zoom: 11
});
var input = document.getElementById('pac-input');
var autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.bindTo('bounds', map);
autocomplete.setFields(
['place_id', 'geometry', 'name', 'formatted_address']);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
var infowindow = new google.maps.InfoWindow();
var infowindowContent = document.getElementById('infowindow-content');
infowindow.setContent(infowindowContent);
var marker = new google.maps.Marker({map: map});
marker.addListener('click', function() {
infowindow.open(map, marker);
});
autocomplete.addListener('place_changed', function() {
infowindow.close();
var place = autocomplete.getPlace();
if (!place.geometry) {
return;
}
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
marker.setPlace({
placeId: place.place_id,
location: place.geometry.location,
});
marker.setVisible(true);
infowindowContent.children['place-name'].textContent = place.name;
infowindowContent.children['place-id'].textContent = place.place_id;
infowindowContent.children['place-address'].textContent = place.formatted_address;
infowindow.open(map, marker);
var frame = document.getElementById("map");
frame.innerHTML = '<iframe width="100%" height="100%" frameborder="0" style="border:0" src="https://www.google.com/maps/embed/v1/place?q=place_id:'.concat(place.place_id).concat('&key=XXXXXXX" allowfullscreen></iframe>');
frame.innerHTML += '<p id="ggg"><button type="button" onclick="location.reload()">Try again!</button></p>';
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXX&libraries=places&callback=initMap" async defer></script>
</body>
</html>
You will need to replace API KEY with your API KEY. Try e.g."Nea Smyrni 171 21, Greece" in the input and then select the first drop down option and notice that it automatically highlights the area!

How can I vertically align a Google StreetView display with text, inside an infowindow?

This is unnecessarily difficult, thanks to CSS's vertical-align: middle oddities. I understand (though counter-intuitive) that if you want to vertically center text next to an image, you must do this to the image and not the text...
It seems that this approach only works when the text is in a span container, the image is defined by an img tag, and they are both within a div container.
That being said, I have an infowindow in Google Maps that contains an address (text) to the left of a Google StreetView display (image?). However, instead of the img tag the street view object is in a span container.
Here is the relevant code:
<!DOCTYPE html>
<html>
<head>
<title>address and street-view inside an infowindow</title>
<style type = "text/css">
*
{
margin: 0px;
padding: 0px;
}
html, body
{
height: 100%;
}
#map_canvas
{
min-height: 100%;
}
/* inside infowindow */
#userAddress
{
float: left;
}
#street_canvas
{
float: right;
width: 100px;
height: 100px;
vertical-align: middle;
}
</style>
</head>
<body>
<!-- map here -->
<div id = "map_canvas"></div>
<!-- Google Maps API -->
<script type = "text/javascript" src = "http://maps.googleapis.com/maps/api/js?&sensor=true&v=3.9"></script>
<script type = "text/javascript">
var map;
initialize();
function initialize()
{
var mapOptions =
{
center: new google.maps.LatLng(37.09024, -95.712891), // coordinates for center of the United States
zoom: 4, // smaller number --> zoom out
mapTypeId: google.maps.MapTypeId.TERRAIN // ROADMAP, SATELLITE, TERRAIN, or HYBRID
};
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
} // end of initialize
var coordinates = new google.maps.LatLng(37.414341, -122.07692159999999);
var address = "1401 North Shoreline Boulevard Mountain View, CA 94043";
setMarker(coordinates, address);
function setMarker(userCoordinates, userAddress)
{
var panorama = null;
// user address map marker created here
var marker = new google.maps.Marker(
{
map: map, // from the global variable
position: userCoordinates
});
// infowindow created here
var windowInfo = "<div>" +
"<span id = 'userAddress'>" + userAddress + "</span>" +
"<span id = 'street_canvas'></span>" +
"</div>";
var infoWindow = new google.maps.InfoWindow(
{
content: windowInfo
});
function setStreetView(infoWindow, userCoordinates)
{
google.maps.event.addListener(infoWindow, "domready", function()
{
if(panorama !== null)
{
panorama.unbind("position");
panorama.setVisible(false);
}
// options for streetview inside map marker
var panoramaOptions =
{
position: userCoordinates,
pov:
{
heading: 45, // northwest in degrees
zoom: 1,
pitch: 1 // 0 degrees is level
},
// removing all map controls
addressControl: false,
clickToGo: false,
enableCloseButton: false,
imageDateControl: false,
linksControl: false,
panControl: false,
scrollwheel: false,
zoomControl: false,
disableDoubleClickZoom: true
};
// initializing streetview and settings to global variable
panorama = new google.maps.StreetViewPanorama(document.getElementById("street_canvas"), panoramaOptions);
panorama.bindTo("position", marker);
panorama.setVisible(true);
});
} // end of setStreetView
setStreetView(infoWindow, userCoordinates);
// event listener for infowindow of map marker, onclick
google.maps.event.addListener(marker, "click", function()
{
infoWindow.open(map, this);
map.panTo(this.position);
});
// event listener for closing infowindow of map marker
google.maps.event.addListener(infoWindow, "closeclick", function()
{
// disable streetview, with the global variable
panorama.unbind("position");
panorama.setVisible(false);
panorama = null;
});
} // end of setMarker
</script>
</body>
</html>
See this for a reference on putting a streetview display inside of an infowindow.
So, it was much much easier than I thought -- a line-height attribute must be set in the CSS for the text, equal to the height specified by the streetview div. And that's it, the text is then "vertically centered":
/* inside the infowindow */
#userAddress
{
float: left;
line-height: 100px;
}
#street_canvas
{
float: right;
width: 100px;
height: 100px;
}
There is no need for vertical-align: middle in this case.

Styling Google Maps InfoWindow

I've been attempting to style my Google Maps InfoWindow, but the documentation is very limited on this topic. How do you style an InfoWindow?
Google wrote some code to assist with this. Here are some examples: Example using InfoBubble, Styled markers and Info Window Custom (using OverlayView).
The code in the links above take different routes to achieve similar results. The gist of it is that it is not easy to style InfoWindows directly, and it might be easier to use the additional InfoBubble class instead of InfoWindow, or to override GOverlay. Another option would be to modify the elements of the InfoWindow using javascript (or jQuery), like later ATOzTOA suggested.
Possibly the simplest of these examples is using InfoBubble instead of InfoWindow. InfoBubble is available by importing this file (which you should host yourself): http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobubble/src/infobubble.js
InfoBubble's Github project page.
InfoBubble is very stylable, compared to InfoWindow:
infoBubble = new InfoBubble({
map: map,
content: '<div class="mylabel">The label</div>',
position: new google.maps.LatLng(-32.0, 149.0),
shadowStyle: 1,
padding: 0,
backgroundColor: 'rgb(57,57,57)',
borderRadius: 5,
arrowSize: 10,
borderWidth: 1,
borderColor: '#2c2c2c',
disableAutoPan: true,
hideCloseButton: true,
arrowPosition: 30,
backgroundClassName: 'transparent',
arrowStyle: 2
});
infoBubble.open();
You can also call it with a given map and marker to open on:
infoBubble.open(map, marker);
As another example, the Info Window Custom example extends the GOverlay class from the Google Maps API and uses this as a base for creating a more flexible info window. It first creates the class:
/* An InfoBox is like an info window, but it displays
* under the marker, opens quicker, and has flexible styling.
* #param {GLatLng} latlng Point to place bar at
* #param {Map} map The map on which to display this InfoBox.
* #param {Object} opts Passes configuration options - content,
* offsetVertical, offsetHorizontal, className, height, width
*/
function InfoBox(opts) {
google.maps.OverlayView.call(this);
this.latlng_ = opts.latlng;
this.map_ = opts.map;
this.offsetVertical_ = -195;
this.offsetHorizontal_ = 0;
this.height_ = 165;
this.width_ = 266;
var me = this;
this.boundsChangedListener_ =
google.maps.event.addListener(this.map_, "bounds_changed", function() {
return me.panMap.apply(me);
});
// Once the properties of this OverlayView are initialized, set its map so
// that we can display it. This will trigger calls to panes_changed and
// draw.
this.setMap(this.map_);
}
after which it proceeds to override GOverlay:
InfoBox.prototype = new google.maps.OverlayView();
You should then override the methods you need: createElement, draw, remove and panMap. It gets rather involved, but in theory you are just drawing a div on the map yourself now, instead of using a normal Info Window.
You can modify the whole InfoWindow using jquery alone...
var popup = new google.maps.InfoWindow({
content:'<p id="hook">Hello World!</p>'
});
Here the <p> element will act as a hook into the actual InfoWindow. Once the domready fires, the element will become active and accessible using javascript/jquery, like $('#hook').parent().parent().parent().parent().
The below code just sets a 2 pixel border around the InfoWindow.
google.maps.event.addListener(popup, 'domready', function() {
var l = $('#hook').parent().parent().parent().siblings();
for (var i = 0; i < l.length; i++) {
if($(l[i]).css('z-index') == 'auto') {
$(l[i]).css('border-radius', '16px 16px 16px 16px');
$(l[i]).css('border', '2px solid red');
}
}
});
You can do anything like setting a new CSS class or just adding a new element.
Play around with the elements to get what you need...
I used the following code to apply some external CSS:
boxText = document.createElement("html");
boxText.innerHTML = "<head><link rel='stylesheet' href='style.css'/></head><body>[some html]<body>";
infowindow.setContent(boxText);
infowindow.open(map, marker);
google.maps.event.addListener(infowindow, 'domready', function() {
// Reference to the DIV that wraps the bottom of infowindow
var iwOuter = $('.gm-style-iw');
/* Since this div is in a position prior to .gm-div style-iw.
* We use jQuery and create a iwBackground variable,
* and took advantage of the existing reference .gm-style-iw for the previous div with .prev().
*/
var iwBackground = iwOuter.prev();
// Removes background shadow DIV
iwBackground.children(':nth-child(2)').css({'display' : 'none'});
// Removes white background DIV
iwBackground.children(':nth-child(4)').css({'display' : 'none'});
// Moves the infowindow 115px to the right.
iwOuter.parent().parent().css({left: '115px'});
// Moves the shadow of the arrow 76px to the left margin.
iwBackground.children(':nth-child(1)').attr('style', function(i,s){ return s + 'left: 76px !important;'});
// Moves the arrow 76px to the left margin.
iwBackground.children(':nth-child(3)').attr('style', function(i,s){ return s + 'left: 76px !important;'});
// Changes the desired tail shadow color.
iwBackground.children(':nth-child(3)').find('div').children().css({'box-shadow': 'rgba(72, 181, 233, 0.6) 0px 1px 6px', 'z-index' : '1'});
// Reference to the div that groups the close button elements.
var iwCloseBtn = iwOuter.next();
// Apply the desired effect to the close button
iwCloseBtn.css({opacity: '1', right: '38px', top: '3px', border: '7px solid #48b5e9', 'border-radius': '13px', 'box-shadow': '0 0 5px #3990B9'});
// If the content of infowindow not exceed the set maximum height, then the gradient is removed.
if($('.iw-content').height() < 140){
$('.iw-bottom-gradient').css({display: 'none'});
}
// The API automatically applies 0.7 opacity to the button after the mouseout event. This function reverses this event to the desired value.
iwCloseBtn.mouseout(function(){
$(this).css({opacity: '1'});
});
});
//CSS put in stylesheet
.gm-style-iw {
background-color: rgb(237, 28, 36);
border: 1px solid rgba(72, 181, 233, 0.6);
border-radius: 10px;
box-shadow: 0 1px 6px rgba(178, 178, 178, 0.6);
color: rgb(255, 255, 255) !important;
font-family: gothambook;
text-align: center;
top: 15px !important;
width: 150px !important;
}
I have design google map infowindow with image & some content as per below.
map_script (Just for infowindow html reference)
for (i = 0; i < locations.length; i++) {
var latlng = new google.maps.LatLng(locations[i][1], locations[i][2]);
marker = new google.maps.Marker({
position: latlng,
map: map,
icon: "<?php echo plugins_url( 'assets/img/map-pin.png', ELEMENTOR_ES__FILE__ ); ?>"
});
var property_img = locations[i][6],
title = locations[i][0],
price = locations[i][3],
bedrooms = locations[i][4],
type = locations[i][5],
listed_on = locations[i][7],
prop_url = locations[i][8];
content = "<div class='map_info_wrapper'><a href="+prop_url+"><div class='img_wrapper'><img src="+property_img+"></div>"+
"<div class='property_content_wrap'>"+
"<div class='property_title'>"+
"<span>"+title+"</span>"+
"</div>"+
"<div class='property_price'>"+
"<span>"+price+"</span>"+
"</div>"+
"<div class='property_bed_type'>"+
"<span>"+bedrooms+"</span>"+
"<ul><li>"+type+"</li></ul>"+
"</div>"+
"<div class='property_listed_date'>"+
"<span>Listed on "+listed_on+"</span>"+
"</div>"+
"</div></a></div>";
google.maps.event.addListener(marker, 'click', (function(marker, content, i) {
return function() {
infowindow.setContent(content);
infowindow.open(map, marker);
}
})(marker, content, i));
}
Most important thing is CSS
#propertymap .gm-style-iw{
box-shadow:none;
color:#515151;
font-family: "Georgia", "Open Sans", Sans-serif;
text-align: center;
width: 100% !important;
border-radius: 0;
left: 0 !important;
top: 20px !important;
}
#propertymap .gm-style > div > div > div > div > div > div > div {
background: none!important;
}
.gm-style > div > div > div > div > div > div > div:nth-child(2) {
box-shadow: none!important;
}
#propertymap .gm-style-iw > div > div{
background: #FFF!important;
}
#propertymap .gm-style-iw a{
text-decoration: none;
}
#propertymap .gm-style-iw > div{
width: 245px !important
}
#propertymap .gm-style-iw .img_wrapper {
height: 150px;
overflow: hidden;
width: 100%;
text-align: center;
margin: 0px auto;
}
#propertymap .gm-style-iw .img_wrapper > img {
width: 100%;
height:auto;
}
#propertymap .gm-style-iw .property_content_wrap {
padding: 0px 20px;
}
#propertymap .gm-style-iw .property_title{
min-height: auto;
}
Use the InfoBox plugin from the Google Maps Utility Library. It makes styling/managing map pop-ups much easier.
Note that you'll need to make sure it loads after the google maps API:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY&callback=initMap" async defer></script>
<script src="/js/infobox_packed.js" async defer></script>
Map InfoWindow supports html and css.
I usually create html string with css class. So I can attach any style I want to.
var contentString = '<div>Any Html here</div>';
marker.infowindow = new google.maps.InfoWindow({
content: contentString,
});
Here is the ref.
You could use a css class too.
$('#hook').parent().parent().parent().siblings().addClass("class_name");
Good day!

Resources