Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 11th, 2012  |  syntax: None  |  size: 25.43 KB  |  hits: 48  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. Ext.ns('Ext.ux');
  2.  
  3. Ext.define('Ext.ux.GMapPanel', {
  4.    
  5.     extend: 'Ext.panel.Panel',
  6.     alias: 'widget.gmappanel',
  7.  
  8.     /**
  9.      * @cfg {Boolean} border
  10.      * Defaults to <tt>false</tt>.  See {@link Ext.Panel}.<code>{@link Ext.Panel#border border}</code>.
  11.      */
  12.     border: false,
  13.  
  14.     /**
  15.      * @cfg {Array} respErrors
  16.      * An array of msg/code pairs.
  17.      */
  18.     respErrors: [{
  19.             code: 'UNKNOWN_ERROR',
  20.             msg: 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.'
  21.         },{
  22.             code: 'ERROR',
  23.             msg: 'There was a problem contacting the Google servers.'
  24.         },{
  25.             code: 'ZERO_RESULTS',
  26.             msg: 'The request did not encounter any errors but returns zero results.'
  27.         },{
  28.             code: 'INVALID_REQUEST',
  29.             msg: 'This request was invalid.'
  30.         },{
  31.             code: 'REQUEST_DENIED',
  32.             msg: 'The webpage is not allowed to use the geocoder for some reason.'
  33.         },{
  34.             code: 'OVER_QUERY_LIMIT',
  35.             msg: 'The webpage has gone over the requests limit in too short a period of time.'
  36.     }],
  37.     /**
  38.      * @cfg {Array} locationTypes
  39.      * An array of msg/code/level pairs.
  40.      */
  41.     locationTypes: [{
  42.             level: 4,
  43.             code: 'ROOFTOP',
  44.             msg: 'The returned result is a precise geocode for which we have location information accurate down to street address precision.'
  45.         },{
  46.             level: 3,
  47.             code: 'RANGE_INTERPOLATED',
  48.             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.'
  49.         },{
  50.             level: 2,
  51.             code: 'GEOMETRIC_CENTER',
  52.             msg: 'The returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region).'
  53.         },{
  54.             level: 1,
  55.             code: 'APPROXIMATE',
  56.             msg: 'The returned result is approximate.'
  57.     }],
  58.     /**
  59.      * @cfg {String} respErrorTitle
  60.      * Defaults to <tt>'Error'</tt>.
  61.      */
  62.     respErrorTitle : 'Error',
  63.     /**
  64.      * @cfg {String} geoErrorMsgUnable
  65.      * Defaults to <tt>'Unable to Locate the Address you provided'</tt>.
  66.      */
  67.     geoErrorMsgUnable : 'Unable to Locate the Address you provided',
  68.     /**
  69.      * @cfg {String} geoErrorTitle
  70.      * Defaults to <tt>'Address Location Error'</tt>.
  71.      */
  72.     geoErrorTitle : 'Address Location Error',
  73.     /**
  74.      * @cfg {String} geoErrorMsgAccuracy
  75.      * Defaults to <tt>'The address provided has a low accuracy.<br><br>{0} Accuracy.'</tt>.
  76.      * <div class="mdetail-params"><ul>
  77.      * <li><b><code>ROOFTOP</code></b> : <div class="sub-desc"><p>
  78.      * The returned result is a precise geocode for which we have location information accurate down to street address precision.
  79.      * </p></div></li>
  80.      * <li><b><code>RANGE_INTERPOLATED</code></b> : <div class="sub-desc"><p>
  81.      * 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.
  82.      * </p></div></li>
  83.      * <li><b><code>GEOMETRIC_CENTER</code></b> : <div class="sub-desc"><p>
  84.      * The returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region).
  85.      * </p></div></li>
  86.      * <li><b><code>APPROXIMATE</code></b> : <div class="sub-desc"><p>
  87.      * The returned result is approximate.
  88.      * </p></div></li>
  89.      * </ul></div>
  90.      */
  91.     geoErrorMsgAccuracy : 'The address provided has a low accuracy.<br><br>"{0}" Accuracy.<br><br>{1}',
  92.     /**
  93.      * @cfg {String} gmapType
  94.      * The type of map to display, generic options available are: 'map', 'panorama'.
  95.      * Defaults to <tt>'map'</tt>.
  96.      * More specific maps can be used by specifying the google map type:
  97.      * <div class="mdetail-params"><ul>
  98.      * <li><b><code>G_NORMAL_MAP</code></b> : <div class="sub-desc"><p>
  99.      * Displays the default road map view
  100.      * </p></div></li>
  101.      * <li><b><code>G_SATELLITE_MAP</code></b> : <div class="sub-desc"><p>
  102.      * Displays Google Earth satellite images
  103.      * </p></div></li>
  104.      * <li><b><code>G_HYBRID_MAP</code></b> : <div class="sub-desc"><p>
  105.      * Displays a mixture of normal and satellite views
  106.      * </p></div></li>
  107.      * <li><b><code>G_DEFAULT_MAP_TYPES</code></b> : <div class="sub-desc"><p>
  108.      * Contains an array of the above three types, useful for iterative processing.
  109.      * </p></div></li>
  110.      * <li><b><code>G_PHYSICAL_MAP</code></b> : <div class="sub-desc"><p>
  111.      * Displays a physical map based on terrain information.
  112.      * </p></div></li>
  113.      * <li><b><code>G_MOON_ELEVATION_MAP</code></b> : <div class="sub-desc"><p>
  114.      * Displays a shaded terrain map of the surface of the Moon, color-coded by altitude.
  115.      * </p></div></li>
  116.      * <li><b><code>G_MOON_VISIBLE_MAP</code></b> : <div class="sub-desc"><p>
  117.      * Displays photographic imagery taken from orbit around the moon.
  118.      * </p></div></li>
  119.      * <li><b><code>G_MARS_ELEVATION_MAP</code></b> : <div class="sub-desc"><p>
  120.      * Displays a shaded terrain map of the surface of Mars, color-coded by altitude.
  121.      * </p></div></li>
  122.      * <li><b><code>G_MARS_VISIBLE_MAP</code></b> : <div class="sub-desc"><p>
  123.      * Displays photographs taken from orbit around Mars.
  124.      * </p></div></li>
  125.      * <li><b><code>G_MARS_INFRARED_MAP</code></b> : <div class="sub-desc"><p>
  126.      * Displays a shaded infrared map of the surface of Mars, where warmer areas appear brighter and colder areas appear darker.
  127.      * </p></div></li>
  128.      * <li><b><code>G_SKY_VISIBLE_MAP</code></b> : <div class="sub-desc"><p>
  129.      * Displays a mosaic of the sky, as seen from Earth, covering the full celestial sphere.
  130.      * </p></div></li>
  131.      * </ul></div>
  132.      * Sample usage:
  133.      * <pre><code>
  134.      * gmapType: G_MOON_VISIBLE_MAP
  135.      * </code></pre>
  136.      */
  137.     gmapType : 'map',
  138.     /**
  139.      * @cfg {Object} setCenter
  140.      * The initial center location of the map. The map needs to be centered before it can be used.
  141.      * A marker is not required to be specified.
  142.      * More markers can be added to the map using the <code>{@link #markers}</code> array.
  143.      * For example:
  144.      * <pre><code>
  145. setCenter: {
  146.     geoCodeAddr: '4 Yawkey Way, Boston, MA, 02215-3409, USA',
  147.     marker: {title: 'Fenway Park'}
  148. },
  149.  
  150. // or just specify lat/long
  151. setCenter: {
  152.     lat: 42.345573,
  153.     lng: -71.098326
  154. }
  155.      * </code></pre>
  156.      */
  157.     /**
  158.      * @cfg {Number} zoomLevel
  159.      * The zoom level to initialize the map at, generally between 1 (whole planet) and 40 (street).
  160.      * Also used as the zoom level for panoramas, zero specifies no zoom at all.
  161.      * Defaults to <tt>3</tt>.
  162.      */
  163.     zoomLevel: 3,
  164.     /**
  165.      * @cfg {Number} yaw
  166.      * The Yaw, or rotational direction of the users perspective in degrees. Only applies to panoramas.
  167.      * Defaults to <tt>180</tt>.
  168.      */
  169.     yaw: 180,
  170.     /**
  171.      * @cfg {Number} pitch
  172.      * The pitch, or vertical direction of the users perspective in degrees.
  173.      * Defaults to <tt>0</tt> (straight ahead). Valid values are between +90 (straight up) and -90 (straight down).
  174.      */
  175.     pitch: 0,
  176.     /**
  177.      * @cfg {Boolean} displayGeoErrors
  178.      * True to display geocoding errors to the end user via a message box.
  179.      * Defaults to <tt>false</tt>.
  180.      */
  181.     displayGeoErrors: false,
  182.     /**
  183.      * @cfg {Boolean} minGeoAccuracy
  184.      * The level to display an accuracy error below. Defaults to <tt>ROOFTOP</tt>. For additional information
  185.      * see <a href="http://code.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy">here</a>.
  186.      */
  187.     minGeoAccuracy: 'ROOFTOP',
  188.     /**
  189.      * @cfg {Array} mapConfOpts
  190.      * Array of strings representing configuration methods to call, a full list can be found
  191.      * <a href="http://code.google.com/apis/maps/documentation/reference.html#GMap2">here</a>.
  192.      * For example:
  193.      * <pre><code>
  194.      * mapConfOpts: ['enableScrollWheelZoom','enableDoubleClickZoom','enableDragging'],
  195.      * </code></pre>
  196.      */
  197.     /**
  198.      * @cfg {Array} mapControls
  199.      * Array of strings representing map controls to initialize, a full list can be found
  200.      * <a href="http://code.google.com/apis/maps/documentation/reference.html#GControlImpl">here</a>.
  201.      * For example:
  202.      * <pre><code>
  203.      * mapControls: ['GSmallMapControl','GMapTypeControl','NonExistantControl']
  204.      * </code></pre>
  205.      */
  206.     /**
  207.      * @cfg {Array} markers
  208.      * Markers may be added to the map. Instead of specifying <code>lat</code>/<code>lng</code>,
  209.      * geocoding can be specified via a <code>geoCodeAddr</code> string.
  210.      * For example:
  211.      * <pre><code>
  212. markers: [{
  213.     //lat: 42.339641,
  214.     //lng: -71.094224,
  215.     // instead of lat/lng:
  216.     geoCodeAddr: '465 Huntington Avenue, Boston, MA, 02215-5597, USA',
  217.     marker: {title: 'Boston Museum of Fine Arts'},
  218.     listeners: {
  219.         click: function(e){
  220.             Ext.Msg.alert('Its fine', 'and its art.');
  221.         }
  222.     }
  223. },{
  224.     lat: 42.339419,
  225.     lng: -71.09077,
  226.     marker: {title: 'Northeastern University'}
  227. }]
  228.      * </code></pre>
  229.      */
  230.     // private
  231.     mapDefined: false,
  232.     // private
  233.     mapDefinedGMap: false,
  234.     initComponent : function(){
  235.        
  236.         this.addEvents(
  237.             /**
  238.              * @event mapready
  239.              * Fires when the map is ready for interaction
  240.              * @param {GMapPanel} this
  241.              * @param {GMap} map
  242.              */
  243.             'mapready',
  244.             /**
  245.              * @event apiready
  246.              * Fires when the Google Maps API is loaded
  247.              */
  248.             'apiready'
  249.         );
  250.        
  251.         Ext.applyIf(this,{
  252.           markers: [],
  253.           cache: {
  254.               marker: [],
  255.               polyline: [],
  256.               infowindow: []
  257.           }
  258.         });
  259.        
  260.         Ext.ux.GMapPanel.superclass.initComponent.call(this);        
  261.  
  262.         if (window.google && window.google.maps){
  263.           this.on('afterrender', this.apiReady, this);
  264.  
  265.         }else{
  266.           window.gmapapiready = this.apiReady.createDelegate(this);
  267.           this.buildScriptTag('http://maps.google.com/maps/api/js?sensor=false&callback=gmapapiready');
  268.         }
  269.  
  270.     },
  271.     apiReady : function(){
  272.        
  273.         if (this.rendered){
  274.  
  275.           Ext.defer(function(){            
  276.               if (this.gmapType === 'map'){            
  277.                   this.gmap = new google.maps.Map(this.getEl().dom, {zoom:this.zoomLevel,mapTypeId: google.maps.MapTypeId.ROADMAP});
  278.                   this.mapDefined = true;
  279.                   this.mapDefinedGMap = true;
  280.               }
  281.              
  282.               if (this.gmapType === 'panorama'){
  283.                   this.gmap = new GStreetviewPanorama(this.getEl().dom);
  284.                   this.mapDefined = true;
  285.               }
  286.      
  287.               if (!this.mapDefined && this.gmapType){
  288.                 console.log ('sss');
  289.                  this.gmap = new google.maps.Map(this.getEl().dom, {zoom:this.zoomLevel,mapTypeId: google.maps.MapTypeId.ROADMAP});
  290.                  this.gmap.setMapTypeId(this.gmapType);
  291.                  this.mapDefined = true;
  292.                  this.mapDefinedGMap = true;
  293.               }
  294.              
  295.               google.maps.event.addListenerOnce(this.getMap(), 'tilesloaded', Ext.Function.bind(this.onMapReady, this));
  296.               google.maps.event.addListener(this.getMap(), 'dragend', Ext.Function.bind(this.dragEnd, this));
  297.  
  298.              
  299.               if (typeof this.setCenter === 'object') {
  300.                   if (typeof this.setCenter.geoCodeAddr === 'string'){
  301.                       this.geoCodeLookup(this.setCenter.geoCodeAddr, this.setCenter.marker, false, true, this.setCenter.listeners);
  302.                   }else{
  303.                       if (this.gmapType === 'map'){
  304.                           var point = new google.maps.LatLng(this.setCenter.lat,this.setCenter.lng);
  305.                           this.getMap().setCenter(point, this.zoomLevel);
  306.                           this.lastCenter = point;  
  307.                       }
  308.                       if (typeof this.setCenter.marker === 'object' && typeof point === 'object') {
  309.                           this.addMarker(point, this.setCenter.marker, this.setCenter.marker.clear);
  310.                       }
  311.                   }
  312.                   if (this.gmapType === 'panorama'){
  313.                       this.getMap().setLocationAndPOV(new google.maps.LatLng(this.setCenter.lat,this.setCenter.lng), {yaw: this.yaw, pitch: this.pitch, zoom: this.zoomLevel});
  314.                   }
  315.               }          
  316.         }, 200,this); // Ext.defer
  317.          
  318.         }else{
  319.           this.on('afterrender', this.apiReady, this);
  320.         }
  321.     },
  322.     // private
  323.     afterRender : function(){
  324.        
  325.         var wh = this.ownerCt.getSize();
  326.         Ext.applyIf(this, wh);        
  327.         Ext.ux.GMapPanel.superclass.afterRender.call(this);
  328.  
  329.     },
  330.     // private
  331.     buildScriptTag: function(filename, callback) {
  332.         var script  = document.createElement('script'),
  333.         head        = document.getElementsByTagName("head")[0];
  334.         script.type = "text/javascript";
  335.         script.src  = filename;    
  336.        
  337.         return head.appendChild(script);
  338.     },
  339.     // private
  340.     onMapReady : function(){    
  341.         this.addMapControls();
  342.         this.addOptions();        
  343.         this.addMarkers(this.markers);        
  344.         this.fireEvent('mapready', this, this.getMap());
  345.         return this;
  346.     },
  347.     // private
  348.     onResize : function(w, h){
  349.        
  350.         Ext.ux.GMapPanel.superclass.onResize.call(this, w, h);
  351.  
  352.         // check for the existance of the google map in case the onResize fires too early
  353.         if (typeof this.getMap() == 'object') {
  354.             google.maps.event.trigger(this.getMap(), 'resize');
  355.             if (this.lastCenter){
  356.               this.getMap().setCenter(this.lastCenter, this.zoomLevel);
  357.             }
  358.         }
  359.  
  360.     },
  361.     // private
  362.     setSize : function(width, height, animate){
  363.        
  364.         Ext.ux.GMapPanel.superclass.setSize.call(this, width, height, animate);
  365.  
  366.         // check for the existance of the google map in case setSize is called too early
  367.         if (Ext.isObject(this.getMap())) {
  368.             google.maps.event.trigger(this.getMap(), 'resize');
  369.             if (this.lastCenter){
  370.               this.getMap().setCenter(this.lastCenter, this.zoomLevel);
  371.             }
  372.         }
  373.        
  374.     },
  375.     // private
  376.     dragEnd: function(){        
  377.       this.lastCenter = this.getMap().getCenter();
  378.     },
  379.     /**
  380.      * Returns the current google map which can be used to call Google Maps API specific handlers.
  381.      * @return {GMap} this
  382.      */
  383.     getMap : function(){
  384.        
  385.         return this.gmap;
  386.        
  387.     },
  388.     /**
  389.      * Returns the maps center as a GLatLng object
  390.      * @return {GLatLng} this
  391.      */
  392.     getCenter : function(){
  393.        
  394.         return this.getMap().getCenter();
  395.        
  396.     },
  397.     /**
  398.      * Returns the maps center as a simple object
  399.      * @return {Object} this has lat and lng properties only
  400.      */
  401.     getCenterLatLng : function(){
  402.        
  403.         var ll = this.getCenter();
  404.         return {lat: ll.lat(), lng: ll.lng()};
  405.        
  406.     },
  407.     /**
  408.      * Creates markers from the array that is passed in. Each marker must consist of at least
  409.      * <code>lat</code> and <code>lng</code> properties or a <code>geoCodeAddr</code>.
  410.      * @param {Array} markers an array of marker objects
  411.      */
  412.     addMarkers : function(markers) {
  413.  
  414.         if (Ext.isArray(markers)){
  415.             for (var i = 0; i < markers.length; i++) {
  416.                 if (markers[i]) {
  417.                     if (typeof markers[i].geoCodeAddr == 'string') {
  418.                         this.geoCodeLookup(markers[i].geoCodeAddr, markers[i].marker, false, markers[i].setCenter, markers[i].listeners);
  419.                     } else {
  420.                         var mkr_point = new google.maps.LatLng(markers[i].lat, markers[i].lng);
  421.                         this.addMarker(mkr_point, markers[i].marker, false, markers[i].setCenter, markers[i].listeners);
  422.                     }
  423.                 }
  424.             }
  425.         }
  426.        
  427.     },
  428.     /**
  429.      * Creates a single marker.
  430.      * @param {Object} point a GLatLng point
  431.      * @param {Object} marker a marker object consisting of at least lat and lng
  432.      * @param {Boolean} clear clear other markers before creating this marker
  433.      * @param {Boolean} center true to center the map on this marker
  434.      * @param {Object} listeners a listeners config
  435.      */
  436.     addMarker : function(point, marker, clear, center, listeners){
  437.        
  438.         Ext.applyIf(marker,{});
  439.  
  440.         if (clear === true){
  441.             this.clearMarkers();
  442.         }
  443.         if (center === true) {
  444.             this.getMap().setCenter(point, this.zoomLevel)
  445.             this.lastCenter = point;
  446.         }
  447.  
  448.         var mark = new google.maps.Marker(Ext.apply(marker, {
  449.             position: point
  450.         }));
  451.        
  452.         if (marker.infoWindow){
  453.             this.createInfoWindow(marker.infoWindow, point, mark);
  454.         }
  455.        
  456.         this.cache.marker.push(mark);
  457.         mark.setMap(this.getMap());
  458.  
  459.         if (typeof listeners === 'object'){
  460.             for (evt in listeners) {
  461.                 google.maps.event.addListener(mark, evt, listeners[evt]);
  462.             }
  463.         }
  464.        
  465.         return mark;
  466.        
  467.     },
  468.     /**
  469.      * Creates a single polyline.
  470.      * @param {Array} points an array of polyline points
  471.      * @param {Object} linestyle an object defining the line style to use
  472.      */
  473.     addPolyline : function(points, linestyle){
  474.        
  475.         var plinepnts = new google.maps.MVCArray, pline, linestyle = linestyle ? linestyle : {
  476.             strokeColor: '#FF0000',
  477.             strokeOpacity: 1.0,
  478.             strokeWeight: 2
  479.         };
  480.        
  481.         Ext.each(points, function(point){
  482.             plinepnts.push(new google.maps.LatLng(point.lat, point.lng));
  483.         }, this);
  484.        
  485.         var pline = new google.maps.Polyline(Ext.apply({
  486.           path: plinepnts
  487.         },linestyle));
  488.        
  489.         this.cache.polyline.push(pline);
  490.        
  491.         pline.setMap(this.getMap());
  492.  
  493.     },
  494.     /**
  495.      * Creates an Info Window.
  496.      * @param {Object} inwin an Info Window configuration
  497.      * @param {GLatLng} point the point to show the Info Window at
  498.      * @param {GMarker} marker a marker to attach the Info Window to
  499.      */
  500.     createInfoWindow : function(inwin, point, marker){
  501.        
  502.         var me = this, infoWindow = new google.maps.InfoWindow({
  503.             content: inwin.content,
  504.             position: point
  505.         });
  506.        
  507.         if (marker) {
  508.             google.maps.event.addListener(marker, 'click', function(){
  509.                 me.hideAllInfoWindows();
  510.                 infoWindow.open(me.getMap());
  511.             });
  512.         }
  513.        
  514.         this.cache.infowindow.push(infoWindow);
  515.  
  516.         return infoWindow;
  517.  
  518.     },
  519.     // private
  520.     hideAllInfoWindows : function(){
  521.         for (var i = 0; i < this.cache.infowindow.length; i++) {
  522.             this.cache.infowindow[i].close();
  523.         }
  524.     },
  525.     // private
  526.     clearMarkers : function(){
  527.        
  528.         this.hideAllInfoWindows();
  529.         this.hideMarkers();
  530.  
  531.     },
  532.     // private
  533.     hideMarkers : function(){
  534.         Ext.each(this.cache.marker, function(mrk){
  535.             mrk.setMap(null);
  536.         });
  537.     },
  538.     // private
  539.     showMarkers : function(){
  540.         Ext.each(this.cache.marker, function(mrk){
  541.             mrk.setMap(this.getMap());
  542.         },this);
  543.     },
  544.     // private
  545.     addMapControls : function(){
  546.        
  547.         if (this.gmapType === 'map') {
  548.             if (Ext.isArray(this.mapControls)) {
  549.                 for(i=0;i<this.mapControls.length;i++){
  550.                     //this.addMapControl(this.mapControls[i]);
  551.                 }
  552.             }else if(typeof this.mapControls === 'string'){
  553.                 //this.addMapControl(this.mapControls);
  554.             }else if(typeof this.mapControls === 'object'){
  555.                 //this.getMap().add_control(this.mapControls);
  556.             }
  557.         }
  558.        
  559.     },
  560.     /**
  561.      * Adds a GMap control to the map.
  562.      * @param {String} mc a string representation of the control to be instantiated.
  563.      */
  564.     addMapControl : function(mc){
  565.        
  566.         var mcf = window[mc];
  567.         if (typeof mcf === 'function') {
  568.             //this.getMap().addControl(new mcf());
  569.         }    
  570.        
  571.     },
  572.     // private
  573.     addOptions : function(){
  574.        
  575.         if (Ext.isArray(this.mapConfOpts)) {
  576.             var mc;
  577.             for(i=0;i<this.mapConfOpts.length;i++){
  578.                 //this.addOption(this.mapConfOpts[i]);
  579.             }
  580.         }else if(typeof this.mapConfOpts === 'string'){
  581.             //this.addOption(this.mapConfOpts);
  582.         }        
  583.        
  584.     },
  585.     /**
  586.      * Adds a GMap option to the map.
  587.      * @param {String} mo a string representation of the option to be instantiated.
  588.      */
  589.     addOption : function(mo){
  590.        
  591.         var mof = this.getMap()[mo];
  592.         if (typeof mof === 'function') {
  593.             this.getMap()[mo]();
  594.         }    
  595.        
  596.     },
  597.     /**
  598.      * Looks up and address and optionally add a marker, center the map to this location, or
  599.      * clear other markers. Sample usage:
  600.      * <pre><code>
  601. buttons: [
  602.     {
  603.         text: 'Fenway Park',
  604.         handler: function(){
  605.             var addr = '4 Yawkey Way, Boston, MA, 02215-3409, USA';
  606.             Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined);
  607.         }
  608.     },{
  609.         text: 'Zoom Fenway Park',
  610.         handler: function(){
  611.             Ext.getCmp('my_map').zoomLevel = 19;
  612.             var addr = '4 Yawkey Way, Boston, MA, 02215-3409, USA';
  613.             Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined);
  614.         }
  615.     },{
  616.         text: 'Low Accuracy',
  617.         handler: function(){
  618.             Ext.getCmp('my_map').geoCodeLookup('Paris, France', undefined, false, true, undefined);
  619.         }
  620.     },{
  621.  
  622.         text: 'Bogus Address',
  623.         handler: function(){
  624.             var addr = 'Some Fake, Address, For, Errors';
  625.             Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined);
  626.         }
  627.     }
  628. ]
  629.      * </code></pre>
  630.      * @param {String} addr the address to lookup.
  631.      * @param {Object} marker the marker to add (optional).
  632.      * @param {Boolean} clear clear other markers before creating this marker
  633.      * @param {Boolean} center true to set this point as the center of the map.
  634.      * @param {Object} listeners a listeners config
  635.      */
  636.     geoCodeLookup : function(addr, marker, clear, center, listeners) {
  637.        
  638.         if (!this.geocoder) {
  639.             this.geocoder = new google.maps.Geocoder();
  640.         }
  641.         this.geocoder.geocode({
  642.                         address: addr
  643.                 }, this.addAddressToMap.createDelegate(this, [addr, marker, clear, center, listeners], true));
  644.        
  645.     },
  646.         // private
  647.         centerOnClientLocation : function(){
  648.                 this.getClientLocation(function(loc){
  649.                         var point = new google.maps.LatLng(loc.latitude,loc.longitude);
  650.         this.getMap().setCenter(point, this.zoomLevel);
  651.         this.lastCenter = point;
  652.                 });
  653.         },
  654.         // private
  655.         getClientLocation : function(fn, errorFn){
  656.                 if (!errorFn) {
  657.           errorFn = Ext.emptyFn;
  658.       }
  659.                 if (!this.clientGeo) {
  660.                         this.clientGeo = google.gears.factory.create('beta.geolocation');
  661.                 }
  662.                 geo.getCurrentPosition(fn.createDelegate(this), errorFn);
  663.         },
  664.     // private
  665.     addAddressToMap : function(response, status, addr, marker, clear, center, listeners){
  666.         if (!response || status !== 'OK') {
  667.             this.respErrorMsg(status);
  668.         }else{
  669.             var place = response[0].geometry.location,
  670.                                   accuracy = this.getLocationTypeInfo(response[0].geometry.location_type,'level'),
  671.                                   reqAccuracy = this.getLocationTypeInfo(this.minGeoAccuracy,'level');
  672.             if (accuracy === 0) {
  673.                 this.geoErrorMsg(this.geoErrorTitle, this.geoErrorMsgUnable);
  674.             }else{
  675.                 if (accuracy < reqAccuracy) {
  676.                     this.geoErrorMsg(this.geoErrorTitle, String.format(this.geoErrorMsgAccuracy, response[0].geometry.location_type, this.getLocationTypeInfo(response[0].geometry.location_type,'msg')));
  677.                 }else{
  678.                     point = new google.maps.LatLng(place.xa,place.za);
  679.                     if (center){
  680.                         this.getMap().setCenter(point, this.zoomLevel);
  681.                         this.lastCenter = point;
  682.                     }
  683.                     if (typeof marker === 'object') {
  684.                         if (!marker.title){
  685.                             marker.title = response.formatted_address;
  686.                         }
  687.                         var mkr = this.addMarker(point, marker, clear, false, listeners);
  688.                         if (marker.callback){
  689.                           marker.callback.call(this, mkr, point);
  690.                         }
  691.                     }
  692.                 }
  693.             }
  694.         }
  695.        
  696.     },
  697.     // private
  698.     geoErrorMsg : function(title,msg){
  699.         if (this.displayGeoErrors) {
  700.             Ext.MessageBox.alert(title,msg);
  701.         }
  702.     },
  703.     // private
  704.     respErrorMsg : function(code){
  705.         Ext.each(this.respErrors, function(obj){
  706.             if (code == obj.code){
  707.                 Ext.MessageBox.alert(this.respErrorTitle, obj.msg);
  708.             }
  709.         }, this);
  710.     },
  711.     // private
  712.     getLocationTypeInfo: function(location_type,property){
  713.       var val = 0;
  714.       Ext.each(this.locationTypes, function(itm){
  715.         if (itm.code === location_type){
  716.           val = itm[property];
  717.         }
  718.       });
  719.       return val;
  720.     }
  721. });