很多人尝试google maps api的开发,通常会涉及到在Google maps上进行标注功能的开发。Helloj2ee学习一项技术通常不在看书,而是多以帮助为主。当我看完之后,我将Overlay这一章翻译成中文,和大家共享。该文英文全文是Google maps api javascript v3帮助,链接:https://developers.google.com/maps/documentation/javascript/overlays
相应会有一个中文的Google翻译:https://developers.google.com/maps/documentation/javascript/overlays?hl=zh-cn。但是这篇译文和Google的译文相比,会有如下不同:
1 我会保留诸如Overlay,marker保留其英文原文,通常该词第一次出现,我会以中文英文同时出现的方式,而第二次只保留英文;
2 代码中的英文注释将其翻译成了对应中文;
3 对于Google翻译中生硬的地方做了修改;
4 Google的中文文档帮助和英文文档帮助并不对应,我会英文中没有的对应翻译过来(目录中标红的地方)
5 由于众所周知的原因,大家未必能够很顺畅地浏览V3中的例子,我将该篇用到的示例一并打包。链接地址:http://vdisk.weibo.com/s/n5w3t
目录:
1 叠加层(Overlay)概述
1.1 添加Overlay
1.2 删除Overlay
2 符号(Symbol)
2.1 预定义路径(Path)
3 标注(Marker)
3.1 Marker动画
3.2 自定义Marker
3.2.1 简单图标(Icon)
3.2.2 复杂Icon
3.2.3 矢量Icon
4 折线(Polyline)
4.1 Polyline选项(Options)
4.2 Polyline数组
4.3 Polyline符号化
5 多边形(Polygon)
5.1 Polygon选项
5.2 Polygon自动闭合
5.3 Polygon数组
6 圆和矩形
6.1 圆
6.2 矩形
7 可编辑形状
7.1 编辑事件
8 绘图(Drawing)库
8.1 DrawingManager选项
8.2 图形绘制工具控件更新
8.3 绘图事件
9 信息窗口(info window)
10 Ground Overlays
11 自定义overlay
11.1 overlay的子类化
11.2 初始化自定义的overlay
11.3 自定义overlay的绘制
11.4 隐藏和显示自定义的overlay
Overlay是地图上有经纬坐标的对象集合,因此Overlay会随地图拖拽或缩放而移动。Overlay表示的是“添加”到地图上具有明确位置的点、线、面或者三者集合的对象。
Google Maps API有以下几种类型的Overlay:
Overlay通常在构造时,添加到地图中。所有的Overlay都定义了选项(Options)对象,来指定Overlay在哪个地图上显示。当然您也可以直接使用Overlay的SetMap方法,将Overlay添加到指定的地图上。
var myLatlng = new google.maps.LatLng(-25.363882,131.044922); var myOptions = { zoom: 4, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP, } var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); var marker = new google.maps.Marker({ position: myLatlng, title:"Hello World!" }); // 调用setMap方法,将Marker添加到地图上 marker.setMap(map);
要从地图上删除Overlay,同样可调用Overlay对象的 setMap() 方法,只是传递 null参数。请注意,调用此方法不会删除Overlay,而只是从地图上删除Overlay。如果您要真正删除Overlay,则应当从地图上删除Overlay,然后将Overlay设置为 null。
如果要管理一组Overlay对象,则应当创建一个数组来存储这些Overlay。使用数组时,如果需要删除Overlay,需要对数组中的每个Overlay依次调用 setMap()。(注意,与第 2 版不同,该版本中未提供 clearOverlays() 方法。您需要自己负责追踪Overlay的状态,并在不需要他们时,将其删除。)您可以通过在地图上依次移除Overlay,并将数组的长度(Length)设置为0,以此删除Overlay。但该操作会删除所有对Overlay的外部引用。
下面示例是单击地图时将Marker放在地图上,然后将Marker存入数组中。Overlay可以隐藏、显示或者删除:
var map; var markersArray = []; function initialize() { var haightAshbury = new google.maps.LatLng(37.7699298, -122.4469157); var mapOptions = { zoom: 12, center: haightAshbury, mapTypeId: google.maps.MapTypeId.TERRAIN }; map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); google.maps.event.addListener(map, 'click', function(event) { addMarker(event.latLng); }); } function addMarker(location) { marker = new google.maps.Marker({ position: location, map: map }); markersArray.push(marker); } // 从地图中移除overlay,但仍然保存在数组中 function clearOverlays() { if (markersArray) { for (i in markersArray) { markersArray[i].setMap(null); } } } // 在数组中显示当前的overlay function showOverlays() { if (markersArray) { for (i in markersArray) { markersArray[i].setMap(map); } } } // 删除数组中所有的marker function deleteOverlays() { if (markersArray) { for (i in markersArray) { markersArray[i].setMap(null); } markersArray.length = 0; } }
查看示例 (overlay-remove.html)
Symbol是一种基于矢量的图像,它可以应用在Marker或者Polyline对象上。Symbol通过路径(path)来定义(使用SVG Path语法规则),其他选项控制Symbol如何显示。SymbolPath对象已经预定义了若干个Symbol。除了Path这个唯一必须设置的属性外,Symbol类还支持若干个显示设置的属性,比如画笔填充色以及画笔宽度等。
读者希望学习线要素符号化和动画的相关知识,请参见Polyline符号化一节。读者希望学习marker符号化的相关知识,请参见矢量Icon一节。
下面示例创建了一个黄色五角星的Symbol,用浅黄色填充,并且用深黄色描边。
var goldStar = { path: 'M 125,5 155,90 245,90 175,145 200,230 125,180 50,230 75,145 5,90 95,90 z', fillColor: "yellow", fillOpacity: 0.8, scale: 1, strokeColor: "gold", strokeWeight: 14 }; var marker = new google.maps.Marker({ position: new google.maps.LatLng(-25.363, 131.044), icon: goldStar, map: map });
Google Maps JavaScript API提供内置的符号,可以应用在Marker或者Polyline上。默认的符号包括圆,两种类型的箭头。在Polyline上的Symbol方向是固定的,因此需要前方和后方两种箭头,前方是Polyline前进的方向。内置的Symbol如下表所示。
您也可以通过Symbol options修改内置符号的画笔或者填充属性。
标注(Marker)用于标识地图上的位置。默认情况下,标注使用的是标准图标(Icon),但可以在标注的构造函数中设置一个自定义Icon,或者通过调用 setIcon方法 来设置一个自定义Icon。google.maps.Marker 构造函数采用了一个Marker options对象设置Marker的初始属性。在构造Marker时,下面的属性非常重要,而且经常会被设置。
注意,在 Marker构造函数中需要指定为哪个地图添加Marker。如果不指定该参数,那么,只能创建Marker,而无法将其添加到地图上(或显示在地图上)。但是可以在后面通过调用Marker的setMap()方法在地图上添加Marker。如果要移除Marker,则调用setMap()方法时,传递null参数。
Marker也可设计成交互的。比如,默认情况下它们接收 'click' 事件,常在该事件响应函数中弹出信息窗口。并且将Marker的draggable属性设置成true,就能够使Marker在地图上可拖拽。
以下示例介绍了如何将一个简单的Marker添加到澳大利亚中心区域的Uluru的地图上:
var myLatlng = new google.maps.LatLng(-25.363882,131.044922); var mapOptions = { zoom: 4, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); var marker = new google.maps.Marker({ position: myLatlng, map: map, title:"Hello World!" });
Marker 标题将会以提示框(Tooltip)的形式显示。
如果不想在Marker的构造函数中传递任何 Marker options,那么,请在构造函数的参数中传递一个空对象 {}。
查看示例 (marker-simple.html)
您也可以对Marker添加动画效果,以便它们在各种不同的环境中展现动态运动效果。为Marker添加动画效果的方法是设置Marker的 animation 属性(该属性属于 google.maps.Animation 类型)。系统目前支持以下 Animation 值:
可以调用 Marker 对象的 setAnimation()方法,对现有Marker添加动画效果。
下面示例在瑞典斯德哥尔摩(Stockholm)市创建了一个采用 DROP 动画的Marker。点击该Marker时,可使它在 BOUNCE 动画和无动画之间切换:
var stockholm = new google.maps.LatLng(59.32522, 18.07002); var parliament = new google.maps.LatLng(59.327383, 18.06747); var marker; var map; function initialize() { var mapOptions = { zoom: 13, mapTypeId: google.maps.MapTypeId.ROADMAP, center: stockholm }; map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); marker = new google.maps.Marker({ map:map, draggable:true, animation: google.maps.Animation.DROP, position: parliament }); google.maps.event.addListener(marker, 'click', toggleBounce); } function toggleBounce() { if (marker.getAnimation() != null) { marker.setAnimation(null); } else { marker.setAnimation(google.maps.Animation.BOUNCE); } }
查看示例 (marker-animations.html)
注意:如果您有多个Marker,则不应让所有Marker同时掉落到地图上。您可以调用 setTimeout()方法,(类似于以下示例中所示)来间隔显示标记的动画效果。
查看示例 (marker-animations-iteration.html)
Marker也可以定义为图标(icon)来替代原默认的Google图钉形状。定义icon涉及到一系列关于Marker外观的属性设置。
3.2.1简单图标(Icon)
在绝大多数情况下,可以通过设置Marker的icon属性为某一图像的URL地址的方法,来替换掉默认的Google图钉图标。
在下面的例子中,创建了一个icon标示澳大利亚Bondi海滩的位置。
function initialize() { var myLatlng = new google.maps.LatLng(-25.363882,131.044922); var myOptions = { zoom: 4, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); var image = 'beachflag.png'; var myLatLng = new google.maps.LatLng(-33.890542, 151.274856); var beachMarker = new google.maps.Marker({ position: myLatLng, map: map, icon: image }); }
查看示例 (icon-simple.html)
3.2.2 复杂Icon
复杂Icon可用于指定复杂的形状(表示用户可点击的区域)、添加阴影,以及指定这些形状与其他叠加层在显示时的“压盖顺序”。以这种方式设定的Icon需要将Marker的 icon 属性和 shadow 属性设置为 MarkerImage 类型的对象。
阴影通常应该和主图像成 45 度夹角(向右上方倾斜),并且阴影的左下角应与图标图像的左下角对齐。阴影图像应是半透明的 24 位 PNG 图像,这样图像边界便可以在地图上正确显示。
MarkerImage 对象不仅可以定义显示的图像,还可以定义图标的大小、图标的原点(比如,您所需要的图像只是一幅较大图像的一部分。)以及图标所定位的热点对应的 anchor属性(基于原点距离)。
以下示例介绍了如何创建复杂的Icon,来表示澳大利亚新南威尔士悉尼附近的海滩。请注意,应当将 anchor 设置为 (0,32),从而与旗杆的基座相对应。
function initialize() { var mapOptions = { zoom: 10, center: new google.maps.LatLng(-33.9, 151.2), mapTypeId: google.maps.MapTypeId.ROADMAP } var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); setMarkers(map, beaches); } /** * Marker包括的数据项分别为名称,经纬度,以及zIndex(标示彼此压盖顺序) */ var beaches = [ ['Bondi Beach', -33.890542, 151.274856, 4], ['Coogee Beach', -33.923036, 151.259052, 5], ['Cronulla Beach', -34.028249, 151.157507, 3], ['Manly Beach', -33.80010128657071, 151.28747820854187, 2], ['Maroubra Beach', -33.950198, 151.259302, 1] ]; function setMarkers(map, locations) { // 将Marker添加到地图上 // Marker的大小用X,Y表示 // 图像(0,0)表示的是图像的左上角 // Origins, anchor的坐标都是横轴向右增加,纵轴向下增加 var image = new google.maps.MarkerImage('images/beachflag.png', // 该marker 20个像素宽,32个像素高 new google.maps.Size(20, 32), // 图像原点0,0. new google.maps.Point(0,0), // 图像anchor属性为(0,32) new google.maps.Point(0, 32)); var shadow = new google.maps.MarkerImage('images/beachflag_shadow.png', // 阴影在横轴方向宽 // 高和主图像相同 new google.maps.Size(37, 32), new google.maps.Point(0,0), new google.maps.Point(0, 32)); // shape定义了图标可点击的区域 // 该类型是一系列x,y坐标串。最后一个坐标和第一个坐标自动闭合。 var shape = { coord: [1, 1, 1, 20, 18, 20, 18 , 1], type: 'poly' }; for (var i = 0; i < locations.length; i++) { var beach = locations[i]; var myLatLng = new google.maps.LatLng(beach[1], beach[2]); var marker = new google.maps.Marker({ position: myLatLng, map: map, shadow: shadow, icon: image, shape: shape, title: beach[0], zIndex: beach[3] }); } }
查看示例 (icon-complex.html)
3.2.3 矢量Icon
Marker既支持栅格图像也支持矢量路径(也称之为Symbol)。为了显示矢量路径(path),需要将Maker的Icon属性设置成一个Symbol对象。您可以使用google.maps.SymbolPath内置的path,也可以通过SVG Path语法规则自定义Path。
更多关于Google maps矢量图形信息,参见symbol的相关文档。
下面示例展示的通过内置的矢量path创建一个icon。详细的示例,参见Symbol一节。
marker = new google.maps.Marker({ position: new google.maps.LatLng(-25.363882, 131.044922), icon: { path: google.maps.SymbolPath.CIRCLE, scale: 10 }, draggable: true, map: map });
Polyline 类定义地图上线段彼此相连的折线。Polyline 对象包含一组经纬度位置,由此创建了一系列按顺序相连的线段。
Polyline 构造函数通过Polyline Options对象来指定线的经纬度坐标,以及线的外观。
Polyline 就是在地图上绘制的一系列直线段。您可以在构造Polyline时,通过 Polyline options 对象指定线的画笔颜色、粗细和透明度,或者在构造之后更改这些属性。Polyline支持以下画笔样式:
除此之外,Polyline的editable属性定义的是该形状是否允许用户在地图上编辑。
以下代码段绘制一条粗细为 2 像素的红色折线,连接威廉·金斯福德·史密斯 (William Kingsford Smith) 从美国加利福尼亚州奥克兰到澳大利亚布里斯班的首次跨太平洋飞行路线。
function initialize() { var myLatLng = new google.maps.LatLng(0, -180); var myOptions = { zoom: 3, center: myLatLng, mapTypeId: google.maps.MapTypeId.TERRAIN }; var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); var flightPlanCoordinates = [ new google.maps.LatLng(37.772323, -122.214897), new google.maps.LatLng(21.291982, -157.821856), new google.maps.LatLng(-18.142599, 178.431), new google.maps.LatLng(-27.46758, 153.027892) ]; var flightPath = new google.maps.Polyline({ path: flightPlanCoordinates, strokeColor: "#FF0000", strokeOpacity: 1.0, strokeWeight: 2 }); flightPath.setMap(map); }
Polyline通过Latlng对象数组来设定一系列坐标。要访问这些坐标,需要调用Polyline的GetPath方法,它会传回MVCArray类型的数组。并且可以使用以下方法来操作和检查数组:
注意:不能只是使用语法 mvcArray[i] 检索数组的第 i 个元素,而必须使用 mvcArray.getAt(i)。
以下代码创建了一幅交互式地图,其中的折线是根据用户的点击构造的。请注意,只有当折线的 path 属性包含两个 LatLng 坐标时,折线才会显示。
var poly; var map; function initialize() { var chicago = new google.maps.LatLng(41.879535, -87.624333); var myOptions = { zoom: 7, center: chicago, mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map(document.getElementById('map_canvas'), myOptions); var polyOptions = { strokeColor: '#000000', strokeOpacity: 1.0, strokeWeight: 3 } poly = new google.maps.Polyline(polyOptions); poly.setMap(map); //对”click”事件添加监听器 google.maps.event.addListener(map, 'click', addLatLng); } /** * 处理地图上单击事件,并且为Polyline添加新的点。 * @param {MouseEvent} mouseEvent */ function addLatLng(event) { var path = poly.getPath(); // 由于path是MVCArray类型, 我们只是简单添加新的坐标, // 并且Path将自动显示 path.push(event.latLng); // 在Polyline上新增的点上再增加一个Marker var marker = new google.maps.Marker({ position: event.latLng, title: '#' + path.getLength(), map: map }); }
查看示例 (polyline-complex.html)
您可以对Polyline进行符号化。为了对Polyline符号化,需要设置PolylineOptions对象的icons[]属性。Icons数组中会有一个或者多个IconSequence序列,IconSequence包含如下几项:
如果Polyline是具有地理坐标的一条线,那么offset和repeat距离的默认单位应该是米。将offset或者repeat设置为象素值,那么Google会自动计算该距离在屏幕上的象素值。
通过对符号的组合,以及使用PolylineOptions类,您还可以对地图上的线外观有更多的控制。下面是几个典型的例子。
箭头
使用IconSequence.offset属性,可以为线的两端天价箭头。在这个例子中将offset设置为100%,这样把箭头就放置在线的末端。
var lineCoordinates = [ new google.maps.LatLng(22.291, 153.027), new google.maps.LatLng(18.291, 153.027) ]; var lineSymbol = { path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW }; var line = new google.maps.Polyline({ path: lineCoordinates, icons: [{ icon: lineSymbol, offset: '100%' }], map: map });
您可以先将Polyline的透明度设置为0%,然后每隔固定间隔绘制不透明的符号来达到虚线的效果。
var lineCoordinates = [ new google.maps.LatLng(22.291, 153.027), new google.maps.LatLng(18.291, 153.027) ]; var lineSymbol = { path: 'M 0,-1 0,1', strokeOpacity: 1, scale: 4 }; var line = new google.maps.Polyline({ path: lineCoordinates, strokeOpacity: 0, icons: [{ icon: lineSymbol, offset: '0', repeat: '20px' }], map: map });
自定义符号允许您在Polyline上添加多个不同的形状。
var lineCoordinates = [ new google.maps.LatLng(22.291, 153.027), new google.maps.LatLng(18.291, 153.027) ]; var symbolOne = { path: 'M -2,0 0,-2 2,0 0,2 z', strokeColor: '#F00', fillColor: '#F00', fillOpacity: 1 }; var symbolTwo = { path: 'M -2,-2 2,2 M 2,-2 -2,2', strokeColor: '#292', strokeWeight: 4 }; var symbolThree = { path: 'M -1,0 A 1,1 0 0 0 -3,0 1,1 0 0 0 -1,0M 1,0 A 1,1 0 0 0 3,0 1,1 0 0 0 1,0M -3,3 Q 0,5 3,3', strokeColor: '#00F', rotation: 0 }; var line = new google.maps.Polyline({ path: lineCoordinates, icons: [{ icon: symbolOne, offset: '0%' },{ icon: symbolTwo, offset: '50%' },{ icon: symbolThree, offset: '100%' } ], map: map });
可以通过setTimeout()函数在固定时间间隔内改变符号的偏移量,从而使得符号似乎沿某一路径在运动。
var line; function initialize() { var mapOptions = { center: new google.maps.LatLng(20.291, 153.027), zoom: 6, mapTypeId: google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); var lineCoordinates = [ new google.maps.LatLng(22.291, 153.027), new google.maps.LatLng(18.291, 153.027) ]; var lineSymbol = { path: google.maps.SymbolPath.CIRCLE, scale: 8, strokeColor: '#393' }; line = new google.maps.Polyline({ path: lineCoordinates, icons: [{ icon: lineSymbol, offset: '100%' }], map: map }); } function animateCircle() { var count = 0; offsetId = window.setInterval(function() { count = (count + 1) % 200; var icons = line.get('icons'); icons[0].offset = (count / 2) + '%'; line.set('icons', icons); }, 20); }
Polygon 对象类似于 Polyline 对象,都由一系列有序坐标构成。不过,多边形不像折线一样有两个端点,而是定义闭合区域。与折线类似的是,您可以定义影响多边形轮廓的画笔;不同的是,您还可以定义多边形内的填充区域。
此外,Polygon 还可以展示复杂形状,包括不连续形状(多个多边形定义为一个多边形)、“圆环”(多边形区域在多边形内显示为“岛”)以及一个或多个多边形的交叉重叠。因此,一个多边形可指定多条路径(Path)。
与Polyline一样,您可以定义Polygon的边(“画笔”)的自定义颜色、粗细和不透明度,以及封闭区域(“填充”)的自定义颜色和不透明度。颜色应当采用十六进制数字的HTML样式。
由于Polygon区域可能包括多条独立的Path,因此 Polygon 对象的 paths 属性指定成“数组的数组”(每个都是 MVCArray 类型),其中每个数组分别定义一系列 LatLng 有序坐标。
但是,对于只包含一条Path的简单Polygon,为方便起见,您可以采用单个 LatLng 坐标数组构造 Polygon。在将数组存储到 Polygon 的 paths 属性时,Google Maps API 会在构造时将其转换为“数组的数组”。同样,该API还为只包含一条Path的简单多边形提供了简单的 getPath() 方法。
注意:如果采用此方式构造Polygon,则仍需要将路径处理为 MVCArray,以便检索多边形的值。
除此之外, Polygon的editable值规定了地图上的Polygon是否可编辑。
以下代码段创建一个表示百慕大三角的多边形:
function initialize() { var myLatLng = new google.maps.LatLng(24.886436490787712, -70.2685546875); var mapOptions = { zoom: 5, center: myLatLng, mapTypeId: google.maps.MapTypeId.TERRAIN }; var bermudaTriangle; var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); var triangleCoords = [ new google.maps.LatLng(25.774252, -80.190262), new google.maps.LatLng(18.466465, -66.118292), new google.maps.LatLng(32.321384, -64.75737), new google.maps.LatLng(25.774252, -80.190262) ]; // Construct the polygon // Note that we don't specify an array or arrays, but instead just // a simple array of LatLngs in the paths property bermudaTriangle = new google.maps.Polygon({ paths: triangleCoords, strokeColor: "#FF0000", strokeOpacity: 0.8, strokeWeight: 2, fillColor: "#FF0000", fillOpacity: 0.35 }); bermudaTriangle.setMap(map); }
上例中的 Polygon 包含四个坐标,但第一个坐标和最后一个坐标为相同位置,从而定义了一个环路。不过,实际上由于多边形定义的就是封闭区域,因而无需定义这最后一个坐标。
对于任意指定路径,Google Maps API 将通过绘制连接最后一个坐标和第一个坐标以自动“封闭”任何多边形。
下例除了省略最后一个坐标之外,其他与上例均相同。
查看示例 (polygon-autoclose.html)
多边形将其一系列坐标指定为数组的数组,其中每个数组都是 MVCArray 类型。每个子数组都是 LatLng 坐标的数组,用于指定单条Path。要检索这些坐标,可调用 Polygon 的getPaths() 方法。由于数组为 MVCArray,因此您需要使用以下操作处理和检查该数组:
注意:不能只是使用语法 mvcArray[i] 检索数组的第 i 个元素,而必须使用 mvcArray.getAt(i)。
以下代码通过显示Polygon的坐标信息,处理Polygon的点击事件:
var map; var infoWindow; function initialize() { var myLatLng = new google.maps.LatLng(24.886436490787712, -70.2685546875); var myOptions = { zoom: 5, center: myLatLng, mapTypeId: google.maps.MapTypeId.TERRAIN }; var bermudaTriangle; map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); var triangleCoords = [ new google.maps.LatLng(25.774252, -80.190262), new google.maps.LatLng(18.466465, -66.118292), new google.maps.LatLng(32.321384, -64.75737) ]; bermudaTriangle = new google.maps.Polygon({ paths: triangleCoords, strokeColor: "#FF0000", strokeOpacity: 0.8, strokeWeight: 3, fillColor: "#FF0000", fillOpacity: 0.35 }); bermudaTriangle.setMap(map); // 为click事件添加监听器 google.maps.event.addListener(bermudaTriangle, 'click', showArrays); infowindow = new google.maps.InfoWindow(); } function showArrays(event) { // 因为该Polygon只有一个path,因此调用getpath()方法返回 // LatLngs的MVCArray数组。 var vertices = this.getPath(); var contentString = "<b>Bermuda Triangle Polygon</b><br />"; contentString += "Clicked Location: <br />" + event.latLng.lat() + "," + event.latLng.lng() + "<br />"; // 对顶点进行循环 for (var i =0; i < vertices.length; i++) { var xy = vertices.getAt(i); contentString += "<br />" + "Coordinate: " + i + "<br />" + xy.lat() +"," + xy.lng(); } // 替换掉Infowindow的内容,以及修改其位置 infowindow.setContent(contentString); infowindow.setPosition(event.latLng); infowindow.open(map); }
查看示例 (polygon-array.html)
除了普通的 Polygon 类之外,JavaScript Maps API 还包括面向 Circle 和 Rectangle 的特定类,简化Polygon的构造。
Circle 与 Polygon 类似,您可以自定义Cirlce(“画笔”)边缘的颜色、粗细和透明度,以及封闭区域(“填充”)的颜色和透明度。颜色应当采用十六进制数字的 HTML 样式。
与 Polygon 不同,您不应为 Circle 定义 paths;圆形有两个用于定义其形状的其他属性:
除此之外,Circle的editable属性规定了图形在地图上是否可编辑。
下列代码段创建了用于表示美国人口的圆形:
// 创建一个对象包含经纬度和对应人口 var citymap = {}; citymap['chicago'] = { center: new google.maps.LatLng(41.878113, -87.629798), population: 2842518 }; citymap['newyork'] = { center: new google.maps.LatLng(40.714352, -74.005973), population: 8143197 }; citymap['losangeles'] = { center: new google.maps.LatLng(34.052234, -118.243684), population: 3844829 } var cityCircle; function initialize() { var mapOptions = { zoom: 4, center: new google.maps.LatLng(37.09024, -95.712891), mapTypeId: google.maps.MapTypeId.TERRAIN }; var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); for (var city in citymap) { // 构建圆形大小 var populationOptions = { strokeColor: "#FF0000", strokeOpacity: 0.8, strokeWeight: 2, fillColor: "#FF0000", fillOpacity: 0.35, map: map, center: citymap[city].center, radius: citymap[city].population / 20 }; cityCircle = new google.maps.Circle(populationOptions); } }
查看示例(Circle-simple.html)
Rectangle 与 Polygon 类似,您可以自定义矩形(“画笔”)边缘的颜色、粗细和透明度,以及封闭区域(“填充”)的颜色和透明度。颜色应当采用十六进制数字的 HTML 样式。
与 Polygon 不同,您不应为 Rectangle 定义 path;矩形有一个用于定义其形状的其他属性:
除此之外,Rectangle的editable属性规定了图形在地图上是否可编辑。
以下示例会在任何 'zoom_changed' 事件发生时基于前一个视口创建矩形:
任何一个图形Overlay(折线,多边形,圆和矩形)都可通过将Shape选项中的editable属性设置为true,变成“可编辑”的。
为了使marker可拖拽,需要将maker option中的draggable属性设置为true。
var circleOptions = { center: new google.maps.LatLng(-34.397, 150.644), radius: 25000, map: map, editable: true }; var circle = new google.maps.Circle(circleOptions);
查看示例(user-editable-shape.html例子)
在两个会话间,对几何对象所做的修改是无法保存的。如果您需要保存对Polygon的修改,那么您必须自己保存这些信息。
当一个图形被编辑时,编辑完成后会触发编辑事件,如下所示:
图形 |
事件 |
Circle |
radius_changed center_changed |
Polygon |
insert_at remove_at set_at 必须在Polygon的Path上设置事件的监听器,如果Polygon有多个path,那么必须在各个path上设置监听器。 |
Rectangle |
bounds_changed |
google.maps.event.addListener(circle, 'radius_changed', function() { radius = circle.getRadius(); }); google.maps.event.addListener(outerPath, 'set_at', function() { print('Vertex moved on outer path.'); }); google.maps.event.addListener(innerPath, 'insert_at', function() { print('Vertex removed from inner path.'); });
在这篇文档中绘图库的概念是指google.maps.drawing库。默认情况下,当加载地图Javascritp API时,该库不会被加载,必须通过“libraries”指令显式指定才能加载。
http://maps.googleapis.com/maps/api/js?sensor=false&libraries=drawing
更多相关信息参见 Libraries in the V3 Maps API
DrawingManager类提供了一个绘图接口,供用户在地图上绘制多边形、矩形、折线、圆以及Marker。下面是创建一个DrawingManager对象。
var drawingManager = new google.maps.drawing.DrawingManager(); drawingManager.setMap(map);
DrawingManager构造函数接受一组选项参数,来定义控件的显示外观,位置以及初始绘制状态。
为了图形被创建后可编辑,需要将editable设置为true。
var drawingManager = new google.maps.drawing.DrawingManager({ drawingMode: google.maps.drawing.OverlayType.MARKER, drawingControl: true, drawingControlOptions: { position: google.maps.ControlPosition.TOP_CENTER, drawingModes: [ google.maps.drawing.OverlayType.MARKER, google.maps.drawing.OverlayType.CIRCLE, google.maps.drawing.OverlayType.POLYGON, google.maps.drawing.OverlayType.POLYLINE, google.maps.drawing.OverlayType.RECTANGLE ] }, markerOptions: { icon: new google.maps.MarkerImage('http://www.example.com/icon.png') }, circleOptions: { fillColor: '#ffff00', fillOpacity: 1, strokeWeight: 5, clickable: false, zIndex: 1, editable: true } }); drawingManager.setMap(map);
查看示例 (drawing-tools.html)
DrawingManager对象被创建后,您可以通过调用SetOptions方法传入参数来更新该控件。
drawingManager.setOptions({
drawingControlOptions: {
position: google.maps.ControlPosition.BOTTOM_LEFT,
drawingModes: [google.maps.drawing.OverlayType.MARKER]
}
})
隐藏或者显示drawing tools控件。
// 隐藏: drawingManager.setOptions({ drawingControl: false }); // 显示: drawingManager.setOptions({ drawingControl: true });
在map对象上移除绘图控件。
drawingManager.setMap(null);
隐藏绘图控件会使得该控件不显示,但是DrawingManager类的功能依然可用。如果需要,您可以按照此方式实现自己的控件。从map对象上移除DrawingManager类,则会移除所有绘图功能。如果所有绘制要素要重置的话,那么DrawingManager类通过drawingManager.setMap(map)或者构造新的DrawingManager对象来和地图重新关联。
当一个图形Overlay被创建时,有两个事件会被激发:
google.maps.event.addListener(drawingManager, 'circlecomplete', function(circle) { var radius = circle.getRadius(); }); google.maps.event.addListener(drawingManager, 'overlaycomplete', function(event) { if (event.type == google.maps.drawing.OverlayType.CIRCLE) { var radius = event.overlay.getRadius(); } });
InfoWindow 在地图上方的浮动窗口中显示内容。信息窗口有点像漫画书上的文字气球,它有一个内容区域和锥形引线,引线的头位于地图的指定位置上。通过点击 Google Maps 上的商户标记,您可以看到活动的信息窗口。
InfoWindow 构造函数采用的是 InfoWindow options 对象,该对象指定了用于显示信息窗口的一组初始参数。在创建信息窗口的过程中,系统不会在地图上添加信息窗口。要显示信息窗口,您需要调用 InfoWindow 上的 open() 方法,向其传递要在其中打开信息窗口的 Map,以及向其传递用于锚定信息窗口的 Marker(可选)。(如果未提供任何标记,那么,会在其 position 属性上打开信息窗口)。
InfoWindow options 对象是包含以下字段的对象常量:
InfoWindow 的内容可以是文本字符串、HTML 代码段或 DOM 元素本身。要设置此内容,请在 InfoWindow options 构造函数中传递该内容,或者对InfoWindow显式调用 setContent()。如果想要显式调整内容的大小,您可以使用 <div> 进行此操作,如果您愿意,还可以启用滚动功能。请注意,如果您没有启用滚动功能,而内容的大小又超过了信息窗口的可用空间,那么,内容可能会从信息窗口中“溢”出。
InfoWindow 可附加到 Marker 对象(在这种情况下,它们的位置取决于标记的位置)上,或附加到地图本身指定的 LatLng 位置上。如果您一次只想显示一个信息窗口(正如 Google Maps 上的相应行为),那么,您只需创建一个信息窗口,然后在地图事件(例如用户点击)执行过程中将此信息窗口重新分配到不同的位置或标记中。但与 Google Maps API 第 2 版中的相应行为不同的是,如果您选择进行上述操作,那么,地图可能会立即显示多个 InfoWindow 对象。
要更改信息窗口的位置,您可以对信息窗口调用 setPosition() 以显式的方式更改其位置,或者使用 InfoWindow.open() 方法将信息窗口附加到新标记上。请注意,如果您在没有传递标记的情况下调用了 open(),那么,InfoWindow 将会使用在构建过程中通过 InfoWindow options 对象指定的位置。
以下代码显示了澳大利亚中心位置的标记。点击该标记可显示信息窗口。
var myLatlng = new google.maps.LatLng(-25.363882,131.044922); var mapOptions = { zoom: 4, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); var contentString = '<div id="content">'+ '<div id="siteNotice">'+ '</div>'+ '<h2 id="firstHeading" class="firstHeading">Uluru</h2>'+ '<div id="bodyContent">'+ '<p><b>Uluru</b>, also referred to as <b>Ayers Rock</b>, is a large ' + 'sandstone rock formation in the southern part of the '+ 'Northern Territory, central Australia. It lies 335 km (208 mi) '+ 'south west of the nearest large town, Alice Springs; 450 km '+ '(280 mi) by road. Kata Tjuta and Uluru are the two major '+ 'features of the Uluru - Kata Tjuta National Park. Uluru is '+ 'sacred to the Pitjantjatjara and Yankunytjatjara, the '+ 'Aboriginal people of the area. It has many springs, waterholes, '+ 'rock caves and ancient paintings. Uluru is listed as a World '+ 'Heritage Site.</p>'+ '<p>Attribution: Uluru, <a href="http://en.wikipedia.org/w/index.php?title=Uluru&oldid=297882194">'+ 'http://en.wikipedia.org/w/index.php?title=Uluru</a> (last visited June 22, 2009).</p>'+ '</div>'+ '</div>'; var infowindow = new google.maps.InfoWindow({ content: contentString }); var marker = new google.maps.Marker({ position: myLatlng, map: map, title:"Uluru (Ayers Rock)" }); google.maps.event.addListener(marker, 'click', function() { infowindow.open(map,marker); });
查看示例 (infowindow-simple.html)
以下显示了将信息窗口 maxWidth 设置为 200 像素的示例:
查看示例 (infowindow-simple-max.html)
多边形可以表示任意不规则的区域,但是它们无法显示图像。如果您有图像希望显示在地图上,那么需要用到GroundOverlay对象。GroundOverlay的构造函数中需要指定图像的URL以及图像的边界(LatLngBounds)。该图像将显示在地图上,并且限制在指定的边界里,同时使用当前地图的投影。
下面的例子是将新泽西州的纽瓦克古地图作为一个Overlay叠加到地图上。
var newark = new google.maps.LatLng(40.740, -74.18); var imageBounds = new google.maps.LatLngBounds( new google.maps.LatLng(40.716216,-74.213393), new google.maps.LatLng(40.765641,-74.139235)); var mapOptions = { zoom: 13, center: newark, mapTypeId: google.maps.MapTypeId.ROADMAP } var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); var oldmap = new google.maps.GroundOverlay( "http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg", imageBounds); oldmap.setMap(map);
查看示例(groundoverlay-simple.html)
Google Maps API 第 3 版提供了用于创建自定义叠加层的 OverlayView 类。OverlayView 是一个基类,提供了您在创建Overlay时必须实现的若干方法。该类还提供了一些方法,用于实现屏幕坐标和地图位置之间的转换。
要创建自定义叠加层,请执行以下操作:
我们将会在以下各部分中逐步介绍这些操作。
我们将会使用 OverlayView 创建简单的图像叠加层(与第 2 版 API 中的 GGroundOverlay 相似)。我们还会创建一个 USGSOverlay 对象,它包含了相关区域的 USGS 图像以及图像的边界。
var overlay; function initialize() { var myLatLng = new google.maps.LatLng(62.323907, -150.109291); var mapOptions = { zoom: 11, center: myLatLng, mapTypeId: google.maps.MapTypeId.SATELLITE }; var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); var swBound = new google.maps.LatLng(62.281819, -150.287132); var neBound = new google.maps.LatLng(62.400471, -150.005608); var bounds = new google.maps.LatLngBounds(swBound, neBound); //美国地质调查局影像 var srcImage = 'images/talkeetna.png'; overlay = new USGSOverlay(bounds, srcImage, map); }
接下来,我们则会创建该类的一个构造函数,并将已传递的参数初始化为新对象的属性。此外,我们还需要显式地将 USGSOverlay 中的 OverlayView 子类化。我们可通过将新类的 prototype 设置为父类的一个实例进行上述操作(由于我们不希望修改父类,因此,我们在此处将prototype设置为父类实例,而非父类本身)。
function USGSOverlay(bounds, image, map) { //初始化所有属性. this.bounds_ = bounds; this.image_ = image; this.map_ = map; // 定义一个能存储影像的Div.在add() // 方法里创建该div,现在将其设为null值 this.div_ = null; // 显式调用setMap方法 this.setMap(map); } USGSOverlay.prototype = new google.maps.OverlayView();
当Overlay第一次创建并处于准备显示状态时,我们需要通过浏览器的 DOM模型将Overlay和地图连接起来。当Overlay添加到地图上时,会调用overlay的onAdd()方法。在这个方法中,我们会创建一个<div>来保存我们的图像,并且
在处理此方法时,我们会创建一个用于保存图像的 <div>,添加一个 <img> 元素,将该元素附加到 <div>,最后将叠加层附加到地图的一个“窗格”(即 DOM 树中的节点)中。
一组 MapPanes 类型的窗格用于指定不同的层在地图上的堆叠顺序。您可以使用以下窗格,并且可以按照由下至上的堆叠顺序枚举这些窗格。
由于我们的图像为“ground overlay”,因此,我们将会使用 overlayLayer 地图窗格。创建了此窗格后,我们会以子对象的形式将对象附加到窗格上。
USGSOverlay.prototype.onAdd = function() { // 注意:overlay的onAdd()方法表明地图的 // pane可以通过DOM模型将overlay和map关联起来 // 创建一个Div,并且设置若干基础属性 var div = document.createElement('div'); div.style.border = "none"; div.style.borderWidth = "0px"; div.style.position = "absolute"; // 创建img标签,并将img和div联系起来 var img = document.createElement("img"); img.src = this.image_; img.style.width = "100%"; img.style.height = "100%"; div.appendChild(img); // 将overlay的div和该div关联起来 this.div_ = div; // 通过map的pane将overlay和map关联起来 // 将overlay添加到overlayimage pane上 var panes = this.getPanes(); panes.overlayLayer.appendChild(div); }
请注意,在上述操作中,我们实际上并未调用任何特殊的视觉显示。每当需要在地图上绘制叠加层时(其中包括首次添加叠加层时),API 都会对叠加层调用独立的 draw() 方法。
因此,我们将会实现此 draw() 方法,然后使用 getProjection() 检索overlay的 MapCanvasProjection,并计算对象的右上角和左下角锚定点的准确坐标,以此重新调整 <div> 的大小;反之,此操作又可重新调整图像的大小,从而让图像与我们在overlay的构造函数中所指定的范围相匹配。
USGSOverlay.prototype.draw = function() { // 调整overlay的尺寸和位置。我们使用overlay的西南和东北 // 两点来调整overlay正确的位置和尺寸。我们需要从overlay // 获得投影来完成 var overlayProjection = this.getProjection(); // 获得overlay的西南和东北坐标(latlngs),然后将其转换为 // 屏幕像素坐标。我们使用该坐标来调整Div。 var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest()); var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast()); // 调整图像的Div来满足所指定的坐标 var div = this.div_; div.style.left = sw.x + 'px'; div.style.top = ne.y + 'px'; div.style.width = (ne.x - sw.x) + 'px'; div.style.height = (sw.y - ne.y) + 'px'; }
我们还会添加 onRemove() 方法,完全删除地图中的叠加层。如果我们曾经将叠加层的 map 属性设置为 null,那么,系统将会自动通过 API 调用此方法。
USGSOverlay.prototype.onRemove = function() { this.div_.parentNode.removeChild(this.div_); this.div_ = null; }
查看示例(overlay-simple.html)
如果您想要隐藏或显示overlay,而不只是创建或删除overlay,您可以实现 hide() 和 show() 方法,以调整overlay的可见性。或者,您也可以将overlay与地图的 DOM 分离,但这种操作的成本有些过高。请注意,如果您随后将叠加层重新附加到地图的 DOM 上,则系统会重新调用叠加层的 onAdd()方法。
以下示例介绍了如何将 hide() 和 show() 方法添加到overlay的原型中,这样可以切换显示容器 <div>。此外,我们还添加了 toogleDOM() 方法,它可将overlay附加到地图,或者将两者分离开来。请注意,如果我们将visibility设置为 "hidden",然后通过 toggleDOM() 将地图与 DOM 分离,随后又重新附加了地图,那么,叠加层会再次显示出来,这是因为,我们在叠加层的 onAdd() 方法中重新创建了其中所包含的 <div>。
// 注意visibility属性必须是个字符串 USGSOverlay.prototype.hide = function() { if (this.div_) { this.div_.style.visibility = "hidden"; } } USGSOverlay.prototype.show = function() { if (this.div_) { this.div_.style.visibility = "visible"; } } USGSOverlay.prototype.toggle = function() { if (this.div_) { if (this.div_.style.visibility == "hidden") { this.show(); } else { this.hide(); } } } USGSOverlay.prototype.toggleDOM = function() { if (this.getMap()) { this.setMap(null); } else { this.setMap(this.map_); } }
// 现在添加一个按钮来触发该事件 <div id ="toolbar" width="100%; height:20px;" style="text-align:center"> <input type="button" value="Toggle Visibility" onclick="overlay.toggle();"></input> <input type="button" value="Toggle DOM Attachment" onclick="overlay.toggleDOM();"></input> </div> <div id="map_canvas" style="width: 100%; height: 95%;"></div>