Mission:Start map
Goal:Reduce fails
Step1. Test yourself
In the beggining - test your own map application.Do this in two steps:
Impliment some king of "loading guard", it will fires if map wont start in 40 seconds
setTimeout(function(){
somehow test what map is ready and workable.
for example - map will fires event "weAreDone".
catch it!
},40000);
/* i thing 40sec is alot of time*/
and then define global error catcher
function global_error_catcher(msg, url, num, more){
if(msg && msg.name){
var _event=msg;
msg=(_event.name+"] "+e.fileName+":"+e.lineNumber+"\n"+e+"\n"+e.stack);
}
if(typeof(msg)=='object'){
var evt=msg;
msg='';
for(i in evt)msg+=i+":"+evt[i]+"\n";
}
var textout=("global error:\n"+msg+",\n"+url+":"+num+"\n:"+more);
new Ajax.Request("loader/report_site_error.php",{parameters:{'message':textout},async:true});
return true;
}
window.onerror=global_error_catcher;
Then put this application online and see logs.So i say "if map working for you - it can not work for others"
And this is true.
some time ago i got bug report "hey men, there is no map on your site".
I test it - map exists, i test my site on other PC.. map exists..
I try to ask friends to test site... and.. MAP EXISTS!!!
but next day i`v got same bug report from other user..
So i impliment listed debug scripts and then i see..
2000 users per day see my site with out map.
2000 users of 50k - 4%
So how to fix it
Step2. Start map
First include google loader
function add_script(src){
var fileref=document.createElement("script");
fileref.type="text/javascript";
fileref.src=src;
document.getElementsByTagName("head")[0].appendChild(fileref);
}
function _do_requestLoader(domain){
add_script("http://www.google."+domain+"/jsapi?hl=ru&key="+GM_APIKEY);
}
var requestLoader_try=0;
function requestLoader(){
if(requestLoader_try==0)_do_requestLoader("your domain code(.us,.ru,not just .com)");
else _do_requestLoader("com");
requestLoader_try++;
map.__init_loadingCycle(0);
}
Next try to call it and include google maps
GoogleMap.prototype.__init_loadingCycle = function (tick){
clearTimeout(this.__loadingTm);
if(tick++>200){
requestLoader();
return;
}
var thisworker=this;
//we have google loaded. sometimes( apple\safari google loads in 2-5 tick! )
if(window.google && typeof(window.google)!=undefined && typeof(window.google.load)=='function'){
this.console("google start at "+tick+" tick");
thisworker._enterState('GMaps.load',function(){
google.load("maps", "3", {other_params:"sensor=true",
"callback" : function(){
if(thisworker.isClosed){
thisworker.console("google post-activaion");
return;
}
thisworker._enterState("google start",function(){
thisworker.start();
},0);
},
"sensor":"true",
//and some others params like
"language" : "ru",
"hl":"ru",
"base_domain":"maps.google.ru"
});
},0);
}
else{
//start timer
this.__loadingTm=setTimeout(function(){thisworker.__init_loadingCycle(tick)},10);
}
}
Next wait until maps starts, and request maps projection
//lest define projection helper
function GoogleV3ProjectionHelperOverlay(map)
{
this.setMap(map);
}
GoogleMap.prototype.start = function ()
{
var _this=this;
//leave loading state
this._leaveState(this.loadingState);
var myOptions = {
zoom: this.driver.getZoom(),
center: this.fromLatLng(this.driver.getPosition()),
mapTypeId: this.decodeMapType(this.driver.getMapType()),
disableDefaultUI:true,
scrollwheel:true,
keyboardShortcuts:false
}
var thisworker=this;
this.api = new google.maps.Map(this.divId,myOptions);
this.helperOverlay=0;
this.startIniter=0;
//then define help projector
GoogleV3ProjectionHelperOverlay.prototype = new google.maps.OverlayView();
GoogleV3ProjectionHelperOverlay.prototype.draw = function () {
if (!this.ready) {
google.maps.event.trigger(this, 'ready');
this.ready = true;
//if this overlay ready - start maps
this.tearMapOn(0);
}
};
GoogleV3ProjectionHelperOverlay.prototype.tearMapOn = function(tick){
//if it have panes - start map
if(this.getPanes()){
_this._enterState("google-doStartInit - "+tick,function(){
_this.doStartInit();
});
}
else{
var __this=this;
setTimeout(function(){__this.tearMapOn(tick++)},1);
}
}
//sometimes it good to know how much time took loading of all tiles of map
this.idleTimer=google.maps.event.addListener(this.api,'idle',function(){
_this.weAreDone();
google.maps.event.removeListener(_this.idleTimer);
});
this.api.setCenter(myOptions.center);
this.api.setZoom(myOptions.zoom);
this.api.setMapTypeId(myOptions.mapTypeId);
//call some callback on API init
this.onReadyAPI('google','init',this);
//init helperOverlay
this.helperOverlay=new GoogleV3ProjectionHelperOverlay(this.api);
this.helperOverlay.setMap(this.api);
this.helperOverlay.draw();
}
//this function will be called this helperOverlay starts
GoogleMap.prototype.doStartInit = function ()
{
if( this.startIniter )
google.maps.event.removeListener(this.startIniter);
this.onMapReady();
}
Map started!and after this step we can convert latlng to pixels as in v2.
Many users want fromLatLngToContainerPixel - here it is!
GoogleMap.prototype.modPointByOffset=function(point,fac){
var bounds=this.api.getBounds();//this.getBounds();
var swPoint = this.fromLatLngToDivPixel(bounds.getSouthWest());
var nePoint = this.fromLatLngToDivPixel(bounds.getNorthEast());
return {x:point.x-swPoint.x*fac,y:point.y-nePoint.y*fac};
}
GoogleMap.prototype.fromLatLngToContainerPixel=function(a){
var point=this.fromLatLngToDivPixel(a);
return this.modPointByOffset(point,1);
}
GoogleMap.prototype.fromContainerPixelToLatLng=function(a){
var point=this.modPointByOffset(a,-1);
return this.fromDivPixelToLatLng(point);
}
GoogleMap.prototype.fromLatLngToDivPixel =function(a){
if(!this.helperOverlay) return {x:0,y:0};
return this.helperOverlay.getProjection().fromLatLngToDivPixel(a);
}
GoogleMap.prototype.fromDivPixelToLatLng =function(a){
return this.toLatLng(this.helperOverlay.getProjection().fromDivPixelToLatLng(a));
}
Step3. Test it again
So we use enter and leavestate functions. The log working flow. If some event "enters", but not "leaves" - we will log.
GoogleMap.prototype._leaveState = function(_event){
var _this=this;
_event.leave=_this.microtime();
_this.console("["+_event.name+"] took " +(_event.leave-_event.enter));
return _event;
}
GoogleMap.prototype.__callState = function (_event){
try
{
_event.func();
this._leaveState(_event) ;
}catch(e){
_event.error=e;
this.console("state-error ["+_event.name+"] "+e.fileName+":"+e.lineNumber+"\n"+e+"\n"+e.stack);
this._leaveState(_event) ;
this.__stateException(_event,e);
;
}
}
GoogleMap.prototype._enterState = function(name,func,sync,catcheble){
var _event={'name':name,'func':func,'enter':this.microtime(),'leave':0,'catcheble':catcheble};
var _this=this;
this.console('entering ['+name+']'+this._stages.length);
this._stages.push(_event);
if(func){
clearTimeout(this._stageTimeout);
if(sync){ _this.__callState(_event);
}
else{
this._stageTimeout=setTimeout(
function(){
_this.__callState(_event);
},1);
}
}
return _event;
}
See error logs again.
W\O this patches 1-5% of request fails
with this patches still some request fails, but just some of this.so test yourself and see. I test this on 4 sites with 150k unique visitors per day. And i think it is true that map exists not for all of then then you use "standart" way
What about you?
If you want to know more - ask