Tutorial: How to use Google Maps API with Ext.JS
http://ongmap.com/ext20_gmap/
Contents
- 1. Source files for this tutorial
- 2. Set up the initial parameters and html structure (index.php)
- 3. Combine Google Maps API and Ext (ext2_gmap.js)
- 4. Server-side PHP script (handler.php)
1. Source files for this tutorial
Sample program for this tutorial consists of four fileshere):
index.php
Handles the url parameters and api key for Google Maps API, load external scripts and defines the basic html structure for the application
handler.php
Handles the AJAX requests from ext2_gmap.js triggered by user’s interaction
ext2_gmap.js
Creates and places all the widgets and the map, and define their actions
base.css
Defines some styles for application
In the program, some useful web APIs are utilized together with Google Maps API:
- Google AJAX Search API for local search
- Yahoo Weather RSS (wrapped by Weather API of ONGMAP.COM) for local weather
- GeoIP from MaxMind to decode user’s IP address into country/city/latitude/longitude
2. Set up the initial parameters and html structure (index.php)
2.1. HTML
At first, we need to define the html structure for this program.
This program uses Ext’s Border layout and consists of two regions, west and center. West region is the control panel of this sample appication and holds three panels for search, navigation and weather. Center region holds only one panel for the map. In total, we need 4 panels.
In index.php, we put 4 empty DIVs which will correspond to 4 panels. We give them ids (”tree”, “weather”, “search” and “map”) so that they can be easily referred inside the program.
We have also added another DIV for loading message. Displaying a loading message is a good idea because loading Google Maps together with Ext library sometimes takes several seconds (and if you are going to use GeoIP, loading time get even longer!)
Below is the base html structure for this sample, very simple:
<body>
<div id="loading_message">
<img src="./images/loading.gif" />
<span>This is a demo site for Ext2.0 x Google Map API.</span><br />
<span>Please wait while we load the program.</span><br />
<span>It may take us a moment to determine which part of the world you are from.<br />
Thank you for your patience</span>
</div>
<div id="tree"></div>
<div id="weather"></div>
<div id="search"></div>
<div id="map" class="gmap_full"></div>
</body>
2.2. External script loading
In addition to above html codes, we need to include lines to load Google Maps API and Ext. Header lines in index.php will look like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="./master.css" type="text/css" media="screen,tv" />
<style type="text/css">
v:* {behavior:url(#default#VML);}
</style>
<link rel="stylesheet" type="text/css" href="/path/to/ext/resources/css/ext-all">
<script src="http://www.google.com/jsapi?key=[your Google Maps API key]" type="text/javascript"></script>
<script type="text/javascript">
google.load("maps", "2");
google.load("search", "1");
</script>
<script type="text/javascript" src="./jslib/ext/adapter/ext/ext-base"></script>
<script type="text/javascript" src="./jslib/ext/ext-all"></script>
<script language="JavaScript" src="http://j.maxmind.com/app/geoip.js"></script>
<script src="./jslib/ext2_gmap" type="text/javascript"></script>
<title>Ext 2.0 x Google Map</title>
</head>
Please note that we are using relatively new Google AJAX API loader. With this loader, we only need to include one source file to load both Maps and Search apis. You can achieve the same result by using the traditional method for Google Maps API.
We are also loading MaxMind’s GeoIP to use it in the program. If you are not going to use GeoIP, you can exlude this line.
2.3. User input handling
If we want to allow users to specify initial latitude/longitude, zoom level or map type, we can add a small php script in front the header lines:
<?php
$host = $_SERVER[HTTP_HOST];
// You need different API keys for different hosts
if($host=="localhost"){
$gmap_key = [your api key for dev environment here];
}elseif($host=="ongmap.com"){
$gmap_key = [your api key for operation environment here];
}
// Initialize the parameters
$lat = 0; $lng = 0; $zoom = 10; $map_type = 'normal';
if(isset($_GET['lat']) && $_GET['lat']!=null && is_numeric($_GET['lat'])){
$lat = $_GET['lat'];
if($lat>90 || $lat<-90){ $lat = 0; } // If invalid latitude is passed, set it to zero
if(isset($_GET['lng']) && $_GET['lng']!=null && is_numeric($_GET['lng'])){
$lng = $_GET['lng'];
if($lng>180 || $lng<-180){ $lng = 0; } // If invalid longitude is passed, set it to zero
if(isset($_GET['zoom']) && $_GET['zoom']!=null && is_numeric($_GET['zoom'])){
$zoom = $_GET['zoom'];
if($zoom<0 || $zoom>19){ $zoom = 10; } // If invalid zoom level is passed, set it to 10
$map_types = array('normal','air','hybrid');
if(isset($_GET['map_type']) && $_GET['map_type']!=null && in_array($_GET['map_type'],$map_types)){
$map_type = $_GET['map_type'];
}
?>
then we need to add the following lines after loading Google Maps API to pass url parameters to the program:
var _centerLat = <?php echo $lat; ?>;
var _centerLng = <?php echo $lng; ?>;
var _zoom = <?php echo $zoom; ?>;
var _lang = "<?php echo $lang; ?>";
var _Gmap_types = {
normal: G_NORMAL_MAP,
air : G_SATELLITE_MAP,
hybrid: G_HYBRID_MAP
};
var _mapType = _Gmap_types["<?php echo $map_type; ?>"];
</script>
and the lines for loading Google Maps API and GeoIP should be modified as well:
<script src="http://www.google.com/jsapi?key=<?php echo $gmap_key; ?>" type="text/javascript"></script>
<?php if($lat==0 && $lng==0){ ?>
<script language="JavaScript" src="http://j.maxmind.com/app/geoip.js"></script>
<?php } ?>
index.php is now complete and we are ready to start coding in Google Maps API and Ext!
3. Combine Google Maps API and Ext (ext2_gmap.js)
3.1. Overall structure
At this section, we will go through the lines of ext2_gmap.js to see how to use Google Maps API together with Ext.
Since we are using Google AJAX API loader, we declare some global shortcuts for frequently used classes:
var GMap2 = google.maps.Map2;
var GLatLng = google.maps.LatLng;
var GMarker = google.maps.Marker;
var GEvent = google.maps.Event;
The rest of the program will be like this:
Ext2Gmap = function(){};
Ext2Gmap.prototype = {
// methods for class Ext2Gmap are defined here
};
var mapObj = new Ext2Gmap();
window.onload = function(){
mapObj.init();
};
window.onunload = function(){
mapObj.unload();
};
3.2. Ext2Gmap class overview
We define a class (Ext2Gmap) to encapsulate all the logics we need for this program, and create a global instance of that class. Then, we call for necessary methods at window.onload and unload events.
For this sample program, we are going to define seven methods for Ext2Gmap, namely:
- Ext2Gmap.init() : handles the url parameters and load initial data needed by the program
- Ext2Gmap.prepare(): sets up all the layouts, widgets, the map and the events
- Ext2Gmap.searchAddress(): searches for a locations which matches with the input argument
- Ext2Gmap.searchLocal(): searches for local spots which matches with the input argument within the boundary of current map
- Ext2Gmap.panAndMark(): set the center of the map to the specified location, add a marker on the map
- Ext2Gmap.getWeather(): load the weather information neares to the center of the current map
- Ext2Gmap.unload(): detach all the Ext event listeners and unload Google Map resources
Let’s look at each methods.
3.3. Ext2Gmap.init
This method first checks if the user’s browser is compatible with Google Maps API, then takes care of the user inputs from url parameters (if there is no input, GeoIP is used to determine initial latitude and longitude).
init: function(){
if(google.maps.BrowserIsCompatible()){
// Check user input
this.lat = _centerLat?_centerLat:null;
this.lng = _centerLng?_centerLng:null;
this.mapType = _mapType?_mapType:'normal';
this.zoom = _zoom?_zoom:10;
// Check where user is coming from by GeoIP
if(!_centerLat || !_centerLng){
this.lat = geoip_latitude();
this.lng = geoip_longitude();
}
// if geoip failed
if(!this.lat || !this.lng){
this.lat = 0;
this.lng = 0;
}
Once all the resources are ready (loading external scripts and DOM), Ext.onReady is called.
Within Ext.onReady, we are making a call to handler.php via Ext.data.Connection to load the initial data for the program (actually, for this sample program, no initial data is loaded. Only the string “OK” is echoed back from handler.php. For real application, you can load message data for different languages or html templates for message boxes on the map and so forth)
Ext.onReady(function(){
// Initialize data
var conn = new Ext.data.Connection();
conn.request({
url : "./handler.php",
params : { mode : "init" },
scope : this,
callback: function(o,s,r){
if(s){
if(r.responseText.length==0){
Ext.Msg.alert("ERROR","Failed to initialize. Please reload");
}else{
var res = r.responseText;
/* Do some initial tasks here */
Ext.get("loading_message").remove();
Ext.Msg.wait("Loading","Loadind data...");
setTimeout(function(){Ext.Msg.hide();}, 1000);
this.prepare();
}
}
}
});
},this);
}else{
// Somehting to do for Google Map imcompatible browsers
}
},
At the end of the callback for Ext.onReady, the DIV for loading message is removed before rendering the map and the widgets begin via Ext2Gmap.prepare method. Instead of loading message, Ext.Msg.wait() is now called to display a modal dialog box for 1 second to notify users that the program is still loading.
3.4. Ext2Gmap.prepare
If Ext2Gmap.init is successfully called, this method takes care the rest. This method renders the widgets and the map and bind all the necessary callback functions to the user triggered events.
At first, we create three panels by calling “new Ext.Panel()” for “tree”, “search” and “weather” DIVs we have defined in index.php. These panels are created explicitly whereas the panel for “map” DIV will be created implicitly within a call to Ext.Viewport. This is because we want to add event listeners to these three panels.
prepare: function(){
var nav_panel = new Ext.Panel({
contentEl: 'tree', // specify the DIV id in index.php
title:'Navigation',
border:false
});
var search_panel = new Ext.Panel({
contentEl: 'search', // specify the DIV id in index.php
title:'Search',
border:false
});
var weather_panel = new Ext.Panel({
contentEl: 'weather', // specify the DIV id in index.php
title:'Weather',
border:false
});
// Add event listeners for "expand" event
nav_panel.on('expand',function(){this.mode = 'navigation';},this);
search_panel.on('expand',function(){this.mode = 'search';},this);
weather_panel.on('expand',function(){
this.mode = 'weather';
this.getWeather();
},this);
// Store the references to these panels to "this" so that event listeners can be purged at unload
this.panels = [search_panel,nav_panel,weather_panel];
We now call “new Ext.Viewport()” to create a viewport with border layout. Since we only need “west” and “center” regions, we add two regions in items.
For the west region, we would like to layout the three panels in Accrordion layout. So, we set “layout” to “accordion” for west region and “items” to “this.panels”.
For the center region, we only need a panel for “map”. So, we just set “items” to an object notation “{contentEl:’map’}” to implicitly create an Ext.Panel and apply it to ‘map’ DIV.
var viewport = new Ext.Viewport({
layout:'border',
items:[{
region:'west',
id:'west_region',
title:'Control Panel',
width: 200,
collapsible: true,
margins:'0 0 0 5',
layout:'accordion',
layoutConfig:{ animate:true },
items: this.panels
},{
region:'center',
id:'center_region',
items: { contentEl:'map' }
}]
});
By this point, the frame has been set up. We need to fill in the panels with content.
First we set up a nagivation tree. Tree set up codes look like this:
var Tree = Ext.tree;
var tree = new Tree.TreePanel({
el: 'tree', // specify the DIV id to render the tree on
autoScroll: true,
animate:true,
border: false,
containerScroll: true,
height: 'auto',
loader: new Tree.TreeLoader({
dataUrl : './handler.php',
baseParams : { mode : 'tree' }
})
});
var root = new Tree.AsyncTreeNode({
text: 'Countries',
draggable:false,
id:'source'
});
tree.setRootNode(root);
tree.render();
root.expand();
Ext.tree.TreeLoader will call handler.php to load the data for the node. We use Ext.tree.AsyncTreeNode so that we don’t have to load all the data for tree nodes (for this sample, the data for tree nodes is very small, but for real applications, we usually have large set of data for the nodes. Creating a tree with large data could slow down your application. So, it is a good idea to use AsyncTreeNode to break up node data into smaller chunks)
TreeLoader requires the dataUrl (handler.php) to return the data in JSON format with specific attributes, e.g. “id”, “text”, “leaf”, “cls”, “children” etc, but it also accepts extra data with custom attributes.
With these extra data, we can set up an event listener like this:
tree.on('click',function(n,e){
if(n.attributes.lat && n.attributes.lng){
var p = new GLatLng(n.attributes.lat,n.attributes.lng);
var msg = "<p>"+n.attributes.text+"</p>";
msg += "<p>Latitude="+p.lat()+"</p>";
msg += "<p>Longitude="+p.lng()+"</p>";
this.panAndMark({point:p,msg:msg});
}
},this);
this.tree = tree; // for unload puropose
Above code will check if the node has attributes with names “lat” and “lng”, and if it does, it will create an html fragment and call Ext2Gmap.panAndMark when the node is clicked.
Search panel is fairly straightforward. The code looks like this:
var search_key = new Ext.form.TextField({
hideLabel : true,
name : "search_keywords",
id : "search_keywords",
width : 180
});
var search_option = new Ext.data.SimpleStore({
fields: ['option', 'option_title'],
data : [[0,'Address'], [1,'Local Spots']]
});
var search_combo = new Ext.form.ComboBox({
hideLabel : true,
store: search_option,
displayField:'option_title',
valueField:'option',
value: 0,
mode: 'local',
triggerAction: 'all',
readOnly: true,
selectOnFocus:true,
width: 170,
listWidth: 170
});
var search_form = new Ext.form.FormPanel({
border: false,
labelWidth : 0,
width : 198,
style : {border: "none", 'margin-top':'3px',padding:0}
items : [search_key,search_combo]
});
We have created a text field for search string and a combo box for search option, then added to the form.
search_form.addButton({
text : 'Search',
scope : this,
handler : function(){
var op = search_combo.getValue();
var sk = search_key.getRawValue();
if(sk.length==0){
search_key.markInvalid("Input search keyword");
return;
}
switch(op){
case 0:
this.searchAddress(sk); break;
case 1:
this.searchLocal(sk); break;
default:
break;
}
}
});
search_form.render(Ext.get('search'));
this.form = search_form;
Since we have set up two options in combo box (Address and Local Spots), we also need to set up the handler for the search button to switch its action.
If the text field is not empty, the form checks the combo box for the search type and calls either Ext2Gmap.searchAddress or Ext2Gmap.searchLocal with entered search string.
Weather panel will be left empty until Ext2Gmap.getWeather is called (triggered by clicking on the weather panel).
Finally, we create the map. Creating map is very simple:
var map = new GMap2(Ext.get('map').dom);
We can enable options and add controls by calling the following methods of GMap2:
map.enableDoubleClickZoom();
map.enableContinuousZoom();
map.enableScrollWheelZoom();
map.addControl(new google.maps.LargeMapControl());
map.addControl(new google.maps.MapTypeControl());
map.addControl(new google.maps.ScaleControl());
map.addControl(new google.maps.OverviewMapControl());
We now set the center of the map (and zoom level and map type) specified by the user or obtained from GeoIP:
map.setCenter(new GLatLng(this.lat,this.lng),this.zoom);
map.setMapType(this.mapType);
We can attach event listeners to the map itself via GEvent.addListener method.
For this sample program, we want weather information to get automatically updated as user drags the map (or changes the zoom level) if the weather panel is open. We also want “Local Spots” search to automatically update the search results when user drags the map if the search panel is open.
For those purposes, we add listeners to the map for ‘dragend’ and ‘zoomend’ events like this:
var obj = this; // need this line to refer to "this" inside event listener
GEvent.addListener(map,'dragend',function(){
if(search_key.getRawValue() && obj.mode && obj.mode=='localSearch'){
obj.searchLocal(search_key.getRawValue());
}else if(obj.mode && obj.mode=='weather'){
obj.getWeather();
}
});
GEvent.addListener(map,'zoomend',function(){
if(search_key.getRawValue() && obj.mode && obj.mode=='localSearch'){
obj.searchLocal(search_key.getRawValue());
}else if(obj.mode && obj.mode=='weather'){
obj.getWeather();
}
});
Make sure to save the referece to the map:
this.map = map;
One last thing in this method is specifically for Internet Explorer. Without the following code, the height of the map will not be as expected (there should be some other way to avoid this…)
if(Ext.isIE){
Ext.get('map').setStyle({height:Ext.get('center_region').getHeight()});
map.checkResize();
Ext.get('center_region').on('resize',function(){
Ext.get('map').setStyle({height:Ext.get('center_region').getHeight()});
this.map.checkResize();
},this);
}
3.5. Ext2Gmap.searchAddress
This method searches for the latitude and longitude which best matches with given argument. If the match is found, then the map will be panned to the matched location and a marker and an information window will be dislayed. If none matches, a message box appears telling nothing found.
Inside the method, Google Maps API’s ClientGeocoder method is utilized to geocode the input string:
searchAddress : function(opt){
var m = this;
var geo = new google.maps.ClientGeocoder();
geo.getLocations(opt,function(d){
if(d.Status.code==200 && d.Placemark){
var pm = d.Placemark[0];
var p = new GLatLng(pm.Point.coordinates[1],pm.Point.coordinates[0]);
var msg = "<p>"+pm.address+"</p>";
msg += "<p>Latitude="+p.lat()+"</p>";
msg += "<p>Longitude="+p.lng()+"</p>";
m.panAndMark({point:p,msg:msg});
}else{
Ext.Msg.alert("Not Found","No location was found for "+opt);
}
});
this.mode = 'addressSearch';
},
3.6. Ext2Gmap.searchLocal
This method searches for the local spots like restaurants and schools within the boundary of the current map. Matched spots will be displayed on the map (markers) as well as below the search form (list).
Inside the method, Google AJAX Search API’s LocalSearch method is utilized:
searchLocal : function(opt){
var m = this;
var geo = new google.search.LocalSearch();
geo.setCenterPoint(m.map); // pass the map object to specify the center
geo.setResultSetSize(google.search.Search.LARGE_RESULTSET);
geo.execute(opt); // a bit differenct style from ClientGeocoder
if(m.grid){ m.grid.destroy(); }
Ext.DomHelper.append('search','<img id="loading_icon" src="./images/loading.gif" />');
geo.setSearchCompleteCallback(geo,function(){
Ext.get('loading_icon').remove();
m.map.clearOverlays();
var res = this.results; // "this" referes to "geo"
if(res && res.length>0){
var data = [];
var markers = []
for(var i=0; i<res.length; i++){
markers[i] = (function(pt){
var marker = new GMarker(new GLatLng(pt.lat,pt.lng));
GEvent.addListener(marker,'click',function(){
marker.openInfoWindowHtml(pt.html);
});
m.map.addOverlay(marker);
data[i] = [pt.html.innerHTML];
return marker;
})(res[i]);
}
var ds = new Ext.data.Store({
reader : new Ext.data.ArrayReader({},[{name: 'html'}])
});
ds.loadData(data);
var sm = new Ext.grid.RowSelectionModel({singleSelect:true});
sm.on('rowselect', function(sm,ri){
GEvent.trigger(markers[ri],'click');
});
var grid = new Ext.grid.GridPanel({
store: ds,
columns:[{header: '', width: 195, dataIndex: 'html' }],
width: 195,
height:300,
autoScroll: true,
sm: sm
});
grid.render(Ext.get('search'));
m.grid = grid;
}else{
Ext.get('loading_icon').destroy();
Ext.Msg.alert("Not Found","No \""+opt+ "\" was found for this area");
}
});
this.mode = 'localSearch';
},
There are a couple of tricky code inside this method we should be careful about:
When creating markers from search results, we used anonymous function in which marker is created, mapped to the map and event is attached. This way, we can set different messages for each markers information window which are displayed when markers are clicked:
for(var i=0; i<res.length; i++){
markers[i] = (function(pt){
var marker = new GMarker(new GLatLng(pt.lat,pt.lng));
GEvent.addListener(marker,'click',function(){
marker.openInfoWindowHtml(pt.html);
});
m.map.addOverlay(marker);
data[i] = [pt.html.innerHTML];
return marker;
})(res[i]);
}
Also, please note that inside the for loop above, we are creating a multi-dimensional array:
data[i] = [pt.html.innerHTML];
This is necessary because Ext.data.ArrayReader requires a multi-deimensional array as its input:
var ds = new Ext.data.Store({
reader : new Ext.data.ArrayReader({},[{name: 'html'}])
});
ds.loadData(data);
Another trick is at ‘rowselect’ event. When we created markers, we have stored them in an array “markers”. Since all the items in this array have event listeners attached, we can do something like this:
var sm = new Ext.grid.RowSelectionModel({singleSelect:true});
sm.on('rowselect', function(sm,ri){
GEvent.trigger(markers[ri],'click');
});
At ‘rowselect’ event, a callback function is called with two arguments, selected row (sm) and its index value (ri). So, we can set up a callback function to trigger the click event of marker with the same index as the row just selected. GEvent.trigger is a very useful method for a case like this.
3.7.Ext2Gmap.panAndMark
This method pan the map to the given latitude and longitude. If an html fragment is given, this method will also add a marker to the map and open a information bubble:
panAndMark: function(opt){
var m = this.map;
var p = opt.point;
var mrk = new GMarker(p);
m.clearOverlays();
m.addOverlay(mrk);
m.setCenter(p);
if(opt.msg){
mrk.openInfoWindowHtml(opt.msg);
GEvent.addListener(mrk,'click',function(){
this.openInfoWindow(opt.msg);
});
}
},
3.8. Ext2Gmap.getWeather
This method sends out the center latitude and longitude of the map to handler.php and receive the weather information of the nearest observation point. With returned values, this method generates an html fragment and add it to the weather panel:
getWeather: function(){
if(this.w_request && this.w_request.isLoading()){
this.w_request.abort();
if(Ext.get('loading_icon')){
Ext.get('loading_icon').remove();
}
}
var conn = new Ext.data.Connection();
this.w_request = conn;
var center = this.map.getCenter();
var lat = center.lat();
var lng = center.lng();
var wt = Ext.get('weather_table')
if(wt){ wt.remove(); }
Ext.DomHelper.append('weather','<img id="loading_icon" src="./images/loading.gif" />');
conn.request({
url : "./handler.php",
params : {
mode : "weather",
lat : lat,
lng : lng
},
scope : this,
callback: function(o,s,r){
Ext.get('loading_icon').remove();
if(s){
if(r.responseText.length==0){ return; }
eval("var res = {result:"+r.responseText+"}");
if(res.length==0){ return; }
var result = res.result;
var weather_table = '<div id="weather_table" class="weather">'
+ '<span class="weather_title">'+result.title+'</span>'
+ '<table><tbody>'
+ '<tr><td>Today</td><td>-></td></tr><tr>'
+ '<td class="weather_item"><img src="'+result.today.icon+'" /></td>'
+ '<td class="weather_item"><img src="'+result.tomorrow.icon+'" /></td>'
+ '</tr><tr>'
+ '<td class="weather_item"><span class="weather_hi">'+result.today.hi+'</span>'
+ '/<span class="weather_lo">'+result.today.lo+'</span></td>'
+ '<td class="weather_item"><span class="weather_hi">'+result.tomorrow.hi+'</span>'
+ '/<span class="weather_lo">'+result.tomorrow.lo+'</span></td>'
+ '</tr></tbody></table>'
+ '<span class="weather_title">Powered by <a href="http://weather.yahoo.com/" target="_blank">Yahoo Weather</a></span>'
+ '</div>';
Ext.DomHelper.append('weather',weather_table);
}
}
});
},
Please make sure to check if the previous request is still loading or finished before making a new request to handler.php. This situation frequently happens because users drag the map more than one times in a very short period while each request for weather information usually takes more than 1 second to finish.
So, if we don’t cancel previous request before we make a new one, the program get confused and unexpected results could happen.
We can check the status of request and cancel it like this:
if(this.w_request && this.w_request.isLoading()){
this.w_request.abort();
if(Ext.get('loading_icon')){
Ext.get('loading_icon').remove();
}
}
var conn = new Ext.data.Connection();
this.w_request = conn;
Also, it is kind to display some kind of indicator icon to tell users that the information is being loaded. We can easily do this by adding and removing the icon before and after the request to handler.php.
3.9. Ext2Gmap.unload
This method unbind the all the Ext event listeners and call google.maps.Unload method. This method should be called on window.unload:
unload: function(){
this.tree.purgeListeners();
this.form.buttons[0].purgeListeners();
for(var i=0; i<this.panels.length; i++){
this.panels[i].purgeListeners();
}
google.maps.Unload();
delete this;
}
Comments
Comment from steve
Time: 2007/11/7 水曜日, 14:57:11
In navigation, the tree is not working.
It only displays ‘Countries’ and no children (such as New York, etc.)
are displayed. Clicking ‘Countries’ node does not do anything, either.
Please help. I spent hours on this already.
Comment from steve
Time: 2007/11/8 木曜日, 3:40:32
It works now. Upgrading to php5.2.4 did the trick. php5.0.x that I used
did not have support for json.
Comment from yuki
Time: 2007/11/9 金曜日, 8:10:49
Thanks for your feedback, steve!
I’ll put a note about PHP version issue when I write PHP part of tutorial.
Comment from Diclonius
Time: 2008/1/21 月曜日, 23:26:25
Work best in IE with..
if(Ext.isIE){
Ext.get(’map’).setStyle({height:Ext.get(’center_region’).getHeight(),width:Ext.get(’center_region’).getWidth()});
map.checkResize();
Ext.get(’center_region’).on(’resize’,function(){
Ext.get(’map’).setStyle({height:Ext.get(’center_region’).getHeight(),width:Ext.get(’center_region’).getWidth()});
this.map.checkResize();
},this);
}
Comment from Diclonius
Time: 2008/1/22 火曜日, 3:57:01
But… If you put a South region..
IE works better with
if(Ext.isIE){
map.checkResize();
Ext.get(’center_region’).on(’resize’,function(){
this.map.checkResize();
},this);
}
I’m crazy m@@m
Comment from Sean
Time: 2008/1/25 金曜日, 10:50:26
Do you have a zip of all the code to run this?
Thanks!
Sean
Comment from yuki
Time: 2008/1/25 金曜日, 11:11:31
Sean,
There is a link to tar.gz file in the first paragraph of “1. Source files for this tutorial” section above (bit hard to find…)
Comment from Bruno
Time: 2008/4/16 水曜日, 23:50:15
Dear Friend,
thank you very much for this wonderfull inspiring job!!!!!
Really impressive
I’m in troubles to obtain the whole map
my ext just show me a little cropped map at the top (look like north area),
and west , the firebug receive the tiles in blank space at center, but it not show.
I’m using ext 2.2 on mac osx 10.4
could you give me some light.
Thanks in advance and sorry for that inconvenience.
Bruno
Comment from yuki
Time: 2008/4/17 木曜日, 0:06:42
Hi Bruno,
Have you tried to set “height:100%” of DIV tag for the map? Without it, the map becomes exactly as you described above.
Have you also downloaded the source of this sample map? Please take a look at its JavaScript as well as its CSS. I put up a link below:
http://ongmap.com/ext20_gmap/ext2gmap.tar.gz
If you can’t still solve the problem, let me take a look at your code ![]()
Comment from Bruno
Time: 2008/4/17 木曜日, 23:05:00
Hey Yuki,
you are a hero!
thanks for your help,, i just copied your base.css (the onlinenot the ziped one) and it works full screen
I hope i can show you the results sooonn!
kindest regards
Bruno
Comment from Simon
Time: 2008/7/24 木曜日, 23:48:03
How to install it? I cannot correctly setup on my testing appserv. Would you please to list more detail on it?
Thank you
Comment from Simon Lee
Time: 2008/7/26 土曜日, 1:12:01
Hello Yuki Naotori,
I would like to know how to setup your file ext2gmap.tar.gz, I was work hard on ext1.0 but have some task to solve. Would you please to let me know the setting for your product?
Best Regards,
Simon
Comment from yuki
Time: 2008/7/26 土曜日, 7:28:07
Hi Simon,
Can you send me an email about your trouble? (you can find my contact at http://ongmap.com/blog/?page_id=16 [at Contact section]). Thanks
Comment from yuki
Time: 2008/7/26 土曜日, 7:29:19
BTW, this sample only works Ext JS 2.0 and up. It won’t work with Ext JS 1.x
Comment from Ramon
Time: 2009/4/8 水曜日, 22:43:57
Hi
I am lookin for a class that permits clicking on the map and write the values of the corrdinates in text input fields to be stored in data base
Comment from pengzai
Time: 2009/5/4 月曜日, 10:04:12
Good job!
Would you send me a zip of all the code ?
Email:pengzai512mail@gmail.com
Thanks!
Comment from willy
Time: 2009/11/22 日曜日, 23:22:34
Hi,
I didn’t find handler.php nor base.css in the on-line version, so I downloaded the *.tar.gz.
I did find the handler.php there, but the base.css contains a copy of the other files in the *.tar.gz.
Can somebody provide me with a copy of the base.css.
Thanks,
Willy.
Comment from Younkee
Time: 2010/2/4 木曜日, 11:17:24
Hi,
I don’t find where i can downloaded this demo. Can you send it to me? My email is younkee@gmail.com.
thanks, younkee
Comment from accommodations
Time: 2010/5/14 金曜日, 0:08:31
Very interest.
Comment from security+ certification
Time: 2010/7/14 水曜日, 16:38:41
Chevrolet hired a couple of motor coach companies to produce a limited number of airport limos in 1957,
Comment from ibm certification
Time: 2010/7/14 水曜日, 16:39:07
the front and rear suspensions and six lug configurations that was utilized on the limos, was used on the Black Widows.
Comment from iseb certification
Time: 2010/7/14 水曜日, 16:40:01
The parts were not from Chevy trucks. The “widow” utilized the parts from the limo which could be easily purchased over the counter at any Chevy dealership in that era. The large fuel tank was from a 57 Chevrolet Taxi and the ceramic brake shoes were commom the the Black Widow.
Comment from java certification dumps
Time: 2010/7/14 水曜日, 16:40:23
You can clone a 150 sedan pretty easily, but some of the one-off pieces would be impossible to find.
Comment from Cialis Online
Time: 2010/8/17 火曜日, 6:02:22
You have hit the mark. It seems to me it is excellent thought. I agree with you.
Comment from Generic Cialis
Time: 2010/8/17 火曜日, 7:05:13
The good result will turn out
Write a comment