ionic not rendering google maps on first load - google-maps

I have an app that is a welcome/sign in screen and after you sign it you are taken to a tab screen with four tabs in it, the first tab of which shows a google map.
Upon first sign in the page does not display it's self but upon refresh of the page the map show's up gracefully as it was expected to do the first time. This happens EVERY time but I only get one javascript error.
error
Uncaught Error: can't load XRegExp twice in the same frame(anonymous function) # xregexp-min.js:2
code
function initialize() {
var mapOptions = {
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(
document.getElementById("map"),
mapOptions
);
var geocoder = new google.maps.Geocoder();
$scope.map = map;
$scope.centerOnMe();
}
google.maps.event.addDomListener(window, 'load', initialize);
$scope.centerOnMe = function() {
if(!$scope.map) {
return;
}
$scope.loading = $ionicLoading.show({
content: 'Getting current location...',
showBackdrop: false
});
// get user location
$cordovaGeolocation
.getCurrentPosition({
timeout:10000,
enableHighAccuracy:true
})
.then(function(position) {
$ionicLoading.hide();
// we found the position
$scope.map.setCenter(
new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude
)
);
}, function(e) {
$ionicLoading.hide();
console.log(e);
alert("Uh oh, we can't find your position! Is your GPS enabled?\n\n" + e);
});
};
edit
This is my latest javascript error, after replacing the google init with the ionic init. I understand what's happening but I don't know where I should move that function declaration to. I moved it inside the init but it still didn't work. Should I set a timeout?
TypeError: $scope.loadLocations is not a function
at initialize (controllers.js:179)
at Object.ionic.Platform.ready (ionic.bundle.js:2120)
at new <anonymous> (controllers.js:182)
at invoke (ionic.bundle.js:12468)
at Object.instantiate (ionic.bundle.js:12476)
at ionic.bundle.js:16745
at IonicModule.controller.self.appendViewElement (ionic.bundle.js:47716)
at Object.IonicModule.factory.ionicViewSwitcher.create.switcher.render (ionic.bundle.js:45973)
at Object.IonicModule.factory.ionicViewSwitcher.create.switcher.init (ionic.bundle.js:45893)
at IonicModule.controller.self.render (ionic.bundle.js:47590)

You don't need $scope.centerOnMe(); in initialize. If you do then compilation is inconsistent; refer to the examples and you will understand.
Also, ionic doesn't work well with DOM in certain cases.
Load map with $scope.init inside the container instead of function initialize().
This answer explains it in detail.
Another way to do it is by replacing google.maps.event.addDomListener(window, 'load', initialize); with ionic.Platform.ready(initialize);. Example here.

Related

How to make sure that tiles are fully rendered in using google map api

I am able to capture the google map image. But I want it to capture automatically. I am able to but it has image which is not fully rendered. So I want to know is there any proper way to know that required tiles are loaded and rendered fully.I tried tilesloaded, idle events but seems not working rightly.
is it a good way to use idle under tilesloaded...i may sound wrong as i'm very new to google map api.
function initialize() {
var mapOptions = {
zoom: 17,
center: new google.maps.LatLng(lat,lng),
mapTypeId: google.maps.MapTypeId.ROADMAP,
rotateControl:true
};
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
google.maps.event.addListener(map, 'tilesloaded', function(event) {
console.log("tilesloaded");
map.addListener('idle', function(event) {
console.log("idle");
});
});
}
google.maps.event.addDomListener(window, 'load', initialize);
you can easily add a listener on the tilesloaded event. Like this:
google.maps.event.addListener(map, 'tilesloaded', function() {
..... your code ...
});

Meteor: modals and 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);
...
};
};

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.

Durandal SPA Google Map API Map Centering

There are a few posts regarding issues with google map api centering properly. I understand the following resizes the map:
google.maps.event.trigger(map, 'resize');
I was able to get the map to display properly within the div element on first page display. However, when navigating back to the html page that holds the map, only a fraction of the map displays within the div. The problem i'm having is figuring out how to incorporate this resize trigger. I'm new to SPA's and Durandal, here is my viewmodel responsible for the map:
define(['async!https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false'], function () {
var vm = {
title: 'Home View',
attached: initialize,
activate: function () {
toastr.success('Map View Activated');
}
};
return vm;
function initialize() {
var mapOptions = {
zoom: 10,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
}
});
Sure, you'd want to do this when the map is visible, i.e. it has a height and width. The best event for this is typically the composition complete event. So:
var vm = {
title: 'Home View',
attached: initialize,
activate: function () {
toastr.success('Map View Activated');
},
compositionComplete: function() {
google.maps.event.trigger(map, 'resize');
}
};
See the list and description of all callbacks here: Hooking Lifecycle Callbacks

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/