自 2021 年 5 月 26 日起,Maps JavaScript API v2 不再可用。因此,您网站的 v2 地图将停止运行,并返回 JavaScript 错误。若要继续在您的网站上使用地图,请改用 Maps JavaScript API v3。本指南将帮助您完成此流程。
概览
每个应用的迁移过程略有不同;不过,有一些步骤是所有项目通用的:
- 获取新密钥。Maps JavaScript API 现在使用 Google Cloud Console 来管理密钥。如果您仍在使用 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 extern 可用于通过 Closure 编译器验证您的代码,或在 IDE 中触发自动补全功能。
详细了解高级编译和 Extern。
- 测试并迭代。此时,您仍然有很多工作要做,但好消息是,您已经可以顺利开始使用自己的新 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 和距离矩阵。
- 改进的路线服务提供了备选路线、路线优化(旅行推销员问题的近似解决方案)、骑车路线(使用骑行图层)、公交路线和可拖动路线。
- 更新了地理编码格式,可提供比 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 客户,可能使用的是包含 client
参数的客户端 ID,而不是使用 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 高级计划)确保提供
client
参数(如 Google Maps Platform 高级计划开发者指南中所述)。
- 移除
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 默认会将所有对象置于全局命名空间中,这可能会导致命名冲突。在 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 or
google.maps.PolylineOptions |
移除过时代码
对于 v2 中的大多数功能,Maps JavaScript API v3 都有对应的功能;但也有一些类不再受支持。在迁移过程中,您应将这些类替换为第三方实用程序库,或从代码中移除这些引用。许多出色的 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 和 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 所涉及的一些关键点。
您可能需要了解更多信息,但这取决于您的应用。以下部分针对您可能遇到的具体情况提供了迁移说明。此外,在升级过程中,您可能会找到一些有用的资源。
如果您对本文有任何问题或疑问,请使用此页面顶部的发送反馈链接。
本部分对 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);
叠加层
叠加层反映的是您“添加”到地图上的对象,用以表示点、线、区域或对象集合。
添加和移除叠层
v2 与 v3 中由叠加层表示的对象类型相同,但处理方式不同。
v2 API 中的叠加层已使用 GMap2
对象的 addOverlay()
和 removeOverlay()
方法向地图添加或从地图中移除。在 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
对象。Geometry 库提供了对多段线进行编码和解码的方法。如需详细了解如何加载此库,请参阅 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
会在您点击地图时保持打开状态。v2 GInfoWindow
会在您点击地图时自动关闭。您可以通过在 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 使用标准的“绘制”道路地图图块。不过,在创建 google.maps.Map
对象时,v3 需要指定特定的地图类型。
常用地图类型
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 也对不太常用的地图类型进行了一些更改:
- 地球以外的天体地图图块在 v3 API 中无法作为地图类型使用,但可以作为自定义地图类型使用,如此示例所示。
- v3 中没有特殊的地图类型可以取代 v2 中的
G_SATELLITE_3D_MAP
类型。您可以改为使用此库将 Google 地球插件集成到 v3 地图中。
Maximum Zoom Imagery
卫星图像并不能始终提供较高的缩放级别。如果想要在设置缩放级别之前了解最高可用缩放级别,请使用 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 Satellite 按钮添加一个子菜单选项。
层
图层是地图上的对象,包含一个或多个叠加层。它们可以作为一个单元进行操作,通常反映对象集合。
支持的图层
v3 API 可以访问多种不同的图层。这些层在以下方面与 v2 GLayer
类重叠:
-
KmlLayer
对象会将 KML 和 GeoRSS 元素渲染到 v3 叠加层中,从而提供与 v2 GeoXml
图层等效的效果。
TrafficLayer
对象会呈现描述路况的图层,与 v2 GTrafficOverlay
叠加层类似。
这些图层与 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);
Traffic 图层
在 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()
方法,该方法接受包含输入字词的对象字面量(以地理编码请求对象的形式)和回调方法。Geocoding API 会返回正向或反向地理编码响应,具体取决于请求是包含文本 address
属性,还是 LatLng
对象。您可以通过向地理编码请求传递其他字段来影响地理编码的执行方式:
- 添加文本
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
类处理。您可以通过 DirectionsRenderer
对象的 setMap()
和 setDirections()
方法将其与任意地图或 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
对象直接访问街景数据。两者都提供了类似的界面来检索或检查街景数据的可用性,并允许按位置或全景 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);
}