var x = document.createElement('script');
x.src = _cf_ajaxscriptsrc + '/jquery/jquery.js';
document.getElementsByTagName("head")[0].appendChild(x);
Ext.namespace('Ext.ux.panel');
Ext.ux.GMapPanel = Ext.extend(Ext.Panel, {
/**
* @cfg {Boolean} border
* Defaults to false. See {@link Ext.Panel}.{@link Ext.Panel#border border}.
*/
border: false,
/**
* @cfg {Array} respErrors
* An array of msg/code pairs.
*/
respErrors: [{
code: 'UNKNOWN_ERROR',
msg: 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.'
},{
code: 'ERROR',
msg: 'There was a problem contacting the Google servers.'
},{
code: 'ZERO_RESULTS',
msg: 'The request did not encounter any errors but returns zero results.'
},{
code: 'INVALID_REQUEST',
msg: 'This request was invalid.'
},{
code: 'REQUEST_DENIED',
msg: 'The webpage is not allowed to use the geocoder for some reason.'
},{
code: 'OVER_QUERY_LIMIT',
msg: 'The webpage has gone over the requests limit in too short a period of time.'
}],
/**
* @cfg {Array} locationTypes
* An array of msg/code/level pairs.
*/
locationTypes: [{
level: 4,
code: 'ROOFTOP',
msg: 'The returned result is a precise geocode for which we have location information accurate down to street address precision.'
},{
level: 3,
code: 'RANGE_INTERPOLATED',
msg: 'The returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address.'
},{
level: 2,
code: 'GEOMETRIC_CENTER',
msg: 'The returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region).'
},{
level: 1,
code: 'APPROXIMATE',
msg: 'The returned result is approximate.'
}],
/**
* @cfg {String} respErrorTitle
* Defaults to 'Error'.
*/
respErrorTitle : 'Error',
/**
* @cfg {String} geoErrorMsgUnable
* Defaults to 'Unable to Locate the Address you provided'.
*/
geoErrorMsgUnable : 'Unable to Locate the Address you provided',
/**
* @cfg {String} geoErrorTitle
* Defaults to 'Address Location Error'.
*/
geoErrorTitle : 'Address Location Error',
/**
* @cfg {String} geoErrorMsgAccuracy
* Defaults to 'The address provided has a low accuracy.
{0} Accuracy.'.
*
ROOFTOP : * The returned result is a precise geocode for which we have location information accurate down to street address precision. *
RANGE_INTERPOLATED : * The returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address. *
GEOMETRIC_CENTER : * The returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region). *
APPROXIMATE : * The returned result is approximate. *
G_NORMAL_MAP : * Displays the default road map view *
G_SATELLITE_MAP : * Displays Google Earth satellite images *
G_HYBRID_MAP : * Displays a mixture of normal and satellite views *
G_DEFAULT_MAP_TYPES : * Contains an array of the above three types, useful for iterative processing. *
G_PHYSICAL_MAP : * Displays a physical map based on terrain information. *
G_MOON_ELEVATION_MAP : * Displays a shaded terrain map of the surface of the Moon, color-coded by altitude. *
G_MOON_VISIBLE_MAP : * Displays photographic imagery taken from orbit around the moon. *
G_MARS_ELEVATION_MAP : * Displays a shaded terrain map of the surface of Mars, color-coded by altitude. *
G_MARS_VISIBLE_MAP : * Displays photographs taken from orbit around Mars. *
G_MARS_INFRARED_MAP : * Displays a shaded infrared map of the surface of Mars, where warmer areas appear brighter and colder areas appear darker. *
G_SKY_VISIBLE_MAP : * Displays a mosaic of the sky, as seen from Earth, covering the full celestial sphere. *
* gmapType: G_MOON_VISIBLE_MAP
*
*/
gmapType : 'map',
/**
* @cfg {Object} setCenter
* The initial center location of the map. The map needs to be centered before it can be used.
* A marker is not required to be specified.
* More markers can be added to the map using the {@link #markers} array.
* For example:
*
setCenter: {
geoCodeAddr: '4 Yawkey Way, Boston, MA, 02215-3409, USA',
marker: {title: 'Fenway Park'}
},
// or just specify lat/long
setCenter: {
lat: 42.345573,
lng: -71.098326
}
*
*/
/**
* @cfg {Number} zoomLevel
* The zoom level to initialize the map at, generally between 1 (whole planet) and 40 (street).
* Also used as the zoom level for panoramas, zero specifies no zoom at all.
* Defaults to 3.
*/
zoomLevel: 3,
/**
* @cfg {Number} yaw
* The Yaw, or rotational direction of the users perspective in degrees. Only applies to panoramas.
* Defaults to 180.
*/
yaw: 180,
/**
* @cfg {Number} pitch
* The pitch, or vertical direction of the users perspective in degrees.
* Defaults to 0 (straight ahead). Valid values are between +90 (straight up) and -90 (straight down).
*/
pitch: 0,
/**
* @cfg {Boolean} displayGeoErrors
* True to display geocoding errors to the end user via a message box.
* Defaults to false.
*/
displayGeoErrors: false,
/**
* @cfg {Boolean} minGeoAccuracy
* The level to display an accuracy error below. Defaults to ROOFTOP. For additional information
* see here.
*/
minGeoAccuracy: 'ROOFTOP',
/**
* @cfg {Array} mapConfOpts
* Array of strings representing configuration methods to call, a full list can be found
* here.
* For example:
*
* mapConfOpts: ['enableScrollWheelZoom','enableDoubleClickZoom','enableDragging'],
*
*/
/**
* @cfg {Array} mapControls
* Array of strings representing map controls to initialize, a full list can be found
* here.
* For example:
*
* mapControls: ['GSmallMapControl','GMapTypeControl','NonExistantControl']
*
*/
/**
* @cfg {Array} markers
* Markers may be added to the map. Instead of specifying lat/lng,
* geocoding can be specified via a geoCodeAddr string.
* For example:
*
markers: [{
//lat: 42.339641,
//lng: -71.094224,
// instead of lat/lng:
geoCodeAddr: '465 Huntington Avenue, Boston, MA, 02215-5597, USA',
marker: {title: 'Boston Museum of Fine Arts'},
listeners: {
click: function(e){
Ext.Msg.alert('Its fine', 'and its art.');
}
}
},{
lat: 42.339419,
lng: -71.09077,
marker: {title: 'Northeastern University'}
}]
*
*/
// private
mapDefined: false,
// private
mapDefinedGMap: false,
initComponent : function(){
this.addEvents(
/**
* @event mapready
* Fires when the map is ready for interaction
* @param {GMapPanel} this
* @param {GMap} map
*/
'mapready',
/**
* @event apiready
* Fires when the Google Maps API is loaded
*/
'apiready'
);
Ext.applyIf(this,{
markers: [],
cache: {
marker: [],
polyline: [],
infowindow: []
}
});
Ext.ux.GMapPanel.superclass.initComponent.call(this);
if (window.google && window.google.maps){
this.on('afterrender', this.apiReady, this);
}else{
window.gmapapiready = this.apiReady.createDelegate(this);
this.buildScriptTag('http://maps.google.com/maps/api/js?sensor=false&callback=gmapapiready');
}
},
apiReady : function(){
if (this.rendered){
(function(){
this.gmapType = this.gmapType.toLowerCase();
var mapType;
switch(this.gmapType){
case 'map':
mapType = google.maps.MapTypeId.ROADMAP;
break;
case 'satellite':
mapType = google.maps.MapTypeId.SATELLITE;
break;
case 'hybrid':
mapType = google.maps.MapTypeId.HYBRID;
break;
case 'terrain':
mapType = google.maps.MapTypeId.TERRAIN;
break;
case 'earth':
mapType = google.maps.MapTypeId.ROADMAP;
break;
}
if (this.gmapType.toLowerCase() === 'map'){
this.gmap = new google.maps.Map(this.body.dom,
{
zoom:this.zoomLevel,
mapTypeControl : this.mtc,
mapTypeControlOptions: {
style: this.mtco
},
scrollwheel:this.swz,
zoomControl: this.zc,
zoomControlOptions: {
style: this.zco
},
mapTypeId: google.maps.MapTypeId.ROADMAP
});
this.mapDefined = true;
this.mapDefinedGMap = true;
}
if (this.gmapType === 'panorama'){
this.gmap = new GStreetviewPanorama(this.body.dom);
this.mapDefined = true;
}
if (!this.mapDefined && this.gmapType){
this.gmap = new google.maps.Map(this.body.dom,
{
zoom:this.zoomLevel,
mapTypeControl : this.mtc,
mapTypeControlOptions: {
style: this.mtco
},
scrollwheel:this.swz,
zoomControl: this.zc,
zoomControlOptions: {
style: this.zco
},
mapTypeId: google.maps.MapTypeId.ROADMAP
});
this.gmap.setMapTypeId(mapType);
this.mapDefined = true;
this.mapDefinedGMap = true;
}
google.maps.event.addListenerOnce(this.getMap(), 'tilesloaded', this.onMapReady.createDelegate(this));
google.maps.event.addListener(this.getMap(), 'dragend', this.dragEnd.createDelegate(this));
if (typeof this.setCenter === 'object') {
if (typeof this.setCenter.geoCodeAddr === 'string'){
this.geoCodeLookup(this.setCenter.geoCodeAddr, this.setCenter.marker, false, true, this.setCenter.listeners);
}else{
var point = new google.maps.LatLng(this.setCenter.lat,this.setCenter.lng);
this.getMap().setCenter(point, this.zoomLevel);
this.lastCenter = point;
if (typeof this.setCenter.marker === 'object' && typeof point === 'object' && this.noCenterMarker === false) {
this.addMarker(point, this.setCenter.marker, this.setCenter.marker.clear,true, this.setCenter.listeners);
}
}
if (this.gmapType === 'panorama'){
this.getMap().setLocationAndPOV(new google.maps.LatLng(this.setCenter.lat,this.setCenter.lng), {yaw: this.yaw, pitch: this.pitch, zoom: this.zoomLevel});
}
}
}).defer(200,this);
}else{
this.on('afterrender', this.apiReady, this);
}
},
// private
afterRender : function(){
var wh = this.ownerCt.getSize();
Ext.applyIf(this, wh);
Ext.ux.GMapPanel.superclass.afterRender.call(this);
},
// private
buildScriptTag: function(filename, callback) {
var script = document.createElement('script'),
head = document.getElementsByTagName("head")[0];
script.type = "text/javascript";
script.src = filename;
return head.appendChild(script);
},
// private
onMapReady : function(){
this.addMapControls();
this.addOptions();
this.addMarkers(this.markers);
this.fireEvent('mapready', this, this.getMap());
if (typeof this.onLoadhandler === 'function') {
this.onLoadhandler.call(null, this.name);
}
},
// private
onResize : function(w, h){
Ext.ux.GMapPanel.superclass.onResize.call(this, w, h);
// check for the existance of the google map in case the onResize fires too early
if (typeof this.getMap() == 'object') {
google.maps.event.trigger(this.getMap(), 'resize');
if (this.lastCenter){
this.getMap().setCenter(this.lastCenter, this.zoomLevel);
}
}
},
// private
setSize : function(width, height, animate){
Ext.ux.GMapPanel.superclass.setSize.call(this, width, height, animate);
// check for the existance of the google map in case setSize is called too early
if (Ext.isObject(this.getMap())) {
google.maps.event.trigger(this.getMap(), 'resize');
if (this.lastCenter){
this.getMap().setCenter(this.lastCenter, this.zoomLevel);
}
}
},
// private
dragEnd: function(){
this.lastCenter = this.getMap().getCenter();
},
/**
* Returns the current google map which can be used to call Google Maps API specific handlers.
* @return {GMap} this
*/
getMap : function(){
return this.gmap;
},
/**
* Returns the maps center as a GLatLng object
* @return {GLatLng} this
*/
getCenter : function(){
return this.getMap().getCenter();
},
/**
* Returns the maps center as a simple object
* @return {Object} this has lat and lng properties only
*/
getCenterLatLng : function(){
var ll = this.getCenter();
return {lat: ll.lat(), lng: ll.lng()};
},
/**
* Creates markers from the array that is passed in. Each marker must consist of at least
* lat and lng properties or a geoCodeAddr.
* @param {Array} markers an array of marker objects
*/
addMarkers : function(markers) {
if (Ext.isArray(markers)){
for (var i = 0; i < markers.length; i++) {
if (markers[i]) {
if (typeof markers[i].geoCodeAddr == 'string') {
this.addMarkerInProcess = true;
this.geoCodeLookup(markers[i].geoCodeAddr, markers[i].marker, false, markers[i].setCenter, markers[i].listeners);
}
else if (typeof markers[i].address === 'string') {
this.addMarkerInProcess = true;
this.geoCodeLookup(markers[i].address, markers[i].marker, false, markers[i].setCenter, markers[i].listeners);
}else {
var mkr_point = new google.maps.LatLng(markers[i].lat, markers[i].lng);
this.addMarker(mkr_point, markers[i].marker, false, markers[i].setCenter, markers[i].listeners);
}
}
}
}
},
geoLatiLongiLookup : function(addr, markerIndex) {
this.geocoder = new google.maps.Geocoder();
var markerObject = this.markers[markerIndex];
markerObject.parent = this;
this.geocoder.geocode(addr, this.addMarkerToMapCallBack.createDelegate(markerObject));
},
addMarkerToMapCallBack: function(latlngObject){
if (latlngObject == null || typeof latlngObject != 'object') {
ColdFusion.handleError(null, 'map.addmarker.addressnotfound', "map", [this.address], null, null, false);
return null;
}
var point = new google.maps.LatLng(latlngObject.lat(), latlngObject.lng());
var markerObj = this;
var parent = this.parent;
delete this.parent;
parent.addMarker(point, markerObj.marker, false, false, markerObj.listeners);
},
/**
* Creates a single marker.
* @param {Object} point a GLatLng point
* @param {Object} marker a marker object consisting of at least lat and lng
* @param {Boolean} clear clear other markers before creating this marker
* @param {Boolean} center true to center the map on this marker
* @param {Object} listeners a listeners config
*/
addMarker : function(point, marker, clear, center, listeners){
//Ext.applyIf(marker,{});
if(marker.markercolor != null && typeof marker.markercolor != 'undefined')
marker.icon = MapIconMaker.createMarkerIcon({width: 32, height: 32, primaryColor: marker.markercolor });
else
{
if(marker.markericon == null)
{
marker.icon = new google.maps.MarkerImage(_cf_ajaxscriptsrc + '/resources/cf/map/marker.png');
}
else
{
marker.icon = new google.maps.MarkerImage(marker.markericon);
}
}
// Initially latLangitude bound will not be defined. While adding first marker
// this will be null. So we will initilize it. We need to keep count of marker added,
// so that we can set the right zoom level once all marker are added.
if(!this.latLongBound)
{
this.latLongBound = new google.maps.LatLngBounds();
this.markerAddedCount = 0;
}
this.latLongBound.extend(point);
this.markerAddedCount++;
if (clear === true){
this.clearMarkers();
this.latLongBound = null;
}
if (center === true) {
this.getMap().setCenter(point, this.zoomLevel)
this.lastCenter = point;
}
if (marker.infoWindow){
this.createInfoWindow(marker.infoWindow, point, mark);
}
var showcenter = true;
if(this.noCenterMarker == true && marker.iscenter == true)
showcenter = false;
if (showcenter)
{
var mark = new google.maps.Marker(Ext.apply(marker, {
position: point
}));
this.cache.marker.push(mark);
mark.setMap(this.getMap());
if (typeof listeners === 'object'){
var scopeObj = {marker:mark, bindcallback:marker.bindcallback, name:marker.name, statictext: marker.markerwindowcontent, address:marker.address};
mark.scope = scopeObj;
for (evt in listeners) {
google.maps.event.addListener(mark, evt, listeners[evt]);
}
}
}
if(this.showAllMarker && this.markers.length > 0 && this.markerAddedCount > this.markers.length)
{
//Bugid:78545, If zoomlevel is set to lower value then showallmarker should not optimize it
// to higher value. Ideally, showallmarker should only lower the zoomlevel if required to
// accomodate all markers.
//this.getMap().fitBounds(latLongBound);
var optimalZoomLevel = getZoomByBounds(this.getMap(),this.latLongBound);//this.getMap().getBoundsZoomLevel(this.latLongBound);
if (optimalZoomLevel <= this.zoomLevel)
{
this.getMap().setZoom(optimalZoomLevel);
this.getMap().setCenter(this.latLongBound.getCenter());
}
}
return mark;
},
addEventToMap : function (event, listener,scope)
{
if(scope == null || typeof scope == 'undefined')
scope = this.getMap();
google.maps.event.addListener(this.getMap(), event, bind(scope, listener));
},
addAddressToMap : function(response) {
if (!response || response.Status.code != 200) {
this.onErrorhandler.call(null, this.name, response.Status.code);
}else{
place = response.Placemark[0];
addressinfo = place.AddressDetails;
accuracy = addressinfo.Accuracy;
if (accuracy === 0) {
this.onErrorHandler.call(null, this.name, 602);
}else{
point = new google.maps.LatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
if (typeof this.setCenter.marker === 'object' && typeof point === 'object' ){
this.addMarker(point,this.setCenter.marker,this.setCenter.marker.clear,true, this.setCenter.listeners);
}
}
} } ,
/**
* Creates a single polyline.
* @param {Array} points an array of polyline points
* @param {Object} linestyle an object defining the line style to use
*/
addPolyline : function(points, linestyle){
var plinepnts = new google.maps.MVCArray, pline, linestyle = linestyle ? linestyle : {
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 2
};
Ext.each(points, function(point){
plinepnts.push(new google.maps.LatLng(point.lat, point.lng));
}, this);
var pline = new google.maps.Polyline(Ext.apply({
path: plinepnts
},linestyle));
this.cache.polyline.push(pline);
pline.setMap(this.getMap());
},
/**
* Creates an Info Window.
* @param {Object} inwin an Info Window configuration
* @param {GLatLng} point the point to show the Info Window at
* @param {GMarker} marker a marker to attach the Info Window to
*/
createInfoWindow : function(inwin, point, marker){
var me = this, infoWindow = new google.maps.InfoWindow({
content: inwin.content,
position: point
});
if (marker) {
google.maps.event.addListener(marker, 'click', function(){
me.hideAllInfoWindows();
infoWindow.open(me.getMap());
});
}
this.cache.infowindow.push(infoWindow);
return infoWindow;
},
// private
hideAllInfoWindows : function(){
for (var i = 0; i < this.cache.infowindow.length; i++) {
this.cache.infowindow[i].close();
}
},
// private
clearMarkers : function(){
this.hideAllInfoWindows();
this.hideMarkers();
},
// private
hideMarkers : function(){
Ext.each(this.cache.marker, function(mrk){
mrk.setMap(null);
});
},
// private
showMarkers : function(){
Ext.each(this.cache.marker, function(mrk){
mrk.setMap(this.getMap());
},this);
},
// private
addMapControls : function(){
if (this.gmapType === 'map') {
if (Ext.isArray(this.mapControls)) {
for(i=0;i
buttons: [
{
text: 'Fenway Park',
handler: function(){
var addr = '4 Yawkey Way, Boston, MA, 02215-3409, USA';
Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined);
}
},{
text: 'Zoom Fenway Park',
handler: function(){
Ext.getCmp('my_map').zoomLevel = 19;
var addr = '4 Yawkey Way, Boston, MA, 02215-3409, USA';
Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined);
}
},{
text: 'Low Accuracy',
handler: function(){
Ext.getCmp('my_map').geoCodeLookup('Paris, France', undefined, false, true, undefined);
}
},{
text: 'Bogus Address',
handler: function(){
var addr = 'Some Fake, Address, For, Errors';
Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined);
}
}
]
*
* @param {String} addr the address to lookup.
* @param {Object} marker the marker to add (optional).
* @param {Boolean} clear clear other markers before creating this marker
* @param {Boolean} center true to set this point as the center of the map.
* @param {Object} listeners a listeners config
*/
geoCodeLookup : function(addr, marker, clear, center, listeners) {
if (!this.geocoder) {
this.geocoder = new google.maps.Geocoder();
}
this.geocoder.geocode({
address: addr
}, this.addAddressToMap.createDelegate(this, [addr, marker, clear, center, listeners], true));
},
// private
centerOnClientLocation : function(){
this.getClientLocation(function(loc){
var point = new google.maps.LatLng(loc.latitude,loc.longitude);
this.getMap().setCenter(point, this.zoomLevel);
this.lastCenter = point;
});
},
// private
getClientLocation : function(fn, errorFn){
if (!errorFn) {
errorFn = Ext.emptyFn;
}
if (!this.clientGeo) {
this.clientGeo = google.gears.factory.create('beta.geolocation');
}
geo.getCurrentPosition(fn.createDelegate(this), errorFn);
},
// private
addAddressToMap : function(response, status, addr, marker, clear, center, listeners){
if (!response || status !== 'OK') {
this.onErrorhandler.call(null, this.name, status);
}else{
var place = response[0].geometry.location,
accuracy = this.getLocationTypeInfo(response[0].geometry.location_type,'level'),
reqAccuracy = this.getLocationTypeInfo(this.minGeoAccuracy,'level');
if (accuracy === 0) {
this.geoErrorMsg(this.geoErrorTitle, this.geoErrorMsgUnable);
}else{
if (accuracy <-1) {
this.geoErrorMsg(this.geoErrorTitle, String.format(this.geoErrorMsgAccuracy, response[0].geometry.location_type, this.getLocationTypeInfo(response[0].geometry.location_type,'msg'))); }else{
point = new google.maps.LatLng(place.lat(),place.lng());
if (center){
this.getMap().setCenter(point, this.zoomLevel);
this.lastCenter = point;
}
if (typeof marker === 'object') {
if (!marker.title){
marker.title = response.formatted_address;
}
var mkr = this.addMarker(point, marker, clear, false, listeners);
if (marker.callback){
marker.callback.call(this, mkr, point);
}
}
}
}
}
},
// private
geoErrorMsg : function(title,msg){
if (this.displayGeoErrors) {
Ext.MessageBox.alert(title,msg);
}
},
// private
respErrorMsg : function(code){
Ext.each(this.respErrors, function(obj){
if (code == obj.code){
Ext.MessageBox.alert(this.respErrorTitle, obj.msg);
}
}, this);
},
// private
getLocationTypeInfo: function(location_type,property){
var val = 0;
Ext.each(this.locationTypes, function(itm){
if (itm.code === location_type){
val = itm[property];
}
});
return val;
}
});
function bind(object, method) {
return function() {
return method.apply(object, arguments);
}
}
/**
* Returns the zoom level at which the given rectangular region fits in the map view.
* The zoom level is computed for the currently selected map type.
* @param {google.maps.Map} map
* @param {google.maps.LatLngBounds} bounds
* @return {Number} zoom level
**/
function getZoomByBounds( map, bounds ){
var MAX_ZOOM = map.mapTypes.get( map.getMapTypeId() ).maxZoom || 21 ;
var MIN_ZOOM = map.mapTypes.get( map.getMapTypeId() ).minZoom || 0 ;
var ne= map.getProjection().fromLatLngToPoint( bounds.getNorthEast() );
var sw= map.getProjection().fromLatLngToPoint( bounds.getSouthWest() );
var worldCoordWidth = Math.abs(ne.x-sw.x);
var worldCoordHeight = Math.abs(ne.y-sw.y);
//Fit padding in pixels
var FIT_PAD = 40;
for( var zoom = MAX_ZOOM; zoom >= MIN_ZOOM; --zoom ){
if( worldCoordWidth*(1<