2008年11月28日星期五

谷歌地图上的快捷键

前面设置地图的博文里面其实漏掉了一个很有意思而又不太引人注目的地图特性,就是设置地图的快捷键。
说实话,之前我也没有注意过这一点,甚至都没有想过地图可以支持快捷键,一个以拖拽成名的应用,谁又能想到可以用快捷键来控制呢。
有一天无聊的上下翻动地图API的文档,突然发现一个很陌生的类,GKeyboardHandler,没见过!
仔细看了一下,居然是用来使地图支持键盘操作的,更有意思的是,这个类在文档顶部的类名列表中没有出现,不知道是整理文档的疏漏,还是因为这个类太小,小的连一个方法或者参数都没有,只有光秃秃一个类充作构造函数。也可能是这个类所支持的键盘操作有限吧,我把支持的键做了个列表:

动作
方向键 向对应的方向连续移动地图,同时按下邻近的两个会向对角移动
Home/End以3/4的幅度左右平移地图 ,动画效果
Page Up/Page Down 以3/4的幅度上下平移地图,动画效果
+ / -
放大/缩小一个级别的地图

 只有地图的移动和缩放操作,特意到地图主页上试了试,支持,没有问题,只不过你需要先点击地图,使地图容器处于激活状态。用起来也不错,感觉地图的移动居然比鼠标拖动时还要平滑。
如果需要在你自己的地图上使用,只需要一句话:

new GKeyboardHandler(map);

够简单吧,呵呵,赶紧扔开你的鼠标到右边的地图上试试吧。

给你的地图加上API提供的默认控件

地图上的控件一般是指悬浮在地图上、不随地图移动的图片、按钮等等DOM元素,可以用来控制地图、帮助用户和地图交互、显示地图的特定信息和状态。
在谷歌地图主页上,有可以控制地图缩放的控件、有切换地图类型的控件、有显示缩略图的控件等等,这些控件在地图API里默认也都是提供的,所以,你可以在你的地图上加上这些控件,并且可以根据你的需要随意调整地图控件的位置、改变控件的外观,就像我在右边的地图上把缩放控件移到右上角而不是默认的左上角、并且使用了一个微型化的外观。下面先看看可以在地图上添加哪些控件吧。

地图API中默认控件的种类
1、地图缩放控件
   缩放控件是可以控制地图移动和放大级别的,默认有三种:
   1) 全功能控件 GLargeMapControl 
        有方向按钮、恢复按钮、缩放按钮和缩放滑块
   2) 微型化控件 GSmallMapControl 
       把全功能控件去掉恢复按钮和缩放滑块后的控件
   3) 微型缩放控件 GSmallZoomControl
       只有放大/缩小两个按钮
   下面从左到右依次是GLargeMapControl,GSmallMapControl,GSmallZoomControl这三个控件,选用哪一个就看你的空间有多大了。不过,我认为通过GMap2提供的设置项允许用户使用滚轮和双击缩放地图比使用一个大大的缩放控件更方便。
            
    这几天谷歌地图主页刚刚换了新的缩放控件,有点类似于谷歌地球上哪个,不过使用API实现的还没有变,仍然是上面显示的这个样子。

2、地图类型选择控件
    地图类型选择控件是用来选定所显示地图的类型的,比如普通地图、卫星地图、地形地图等等,也有三种,唉,突然想起孔乙己:)
    1)按钮式标准控件  GMapTypeControl
    每种地图类型对应一个按钮,点击不同的按钮切换地图类型,比如
   
    2)菜单式控件 GMenuMapTypeControl
    所有的地图类型使用一个下拉菜单来显示,选择菜单中的不同项来切换地图类型,比如
   
    3)阶层式标准控件 GHierarchicalMapTypeControl
    类似标准的按钮控件,不过在某些按钮下可以选择在该类型地图下的嵌套内容,比如卫星地图中还可以选择是否使用标签、即是否使用混合类型(Hybrid)的地图,如下:
   
    这个控件目前在中文地图上没有什么作用,因为中文地图还不支持Hybrid类型的地图,也不能在地图上显示Panoramio的图片和Wikipedia的内容。
3、缩略图控件 GOverviewMapControl
    在地图上显示一个比现有地图范围更大、但是尺寸要小得多的缩略图,默认位置在右下角,在该控件的右下角有一个箭头,点击可以收放这个控件,需要移动地图时你也可以直接拖动缩略图里的那个蓝框,会比你直接拖动地图要快一些。
   
4、比例尺控件  GScaleControl
    显示当前地图的比例尺,所以上面的数值会随地图的缩放变化,这个控件不是特别引人注目
   
5、本地搜索控件  GoogleBar
    上一篇介绍GMap2设置项的文章里把这个包括了进去,还是放在这里比较合适,是什么我就不多说了,看图
   

谷歌地图上常用的默认控件基本就这些了,你在我右边的地图里基本都能找到这些控件,想把这些控件加到你的地图上也不难,接着来看。

向地图上添加控件的方法
上面我已经给出了每个控件对应的类名,添加的步骤(以添加右边地图中的微型缩放控件为例):
1、重置控件的位置,如果你使用控件的默认位置,这一步就不需要了。一般情况下也确实不需要,只有在你的地图空间狭小,控件摆布不开的时候才会有,右边的地图就是这种情况。
    GSmallMapControl.prototype.getDefaultPosition = function(){
        return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10, 30));
    }
    注意G_ANCHOR_TOP_RIGHT和new GSize(10, 30)这两个参数,这个其实就决定了右边地图里微型缩放控件的位置,位于右上角(TOP_RIGHT),距地图右边距10px,上边距30px。
2、创建控件对象
    var mapControl = new GSmallMapControl();
3、调用map.addControl()方法添加控件
    map.addControl(mapControl);

怎么样,还没过瘾?API里提供的默认控件基本就这些了,如果你还想加上你自己设置的控件,比如右边地图上的状态控制,那就看看我之前介绍的自定义地图控件的方法吧。

到这里为止,通过指定GMapOptions设定地图设置项、添加默认控件,我们可以在不需要添加任何叠加层、信息窗口、事件侦听的情况下,就可以创建一个内容比较丰富的地图了。当然,等我介绍完本地搜索控件的定制方法,我们的地图内容会更丰富。

2008年11月26日星期三

GMap2可以有哪些设置项

初始化一个GMap2对象除了可以使用GMapOptions参数设置谷歌地图外,在创建GMap2对象后还可以用一些方法设置地图的一些通用属性,照我的使用习惯和频率,做个分类(如果我在标题后没有添加“默认”,则这个属性在默认状态下地图是不支持的,另外,文中的map指GMap2的实例对象,省得用GMap2来作方法声明的时候有人误解):

1、可以连续缩放
    地图缩放的时候旧图块在新图块加载完成之前不会直接消失,图块的切换比较平滑,在网速较慢的时候这种效果会好一些。地图默认情况下不支持,建议打开这个功能。使用map.enableContinuousZoom() / map.disableContinuousZoom() 方法来切换。另外,需要的时候你可以使用map.continuousZoomEnabled()方法来探测一下地图是否支持连续缩放。

2、支持滚轮缩放

    使用鼠标滚轮来实现地图缩放,默认也是不支持的,建议打开。使用map.enableScrollWheelZoom() / map.disableScrollWheelZoom() 方法来切换,使用map.scrollWheelZoomEnabled()方法来探测。

3、支持双击缩放

    左键双击放大地图,默认也是不支持,建议打开。使用map.enableDoubleClickZoom() / map.disableDoubleClickZoom()方法切换,使用map.doubleClickZoomEnabled()方法探测。另外,右键双击缩小地图默认是支持的,没有发现地图API中有方法可以改变右键双击的属性。

4、支持地图拖动(默认)
    按住左键拖动地图,默认是支持的。使用enableDragging/disableDragging方法切换,使用draggingEnabled()方法探测。这个估计是个比较老的方法,因为在已经有静态地图API的情况下实在想不出来有什么理由不让地图可以拖动,除非你是想临时的禁止地图可拖动。

5、支持信息窗口(默认)

   在需要的时候地图可以弹出一个泡状的东东,在里面显示信息,默认也是支持的。使用enableInfoWindow/disableInfoWindow方法切换,使用infoWindowEnabled()方法探测。一般情况下,这个属性让它保持默认就好了,如果你只需要在地图上标注并且不允许任何信息窗口的弹出,或者想上一个地图拖动的属性一样,需要临时性的禁止。

6、添加搜索栏
   把地图左下角的Logo换成一个带搜索框的控件,这样你就可以在你的地图中直接使用谷歌的数据源来支持用户搜索,定制好的话简直就可以当作一个微型的地图主页来用。这个是中文API中新增的功能,以前的文章中我提到使用GMapOptions中的googleBarOptions属性可以来定制这个控件的。这个在地图上默认是没有添加的,所以,如果你没有使用map.enableGoogleBar()方法来显式的声明加上搜索栏的话,googleBarOptions也是不会起作用的。添加搜索栏反向的禁用操作是map.disableGoogleBar()。

2008年11月25日星期二

使用GMapOptions定制你的谷歌地图

  之前我曾经解释过创建一个地图的详细步骤,但是,真正创建地图的核心步骤也就两行代码:
    var map = new GMap2(document.getElementById("mapContainer"));
    map.setCenter(new GLatLng(33.0, 106.0),  3);
   有这两行代码,你就可以在你的网页上展现你的谷歌地图了。但是,这个是最简单的地图,如果你想要对这个地图做一些小小的变动,更符合你的胃口,可以使用GMapOptions来尝试定制地图。
   简单的说,GMapOptions是你在new一个GMap2对象的时候,可以直接使用对象变量的形式作为可选参数传递给GMap2的构造函数,GMapOptions自己没有构造函数(地图API中类构造函数的可选参数多用这种形式来定义),比如:
   var options = {size:GSize(400, 300), backgroundColor:"#FF0000"};
   var map = new GMap2(document.getElementById("mapContainer"), options);
   这里options就是一个GMapOptions,size、backgroundColor就是他的选项。
   在GMapOptions中,我们可以定义以下这些属性来指定地图的某些特性:

   1)size
   默认情况下,你创建的地图大小就是你给定的地图容器的大小,所以,通常情况下,你需要显式的声明你的地图容器的width和height属性,否则,地图是不能正常显示的。但是,有了size这个可选属性后,你就多了一个选择了。你可以在创建地图的时候直接通过size这个属性指定地图的大小,而不需要听命于地图容器了,即使这个地图容器已经显示的定义了width和height的大小。当然,size属性对应的值是一个GSize类型的数据,比如,如果给定options={size:GSize(400, 300)},那么,你所创建的地图大小就是400×300的一个矩形块,而和你指定的容器大小无关,但是地图的左上角和地图容器的左上角还是重合的。

   2)mapTypes
   创建地图后,默认显示的地图类型是普通地图,如果要加上可以选择的卫星地图、地形地图等等其他类型的地图,可以使用GMap2.setMapType()方法,但这样往往会罗列一堆的setMapType。GMapOptions提供了mapTypes这个可选项,通过一个数组就可以给地图加上多种支持类型,比如使用{mapTypes:[G_NORMAL_MAP,G_SATELLITE_MAP,G_PHYSICAL_MAP]},你的地图就拥有三种普通、卫星、地形三种类型了。mapTypes数组中的第一项是地图加载的默认类型,所以,如果你想默认加载卫星地图,把G_SATELLITE_MAP移到数组的第一项就可以了。

  3)draggableCursor、draggingCursor
  这两个选项是用来定义地图上你的光标类型,我把它们放在一起介绍不等于它们必须一起使用,你可以单独使用任何一个。其中,draggableCursor是地图可拖拽状态(默认就是可拖拽的)下的光标,draggingCursor是拖拽地图时的光标,对应的值和你在JavaScript里面设置其他的光标时使用的值一样,比如,{draggableCursor:"crosshair",draggingCursor:"move"}。当然,你也可以使用url形式加上你自己的图标,看你发挥了!

  4)backgroundColor
  在地图图块的图片还没有传送完成之前,地图的显示区域默认会使用灰色填充,这个就是backgroundColor可以发挥作用的地方了,你可以把灰色换成其他任何符合W3C标准的颜色,比如{backgroundColor:"#FF0000"},不过估计没人会喜欢用这种大红做背景的:)。可惜的是这里只能定义color,要是这个选项是background而不是backgroundColor,千方百计想打个Logo的兄弟就真能找着好地方了。

  5)googleBarOptions
  这个和你在地图上通过GMap2.enableGoogleBar()时有关系,指定你添加GoogleBar时的一些默认属性,在以后说GoogleBar的时候再来专门说吧,定制性还是很强的。
  

2008年11月18日星期二

使用谷歌地图API实现自定义控件

  使用谷歌地图API定义自定义的控件其实非常简单,看看我在右边地图的右上角添加的半透明的状态监控栏,这就是一个自定义的控件。

  闲话少说,先看一段Hello World的代码

  function MyControl(){}

  MyControl.prototype = new GControl();

  MyControl.prototype.initialize = function(map){

    this.map = map;

    var container = map.getContainer();

    var label = document.createElement("div");
    container.appendChild(label);

    lable.innerHTML = "Hello World";

    return label;

  }

  MyControl.prototype.getDefaultPosition = function(){

    return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(50, 10));

  }

  上面这段代码中,MyControl就是一个自定义的控件了,在需要的时候,和添加其他默认控件一样,使用map.addControl(new MyControl())就可以在地图上添加这个自定义的控件了,只不过这个控件现在也没什么实际用处,就是在你的地图容器的顶部显示一个Hello World的文本,与地图没什么交互。

   下面来详细解释一下这段代码:

   第一行定义了一个MyControl类;

   接下来,把这个类定义为GControl类的子类,就是把MyControl的prototype指定为GControl类的实例/对象;

   后面的两个方法initiallize和getDefaultPosition是继承GControl类的时候必须实现的两个方法,API文档里定义GControl是接口类,所以可以把这两个方法认为是抽象方法,就不难理解为什么必须要实现了。需要注意的是,这两个方法我们只负责实现,但是不需要我们去显式的调用,在向地图上添加控件时API类库会自动调用这两个方法。

   方法initialize接受一个参数map,就是你创建地图时new出来的GMap2对象。在这个方法中,你使用map.getContainer()方法取得放置地图的DOM容器,然后,你就可以向这个DOM容器里添加任何你想加入的DOM元素了。在上面的示例中我创建了一个div元素,用来显示Hello World,但是,你可以在这里加入任何你想添加的DOM元素,并且可以定义它们的行为,也就是说,这里就是你可以自由发挥的天地了,无论你是想显示动态的信息,还是来控制地图,比如右边地图里的状态监控栏。initialize方法最后需要返回你所创建的最外层的DOM元素,这个千万别忘了。

   方法getDefaultPosition的作用是定义你的控件在地图容器里的位置,实现起来就更简单了,你可以直接把我这里的代码copy过去,改成你需要定位的地方就可以了。GControlPosition的第一个参数是你的控件的锚点,只能使用G_ANCHOR_TOP_LEFT、G_ANCHOR_TOP_RIGHT、G_ANCHOR_BOTTOM_LEFT、G_ANCHOR_BOTTOM_RIGHT这四个代表上左、上右、下左、下右这四个角的常量,后一个参数使用GSize来定义你的控件距离地图容器边界的偏移量,第一个参数是横向偏移、第二个参数是纵向偏移。
   到这里一个自定义的控件就完成了,没什么复杂的吧?刚才看到论坛里有朋友问怎么能把自己的LOGO和地图左下角Google的LOGO并排放在一起,看了自定义控件,你一定知道怎么做了吧。不过,千万别想用你的LOGO覆盖Google的LOGO哦,基本的版权意识咱们还是应该有的,就像你也希望别人能够尊重你的劳动成果一样!


谷歌地图坐标系统总结

    要在地图中定位一个点,最常见的就是使用一个地理坐标来定位。但是,谷歌地图API还提供了不同于地理坐标的多套坐标系统,方便我们在需要的时候使用不同的坐标来定位在地图上显示的信息。我在右边的地图中演示了这些坐标,可以把的鼠标移到地图上看看,注意要展开“鼠标位置”的内容啊:)。
    这些坐标系统可以简单的总结如下(这些系统是我自己命名的,呵呵,有些系统我也不知道应该怎么称呼):
    1、地理坐标系统
    地理坐标纵向以赤道所在维度线为原点,分别向南北极延伸,最大值为90。横向以格林威治天文台旧址所在的经度线(本初子午线)为原点,分别向东西延伸,最大值为180。海拔坐标在这里就暂时忽略吧。
    地理坐标的表示方式主要有两种:一种是以度分秒/度分的方式表示,比如(39°56'N,116°20'E);还有一种是使用十进制数的方式表示,比如(39.9333,116.3333)。在表示一个地理坐标的时候,习惯上都使用先维度后经度的顺序来描述一个坐标,并且,对前一种坐标,是使用追加字母缩写的方式表示方向,而在后一种方式中,一般会使用X轴表示经度,Y轴表示维度,按照上北下南左西右东的的原则来给坐标加上对应的符号,所以,对(39.9333,116.3333)我们通常就理解为北纬39.9333度、东经116.3333度。
    在谷歌地图API中使用后一种方式来表示地理坐标,并使用GLatLng这个类来规范的定义一个地理坐标,该类的构造函数中,第一个参数是维度,第二个参数是经度。需要注意的是,这两个参数的顺序不同于我们在坐标系中先X后Y的表达方式,而是按照地理坐标先维度后经度的习惯来表示一个地理坐标,这个原则基本适用于地图API中所有需要表达地理坐标的地方。
    2、图块坐标系统
    谷歌地图是使用一系列的大小相同的图片拼接起来的,这些图片在谷歌地图中称之为图块(Tile)。所以,你可以把谷歌地图理解为是使用图块/图片填充起来的一系列网格,在不同的缩放级别,地图被分解为不同数目的网格。详细的说,在缩放级别为0的时候,整个世界地图只有一个网格,缩放级别每增大一级,所有的网格在横向和纵向就分割一次,也就是说,对应于某一特定的缩放级别N,网格的数目就是4的N次方,即4N。这些网格所组成的坐标系统,就是图块坐标系统。
    在图块坐标系统中,以缩放级别为0时的世界地图为原点,在缩放级别增大的时候分别向下(Y轴)和向右(X轴)延伸,这样,在指定的缩放级别,我们就可以用一个坐标来指定特定的图块了,如果你有意用你自己的图片替换掉地图中的某个图块,这个坐标系统就能派上用场了。谷歌地图API中还没有一个直接的方法可以取得图块的坐标,要取得这个坐标,你需要继续往下看。
    3、像素坐标系统
    上面说到谷歌地图是由一系列大小相同的图片拼接起来的,其实这些图块的大小也是固定的,都是256×256像素大小,所以,在不同的缩放级别,世界地图的像素大小也是固定,比如在缩放级别为0的时候,世界地图的像素大小就是256×256×40。这样,在特定的缩放级别,因为世界地图的像素大小是固定的,组成世界地图的所有像素点就可以形成了一个完整的坐标系统,我们也就可以用像素坐标代替地理坐标指定地图上的某个点,这个坐标系统就是像素坐标系统。
    像素坐标系统以缩放级别为0时的世界地图的左上角为原点,使用与图块坐标系统相同的X轴和Y轴,在缩放级别增大的时候分别向下和向右延伸。像素坐标与地理坐标可以相互转换,他们之间的主要区别在于,像素坐标是平面的二维坐标,而地理坐标是曲面的二维坐标(不考虑海拔坐标)。
    在谷歌地图API中,可以使用GProjection.fromLatLngToPixel(latlng, zoom)这个方法通过地理坐标得到对应的像素坐标,想法的,可以使用GProjection.fromPixelToLatLng(pixel, zoom)这个方法由像素坐标得出对应的地理坐标。
    现在,我们在看看如何通过像素坐标获取对应的图块坐标。上面已经提到每个图块都是256×256像素的固定大小,所以,使用像素坐标值除以256并取整,就可以得到这个像素坐标所在的图块坐标了。使用代码说话:
    Math.floor(x / 256),x就是像素坐标的x值,这个表达式得到的结果就是像素所在图块的横坐标,纵坐标算法相同。
    4、DOM相对坐标系统
    这里的DOM是指页面上装载地图的容器,一般是div元素。把这个坐标系统看作是基于DOM元素而不是基于地图的坐标系统或许更易于理解,这个系统里的坐标指定的是某个点在这个DOM容器里的位置,以这个容器的左上角为原点,分别向下(Y轴)和向右(X轴)延伸。所谓相对坐标,是指这个坐标系统相对地图是固定的,原点不会随地图的拖拽而变化。
    在谷歌地图API中,使用GMap2.fromLatLngToContainerPixel(latlng)可以取得地图上某个点在DOM容器中的位置,相反,你可以通过GMap2.fromContainerPixelToLatLng(pixel)方法来获取DOM容器中某个位置在当前地图上的坐标。这个坐标系统在你需要在DOM容器上添加一些自定义控件并与地图交互的时候可能会有用。
    5、DOM绝对坐标系统
    这个坐标系统是相对上一个系统来说的,从字面可以理解为这是定位在地图上而不是相对地图的坐标系统,如果你在加载地图后只是缩放而没有拖拽地图,那么你会发现这个坐标系统和DOM相对坐标系统是重合的。但是,一旦你拖拽地图,就会发现他们的差别了,实际效果你可以在右边的地图里试试。结论就是,这个坐标系统的原点是与DOM容器的左上角重合的地图上的点,在拖拽地图的时候原点会随着地图变化,原点左边和上面的点使用负值表示。
    这个坐标系统中的坐标和地图上的地理坐标可以用GMap2.fromLatLngToDivPixel(latlng)、GMap2.fromDivPixelToLatLng(pixel)这两个方法实现相互转换,在你自定义地图上的叠加层的时候,这两个方法就可以派上用场了。
    有一个问题我还没完全理清,就是在DOM容器里出现多个世界地图的时候,也就是DOM容器足够大的容纳下多个世界地图的图块时,DOM相对坐标和DOM绝对坐标这两个系统显示的坐标似乎有点紊乱,如果你理清了,找出了规律,欢迎共享出来。
   最后提一下GSize,在说到地理坐标系统的时候我提到了GLatLng,这是在谷歌地图API里对地理坐标的规范表达,而在表示非地理坐标的时候,就需要用GSize这个类了,这是对以像素为单位的坐标的规范表达,和GLatLng不同的是,它的构造函数中第一个参数表示X轴的坐标,第二个参数表示Y轴的坐标。

2008年11月17日星期一

怎样在你的网页里嵌入地图

  要在自己的网页中嵌入地图,常用的方法可以归纳为以下几种:
  1、最简单的方法 ——使用谷歌地图主页的"链接"
      如果你只需要在自己的页面上显示某个特定范围的地图,比如你的公司所在地,但是不需要在地图上添加任何额外的内容,比如标记、折线等等,那么,使用这个方法来嵌入谷歌地图是最简单的。
      登录谷歌地图主页,定位你需要显示的范围后,点击地图左上角的“链接”,会出现一个信息框,给出两个输入框,把第二个输入框中的内容拷贝到你的页面上就可以了。
      其实,这段嵌入代码就是一个iframe的声明,所以,虽然地图主页提供一个自定义地图并预览的功能,但是只能自定义地图的大小,如果需要的话,我们完全可以通过手动修改这个iframe声明来实现更多的自定义,比如,给这段iframe加上自定义的样式。
  2、最精简的方法 ——使用谷歌静态地图
      如果你需要显示某个特定范围的地图,而且需要在地图上加上一些标记、折线。但是,你并不在乎你网页上的地图能否拖拽,那么,这个静态地图应该就是你需要的了。
      所谓静态地图,意思就是你在页面上嵌入的其实只是一个GIF图片,这个GIF图片是你通过URL从谷歌动态获取的,这样的嵌入地图就有别于我们常用的“动态”地图了,而且,加载这样的地图,比加载一个完整的地图要快捷的多。
      要在你的页面上使用这样的静态地图,只需要使用一个img标签,把这个标签的src属性指定为谷歌静态地图的url就可以了。
      看一个简单的静态地图URL:http://ditu.google.cn/staticmap?center=39.915175,116.389332&zoom=14&size=500x300&key=YOUR_KEY_HERE
      在这个URL中,你可以编辑center、zoom、size这些参数来指定地图的中心点、缩放级别、地图大小等等,当然,如果需要在地图上添加标记、折线,你还可以加上对应的参数。不过,不用担心你要记住这么多参数,这里有一个定制静态地图的向导,简单的几步就可以得到你需要的URL了。如果有兴趣,可以去研究一下谷歌静态地图的API文档
      严格来说,谷歌静态地图也是谷歌地图API的一种,所以,使用静态地图是需要你的谷歌地图API密钥的,如果你之前定义过地图API的密钥,直接copy过来就可以了,不需要再去注册。如果你不知道密钥是怎么回事,那就看看我之前对密钥的解读吧。
  3、最自由的方法  --使用谷歌地图API
      如果上面两种方式都不能满足你的需求,那么,就来试试谷歌地图API吧。虽然谷歌地图API已经细分为JavaScript、Flash、Earth、Static等等多个版本,但是,在我看来,JavaScript API是谷歌地图API的根本,所以,在我的博客里,除非特别指明,说到谷歌地图API都是指谷歌地图JavaScript API。使用这个API,你可以用你愿意的任何可行的表现形式在地图上展现你的数据,甚至可以把你自己的地图做的比谷歌地图还漂亮。
      要使用这个API在页面中嵌入地图,简单的步骤就是:
      1)使用JavaScript标签导入地图API类库;
      2)在页面上定义一个装载地图的元素,通常使用一个div标签,指定width和height;
      3)在你的JavaScript代码中new GMap2(document.getElementById("your map container's id"));
      4)使用GMarker、GPolyline等API中提供的类定制你要在地图上添加的标记、折线等等。
      详细的创建谷歌地图过程可以看看我的“使用JavaScript创建地图步骤详解”。但是,要想自如的使用这个API,你需要具备一定的JavaScript知识和动手能力,此外,强烈建议你先读读谷歌地图JavaScript API的开发指南,能够解决你的一些常见疑问,当然了,你也可以在我的博客里找找你想了解的知识。

    除了上面说的这几种方法,其实还有一些比较少用的方法也可以在网页中嵌入地图,比如使用Google Gadget API,我在博客右边栏嵌入的地图使用的就是Gadget API。

    如果你不需要在自己的页面中嵌入地图,或者,你没有自己的网站,那么,使用Mapplet API也是一个不错的创建你自己的地图的方式。这是一个可以在谷歌地图主页上“我的地图”中运行的小程序,它的API其实就是谷歌地图API的一个子集,因为要在谷歌地图主页中嵌入,所以与谷歌地图API稍稍有一些不同。详细情况可以参考一下Mapplet API的开发文档 。   

2008年11月11日星期二

使用JavaScript创建地图步骤详解

  一段经过精简的代码:
  <script src="http://ditu.google.com/maps?file=api&hl=zh-CN&v=2&key=abcdefg" type="text/javascript"></script>
  <body>
    <div id="mapContainer" style="height:400px; width:400px;"></div>
  </body>
  <script type="text/javascript">
     var map = new GMap2(document.getElementById("mapContainer"));
     map.setCenter(new GLatLng(33.0, 106.0),  3);
  </script>
  新建一个空白的文本文件,把上面这段代码copy过去,不要改变代码的任何顺序,然后把这个文本文件保存为html文件,使用浏览器打开(不要使用MS的IE),看看你能看到什么!

  对这段代码的详细解释
  上面的这段代码就是创建一个地图的核心步骤:
  1、导入地图API类库。
      <script src="http://ditu.google.com/maps?file=api&hl=zh-CN&v=2&key=abcdefg" type="text/javascript"></script>
      注意这里的参数key,我在以前的文章里已经详细解释过了,如果你只是在本地运行,暂时可以不用管它。
  2、在页面的body元素中定义一个地图容器。
      <body>
        <div id="mapContainer" style="height:400px; width:400px;"></div>
      </body>
      这个地图容器一般使用div元素来定义,如果你愿意,使用p元素或者其他你能想到的元素都可以,但是都应该是块元素,并且必须定义它的id,保证在后面的步骤里能够通过document.getElementById找到这个元素。
      容器的style属性在这里是用来定义这个容器的大小,从而决定所显示地图的大小,当然,如果你在这里不定义也可以通过其他的手段来达到目的,这里暂且先认为这个style的定义和id属性一样也是必不可少的吧。
      其实body元素在这里也有一些特殊的作用,就是保证下一步骤在页面的html元素全部加载结束后再执行,详细的理论就不细说了。
  3、定义你自己的script区域,在里面new一个GMap2对象,并且指定其显示所需的两个基本要素:中心、缩放层次。
      <script type="text/javascript">
         var map = new GMap2(document.getElementById("mapContainer"));
         map.setCenter(new GLatLng(33.0, 106.0),  3);
      </script>
     这里的GMap2是谷歌地图API中最重要的核心类,对应在页面上显示的地图,所有对地图的操作都需要在已经创建(new)了GMap2对象的基础上才能够进行。在调用GMap2构造函数是使用的参数就是在上一步定义的地图容器,DOM对象,使用document.getElementById获取。
     要在页面上正常显示地图,仅仅调用GMap2类的构造函数创建一个GMap2对象还不够,你还需要指定这个GMap2对象的中心,通常也顺便指定它的缩放层次,否则就会默认显示缩放层次为0。
     要指定新创建地图的中心,需要使用地图API里面定义的另一个常用类GLatLng,可以把这个类简单的认为是对地理坐标的封装类,构造函数中第一个参数是南北向的纬度,第二个参数是东西向的经度。
     调用GMap2的setCenter方法设定完地图的中心和缩放层次,这个地图就可以正常显示了。
     
  还需要关心的几个问题
    上面的示例代码仅仅是为了显示一个试验性质的简单地图,所以把很多暂时不是很必要的代码都去掉了,如果你需要创建具有很好的兼容性、并且能够发布到你自己的网站上的地图,还需要注意这几个问题:
    1、为了保证有足够的兼容性,谷歌建议使用XHTML来定义显示地图的html页面,所以,你需要在这个页面的顶部声明XHTML的DOCTYPE,并且在html中声明XHTML的命名空间
       <!DOCTYPE html PUBLIC
        "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtmll/DTD/xhtmll-strict.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml">
      当然,最好你自己的页面代码也能够符合XHTML的语法规则。相对我们现在的HTML4.01来说,可以把XHTML语法规则简单的归纳如下:
      html、head、title、body元素一个都不能少,并且只能有html一个root元素;
      不要使用简化的属性,必须使用“name='value'”的形式;
      标签名和属性名都用小写字母,属性值要用引号括起来;
      标签必须是闭合的,并且不能交叉嵌套;
      使用id属性而不是name属性来获取元素;

    2、为了兼容“伟大的”IE浏览器,以便能够在IE中也正确显示地图中的折线,需要在html标签中增加对VML命名空间的声明
        <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
        这个很容易忽略,导致你在IE里的折线不能正常显示,所以把这一点单列出来加以强调。

    3、对于通用的浏览器兼容性检查,地图API提供了一个全局方法GBrowserIsCompatible()来保证地图API是在它所兼容的浏览器里运行的,这个兼容浏览器列表我也没找到最新的,谷歌文档里给出了一个远古时代的列表,所以不列也罢,对我们目前通用的FireFox、IE、Safari、Opera浏览器里运行地图API都没有问题。
      这里只说一下GBrowserIsCompatible()这个方法的使用:
      从名字也可以看出,GBrowserIsCompatible()方法返回一个boolean类型的值,所以,把我们对地图操作的起点放在对这个方法返回值的判断块中,形如:
      if(GBrowserIsCompatible()){
        //开始创建和操作地图
      } else {
        //如果有必要,就在这里定义你对这个异常的处理
      }
      当然,在你自己的代码中,针对不同的浏览器环境你还是需要自己实现兼容性的代码,这里的GBrowserIsCompatible()只是保证地图API类库是在它兼容的环境中运行的。
    4、注册你要发布页面所在网站的谷歌地图API密钥,替换掉示例代码里的key,我在这里详细解释过这个密钥,不多说了。
    5、为了保证你的页面在任何可用的网络环境下都能快速加载并且正确显示,建议定义body元素的onload方法,在onload方法中开始你的JS动作。同时,把读入地图API的script标签放在head元素中,而把你自己的JavaScript代码块放到body标签的后面去定义。如果对浏览器的加载顺序比较熟悉的话,你就不必遵守我说的规则了,自由定义你认为应该的JavaScript声明顺序。
    6、为了避免JavaScript中引用页面的DOM元素可能存在的内存泄漏(尤其是在“伟大的”IE浏览器中),你需要使用地图API中定义的GUnload()方法作为你的body元素的onunload方法,并且最好把这个作为一个必须的规则记住。但是GUnload()方法不是避免内存泄漏的大力丸,所以,你在自己的代码中还是需要注意避免内存泄漏这个问题。
    7、为了能够在页面上正常显示中文,需要把页面的字符集定义为utf-8。

    所以,一个完整的应用谷歌地图API的页面代码如下:
    <!DOCTYPE html PUBLIC
        "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtmll/DTD/xhtmll-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
         <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
         <title>我的谷歌地图</title>
         <script src="http://ditu.google.com/maps?file=api&hl=zh-CN&v=2&key=YOU_API_KEY" type="text/javascript"></script>
      </head>
      <body onload="initialize()" onunload="GUnload()">
        <div id="mapContainer" style="height:400px; width:400px;"></div>
      </body>
      <script type="text/javascript">
        function initialize() {
          if (GBrowserIsCompatible()) {
            var map = new GMap2(document.getElementById("mapContainer"));
            map.setCenter(new GLatLng(33.0, 106.0),  3);
          }
        }
      </script>
    </html>

2008年11月6日星期四

加载谷歌地图API的URL详细解读

    谷歌地图的API类库是通过script标签导入的,形式如下:   

    <script src="http://ditu.google.com/maps?file=api&hl=zh-CN&v=2&key=abcdefg" type="text/javascript"></script>



    我们使用API的时候关心的就是这个script的src属性了,这个属性也就两个部分:
路径:http://ditu.google.com/maps; 参数:file=api&hl=zh-CN&v=2&key=abcdefg

    解剖一下:

    1、 路径
http://ditu.google.com/maps

    路径在这里需要注意的就是它的域名:ditu.google.com。这个和谷歌地图简单背景里介绍的谷歌地图主页的问题类似,就是说,我们主要可以使用maps.google.com、ditu.google.com、ditu.google.cn这三个域名,有些区别和说明:

    1) 如果你需要在地图上显示大陆以外的详细地图,就非maps.google.com莫属了,不过,这个域名对国内地理数据的查询(比如查询地址、路线等等)支持能力有限,如果你这方面有需求就要小心了,而且,这个应该是使用的国外的服务器,所以,访问速度也需要注意;

    2)相反,如果你需要使用谷歌提供的与国内地理数据查询相关的API,就是用ditu.google.com吧,使用这个域名的缺点就在于它和 maps.google.com提供的类库不是完全一致,更新稍微有点滞后,而且,受限于国内数据源在法律等方面的限制,有些功能方面的支持也会受限,比如地址解析(现在已经放开了,这里只是拿来举例);

    3)至于ditu.google.com和ditu.google.cn的区别,我也很糊涂,如果你很想做个听话的好公民,不出一丝差错,那么.cn可能会比.com更让你放心一点吧,臆测,呵呵。

    总得来说,一般的应用使用ditu.google.com就可以了,如果需要使用大陆以外的详细地图,就考虑使用maps.google.com吧。不过,因为使用了相同的命名空间,这两者在一个页面中不能共存,所以,可以考虑用两个iframe来动态切换,这里有个火炬传递的例子,就是这么实现的,咱当初也贡献过一把。


    2、
参数:file=api&hl=zh-CN&v=2&key=abcdefg

    1) file=api 
         这个是请求API的JS文件用的,少不了,不需多说;

    2) hl=zh-CN 
         这个是在设定地图上除了地图图片以外的诸如控件名称、版权声明、使用提示等所需要显示文本的语言版本时候用的,如果没有指定这个参数就使用API的默认值,对ditu.google.com来说,默认是中文简体,maps.google.com默认的是英文。其他的语言版本在这里有一个简单的英文说明 (好像好久没更新了)。

    3) v=2 
         这个是用来指定需要导入的API类库的版本号,可以有四种设定方式:

        
v=2.s   稳定版本,更新最慢,但是最可靠
         v=2     当前版本(只用主版本号),更新速度和可靠性介于s和x之间;
         v=2.x   最新版本,更新最快,包括最新功能,可能没有当前版本可靠;
         v=2.76 指定版本。不建议使用。
         目前谷歌地图API的主版本号是2,这是从2006年4月开放的版本,对之前的第1版做了一些比较重要的升级,不过估计国内用第1版的应该很少,所以也没必要多说了,注意第二版里定义地图对象时使用GMap2而不是GMap就可以了,否则可能会导致一些奇怪的问题,我是见过这样的。
         多罗嗦两句,谷歌地图API正常情况下还是相当稳定的,不过也有一些比较著名的Bug,比如超长的Polyline在某些特定环境下可能会显示不正常。万一有什么问题可以去这里找找是不是别人报过的Bug(英文版),当然,更简单的办法是到谷歌地图API论坛里问问,不过别忘了把你的问题、运行环境描述清楚。我碰到过很多次这样的情况:对JavaScript或者浏览器端的某些技术特性不是很了解,出了一些奇怪的问题,撂一句话就走人,唉,就不评论了,“活到老学到老”还是很有道理的。
     4)key=abcdefg
         这个是设定你注册的API密钥,我在这里费了不少口舌,不是很了解的话可以看看。


使用谷歌地图API之前应该有所了解的一些技术外背景

    这些内容,常用谷歌地图的应该也都知道,我也只写我知道的,了解这些对使用API还是有帮助的。

    1 、 谷歌地图主页
    谷歌地图对应不同的地区都会有一些专门的主页,首次登陆时会显示这些地区,比如,香港的:http://maps.google.com.hk ,台湾的:http://maps.google.com.tw ,日本的:http://maps.google.co.jp
    不过,我们常用的也就三个:
    http://maps.google.com   这个应该是谷歌地图的全球主页,默认显示老美地图,拖拽到不同地区会对应显示不同语言版本的地图,不过目前对中文数据搜索支持的不如下面正式的中文主页;
    http://ditu.google.com   这个么,我叫它是谷歌地图的中文主页,什么意思看下一个你就知道了,用这个可以使用“我的地图”;
    http://ditu.google.cn   这个,我叫他是谷歌地图的大陆主页,目前还没有“我的地图”这个功能;
    后面这两个主页只能显示大陆地区的详细地图,如果想看别的地区的,就只能用全球主页了。
    当然,别以为你抓着漏洞可以注册个maps.google.cn,然后卖给谷歌,不信你试试maps.google.cn,看它跳到哪里了:)

    2、谷歌地图的类型
    其实,谷歌地图的类型主要也就三种:
    普通地图:历史悠久的人工绘制地图,不多说了,不知道的给我留个地址,我快递个板砖给你;
    卫星地图:用卫星图片拼成的地图,不同地图的显示精度有区别,现在中文主页上也有了,曾经可是被禁止的,怕你偷看海南的黑鱼;
    地形地图:用等高线标出海拔的地图,对地理教学和教育相关的相当有用,当然,对军迷也超级有吸引力,不展开!

    把这三种组合起来(主要是普通地图和卫星地图的组合),或者在这些地图上添加其他的数据,就又有一些新的类型了,这个层出不穷,我只说主页上现有的:
    混合地图:就是把普通地图和卫星地图结合,在卫星地图上显示行政区、街道等等,在全球主页上把鼠标移到“卫星”按钮上,会跳出来一个“显示标签”的复选框,选中后地图就是这个类型了,中文还没支持,不知道什么时候可以用;
    交通地图:在地图上显示交通信息。这个理论上是实时的,不过,在目前的中文地图上,吸引眼球的作用更大一些,如果能在手机版上使用就好了(貌似目前还没有),而且只有北京和上海有数据支持;
    街景地图:这个和交通地图一样,严格上不算是一种地图类型,就是使用Flash来显示街道的全景图,我也在等中文地图支持街景了(中文API已经支持StreetView相关的类了,就是没有数据),不久前看到的消息是目前谷歌对这个没有时间表,呵呵,他是“万事俱备,只欠东风”,努力吧!
    在地图API中,后面组合的这三种除了混合地图算作是一种地图类型外,其他两个都不算是地图类型,被看着是在地图上新增的层(术语:叠加层/overlay)。

    3、谷歌地图的数据源
    谷歌是一个服务提供商,而不是一个内容提供商,所以,准确的说,谷歌地图向终端用户提供的是基于地图的搜索服务。从这一点上,可以把谷歌地图上的数据分为三类:
    地理数据:地理、空间信息,包括经纬坐标、航拍/卫星图片、行政区划以及据此绘制的图片等等,由谷歌或其合作伙伴持有;
    商业数据:与地理相关的商业数据,比如餐馆、影院、交通、景点等等,这也是由谷歌或其合作伙伴持有,谷歌可能对这些数据有一个采集、过滤、整理的再加工过程。想被客户搜索到,就来这里标注自己的公司吧;
    用户数据:用户使用谷歌地图API定制地图并在地图上标注的数据,这些数据由用户持有。
   
    这样,通过这个分类,我们可以解决两个非常常见的疑问:
    1)使用谷歌地图API,地图上的数据存在哪里?
      你是你的我是我的。是谷歌提供的数据,由谷歌负责;如果是你自己提供的数据,当然由你负责保存,谷歌相当于给你一个展示数据的平台,除非你愿意把自己的数据无偿贡献给谷歌:)
    2)使用谷歌地图API,终端用户会通过谷歌搜索到我的数据吗?
      对谷歌地图来说,他的数据源只有地理数据和商业数据,所以在谷歌地图主页上不会搜到你的数据。但是,你可以在你的地图上定制谷歌搜索的数据源,使得用户可以搜索你的数据。(不是很肯定的哦,要看你的具体情况的) 

    4、 谷歌地图API
    谷歌地图API就是一系列使用OO方式组织的JavaScript类和静态方法(我有时候也统称为地图API类库),通过创建这些类的实例(对象)或调用API中提供的静态方法,可以在页面上创建和控制地图,也可以在地图上展示任何非谷歌提供的数据/信息。谷歌地图API只涉及浏览器/客户端相关的技术,比如JavaScript、HTML DOM、CSS等,不涉及任何服务器端的技术,或者说,你可以基于任意你需要的服务端使用谷歌地图API(所以,这里面能够展开的东东就太多了,以后再总结吧,我也在学习)。


更新:前两天刚看到谷歌地图的手机版也支持交通地图了,刚刚在我的手机上试过,哈哈,还是不错的

2008年11月5日星期三

谷歌地图API密钥(API Key)的解读和使用技巧


    所谓API密钥(API Key),其实就是一个字符串,在使用script标签导入API类库的时候作为请求参数传给谷歌的地图服务器,形式就是:

    <script src="http://ditu.google.com/maps?file=api&v=2&key=你注册的API密钥" type="text/javascript"></script>
   
    使用谷歌地图API的第一步就是要注册一个API密钥谷歌的API使用条款 对这个密钥的用途有很正式的说明,其实总结起来也很简单:
    1、谷歌地图API提供的服务是免费的,对于通过API正常使用谷歌地图的网站基本没有任何限制;
    2、说“基本”没有限制的原因是,谷歌对每个API密钥对应的网站所作的地理编码/地址解析请求次数有限制,每天(24小时)的请求次数不能超过15000次;

    3、不能使用谷歌地图从事任何非法的行为,否则谷歌应该能够通过这个密钥阻止你的网站使用谷歌地图;
    更简单的说,谷歌使用这个密钥保证能够对所有API用户/网站进行区分,方便必要的时候对“超常规”用户进行阻拦。
    对于地址解析的次数限制,一般来说不会有什么影响,这里主要说API密钥,所以以后有时间可以再详细说说地址解析相关的东东。

    对于API密钥,还有几点需要记下来:
    1、如果使用API的页面还没有发布,只是在本地调试,可以不用密钥,随便用个字符串代替就可以了;
    2、API密钥只对网站目录或者域有效,所以,虽然你是使用同一个谷歌帐号登录后注册的密钥,但是,对不同域的网页,需要用这些域分别注册不同的密钥,对于同一个域里的页面,直接拿你网站的域名注册一个,在这个域里的所有页面就可以通用这个密钥了。

    还有一个关于API密钥的实际问题:
    在论坛里还有人问过,同一个页面需要支持不同的域名,最简单的就是公司有一个cn域名,也有一个com域名,这怎么办?
    其实,对于这种问题,可以提前先注册好不同域名对应的密钥,存在你的JS变量里面,页面加载时通过window.location得到当前请求页面的域名,通过这个域名在找到对应的密钥,然后使用script动态加载的方法加载地图API,用代码描述就是:
    //事先已经注册好的密钥
    var keyMapping = {host1:key1, host2:key2};
    //实际请求页面的域名
    var requestHost = window.location.hostname;
    //找到需要的密钥
    var key = keyMapping[requestHost];
    //构造加载API的script url
    var apiUrl = "http://ditu.google.com/maps?file=api&amp;v=2&amp;key=" + key;
    //使用script动态加载的方法加载地图API
    var scriptTag = document.createElement('script');
    scriptTag.setAttribute('type', 'text/javascript');
    scriptTag.setAttribute('src', apiUrl);
    document.getElementsByTagName('head')[0].appendChild(scriptTag);
    使用这段代码时,需要注意把你自己的JS代码中对API的各个类的调用放在API加载完成以后,详细的解释可以先google一下著名的DomReady的问题,三言两语还是说不清楚的,呵呵。
    这段代码我没有实际跑过,欢迎斧正,如果你有更好的方法,我更愿意洗耳恭听了。