I am using the Google Maps JavaScript API to create a heatmap layer. I would like to add mouseover events to 100+ locations on the map that will display an infowindow. This would get pretty cluttered if I used markers for every event, so I was hoping to find a way to eliminate markers altogether (although I did throw together an ugly mess of a solution in which a button will show/hide those markers). My first thought was to use the LatLngBounds. As a simple example:
var infowindow = new google.maps.InfoWindow(
{ content: "some info",
size: new google.maps.Size(50,50)
});
var southWest = new google.maps.LatLng(-31.203405,125.244141);
var northEast = new google.maps.LatLng(-25.363882,131.044922);
var loc = new google.maps.LatLngBounds(southWest,northEast);
google.maps.event.addListener(loc, 'mouseover', function() {
infowindow.open(map);
});
google.maps.event.addListener(loc, 'mouseout', function() {
infowindow.close();
});
For whatever reason, though, the mouseover event never seems to happen. Is there a problem with the code? Is there a better way to do this than by using LatLngBounds?
First of all, you should make a new rectangle with your bounds:
var southWest = new google.maps.LatLng(-31.203405,125.244141);
var northEast = new google.maps.LatLng(-25.363882,131.044922);
var loc = new google.maps.LatLngBounds(southWest,northEast);
var rectangle = new google.maps.Rectangle({
bounds: loc,
editable: false,
draggable: false,
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35
});
rectangle.setMap(map);
And then just use an event listener on that rectangle
google.maps.event.addListener(rectangle, 'mouseover', openInfoWindow);
function openInfoWindow(event) {
var ne = rectangle.getBounds().getNorthEast();
var sw = rectangle.getBounds().getSouthWest();
var content = 'Infowindow content';
// Set the info window's content and position.
infoWindow.setContent(contentString);
infoWindow.setPosition(ne);
infoWindow.open(map);
}
Related
I am trying to follow this tutorial to create a circle upon map on click event. Here is the initialization of the map under tab1.js:
function initMap() {
forecastmap = new google.maps.Map(document.getElementById('forecastmap'), {
center: {lat: 1.352083, lng: 103.81983600000001},
zoom: 11
});
forecastmap.addListener('click', function(e) {
createBuffer(e.latLng, forecastmap);
});
geocoder = new google.maps.Geocoder();
infowindow = new google.maps.InfoWindow();
}
Then inside my tab2.js where I perform all the logic to add the markers:
function createBuffer(coord, forecastmap) {
console.log('come in');
var marker = new google.maps.Marker({
position: coord,
map: forecastmap
});
clusterData.push(marker);
marker = new google.maps.Circle({
center: coord,
map: forecastmap,
strokeColor: '#000',
strokeWeight: 2,
strokeOpacity: 0.5,
fillColor: '#f0f0f0',
fillOpacity: 0.5,
radius: 20 * 1000
});
clusterData.push(marker);
}
I inserted a dummy message to check if the click event is registered. However, the message did not even printed out. I wonder which part of the code was wrong.
My HTML div:
<div class="box-body">
<div id="forecastmap" style="width:100%;height:350px" onclick="initMap();"></div>
</div>
Thanks!
Note that addListener is not a valid method, and you're either looking for the native addEventListener(), or Google's addDomListener().
I'm not too familiar with Google Maps, but considering the map is generated dynamically, the forecastmap variable may not available on page load. As such, you'll need to hoist the scope to an element that is available on page load, and make use of event delegation.
Instead of:
forecastmap.addListener('click', function(e) {
createBuffer(e.latLng, forecastmap);
});
You probably need something like:
document.getElementsByTagName('body')[0].addEventListener("click", function(e) {
// Check that the click target is #forecastmap
if (e.target && e.target.id == "forecastmap") {
createBuffer(e.latLng, forecastmap);
}
});
Hope this helps! :)
You have a click listener on the map div (the div with id="forecastmap"), that calls the initMap() function (onclick="initMap()"), recreating the map, losing any circle you may have added. If I remove that, and add a google.maps.event.addDomListenerOnce(document.getElementById("forecastmap"), ... that initialized the map on the first click (only), then I get markers and circles.
proof of concept fiddle
code snippet:
var forecastmap;
function initMap() {
forecastmap = new google.maps.Map(document.getElementById('forecastmap'), {
center: {
lat: 1.352083,
lng: 103.81983600000001
},
zoom: 11
});
forecastmap.addListener('click', function(e) {
createBuffer(e.latLng, forecastmap);
});
geocoder = new google.maps.Geocoder();
infowindow = new google.maps.InfoWindow();
}
// google.maps.event.addDomListener(window, 'load', function() {
google.maps.event.addDomListenerOnce(document.getElementById('forecastmap'), "click", initMap);
// });
function createBuffer(coord, forecastmap) {
console.log('come in');
var marker = new google.maps.Marker({
position: coord,
map: forecastmap
});
// clusterData.push(marker);
marker = new google.maps.Circle({
center: coord,
map: forecastmap,
strokeColor: '#000',
strokeWeight: 2,
strokeOpacity: 0.5,
fillColor: '#f0f0f0',
fillOpacity: 0.5,
radius: 20 * 1000
});
// clusterData.push(marker);
}
html,
body,
#forecastmap {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div class="box-body">
<div id="forecastmap" style="width:100%;height:350px"></div>
</div>
I have a problem with google maps on mobile browsers.
The project I'm working on requires about 500 markers to be shown on a map, but when adding them, the ui freezes.
I'm using markerclusterer to add markers, and performance is fine once the markers are on the page. Is there a way to add the markers asynchronously, or to pause adding markers once the user starts scrolling?
This is the code we're using:
var mcOptions = { gridSize: 50, maxZoom: 15, zoomOnClick: false };
var mc = new MarkerClusterer(context.map, [], mcOptions);
getMarkerLocations().then(function(branches){
branches.forEach(function(branch) => {
var marker = new google.maps.Marker({
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 2,
strokeColor: 'red',
fillColor: 'red',
strokeWeight: 2,
fillOpacity: 1
},
position: new google.maps.LatLng(branch.Latitude, branch.Longitude),
visible: true
});
mc.addMarker(marker);
});
});
Thank you geocodezip, that worked like a charm! For anyone else with the same problem, here's how I fixed it:
.then(function(branches){
var loopFunction = function(branchesToAdd) => {
if (branchesToAdd.length === 0) return;
var item = branchesToAdd.pop();
var marker = new google.maps.Marker({
....
});
mc.addMarker(marker);
setTimeout(function(){loopFunction(branchesToAdd)}, 30);
};
loopFunction(branchesToShow);
});
Add the markers asynchronously, use setTimeout to schedule the addition of each marker, which will give the browser some time to render and respond to the UI.
I created a google maps polyline
var flightPlanCoordinates = [new google.maps.LatLng(-27.46758, 153.027892), new google.maps.LatLng(37.772323, -122.214897), new google.maps.LatLng(29.46758, 88.027892), new google.maps.LatLng(20.46758, 97.027892), new google.maps.LatLng(17.772323, 78.214897)];
var flightPath = new google.maps.Polyline({
path: flightPlanCoordinates,
strokeColor: "rgba(255,0,0, .5)",
strokeOpacity: 1.0,
strokeWeight: 4
});
and I created an event (click for example) which displays a box with information. Sample code:
google.maps.event.addListener(flightPath, 'click', function(el) {
var curLat = el.latLng.lat();
var curLng = el.latLng.lng();
var myLatlng = new google.maps.LatLng(curLat,curLng);
infowindow.content = "<div style= ' width: 200px'>STRING HERE<div>";
infowindow.setPosition(myLatlng);
infowindow.open(map);
});
I've defined the infowindow globally so I can re-position it.
The problem now is that wherever I click it always displays the same information. Basically what I want to do is to get the line number clicked (starting form 0, 1 ..) and I can use it to get the appropriate data.
This information is not available via the API.
It would be possible to use the geometryy-library(isLocationOnEdge) and iterate over the single lines to detect on which line the click occurs, but I think it's easier to use single Polylines for each segment:
var flightPlanCoordinates = [
new google.maps.LatLng(-27.46758, 153.027892),
new google.maps.LatLng(37.772323, -122.214897),
new google.maps.LatLng(29.46758, 88.027892),
new google.maps.LatLng(20.46758, 97.027892),
new google.maps.LatLng(17.772323, 78.214897)
],i=0,infowindow=new google.maps.InfoWindow;
while(flightPlanCoordinates.length>1){
(function(i){
var segment= new google.maps.Polyline({
path: [flightPlanCoordinates.shift(),flightPlanCoordinates[0]],
strokeColor: "rgba(255,0,0, .5)",
strokeOpacity: 1.0,
strokeWeight: 4,
map:map
});
google.maps.event.addListener(segment, 'click', function(e){
infowindow.setOptions({map:map,position:e.latLng,content:'Line#'+i});
});
})(i++)
}
I have a map that uses infoBubble.js.
In this map there is an array of locations that I iterate through.
The infoBubble should pop up when the custom icon is clicked but for some reason it only ever opens up the first data item.
Does anyone have an idea as to why that may happen?
I have developed the code for it here;
var arrMarkers = [
['Santiago de Cuba', 20.040450354169483, -75.8331298828125],
['Las Tunas', 20.97682772467435, -76.9482421875],
['Camaguey', 21.39681937408218, -77.9205322265625],
['Playa Santa Lucia', 21.555284406923192, -77.0526123046875],
['Santa Clara', 22.421184710331854, -79.9639892578125],
['Cienfuegos', 22.161970614367977, -80.4473876953125],
['Havana', 23.12520549860231, -82.3919677734375],
['San Cristobel', 22.730590425493833, -83.045654296875],
['Pinar del Rio', 22.43641760076311, -83.69384765625]
];
var arrInfoWindowsCuba = [];
var arrInfoWindows = [];
arrMarkers[i] = marker;
function init() {
var mapCenter = new google.maps.LatLng(21.616579336740603, -78.892822265625);
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 7,
center: mapCenter,
mapTypeId: google.maps.MapTypeId.TERRAIN
});
var image = '/wp-content/themes/Shootcuba/images/map-icon.png';
for (i = 0; i < arrMarkers.length; i++) {
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(arrMarkers[i][1], arrMarkers[i][2]),
icon: image
});
var infoBubble = new InfoBubble({
content: '<div class="phoneytext">' + arrMarkers[i][0] + '<div class="left-col2"></div></div>',
boxClass: 'info-box',
alignBottom: true,
pixelOffset: new google.maps.Size(-150, -40),
maxWidth: 300,
padding: 0,
closeBoxMargin: '0px',
borderColor: '#ffffff',
borderRadius: '0',
maxWidth: 535,
disableAutoPan: false,
hideCloseButton: false,
backgroundClassName: 'phoney'
});
google.maps.event.addListener(marker, 'click', function () {
infoBubble.open(map, marker, i);
console.log(arrMarkers);
});
arrMarkers[i] = marker;
arrInfoWindowsCuba[i] = infoBubble;
}
}
Here's a working example. I took out a few of the arrays you had (I wasn't entirely sure what they were all for, and they were causing errors in just the snippet you posted), but otherwise is pretty true to what you were doing. The big difference is that I made a separate function for creating the markers. This was mainly done to keep the scope of the click events separate from one another, since the click event always triggering the last event indicates to me that the scopes aren't properly separate.
In particular, what I believe was happening is that the event function you kept overriding values to marker and infoBubble, and the event listener would refer to the current values of those variables, not the values when you first attach the listener. Making a separate function call to maintain the scope for the events strikes me as the cleanest solution.
aI know that this one is repeated question,
I am using google map v3 on my Django web based applicaiton. Where i am using Markers, Infowindow and polyline. Everything works fine, except the one when i click on a marker to show the content by Info window, the previous opened info window didn't closed.
I am posting the my map code(only the script part or which are the useful):
var marker = add_marker(flightPlanCoordinates[i][0], flightPlanCoordinates[i][1],"Event Detail",myHtml);
Here myHtml is a variable which contains the Info window content. I didn't define the variable here. SO ignore it.
marker.setMap(map);
}
var flightPath = new google.maps.Polyline({
path: flightPlanCoordinatesSet,
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 2
});
flightPath.setMap(map);
}
function add_marker(lat,lng,title,box_html) {
var infowindow = new google.maps.InfoWindow({
content: box_html
});
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat,lng),
map: map,
title: title
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map,this);
});
return marker;
}
Instead of multiple infoWindows use only one instance.
When clicking on a marker, first close the infoWindow, then set the new content and open the infoWindow.
function add_marker(lat,lng,title,box_html)
{
//create the global instance of infoWindow
if(!window.infowindow)
{
window.infowindow=new google.maps.InfoWindow();
}
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat,lng),
map: map,
title: title
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.close();
infowindow.setContent(box_html);
infowindow.open(map,this)
});
return marker;
}