define([
'aeris/util',
'aeris/util/gmaps',
'aeris/maps/strategy/abstractstrategy',
'aeris/maps/layers/googleroadmap',
'googlemaps!'
], function(_, mapUtil, AbstractStrategy, GoogleRoadMap, gmaps) {
/**
* A strategy for rendering a Google Maps map.
*
* @param {aeris.maps.Map} mapObject
* @class aeris.maps.gmaps.Map
* @extends aeris.maps.gmaps.AbstractStrategy
* @constructor
*/
var GoogleMapStrategy = function(mapObject) {
AbstractStrategy.apply(this, arguments);
this.bindMapEvents_();
// Sync map view with map object.
this.listenTo(this.object_, {
'change:center': this.updateCenter_,
'change:zoom': this.updateZoom_,
'change:baseLayer': this.updateBaseLayer_,
'updateSize': this.updateSize_
}, this);
// Make sure all attributes are in sync
// on init. If pre-existing google.maps.Map object was
// injected as our view, we need to make sure our aeris.maps.Map
// object is updated.
this.updateObjectFromView_();
this.preventZoomOnDblClick_();
};
_.inherits(GoogleMapStrategy, AbstractStrategy);
/**
* @method createView_
*/
GoogleMapStrategy.prototype.createView_ = function() {
var el = this.object_.getElement();
var baseLayer = this.object_.getBaseLayer();
var view;
// Accept a predefined google.maps.Map
// object
if (el instanceof gmaps.Map) {
return el;
}
gmaps.visualRefresh = true;
view = new gmaps.Map(el, {
center: mapUtil.arrayToLatLng(this.object_.get('center')),
zoom: this.object_.get('zoom'),
scrollwheel: this.object_.get('scrollZoom')
});
if (baseLayer) {
_.defer(function() {
baseLayer.setMap(this.object_);
}.bind(this));
}
return view;
};
GoogleMapStrategy.prototype.bindMapEvents_ = function() {
this.googleEvents_.listenTo(this.getView(), {
// Proxy view events to map object.
click: _.bind(this.triggerMouseEvent_, this, 'click'),
dblclick: _.bind(this.triggerMouseEvent_, this, 'dblclick'),
tilesloaded: _.bind(this.object_.trigger, this.object_, 'load'),
// Update the MapExtObj center attr
center_changed: function() {
var latLon = mapUtil.latLngToArray(this.getView().getCenter());
this.object_.set('center', latLon, { validate: true });
},
idle: function() {
var aerisBounds;
var gBounds = this.getView().getBounds();
if (!gBounds) { return; }
aerisBounds = mapUtil.boundsToArray(gBounds);
this.object_.set('bounds', aerisBounds, { validate: true });
},
zoom_changed: function() {
var zoom = this.getView().getZoom();
this.object_.set('zoom', zoom, { validate: true });
}
}, this);
};
GoogleMapStrategy.prototype.triggerMouseEvent_ = function(topic, evtObj) {
var latLon = mapUtil.latLngToArray(evtObj.latLng);
this.object_.trigger(topic, latLon);
};
/**
* @private
* @method updateCenter_
*/
GoogleMapStrategy.prototype.updateCenter_ = function() {
var latLng = mapUtil.arrayToLatLng(this.object_.get('center'));
this.getView().setCenter(latLng);
};
/**
* @method updateAllAttributes_
* @private
*/
GoogleMapStrategy.prototype.updateObjectFromView_ = function() {
this.object_.set({
center: this.getView().getCenter(),
zoom: this.getView().getZoom(),
scrollZoom: this.getView().scrollwheel
});
};
/**
* @private
* @method updateZoom_
*/
GoogleMapStrategy.prototype.updateZoom_ = function() {
var zoom = this.object_.get('zoom');
this.getView().setZoom(zoom);
};
/**
* @method updateBaseLayer_
* @private
*/
GoogleMapStrategy.prototype.updateBaseLayer_ = function() {
var baseLayer = this.object_.getBaseLayer();
if (baseLayer) {
baseLayer.setMap(this.object_);
}
};
GoogleMapStrategy.prototype.fitToBounds = function(bounds) {
var gBounds = mapUtil.arrayToBounds(bounds);
this.view_.fitBounds(gBounds);
};
/**
* @method preventZoomOnDblClick_
* @private
*/
GoogleMapStrategy.prototype.preventZoomOnDblClick_ = function() {
// A hack to prevent zoom on dblclick
// Only if a handler is bound to the 'dblclick' event
this.object_.on = function(topic, handler) {
if (_.isString(topic) && topic === 'dblclick' ||
_.isObject(topic) && _.has(topic, 'dblclick')
) {
this.getView().set('disableDoubleClickZoom', true);
}
// Note that we can't pull this in with ReqJS,
// because we would create a circular dependency.
// Hacks are fun, no?
aeris.maps.Map.prototype.on.apply(this, arguments);
};
};
/**
* @method updateSize_
* @private
*/
GoogleMapStrategy.prototype.updateSize_ = function() {
gmaps.event.trigger(this.getView(), 'resize');
};
return GoogleMapStrategy;
});