Maps JavaScript API v2 自 2021 年 5 月 26 日起不再提供。因此,您网站的 v2 版地图将停止运行,并返回 JavaScript 错误。若要继续在您的网站上使用地图,请迁移至 Maps JavaScript API v3。本指南将帮助您完成此过程。
概览
每个应用的迁移流程都会略有不同;不过,所有项目都有一些共同的步骤:
- 获取新密钥。Maps JavaScript API 现在使用 Google Cloud 控制台来管理密钥。如果您仍在使用 v2 密钥,请务必先获取新的 API 密钥,然后再开始迁移。
- 更新您的 API 引导加载程序。大多数应用都将使用以下代码加载 Maps JavaScript API v3:
<script src="//maps.googleapis.com/maps/api/js?key=
YOUR_API_KEY "></script> - 更新您的代码。所需的更改量在很大程度上取决于您的应用。常见变更包括:
- 始终引用 google.maps 命名空间。在 v3 中,所有 Maps JavaScript API 代码都存储在
google.maps.*
命名空间中,而不是全局命名空间中。在此过程中,大多数对象也已重命名。例如,现在您将加载google.maps.Map
,而不是GMap2
。 - 移除所有对已废弃方法的引用。移除了一些通用实用程序方法,例如
GDownloadURL
和GLog
。 请将此功能替换为第三方实用程序库,或从代码中移除这些引用。 - (可选)将库添加到您的代码中。许多功能已外部化到实用程序库中,因此每个应用只需加载要使用的 API 部分。
- (可选)将您的项目配置为使用 v3 extern。 v3 外部函数可用于帮助您使用 Closure 编译器验证代码,或在 IDE 中触发自动补全。 详细了解 高级编译和外部函数。
- 始终引用 google.maps 命名空间。在 v3 中,所有 Maps JavaScript API 代码都存储在
- 测试并迭代。目前,您仍需要完成一些工作,但好消息是,您已经离新版 v3 地图应用不远了!
Maps JavaScript API v3 中的变更
在规划迁移之前,您应花些时间了解 Maps JavaScript API v2 和 Maps JavaScript API v3 之间的区别。最新版 Maps JavaScript API 是从头开始编写的,重点是采用现代 JavaScript 编程技术、增加库的使用量,以及简化 API。 该 API 中新增了许多功能,并且一些熟悉的功能已发生更改甚至被移除。本部分重点介绍了这两个版本之间的一些主要区别。
v3 API 中的部分变更包括:
- 简化的核心库。许多补充函数已移至库中,这有助于缩短 Core API 的加载和解析时间,从而让您的地图能够在任何设备上快速加载。
- 提升了多项功能(例如多边形渲染和标记放置)的性能。
- 一种客户端使用限制的新方法,可更好地适应移动代理和企业防火墙使用的共享地址。
- 添加了对多种新型浏览器的支持和移动浏览器。已移除对 Internet Explorer 6 的支持。
- 移除了许多通用辅助类(
GLog
或GDownloadUrl
)。目前,有很多出色的 JavaScript 库提供类似的功能,例如 Closure 或 jQuery。 - HTML5 街景实现,可以在任何移动设备上加载。
- 使用您自己的照片制作自定义街景全景图片,以便分享滑雪道、待售住宅或其他有趣地点的全景图片。
- 自定义地图自定义功能,可让您更改基本地图上元素的显示方式,以匹配您的独特视觉样式。
- 支持多项新服务,例如 ElevationService 和 Distance Matrix。
- 改进后的路线服务提供备选路线、路线优化(对 旅行推销员问题的近似解)、骑车路线(带有 骑车图层)、公交路线和 可拖动路线。
- 更新后的地理编码格式,提供比 Geocoding API v2 中的
accuracy
值更准确的类型信息。 - 支持在单张地图上显示多个信息窗口
升级您的应用
您的新密钥
Maps JavaScript API v3 使用了 v2 中的新密钥系统。您可能已经在应用中使用 v3 密钥,在这种情况下,无需进行任何更改。如需进行验证,请检查您用于加载 Maps JavaScript API 的网址是否包含 key
参数。如果键值以“ABQIAA”开头,则表示您使用的是 v2 密钥。如果您使用的是 v2 密钥,则必须在迁移过程中升级到 v3 密钥,这将:
在加载 Maps JavaScript API v3 时传递该密钥。 详细了解如何生成 API 密钥。
请注意,如果您是 Google Maps API for Work 客户,则可以使用客户端 ID 和 client
参数,而不是使用 key
参数。Maps JavaScript API v3 仍支持客户端 ID,且无需完成密钥升级流程。
加载 API
您需要对代码进行的第一个修改涉及 API 的加载方式。在 v2 中,您可以通过对 http://maps.google.com/maps
的请求加载 Maps JavaScript API。如果您要加载 Maps JavaScript API v3,则需要进行以下更改:
- 从
//maps.googleapis.com/maps/api/js
加载 API - 移除
file
参数。 - 使用新的 v3 密钥更新
key
参数。Google Maps API for Work 客户应使用client
参数。 - (仅限 Google Maps Platform 高级计划)确保按照
Google Maps Platform 高级计划开发者指南中所述的方式提供
client
参数。 - 移除
v
参数以请求最新发布的版本,或根据 v3 版本控制方案相应地更改其值。 - (可选)将
hl
参数替换为language
,并保留其值。 - (可选)添加
libraries
参数以加载可选库。
在最简单的情况下,v3 引导加载程序只会指定您的 API 密钥参数:
<script src="//maps.googleapis.com/maps/api/js?key=YOUR_API_KEY "></script>
以下示例请求最新版本的 Maps JavaScript API v2(德语版):
<script src="//maps.google.com/maps?file=api&v=2.x&key=YOUR_API_KEY &hl=de"></script>
下面的示例是 v3 中对应的请求。
<script src="//maps.googleapis.com/maps/api/js?key=YOUR_API_KEY &language=de"></script>
引入 google.maps 命名空间
Maps JavaScript API v3 中最明显的变化可能是引入了 google.maps
命名空间。v2 API 默认会将所有对象放入“Global”命名空间,这可能会导致命名冲突。在 v3 中,所有对象都位于 google.maps
命名空间中。
将应用迁移到 v3 时,您必须更改代码才能使用新命名空间。很遗憾,搜索“G”并替换为“google.maps.”并不能完全解决问题;但在审核代码时,这是一个很好的经验法则。以下是 v2 和 v3 中等效类的一些示例。
v2 | v3 |
---|---|
GMap2 |
google.maps.Map |
GLatLng |
google.maps.LatLng |
GInfoWindow |
google.maps.InfoWindow |
GMapOptions |
google.map.MapOptions |
G_API_VERSION |
google.maps.version |
GPolyStyleOptions |
google.maps.PolygonOptions |
移除过时代码
Maps JavaScript API v3 与 v2 中的大多数功能类似;不过,有些类已不再受支持。在迁移过程中,您应将这些类替换为第三方实用程序库,或从代码中移除这些引用。有很多出色的 JavaScript 库提供类似的功能,例如 Closure 或 jQuery。
以下类在 Maps JavaScript API v3 中没有对等项:
GBounds | GLanguage |
GBrowserIsCompatible | GLayer |
GControl | GLog |
GControlAnchor | GMercatorProjection |
GControlImpl | GNavLabelControl |
GControlPosition | GObliqueMercator |
GCopyright | GOverlay |
GCopyrightCollection | GPhotoSpec |
GDownloadUrl | GPolyEditingOptions |
GDraggableObject | GScreenOverlay |
GDraggableObjectOptions | GStreetviewFeatures |
GFactualGeocodeCache | GStreetviewLocation |
GGeoAddressAccuracy | GStreetviewOverlay |
GGeocodeCache | GStreetviewUserPhotosOptions |
GGoogleBar | GTileLayerOptions |
GGoogleBarAdsOptions | GTileLayerOverlayOptions |
GGoogleBarLinkTarget | GTrafficOverlayOptions |
GGoogleBarListingTypes | GUnload |
GGoogleBarOptions | GXml |
GGoogleBarResultList | GXmlHttp |
GInfoWindowTab | GXslt |
GKeyboardHandler |
|
比较代码
我们来比较一下使用 v2 API 和 v3 API 编写的两个非常简单的应用。
<!DOCTYPE html> <html> <head> <script src="//maps.google.com/maps?file=api&v=2&key=YOUR_API_KEY "></script> <style> html, body, #map { height: 100%; margin: 0; } </style> <script> function initialize() { if (GBrowserIsCompatible()) { var map = new GMap2( document.getElementById('map')); map.setCenter(new GLatLng(37.4419, -122.1419), 13); map.setUIToDefault(); map.addOverlay(new GMarker(new GLatLng(37.4419, -122.1419))); } } </script> </head> <body onload="initialize()" onunload="GUnload()"> <div id="map"></div> </body> </html>
<!DOCTYPE html> <html> <head> <script src="//maps.googleapis.com/maps/api/js?key=YOUR_API_KEY "></script> <style> html, body, #map { height: 100%; margin: 0; } </style> <script> function initialize() { var map = new google.maps.Map( document.getElementById('map'), { center: new google.maps.LatLng(37.4419, -122.1419), zoom: 13, mapTypeId: google.maps.MapTypeId.ROADMAP }); var marker = new google.maps.Marker({ position: new google.maps.LatLng(37.4419, -122.1419), map: map }); } google.maps.event.addDomListener(window, 'load', initialize); </script> </head> <body> <div id="map"></div> </body> </html>
如您所见,这两个应用之间存在一些差异。显著变更包括:
- 加载 API 的地址已经发生变化。
- 在 v3 中,不再需要
GBrowserIsCompatible()
和GUnload()
方法,并且已从 API 中移除。 GMap2
对象已被google.maps.Map
取代,成为 API 中的核心对象。- 系统现在通过选项类加载属性。在上面的示例中,我们通过内嵌的
MapOptions
对象设置了加载地图所需的三个属性:center
、zoom
和mapTypeId
。 - 默认情况下,v3 中的默认用户界面处于启用状态。您可以在
MapOptions
对象中将disableDefaultUI
属性设为 true 来停用此功能。
摘要
至此,您已经了解了从 Maps JavaScript API v2 迁移到 v3 涉及的一些关键要点。 您可能还需要了解更多信息,具体取决于您的应用。在以下部分中,我们列出了针对您可能遇到的具体情况的迁移说明。此外,在升级过程中,您可能还会用到以下一些资源。
- 如需详细了解该 API 及其运作方式,Maps JavaScript API v3 开发者文档是最佳选择。
- Maps JavaScript API v3 参考文档可帮助您详细了解 v3 API 中的新类和方法。
- Stack Overflow 社区是提问代码相关问题的好地方。在该网站上,与 Maps JavaScript API 相关的问题和解答使用“google-maps”或“google-maps-api-3”标记。
- Google Maps Platform 高级计划客户应仔细阅读 Google Maps Platform 高级计划文档。
- 如需了解 API 的最新变化,不妨访问 Google Geo 开发者博客。
如果您对本文有任何问题或疑问,请使用本页面顶部的发送反馈链接。
详细参考
本部分详细比较了 Maps JavaScript API 的 v2 版和 v3 版中最热门的功能。参考文档的每个部分均可单独阅读。我们建议您不要完整阅读本参考文档,而是根据具体情况使用本资料来帮助您进行迁移。
- 事件 - 注册和处理事件。
- 控件 - 操控地图上显示的导航控件。
- 叠加层 - 在地图上添加和修改对象。
- 地图类型 - 构成基本地图的图块。
- 图层 - 以组的形式添加和修改内容,例如 KML 或交通图层。
- 服务 - 使用 Google 的地理编码、路线或街景服务。
事件
Maps JavaScript API v3 的事件模型与 v2 中使用的事件模型类似,但底层发生了许多变化。
全新的 MVC 事件支持
v3 API 添加了一类新事件以反映 MVC 状态变化。现在,事件分为两种类型:
- 用户事件(例如“点击”鼠标事件)会从 DOM 传播到 Maps JavaScript API。这些事件与标准的 DOM 事件相互独立且截然不同。
- MVC 状态变化通知则反映了 Maps API 对象中的变化,并按照
property_changed
规范命名。
每个 Maps API 对象均可导出大量已命名的事件。对特定事件感兴趣的应用应为这些事件注册事件监听器,并在收到这些事件时执行相应代码。这种事件驱动型机制在 Maps JavaScript API v2 和 v3 中是相同的,但命名空间已从 GEvent
更改为 google.maps.event
:
GEvent.addListener(map, 'click', function() { alert('You clicked the map.'); });
google.maps.event.addListener(map, 'click', function() { alert('You clicked the map.'); });
移除事件监听器
出于性能方面的原因,最好在不再需要事件监听器时将其移除。在 v2 和 v3 中,移除事件监听器的方式相同:
- 创建事件监听器时,系统会返回一个不透明对象(v2 中的 GEventListener,v3 中的 MapsEventListener)。
- 如需移除事件监听器,请将此对象传递给
removeListener()
方法(v2 中的GEvent.removeListener()
或 v3 中的google.maps.event.removeListener()
)以移除事件监听器。
监听 DOM 事件
如果您想要捕获并响应 DOM(文档对象模型)事件,v3 提供了 google.maps.event.addDomListener()
静态方法,该方法相当于 v2 中的 GEvent.addDomListener()
方法。
在事件中使用传递的参数
界面事件通常会传递事件参数,事件监听器可以访问这些参数。v3 中的大多数事件参数已简化,以便与 API 中的对象保持一致。(如需了解详情,请参阅 v3 参考文档。)
v3 事件监听器中不存在 overlay
参数。如果您在 v3 地图上注册 click
事件,则只有在用户点击底图时才会发生回调。如果您需要对这些点击做出响应,可以在可点击的叠加层上注册其他回调。
// Passes an overlay argument when clicking on a map var map = new GMap2(document.getElementById('map')); map.setCenter(new GLatLng(-25.363882, 131.044922), 4); map.setUIToDefault(); GEvent.addListener(map,'click', function(overlay, latlng) { if (latlng) { var marker = new GMarker(latlng); map.addOverlay(marker); } });
// Passes only an event argument var myOptions = { center: new google.maps.LatLng(-25.363882, 131.044922), zoom: 4, mapTypeId: google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map(document.getElementById('map'), myOptions); google.maps.event.addListener(map, 'click', function(event) { var marker = new google.maps.Marker({ position: event.latLng, map: map }); });
控件
Maps JavaScript API 会显示界面控件,以便用户与您的地图互动。您可以使用该 API 自定义这些控件的显示方式。
控件类型变更
v3 API 引入了对 control
类型的一些更改。
- v3 API 支持其他地图类型,包括地形地图,并且能够添加自定义地图类型。
- v2 分层控件
GHierarchicalMapTypeControl
已不再可用。 您可以使用google.maps.MapTypeControlStyle.HORIZONTAL_BAR
控件来实现类似的效果。 - v2 中由
GMapTypeControl
提供的横向布局在 v3 中不可用。
向地图添加控件
使用 Maps JavaScript API v2 时,您可以通过地图对象的 addControl()
方法向地图添加控件。在 v3 中,您可以修改关联的 MapOptions
对象,而不是直接访问或修改控件。以下示例展示了如何自定义地图以添加以下控件:
- 让用户可以在可用地图类型之间切换的按钮
- 地图比例
var map = new GMap2(document.getElementById('map')); map.setCenter(new GLatLng(-25.363882, 131.044922), 4); // Add controls map.addControl(new GMapTypeControl()); map.addControl(new GScaleControl());
var myOptions = { center: new google.maps.LatLng(-25.363882, 131.044922), zoom: 4, mapTypeId: google.maps.MapTypeId.ROADMAP, // Add controls mapTypeControl: true, scaleControl: true }; var map = new google.maps.Map(document.getElementById('map'), myOptions);
在地图上定位控件
在 v3 中,定位控件发生了很大变化。在 v2 中,addControl()
方法接受一个可选的第二个参数,可让您指定控件相对于地图角落的位置。
在 v3 中,您可以通过控件选项的 position
属性设置控件的位置。这些控件的定位并不是绝对的;相反,API 将通过使控件在给定约束(例如地图尺寸)内围绕现有地图元素“流动”,以智能方式安排控件布局。
这样可以确保默认控件与您的控件兼容。
如需了解详情,请参阅在 v3 中控制定位。
下面的代码会相对于上面的示例重新定位控件:
var map = new GMap2(document.getElementById('map')); map.setCenter(new GLatLng(-25.363882, 131.044922), 4); // Add map type control map.addControl(new GMapTypeControl(), new GControlPosition( G_ANCHOR_TOP_LEFT, new GSize(10, 10))); // Add scale map.addControl(new GScaleControl(), new GControlPosition( G_ANCHOR_BOTTOM_RIGHT, new GSize(20, 20)));
var myOptions = { center: new google.maps.LatLng(-25.363882, 131.044922), zoom: 4, mapTypeId: google.maps.MapTypeId.ROADMAP, // Add map type control mapTypeControl: true, mapTypeControlOptions: { style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR, position: google.maps.ControlPosition.TOP_LEFT }, // Add scale scaleControl: true, scaleControlOptions: { position: google.maps.ControlPosition.BOTTOM_RIGHT } }; var map = new google.maps.Map(document.getElementById('map'), myOptions);
自定义控件
借助 Maps JavaScript API,您可以创建自定义导航控件。
如需使用 v2 API 自定义控件,您需要对 GControl
类进行子类化,并为 initialize()
和 getDefaultPosition()
方法定义处理脚本。
v3 中没有等同于 GControl
类的类。而是将控件表示为 DOM 元素。如需使用 v3 API 添加自定义控件,请在构造函数中为控件创建 DOM 结构,将其作为 Node
的子元素(例如 <div>
元素)添加,并添加事件监听器来处理任何 DOM 事件。将 Node
推送到地图的 controls[position]
数组中,以将自定义控件的实例添加到地图中。
假设有一个符合上述接口要求的 HomeControl
类实现(如需了解详情,请参阅自定义控件文档),以下代码示例展示了如何向地图添加自定义控件。
map.addControl(new HomeControl(), GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10, 10)));
var homeControlDiv = document.createElement('DIV'); var homeControl = new HomeControl(homeControlDiv, map); map.controls[google.maps.ControlPosition.TOP_RIGHT].push( homeControlDiv);
叠加层
叠加层反映了您“添加”到地图中以指定点、线、区域或对象集合的对象。
添加和移除叠层
Overlay 表示的对象类型在 v2 和 v3 之间相同,但处理方式不同。
使用 GMap2
对象的 addOverlay()
和 removeOverlay()
方法将 v2 API 中的叠加层添加到地图并从地图中移除。在 v3 中,您可以通过关联的叠加层选项类的 map
属性将地图分配给叠加层。您还可以通过调用叠加层对象的 setMap()
方法并指定所需地图,直接添加或移除叠加层。将地图属性设置为 null
会移除叠加层。
v3 中不存在 clearOverlays()
方法。
如果您希望管理一组叠加层,则应该创建一个数组来保存这些叠加层。使用此数组,您就可以对数组中的每个叠加层调用 setMap()
(如果需要移除叠加层,请传递 null
)。
可拖动标记
默认情况下,标记可点击但不可拖动。以下两个示例会添加一个可拖动标记:
var myLatLng = new GLatLng(-25.363882, 131.044922); var map = new GMap2(document.getElementById('map')); map.setCenter(myLatLng, 4); var marker = new GMarker(latLng, { draggable: true }); map.addOverlay(marker);
var myLatLng = new google.maps.LatLng(-25.363882, 131.044922); var map = new google.maps.Map( document.getElementById('map'), { center: myLatLng, zoom: 4, mapTypeId: google.maps.MapTypeId.ROADMAP }); var marker = new google.maps.Marker({ position: myLatLng, draggable: true, map: map });
图标
您可以定义自定义图标,以替代默认标记。如需在 v2 中使用自定义映像,您可以从 G_DEFAULT_ICON type
创建 GIcon
实例并对其进行修改。如果您的图片大于或小于默认图标,您必须使用 GSize
实例指定它。
v3 API 略微简化了此流程。
只需将标记的 icon
属性设置为自定义图片的网址,API 就会自动调整图标大小。
Maps JavaScript API 还支持复杂图标。
复杂图标可以包含多个功能块、复杂形状,或者指定图片相对于其他叠加层的显示方式(即“堆叠顺序”)。如需在 v2 中向标记添加形状,您需要在每个 GIcon
实例中指定额外的属性,并将其作为选项传递给 GMarker
构造函数。在 v3 中,以这种方式指定的图标应将其 icon
属性设置为 Icon
类型的对象。
v3 不支持标记阴影。
以下示例显示了澳大利亚邦迪海滩的海滩旗,图标的透明部分不可点击:
var map = new GMap2(document.getElementById('map')); map.setCenter(new GLatLng(-25.363882, 131.044922), 4); map.setUIToDefault(); var flagIcon = new GIcon(G_DEFAULT_ICON); flagIcon.image = '/images/beachflag.png'; flagIcon.imageMap = [1, 1, 1, 20, 18, 20, 18 , 1]; var bbLatLng = new GLatLng(-33.890542, 151.274856); map.addOverlay(new GMarker(bbLatLng, { icon: flagIcon }));
var map = new google.maps.Map( document.getElementById('map'), { center: new google.maps.LatLng(-25.363882, 131.044922), zoom: 4, mapTypeId: google.maps.MapTypeId.ROADMAP }); var shape = { coord: [1, 1, 1, 20, 18, 20, 18 , 1], type: 'poly' }; var bbLatLng = new google.maps.LatLng(-33.890542, 151.274856); var bbMarker = new google.maps.Marker({ icon: '/images/beachflag.png' shape: shape, position: bbLatLng, map: map });
多段线
多段线由 LatLng
数组以及一系列线段组成,这些线段依照先后次序将这些位置连接起来。在 v3 中创建和显示 Polyline
对象与在 v2 中使用 GPolyline
对象类似。以下示例绘制了一条从苏黎世经新加坡到悉尼的半透明 3 像素宽的测地线多段线:
var polyline = new GPolyline( [ new GLatLng(47.3690239, 8.5380326), new GLatLng(1.352083, 103.819836), new GLatLng(-33.867139, 151.207114) ], '#FF0000', 3, 0.5, { geodesic: true }); map.addOverlay(polyline);
var polyline = new google.maps.Polyline({ path: [ new google.maps.LatLng(47.3690239, 8.5380326), new google.maps.LatLng(1.352083, 103.819836), new google.maps.LatLng(-33.867139, 151.207114) ], strokeColor: '#FF0000', strokeOpacity: 0.5, strokeWeight: 3, geodesic: true }); polyline.setMap(map);
编码折线
v3 不支持直接从编码的多段线创建 Polyline
对象。不过,几何图形库提供了用于编码和解码多段线的方法。如需详细了解如何加载此库,请参阅 v3 Maps API 中的库。
以下示例绘制了相同的编码多段线;v3 代码使用 google.maps.geometry.encoding
命名空间中的 decodePath()
方法。
var polyline = new GPolyline.fromEncoded({ points: 'kwb`Huqbs@ztzwGgvpdQbw}uEoif`H', levels: 'PPP', zoomFactor: 2, numLevels: 18, color: '#ff0000', opacity: 0.8, weight: 3 }); map.addOverlay(polyline);
var polyline = new google.maps.Polyline({ path: google.maps.geometry.encoding.decodePath( 'kwb`Huqbs@ztzwGgvpdQbw}uEoif`H'), strokeColor: '#FF0000', strokeOpacity: 0.5, strokeWeight: 3, }); polyline.setMap(map);
多边形
多边形定义一个闭合区域。与 Polyline
对象非常相似,Polygon
对象由一系列有序排列的点组成。v3 Polygon
类与 v2 GPolygon
类非常相似,但有一个明显的例外情况:您不再需要在路径末尾重复起始顶点来闭合循环。v3 API 将通过绘制一段描边,将最后一个坐标连回第一个坐标,自动闭合任何多边形。以下代码段会创建一个表示百慕大三角的多边形:
var map = new GMap2(document.getElementById('map')); map.setCenter(new GLatLng(24.886436, -70.268554), 5); var bermudaTriangle = new GPolygon( [ new GLatLng(25.774252, -80.190262), new GLatLng(18.466465, -66.118292), new GLatLng(32.321384, -64.75737), new GLatLng(25.774252, -80.190262) ], '#FF0000', 2, 0.8, '#FF0000', 0.35); map.addOverlay(bermudaTriangle);
var map = new google.maps.Map(document.getElementById('map'), { center: new google.maps.LatLng(24.886436, -70.268554), mapTypeId: google.maps.MapTypeId.TERRAIN, zoom: 5 }); var bermudaTriangle = new google.maps.Polygon({ paths: [ new google.maps.LatLng(25.774252, -80.190262), new google.maps.LatLng(18.466465, -66.118292), new google.maps.LatLng(32.321384, -64.75737) ], strokeColor: '#FF0000', strokeWeight: 2, strokeOpacity: 0.8, fillColor: '#FF0000', fillOpacity: 0.35 }); bermudaTriangle.setMap(map);
用户可修改的形状
您可以将折线和多边形设为用户可修改。以下代码段是等效的:
map.addOverlay(polyline); polyline.enableEditing();
polyline.setMap(map); polyline.setEditable(true);
如需使用更高级的绘制功能,请参阅 v3 文档中的绘图库。
信息窗口
InfoWindow
用于在地图上方显示浮动窗口中的内容。v2 和 v3 信息窗口之间存在一些关键区别:
- v2 API 仅支持每个地图一个
GInfoWindow
,而 v3 API 支持每个地图多个并发InfoWindow
。 - 当您点击地图时,v3
InfoWindow
将保持打开状态。当您点击地图时,v2GInfoWindow
会自动关闭。您可以通过在Map
对象上添加click
监听器来模拟 v2 行为。 - v3 API 不支持标签页式
InfoWindow
。
地面叠加层
如需在地图上放置图片,您应使用 GroundOverlay
对象。GroundOverlay
的构造函数在 v2 和 v3 中基本相同:它会将图像的网址和图像的边界指定为参数。
以下示例将新泽西州纽瓦克的古地图作为叠加层放置在地图上:
var bounds = new GLatLngBounds( new GLatLng(40.716216, -74.213393), new GLatLng(40.765641, -74.139235)); var overlay = new GGroundOverlay( 'http://lib.utexas.edu/maps/historical/newark_nj_1922.jpg', bounds); map.addOverlay(overlay);
var bounds = new google.maps.LatLngBounds( new google.maps.LatLng(40.716216, -74.213393), new google.maps.LatLng(40.765641, -74.139235)); var overlay = new google.maps.GroundOverlay( 'http://lib.utexas.edu/maps/historical/newark_nj_1922.jpg', bounds); overlay.setMap(map);
地图类型
v2 和 v3 中提供的地图类型略有不同,但这两个版本的 API 都提供所有基本地图类型。默认情况下,v2 使用标准的“绘制”道路地图图块。不过,在 v3 中,创建 google.maps.Map
对象时需要提供特定的映射类型。
常用地图类型
v2 和 v3 中存在四种基本的地图类型:
MapTypeId.ROADMAP
(取代了G_NORMAL_MAP
)显示道路地图视图。MapTypeId.SATELLITE
(取代G_SATELLITE_MAP
) 显示 Google 地球卫星图像。MapTypeId.HYBRID
(取代G_HYBRID_MAP
)混合显示普通视图和卫星视图。MapTypeId.TERRAIN
(取代了G_PHYSICAL_MAP
)根据地形信息显示自然地图。
下面是在 v2 和 v3 中将地图设为地形视图的示例:
map.setMapType(G_PHYSICAL_MAP);
map.setMapTypeId(google.maps.MapTypeId.TERRAIN);
Maps JavaScript API v3 还对不太常用的地图类型进行了一些更改:
图像最大缩放级别
卫星图像并不能始终提供较高的缩放级别。如果您想在设置缩放级别之前了解可用的最高缩放级别,请使用 google.maps.MaxZoomService
类。此类取代了 v2 中的 GMapType.getMaxZoomAtLatLng()
方法。
var point = new GLatLng( 180 * Math.random() - 90, 360 * Math.random() - 180); var map = new GMap2(document.getElementById("map")); map.setUIToDefault(); map.setCenter(point); map.setMapType(G_HYBRID_MAP); map.getCurrentMapType().getMaxZoomAtLatLng(point, function(response) { if (response.status) { map.setZoom(response.zoom); } else { alert("Error in Max Zoom Service."); } });
var myLatlng = new google.maps.LatLng( 180 * Math.random() - 90, 360 * Math.random() - 180); var map = new google.maps.Map( document.getElementById("map"),{ zoom: 0, center: myLatlng, mapTypeId: google.maps.MapTypeId.HYBRID }); var maxZoomService = new google.maps.MaxZoomService(); maxZoomService.getMaxZoomAtLatLng( myLatlng, function(response) { if (response.status == google.maps.MaxZoomStatus.OK) { map.setZoom(response.zoom); } else { alert("Error in Max Zoom Service."); } });
空中透视图像
在 v3 中启用航拍图像时,控件与 v2 的 GLargeZoomControl3D
控件类似,但多了一个用于按支持的方向旋转的插页式旋转控件。
您可以在此地图上跟踪当前提供 45° 角航拍图像的城市。45° 图像可用时,Maps API 卫星图像按钮会添加一个子菜单选项。
图层
图层是地图上的对象,包含一个或多个叠加层。它们可以作为一个单元进行操作,通常反映的是对象集合。
支持的图层
v3 API 可以访问多种不同的图层。这些层在以下方面与 v2 GLayer
类重叠:
-
KmlLayer
对象会将 KML 和 GeoRSS 元素渲染为 v3 叠加层,提供与 v2GeoXml
图层等效的功能。 TrafficLayer
对象会渲染一个用于描绘路况的图层,类似于 v2GTrafficOverlay
叠加层。
这些图层与 v2 中的有所不同。下面介绍了不同之处。您可以通过调用 setMap()
,向其传递要显示该图层的 Map
对象,将图层添加到地图中。
如需详细了解支持的图层,请参阅图层文档。
KML 图层和 GeoRSS 图层
Maps JavaScript API 支持用于显示地理信息的 KML 和 GeoRSS 数据格式。如果您想在地图中添加 KML 或 GeoRSS 文件,则这些文件必须可供公开访问。在 v3 中,这些数据格式使用 KmlLayer
的实例进行显示,该实例取代了 v2 中的 GGeoXml
对象。
v3 API 在呈现 KML 时更加灵活,可让您抑制 InfoWindows 并修改点击响应。要了解详情,请参阅 v3 KML 和 GeoRSS 图层文档。
渲染 KmlLayer
时,需要遵守大小和复杂性限制;如需了解详情,请参阅 KmlLayer 文档。
下面的示例比较了如何加载 KML 文件。
geoXml = new GGeoXml( 'https://googlearchive.github.io/js-v2-samples/ggeoxml/cta.kml'); map.addOverlay(geoXml);
var layer = new google.maps.KmlLayer( 'https://googlearchive.github.io/js-v2-samples/ggeoxml/cta.kml', { preserveViewport: true }); layer.setMap(map);
路况图层
借助 v3,您可以使用 TrafficLayer
对象向地图添加实时路况信息(如果支持)。系统会提供在请求发出时的实时路况信息。以下示例显示了洛杉矶的交通信息:
var map = new GMap2(document.getElementById('map')); map.setCenter(new GLatLng(34.0492459, -118.241043), 13); map.setUIToDefault(); var trafficOptions = {incidents:false}; trafficInfo = new GTrafficOverlay(trafficOptions); map.addOverlay(trafficInfo);
var map = new google.maps.Map( document.getElementById('map'), { center: new google.maps.LatLng(34.0492459, -118.241043), mapTypeId: google.maps.MapTypeId.ROADMAP, zoom: 13 }); var trafficLayer = new google.maps.TrafficLayer(); trafficLayer.setMap(map);
与 v2 不同,v3 中没有 TrafficLayer
构造函数的选项。v3 不支持突发事件。
服务
地理编码
Maps JavaScript API 提供了一个 geocoder
对象,用于根据用户输入动态地理编码地址。如果您想对已知静态地址进行地理编码,请参阅 Geocoding API 文档。
Geocoding API 已得到大幅升级和增强,新增了一些功能并更改了数据的表示方式。
v2 API 中的 GClientGeocoder
提供了两种不同的正向和反向地理编码方法,以及影响地理编码执行方式的其他方法。相比之下,v3 Geocoder
对象仅提供 geocode()
方法,该方法接受一个包含输入字词的对象字面量(采用地理编码请求对象的形式)和一个回调方法。根据请求包含文本 address
属性还是 LatLng
对象,Geocoding API 将返回正向地理编码响应或逆向地理编码响应。您可以通过向地理编码请求传递其他字段来影响地理编码的执行方式:
- 添加文本
address
会触发正向地理编码,相当于调用getLatLng()
方法。 - 添加
latLng
对象会触发反向地理编码,这相当于调用getLocations()
方法。 - 添加
bounds
属性可启用视口偏向,这相当于调用setViewport()
方法。 - 添加
region
属性可启用地区代码偏向,这相当于调用setBaseCountryCode()
方法。
v3 中的地理编码响应与 v2 响应截然不同。v3 API 会将 v2 使用的嵌套结构替换为更易于解析的扁平结构。此外,v3 响应更详细:每个结果都有多个地址组成部分,有助于更好地了解每个结果的分辨率。
以下代码会接受文本地址,并显示地理编码后的第一个结果:
var geocoder = new GClientGeocoder(); var infoPanel; var map; var AccuracyDescription = [ 'Unknown accuracy', 'country level accuracy', 'region level accuracy', 'sub-region level accuracy', 'town level accuracy', 'post code level accuracy', 'street level accuracy', 'intersection level accuracy', 'address level accuracy', 'premise level accuracy', ]; function geocode_result_handler(response) { if (!response || response.Status.code != 200) { alert('Geocoding failed. ' + response.Status.code); } else { var bounds = new GLatLngBounds(new GLatLng( response.Placemark[0].ExtendedData.LatLonBox.south, response.Placemark[0].ExtendedData.LatLonBox.west ), new GLatLng( response.Placemark[0].ExtendedData.LatLonBox.north, response.Placemark[0].ExtendedData.LatLonBox.east )); map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds)); var latlng = new GLatLng( response.Placemark[0].Point.coordinates[1], response.Placemark[0].Point.coordinates[0]); infoPanel.innerHTML += '<p>1st result is <em>' + // No info about location type response.Placemark[0].address + '</em> of <em>' + AccuracyDescription[response.Placemark[0]. AddressDetails.Accuracy] + '</em> at <tt>' + latlng + '</tt></p>'; var marker_title = response.Placemark[0].address + ' at ' + latlng; map.clearOverlays(); var marker = marker = new GMarker( latlng, {'title': marker_title} ); map.addOverlay(marker); } } function geocode_address() { var address = document.getElementById('input-text').value; infoPanel.innerHTML = '<p>Original address: ' + address + '</p>'; geocoder.getLocations(address, geocode_result_handler); } function initialize() { map = new GMap2(document.getElementById('map')); map.setCenter(new GLatLng(38, 15), 2); map.setUIToDefault(); infoPanel = document.getElementById('info-panel'); }
var geocoder = new google.maps.Geocoder(); var infoPanel; var map; var marker; function geocode_result_handler(result, status) { if (status != google.maps.GeocoderStatus.OK) { alert('Geocoding failed. ' + status); } else { map.fitBounds(result[0].geometry.viewport); infoPanel.innerHTML += '<p>1st result for geocoding is <em>' + result[0].geometry.location_type.toLowerCase() + '</em> to <em>' + result[0].formatted_address + '</em> of types <em>' + result[0].types.join('</em>, <em>').replace(/_/, ' ') + '</em> at <tt>' + result[0].geometry.location + '</tt></p>'; var marker_title = result[0].formatted_address + ' at ' + latlng; if (marker) { marker.setPosition(result[0].geometry.location); marker.setTitle(marker_title); } else { marker = new google.maps.Marker({ position: result[0].geometry.location, title: marker_title, map: map }); } } } function geocode_address() { var address = document.getElementById('input-text').value; infoPanel.innerHTML = '<p>Original address: ' + address + '</p>'; geocoder.geocode({'address': address}, geocode_result_handler); } function initialize() { map = new google.maps.Map(document.getElementById('map'), { center: new google.maps.LatLng(38, 15), zoom: 2, mapTypeId: google.maps.MapTypeId.HYBRID }); infoPanel = document.getElementById('info-panel'); }
路线
Maps JavaScript API v3 将 v2 中的 GDirections
类替换为 DirectionsService
类,以计算路线。
v3 中的 route()
方法会取代 v2 API 中的 load()
和 loadFromWaypoints()
方法。此方法接受一个包含输入字词的 DirectionsRequest
对象字面量,以及一个在收到响应后执行的回调方法。您可以在此对象字面量中提供选项,类似于 v2 中的 GDirectionsOptions
对象字面量。
在 Maps JavaScript API v3 中,提交方向请求的任务已与渲染请求的任务分离,后者现在由 DirectionsRenderer
类处理。您可以通过 setMap()
和 setDirections()
方法将 DirectionsRenderer
对象绑定到任何地图或 DirectionsResult
对象。由于渲染程序是一个 MVCObject
,因此它会检测其属性发生的任何变化,并在其关联路线更改时更新地图。
以下代码演示了如何使用地址中的步道请求前往特定地点的步行路线。请注意,只有 v3 能够在都柏林动物园的步道中提供步行路线。
var map; var directions; var directionsPanel; function initialize() { var origin = new google.maps.LatLng(53.348172, -6.297285); var destination = new google.maps.LatLng(53.355502, -6.30557); directionsPanel = document.getElementById("route"); map = new GMap2(document.getElementById('map')); map.setCenter(origin, 10); map.setUIToDefault(); directions = new GDirections(map, directionsPanel); directions.loadFromWaypoints( [origin, destination], { travelMode: 'G_TRAVEL_MODE_WALKING', }); }
var map; var directionsRenderer; var directionsService = new google.maps.DirectionsService(); function initialize() { var origin = new google.maps.LatLng(53.348172, -6.297285); var destination = new google.maps.LatLng(53.355502, -6.30557); directionsRenderer = new google.maps.DirectionsRenderer(); map = new google.maps.Map( document.getElementById('map'), { center: origin, zoom: 10, mapTypeId: google.maps.MapTypeId.ROADMAP }); directionsRenderer.setPanel(document.getElementById("route")); directionsRenderer.setMap(map); directionsService.route({ origin: origin, destination: destination, travelMode: google.maps.DirectionsTravelMode.WALKING }, function(result, status) { if (status == google.maps.DirectionsStatus.OK) { directionsRenderer.setDirections(result); } }); }
街景
Google 街景提供其覆盖区域内指定地点的互动式 360 度全景视图。v3 API 在浏览器中原生支持街景,而 v2 则需要 Flash® 插件才能显示街景图片。
通过使用 v3 中的 StreetViewPanorama
对象或 v2 中的 GStreetviewPanorama
对象可支持街景图像。这些类具有不同的接口,但它们发挥着相同的作用:将 div
容器与街景图像相关联,并让您指定街景全景图片的位置和视角 (POV)。
function initialize() { var fenwayPark = new GLatLng(42.345573, -71.098326); panoramaOptions = { latlng: fenwayPark, pov: { heading: 35, pitch: 5, zoom: 1 } }; var panorama = new GStreetviewPanorama( document.getElementById('pano'), panoramaOptions); GEvent.addListener(myPano, "error", handleNoFlash); } function handleNoFlash(errorCode) { if (errorCode == FLASH_UNAVAILABLE) { alert('Error: Your browser does not support Flash'); return; } }
function initialize() { var fenway = new google.maps.LatLng(42.345573, -71.098326); var panoramaOptions = { position: fenway, pov: { heading: 35, pitch: 5, zoom: 1 } }; var panorama = new google.maps.StreetViewPanorama( document.getElementById('pano'), panoramaOptions); }
您可以通过 v3 中的 StreetViewService
对象或 v2 中的类似 GStreetviewClient
对象直接访问街景数据。这两个 API 都提供了类似的接口,用于检索或检查街景数据的可用性,并允许按位置或全景图片 ID 进行搜索。
默认情况下,v3 中街景视图处于启用状态。地图上会显示街景小人控件,并且该 API 会重复使用地图 div 来显示街景全景图片。以下代码展示了如何通过将街景全景图分隔到单独的 div 中来模拟 v2 行为。
var marker; var panoClient = new GStreetviewClient(); function initialize() { if (GBrowserIsCompatible()) { var myPano = new GStreetviewPanorama( document.getElementById('pano')); GEvent.addListener(myPano, 'error', handleNoFlash); var map = new GMap2(document.getElementById('map')); map.setCenter(new GLatLng(42.345573, -71.098326), 16); map.setUIToDefault(); GEvent.addListener(map, 'click', function(overlay, latlng) { if (marker) { marker.setLatLng(latlng); } else { marker = new GMarker(latlng); map.addOverlay(marker); } var nearestPano = panoClient.getNearestPanorama( latlng, processSVData); }); function processSVData(panoData) { if (panoData.code != 200) { alert("Panorama data not found for this location."); } var latlng = marker.getLatLng(); var dLat = latlng.latRadians() - panoData.location.latlng.latRadians(); var dLon = latlng.lngRadians() - panoData.location.latlng.lngRadians(); var y = Math.sin(dLon) * Math.cos(latlng.latRadians()); var x = Math.cos(panoData.location.latlng.latRadians()) * Math.sin(latlng.latRadians()) - Math.sin(panoData.location.latlng.latRadians()) * Math.cos(latlng.latRadians()) * Math.cos(dLon); var bearing = Math.atan2(y, x) * 180 / Math.PI; myPano.setLocationAndPOV(panoData.location.latlng, { yaw: bearing }); } function handleNoFlash(errorCode) { if (errorCode == FLASH_UNAVAILABLE) { alert('Error: Your browser does not support Flash'); return; } } } }
// Load the API with libraries=geometry var map; var marker; var panorama; var sv = new google.maps.StreetViewService(); function radians(degrees) { return Math.PI * degrees / 180.0 }; function initialize() { panorama = new google.maps.StreetViewPanorama( document.getElementById("pano")); map = new google.maps.Map( document.getElementById('map'), { center: new google.maps.LatLng(42.345573, -71.098326), mapTypeId: google.maps.MapTypeId.ROADMAP, zoom: 16 }); google.maps.event.addListener(map, 'click', function(event) { if (!marker) { marker = new google.maps.Marker({ position: event.latLng, map: map }); } else { marker.setPosition(event.latLng); } sv.getPanoramaByLocation(event.latLng, 50, processSVData); }); } function processSVData(panoData, status) { if (status == google.maps.StreetViewStatus.OK) { alert("Panorama data not found for this location."); } var bearing = google.maps.geometry.spherical.computeHeading( panoData.location.latLng, marker.getPosition()); panorama.setPano(panoData.location.pano); panorama.setPov({ heading: bearing, pitch: 0, zoom: 1 }); panorama.setVisible(true); marker.setMap(panorama); }