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 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 客户,您可能要搭配使用客户端 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 会将所有对象放在全局命名空间中,这可能会导致命名冲突。在 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 |
移除过时代码
Maps JavaScript API v3 中的大多数功能在 v2 中都有对应功能;不过,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 和 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
控件来实现类似的效果。
GMapTypeControl
在 v2 中提供的水平布局在 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
对象。不过,几何图形库提供了对多段线进行编码和解码的方法。如需详细了解如何加载此库,请参阅 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 地图中。
图像最大缩放级别
卫星图像并不能始终提供较高的缩放级别。如果您希望在设置缩放级别之前了解可用的最高缩放级别,请使用 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 叠加层中,从而为 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()
方法将 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
对象直接访问街景数据。两者都提供类似的界面来检索或检查街景数据的可用性,并允许按位置或全景图片 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);
}