Meteor: modals and google maps - google-maps

I am displaying a google map in a modal and I see lots of people have had this issue and there seems to be a fix but so far nothing I've tried has worked.
Basically I am loading googles places search in Template.map.rendered - it seems like something is happening with the DIVs because when I resize the window it re-renders and displays properly.
Now, I have tried all kinds of tricks (hiding / showing various DIVs), calling google.maps.event.trigger(map, "resize"); etc.
The map template is being loaded into another template that is a form (with other fields etc).
If someone could point me in a fruitful direction that would be awesome - seems like it should be a simple fix but I'm stumped.
Thanks!

You're in luck, we just solved our issue regarding this. Assuming the template map is called within a modal:
Template.map.rendered = function() {
Tracker.autorun(function() {
Session.set('map_available', true);
var center = {
latitude: -1.8445
longitude: 52.9445
}; // end var center
var zoomLevel = 15;
if(Session.equals('map_available', true)) {
GoogleMaps.init({'sensor': true, 'key' : 'OPTIONAL_KEY' },
function() {
var mapOptions = {
zoom: zoomLevel,
minZoom: 15,
maxZoom: 20,
mapTypeId: google.maps.MapTypeId.ROADMAP,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.SMALL
};
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
map.setCenter(new google.maps.LatLng( center.latitude, center.longitude ));
} // end closure param 2 of GoogleMaps init
}); // end GoogleMaps.init
} // end Session.equals 'map_available'
} //end Tracker.autorun
} // end Template.map.rendered
Template.map.destroyed = function() {
Session.set('map_available', false);
}
So the strategy here is to monitor dependency tracking independently and make sure it gets re-added after any DOM reactions. Bonus feature here is that if you include var center modification inside Tracker.autorun (e.g. var center = navigator.location) you will have a map that changes center when you move around (lat, long has changed).
Also, we used the extension mrt:googlemaps for the GoogleMaps integration. Seems to be the best one to use.

Had the same problem that stumped me for an hour. My easy fix was to wrap it in a window onload. Try it, you might like it :-)
Template.mapsAutoComplete.rendered = function() {
window.onload = function () {
var map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
...
};
};

Related

Race conditions in Google Maps loading

I've been having a problem and no amount of googling has led to an answer. I'm building a web application that uses google maps and I keep getting race condition errors after initializing the map. I'm trying to just get the bounds of the map when the page loads, so I can use those boundaries to get data from my API. The problem is that I get incorrect bounds about 20% of the time.
The main things I'm trying to figure out is:
When exactly is a map initialized so I can use it properly?
Is having a fluid map container causing problems?
Is angular.js causing problems for some reason.
The map is assigned to a div called map-canvas which is inside an absolutely positioned map-container
#map-container{
position:absolute;
background-color:#DDD;
top:0px;
bottom:0px;
left:450px;
right:0px;
}
#map-canvas{
width:100%;
height:100%;
}
I'm using jQuery's $(function(){}) method to be notified when the page is loaded. Then I call my initMap() function to initialize the map, where myLatLng is already defined. In order to detect when the map is initialized, I'm adding an 'idle' listener. The autopanning part is for detecting when a user is in the process of dragging the map.
$scope.initMap = function(){
var mapOptions = {
center: myLatLng,
zoom: 14,
mapTypeId: google.maps.MapTypeId.ROADMAP,
panControl: false,
streetViewControl: false,
mapTypeControl: false
};
$scope.map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
google.maps.event.addListener($scope.map, 'idle', function() {
if($scope.autoPanning){
$scope.autoPanning = false;
}else{
$scope.getStories();
}
});
};
In my getStories() method, I get the bounds of the map so I can submit a query to my service. The problem is that latitude_1 will equal latitude_2, giving me essentially a line instead of a box as bounds. This is what I'm currently doing to catch and fix that error:
var bounds = map.getBounds();
var ne = bounds.getNorthEast();
var sw = bounds.getSouthWest();
var bounds = {
latitude_1 : ne.lat(),
longitude_1 : ne.lng(),
latitude_2 : sw.lat(),
longitude_2 : sw.lng()
};
if(bounds.latitude_1 == bounds.latitude_2){
line("---caught invalid map event---------------------");
google.maps.event.trigger($scope.map, 'resize');
setTimeout(function(){
google.maps.event.trigger($scope.map, "resize");
$scope.map.setCenter(myLatlng);
}, 1000);
return;
}
I'm catching that invalid latitudes issue about 20% of the time, and it's really frustrating. Can anyone shine light on this issue?
I finally figured out what the problem was. It was based on a misunderstanding on my part about the $(document).ready and $(window).load:
$(document).ready is fired when the DOM is ready for interaction.
$(window).load fires when all the page assets are loaded.
So window.load happens after document.ready. I was initializing my app on the document.ready event, when google maps assets weren't fully loaded. I switched my initialization code to happen on the window.load event and it works now.

Google Map not rendering correctly after first view with Backbone.js

Im creating a mobile app with Phonegap, Backbone.js, Require.js and PageSlider (https://github.com/ccoenraets/PageSlider).
I want to display a simple Google Map with a marker. The template looks like:
<div class='main-content' id='map-container'>
<a href="geo:51.903679,-8.468274">
<div id="map-canvas"></div>
</a>
</div>
Here is the view:
define(function (require) {
"use strict";
var $ = require('jquery'),
_ = require('underscore'),
Backbone = require('backbone'),
tpl = require('text!tpl/Map.html'),
side_nav = require('text!tpl/SideNav.html'),
template = _.template(tpl),
map, myLatlng, mapOptions, marker;
return Backbone.View.extend({
initialize: function () {
this.render();
},
initMap: function () {
myLatlng = new google.maps.LatLng(51.903679, -8.468274);
mapOptions = {
center: myLatlng,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(this.$el.find('#map-canvas')[0],
mapOptions);
marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Christians Brothers College Cork'
});
},
render: function () {
this.$el.html(template({side_nav:side_nav}));
this.initMap();
},
});
});
Here is a link to the app. When you click on "location", the map renders perfectly. But when you navigate anywhere else, then back to location, only a tiny portion of the map can be seen in the top left hand corner.
I tried doing, which was suggested here:
google.maps.event.trigger(map, 'resize').
but to no avail. Any ideas?
Your view works on a node not appended to the DOM, thus without size, a situation Google Map is not very fond of. It is your router, via PageSlider, that does append the node after your render function has occurred.
Here is a demo of your predicament : http://jsfiddle.net/3C7g3/
You have several options to solve it:
call google.maps.event.trigger(map, 'resize') after the node is inserted into the DOM (this bit of code corresponds to your router entry for the map)
// assuming you stored the map object in your view
require(["app/views/Map"], function (Map) {
var view = new Map();
slider.slidePage(view.$el);
google.maps.event.trigger(view.map, 'resize');
});
http://jsfiddle.net/3C7g3/1/
insert the node into DOM before calling render. In your case, that probably means removing render from the view.initialize and calling view.render after container.append(page); in your slidePageFrom method.
http://jsfiddle.net/3C7g3/2/
a more hackish way would be to temporarily add the element to the DOM, apply Google Maps, and then remove it from the DOM
initMap: function () {
// assuming a temp class that hides the element. For example,
// .temp {position: absolute; visibility:hidden; }
this.$el.addClass('temp');
$('body').append(this.$el);
// ...
this.$el.remove();
this.$el.removeClass('temp');
}
http://jsfiddle.net/3C7g3/3/

Google map in a tab created with angularjs is not centered

I have the following problem:
I'm working in an aplication to book hotels that has tabs ("Hotel Details", "Map", "Reviews") in the overview page. the tabs are created with angularjs.
also, in the page I have the hotel address that is a link to the "Map" tab.
When I click on the "Map" tab, the google map is rendering ok. But, when I click on the hotel address, the "Map" tab opens but the map is not centered. If I refresh the page, it appears centered.
this is the code that process the map:
$scope.loadMap = function (targetID){
var latitude = $scope.latitude;
var longitude = $scope.longitude;
if(latitude && longitude && document.getElementById(targetID) != null ){
var center = new google.maps.LatLng(latitude, longitude);
var map_options = {
zoom: 13,
center: center,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// create map
var map = new google.maps.Map(document.getElementById(targetID), map_options);
// configure marker
var marker_options = {
map: map,
position: center,
title: $scope.hotelName
};
// create marker
var marker = new google.maps.Marker(marker_options);
var infoWindow = new google.maps.InfoWindow();
window.setTimeout(function(){
google.maps.event.trigger(map, 'resize');
},2000);
}
}
Can you help me, please?
I've had this very problem when I was creating maps using Leaflet.js. I was trying to initialize the map inside of my angular service and it was loading very strangely. It appears you are trying to do the same thing, but you're doing it inside of your controller, rather than a service, but the effect is the same thing.
The problem is timing. Your controller is run before the DOM finishes loading and before angular has a chance to scan through the DOM to build out your Map page partial. Because of that, the page is only partially loaded when you call $scope.loadMap, which loads the google map, as you would expect. The problem is that once Angular finishes scanning the DOM partial, it modifies the DOM and then loads it into the view. When this happens, the google map has already been initialized to its default size based on the previous state of the DOM, and doesn't resize properly when angular is finished with the DOM.
Ok, that was a long explanation, but here's how you fix it:
You should do all of your map initialization inside of a directive's linking function. You could create a directive called something like app.directive('hotelMap'), which would initialize your map using the $scope.latitude and $scope.longitude variables from your controller.
link: function(scope, elem, attrs){
var center = new google.maps.LatLng(scope.latitude, scope.longitude);
var map_options = {
zoom: 13,
center: center,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// create map
var map = new google.maps.Map(document.getElementById(targetID), map_options);
// configure marker
var marker_options = {
map: map,
position: center,
title: $scope.hotelName
};
// create marker
var marker = new google.maps.Marker(marker_options);
var infoWindow = new google.maps.InfoWindow();
}
And then in your map partial, you would have an element that looks something like <div hotel-map></div>. This fixes your problem, because your map will never be initialized until Angular has finished scanning/modifying the DOM and has finished rendering your partial. That way, the map's containing element will be at its final size/position and the map will be loaded into the element's center properly. Give it a try and let me know if that works.

Google Map not displaying on website. Controls show, but the map itself does not render

The Google map on my site no longer shows up. I can see the zoom in/out slider, map/satellite buttons, etc... but the map itself no longer shows up. I read somewhere that the map should be in a div tag labeled "map" with both height and width stated in the CSS. The map has always had height/width CSS properties listed, but the ID was labeled differently. I changed the ID to map and corresponding CSS, but the map still will not show up. I read elsewhere that the Google Analytics by Yoast plugin was also causing similar errors. I have disabled all plugins and then one at a time I have reactivated them to see if another plugin might be the issue. However, it seems that none of the plugins running have any effect on the map displaying.
I am a web designer with some HTML/CSS knowledge. I designed this site and had hired a guy to code it into a custom Wordpress theme for me. Like I said, the map had been showing just fine, but no longer does and I have no idea why. I could really use some help to figure this out. I'm trying to learn more about coding so in the future I can debug and fix things like this on my own. A little help would be greatly appreciated!
Here is a link to the page with the map: http://seegerlaw.com/contact-us/
Please let me know if you need any other information from me.
You're using undocumented fields:
function initialize() {
geocoder = new google.maps.Geocoder();
codeAddr(function(lat, lng) {
myLatlng = new google.maps.LatLng(lat,lng);
var mapOptions = {
zoom: 15,
center: myLatlng,
disableDefaultUI: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map
});
});
}
function codeAddr(callback) {
if (geocoder) {
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
console.log(results[0].geometry);
maps_lat = results[0].geometry.location["kb"];
maps_lng = results[0].geometry.location["lb"];
callback(maps_lat, maps_lng);
}
else {
console.log("Geocoding failed: " + status);
}
});
}
}
Use the lat() and lng() properties of LatLng to get their values.
Even better, just pass in the LatLng directly from the Geocoder to the MapOptions object:
codeAddr(function(latLng) {
var mapOptions = {
center: latLng,
...
};
...
});
callback(results[0].geometry.location);
Even better – it appears that you always geocode the same address – just hardcode the LatLng into your code.

Google Maps randomly crashed when enable browser's location tracking, why?

You can go to the live website to see how the problem occurred.
Steps to see the error are following
Go to the live website.
Enable you browser's location tracking.
Click one the the place name, it will open a new tab. It will display Google Map and center the map at the location that you clicked based on URL parameter.
The problem is sometimes it's not working randomly, it's showing plain grey background instead of showing the map.
If you try to refresh or click the place name again. The map might working.
But if you suddenly zoom out, it will crashed. You need to click the marker or dragging the map around, then you can zoom out with no problem.
All these problems are not occurred when you turn off the browser's location tracking.
Try it.
PS. Don't worry about 2 or 3 last digits of parameter. it has nothing
to do with this problem, I have tested it several times). The console log is not throw any errors also.
This is my code that involved when browser's location tracking is enabled. My full code is on JSFiddle.
function initialize() {
var myOptions = { zoom: 12, mapTypeId: google.maps.MapTypeId.ROADMAP };
map = new google.maps.Map(document.getElementById("map"), myOptions);
var infoWindow2 = new google.maps.InfoWindow({ content: '<div style="overflow:hidden;" id="currentInfoWindow"><p>You are here !!!</p></div>' });
// Try W3C Geolocation (Preferred)
if(navigator.geolocation) { // BEGIN IF USER ENABLE
browserSupportFlag = true;
navigator.geolocation.getCurrentPosition(function(position) { //getCurrentPosition
querystring = window.location.search.substr(1);
console.log(querystring);
element = querystring.split(",");
if (querystring) {
clickedLocation = new google.maps.LatLng(element[0],element[1]);
map.setCenter(clickedLocation);
map.setZoom(18);
} else {
initialLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
}
//Set map center to be the user's location
map.setCenter(initialLocation);
//Place the marker of current position
var markerCurrent = new google.maps.Marker({
position: initialLocation,
map: map,
title:"You are here !!!",
icon : 'assets/frontend/images/yourmarker.png'
});
// Attaching a click event to the current marker
google.maps.event.addListener(markerCurrent, "click", function(e) {
infoWindow.close();
this.getMap().setCenter(this.getPosition());
map.setZoom(12);
infoWindow2.open(map, markerCurrent);
});
// IF NOT SUPPORT OR ENABLE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
} // End getCurrentPosition
, function() { handleNoGeolocation(browserSupportFlag); });
} // END IF Browser doesn't support Geolocation
else {
//Other code here.
}
Currently you will never run into this branch:
else {
initialLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
}
because there is always a QUERY_STRING.
Because of that initialLocation is not set, but you use it as argument for setCenter() .
changing this line:
clickedLocation = new google.maps.LatLng(element[0],element[1]);
into
initialLocation = new google.maps.LatLng(element[0],element[1]);
...should fix it.