摘自:https://developers.google.com/maps/documentation/javascript/maptypes
Google Maps JavaScript API V3 地图类型
地图类型
本文档讨论了您可以使用 Google Maps JavaScript API 显示的地图类型。该 API 使用了 MapType
对象来保留这些地图的相关信息。MapType
是一种接口,它定义了地图图块的显示形式和使用方法,以及坐标系从屏幕坐标转换到世界坐标(地图上)的方式。每个 MapType
都必须包含一些用于处理图块的检索和释放的方法,以及定义图块视觉行为的属性。
Maps API 中的地图类型的内部工作方式是一个较为复杂的主题。大部分开发人员可以仅使用下述的基本地图类型。不过,您也可以使用自定义地图类型来定义自己的地图图块,还可以使用样式化地图来修改现有地图类型的显示形式。提供自定义地图类型时,您需要了解如何修改地图的地图类型注册表。
基本地图类型
Google Maps API 中提供了多种地图类型。除了用户熟悉的“绘制”道路地图图块,Google Maps API 还可支持其他地图类型。
Google Maps API 提供了以下地图类型:
MapTypeId.ROADMAP
,用于显示默认的道路地图视图MapTypeId.SATELLITE
,用于显示 Google 地球卫星图像MapTypeId.HYBRID
,用于同时显示普通视图和卫星视图MapTypeId.TERRAIN
,用于根据地形信息显示实际地图。
要通过 Map
修改正在使用的地图类型,您可以设置其 mapTypeId
属性,方法是:在构造函数内设置其 Map options
对象,或者调用地图的 setMapTypeId()
方法。
# # Setting the mapTypeId upon construction # var myLatlng = new google.maps.LatLng(-34.397, 150.644); var myOptions = { zoom: 8, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); # # Modifying the mapTypeId dynamically # map.setMapTypeId(google.maps.MapTypeId.TERRAIN);
请注意,您实际上并没有直接设置地图的地图类型,而是将其 mapTypeId
设置为引用使用标识符的MapType
。Maps JavaScript API V3 使用了地图类型注册表(详见下文)来管理这些引用。
45° 图像
Google Maps API 针对特定位置支持特殊的 45° 图像。这一高分辨率图像可提供朝向各基本方向(东南西北)的透视视图。对于支持的地图类型,这些图像还提供了更高的缩放级别。
下图显示了加利福尼亚州圣塔克鲁兹市木板路的 45° 透视视图:
现有的 google.maps.MapTypeId.SATELLITE
和 google.maps.MapTypeId.HYBRID
地图类型支持高缩放级别的 45° 透视图像(在可用的情况下),前提是您已明确启用了此功能。如果您放大的位置拥有此类图像,那么,这些地图类型将会自动通过以下方式更改其视图:
- 地图上现有的任何平移控件将会变更为在现有的导航控件周围添加一个罗盘转轮。您可以拖动该罗盘转轮来更改任意 45° 图像的方向,然后将方向对准包含图像的最近的支持方向即可。
- 一个旋转控件将会显示在现有的平移和缩放控件之间,它可用于将图像围绕着支持的方向旋转。旋转控件仅支持顺时针方向旋转。
- 以当前位置为中心的 45° 透视图像将会替代卫星图像或混合图像。默认情况下,此类视图会朝向北方。如果您缩小地图,则地图会重新显示默认的卫星图像或混合图像。
- MapType 控件将会启用子菜单切换控件,用于显示 45° 图像。
缩小显示 45° 图像的地图类型将会还原所有更改,并重新构建原始地图类型。
Google 正在不断地为更多城市添加 45° 图像。有关最新信息,请查看 Google Maps API 覆盖率电子表格。
启用 45° 图像
要启用支持的地图类型的 45° 透视图像,请在 Map
对象上调用 setTilt(45)
。默认情况下,45° 图像朝向北方。您可以调用 setTilt(0)
以停止显示 45° 图像。
Map
的 getTilt()
方法将会始终反映地图上所显示的当前倾斜度;如果您在地图上设置了倾斜度后又将其删除(例如通过缩小地图的方式),则地图的 getTilt()
方法将会返回 0
。
以下示例显示了俄勒冈州波特兰市中心的 45° 视图。
var mapOptions = { center: new google.maps.LatLng(37.339085, -121.8914807), zoom: 18, mapTypeId: 'satellite' }; map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); map.setTilt(45);
旋转 45° 图像
实际上,45° 图像是由朝向四个基本方向(东南西北)的一系列图片构成的。当地图显示 45° 图像时,您可以将图像对准某个基本方向,方法是在 Map
对象上调用 setHeading()
,并向该对象传递一个数值,表示偏离北方的角度。
以下示例中显示了一张航拍地图,在您点击按钮后它会每 3 秒钟自动旋转一次:
var map; function initialize() { var mapOptions = { center: new google.maps.LatLng(45.518970, -122.672899), zoom: 18, mapTypeId: google.maps.MapTypeId.SATELLITE }; map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); map.setTilt(45); map.setHeading(90); } function autoRotate() { // Determine if we're showing aerial imagery if (map.getTilt() != 0) { map.setHeading(180); setTimeout('map.setHeading(270)',3000); setTimeout('map.setHeading(0)',6000); setTimeout('map.setHeading(90)',9000); } }
修改地图类型注册表
地图的 mapTypeId
是一种字符串标识符,用于将 MapType
与唯一值关联起来。每个 Map
对象都会保留一个MapTypeRegistry
,其中包含该地图可用的一系列 MapType
。该注册表用于选择地图的某种控件(例如 MapType 控件)中可用的地图类型。
您无法直接读取地图类型注册表,而是应该通过以下方法对注册表进行修改:添加自定义地图类型并将它们与您所选择的字符串标识符进行关联。您无法修改或更改基本地图类型(但您可以通过更改与该地图相关联的mapTypeControlOptions
的显示形式来将这些类型从地图中删除)。
以下代码将地图设置为仅显示其 mapTypeControlOptions
中的两种地图类型,并修改了注册表,将此标识符的关联添加到 MapType
接口的实际实现中。注意:我们有意未在之前的代码中记录自定义地图类型本身的创建。关于构建地图类型的信息,请参见下面的样式化地图或自定义地图类型。
# Modify the control to only display two maptypes, the # default ROADMAP and the custom 'mymap'. # Note that because this is simply an association, we # don't need to modify the MapTypeRegistry beforehand. var MY_MAPTYPE_ID = 'mymaps'; var mapOptions = { zoom: 12, center: brooklyn, mapTypeControlOptions: { mapTypeIds: [google.maps.MapTypeId.ROADMAP, MY_MAPTYPE_ID] }, mapTypeId: MY_MAPTYPE_ID }; # Create our map. This creation will implicitly create a # map type registry. map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); # Create your custom map type using your own code. # (See below.) var myMapType = new <em>MyMapType</em>(); # Set the registry to associate 'mymap' with the # custom map type we created, and set the map to # show that map type. map.mapTypes.set(MY_MAPTYPE_ID, myMapType);
样式化地图
借助 StyledMapType
,您可以自定义 Google 标准基本地图的显示形式,并更改诸如道路、公园和建筑物区域等元素的视觉显示,以体现不同于默认地图类型中所使用的样式。这些组件称为地图项,您可以通过StyledMapType
选择这些地图项,并将可视样式应用于地图项的显示(包括隐藏全部地图项)。借助这些更改,可以在地图上强调特定组件或周围页面的补充内容。
StyledMapType()
构造函数采用 MapTypeStyles
数组作为参数,每个数组均由选择器和样式器组成。选择器指定应选择以应用样式的地图组件,而样式器指定这些元素的可视修改。
地图项
地图由一组地图项构成,如道路或公园,这些地图项使用 MapTypeStyleFeatureType
指定。地图项类型构成类别树,根为 all
。关于地图内可供选择的地图项的完整列表,请参见 Maps
JavaScript API V3 参考。如果将地图项指定为 all
,则会选中所有的地图元素。
某些地图项类型类别还包含子类别,子类别是通过点表示法(如 landscape.natural
或 road.local
)来指定的。如果指定父级地图项(例如 road
),则应用于此选择项的样式也将应用于所有道路(包括子类别)。
此外,地图上的某些地图项通常会包含不同的元素。例如,道路不仅包括地图上绘制的线(几何图形),还包括附加到地图上的用于表示其名称的文本(标签)。您可以通过指定 MapTypeStyleElementType
类型的类别来选择地图项内的元素。系统支持以下元素类型:
all
(默认)用于选择该地图项的所有元素。geometry
只选择该地图项的地理元素。labels
只选择与该地图项关联的文本标签。
如果未指定任何元素类型,则样式将应用于所有元素(不考虑元素类型)。
以下代码段选择所有本地道路的标签:
{ featureType: "road.local", elementType: "labels" }
样式器
样式器为 MapTypeStyler
类型的格式选项,应用于在每个 MapTypeStyle
规则中指定的地图项和元素。目前,系统支持以下 MapTypeStyler
选项:
hue
(RGB 十六进制字符串)用于表示基本颜色。(* 请参见下方的使用说明)。lightness
(介于-100
和100
之间的浮点值)用于表示元素的亮度变化百分比。负值增加暗度(-100 为黑),而正值增加亮度(+100 为白)。saturation
(介于-100
和100
之间的浮点值)用于表示要应用到元素的基本颜色色度的变化百分比。gamma
(介于0.01
和10.0
之间的浮点值,其中1.0
表示不应用任何校正)用于表示要应用到元素的灰度校正量。灰度系数以非线性方式修改色相亮度,而不会影响白色值或黑色值。灰度系数通常用于修改多个元素的对比度。例如,您可以通过修改灰度系数来提高或降低元素的边缘与内部间的对比度。低灰度系数值(小于 1)可提高对比度,而高值(大于 1)则可降低对比度。inverse_lightness
(如果为true
)用于仅颠倒现有的亮度。visibility
(on
、off
或simplified
)用于表示元素是否在地图上出现及其出现方式(如果出现的话)。simplified
可见度表示地图应按照它认为最合适的方式来简化这些元素的显示形式(例如,经过简化的道路结构可能会显示较少的道路)。
样式器规则必须作为不同的操作单独应用,并且按照它们在 MapTypeStyler
数组中显示的顺序进行应用。请勿将多个操作合并为一项样式器操作,而应当在样式器数组中将每个操作定义为单独的元素。顺序非常重要,因为某些操作的顺序是不可交换的。通常而言,通过样式器操作进行修改的地图项和/或元素均已拥有样式,在此情况下,这些操作会应用于上述现有样式(如果有的话)。
请注意,我们在样式器操作中使用色相、饱和度、亮度 (HSL) 模型来表示颜色。这些用于定义色彩的操作在图形设计领域很常见。色相表示基本的颜色,饱和度表示该颜色的色度,而亮度则表示组合色中黑色或白色所占的相对比重。HSL
的所有三个值都可以映射到 RGB 值,反之亦然。灰度校正可以修改色彩空间的饱和度,主要用于提高或降低对比度。此外,HSL 模型还可用于定义坐标空间内的颜色,其中 hue
用于表示色轮内的定向,而饱和度和亮度则用于表示不同轴上的幅度。与大多数
RGB 色彩空间类似,色相也是在 RGB 色彩空间内进行衡量的,唯一不同的是后者缺少黑色和白色的深浅渐变。
RGB 色轮
注意:当 hue
采用 HTML 十六进制色彩值时,它只会将该值用于确定基本颜色(在色轮上的定向),而不是饱和度或亮度(这些值会以变化百分比的形式单独表示)。例如,纯绿色可在 hue
属性内定义为“#00ff00”或“#000100”,这两种色相是相同的(这两个值都指向 HSL 颜色模型中的纯绿色)。由等量的红色、绿色和蓝色组成的 RGBhue
值(例如“#000000”(黑色)和“#FFFFFF”(白色)以及灰色的所有纯阴影颜色)无法指明色相,因为这些值都没有指明
HSL 坐标空间中的定向。要表示黑色、白色或灰色,您必须删除全部 saturation
(将该值设为 -100
),并改为调整 lightness
。
此外,当修改已包含配色方案的现有地图项时,更改诸如 hue
之类的值并不会更改其现有的 saturation
或lightness
。
以下示例显示了布鲁克林的地图,其道路已更改为亮绿色,住宅区已更改为黑色:
var map; var brooklyn = new google.maps.LatLng(40.6743890, -73.9455); function initialize() { var stylez = [ { featureType: "road.local", elementType: "geometry", stylers: [ { hue: "#00ff00" }, { saturation:100 } ] }, { featureType: "landscape", elementType: "geometry", stylers: [ { lightness: -100 } ] } ]; var mapOptions = { zoom: 11, center: brooklyn, mapTypeControlOptions: { mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'hiphop'] } }; map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); var styledMapOptions = { name: "Hip-Hop" } var jayzMapType = new google.maps.StyledMapType( stylez, styledMapOptions); map.mapTypes.set('hiphop', jayzMapType); map.setMapTypeId('hiphop'); }
查看示例 (maptype-styled-simple.html)
下例更为复杂,其中运用了多种操作和简化方法,大致显示了美国道路地图集的外观:
var map; var chicago = new google.maps.LatLng(41.850033, -87.650052); function initialize() { var roadAtlasStyles = [ { featureType: "road.highway", elementType: "geometry", stylers: [ { hue: "#ff0022" }, { saturation: 60 }, { lightness: -20 } ] },{ featureType: "road.arterial", elementType: "all", stylers: [ { hue: "#2200ff" }, { lightness: -40 }, { visibility: "simplified" }, { saturation: 30 } ] },{ featureType: "road.local", elementType: "all", stylers: [ { hue: "#f6ff00" }, { saturation: 50 }, { gamma: 0.7 }, { visibility: "simplified" } ] },{ featureType: "water", elementType: "geometry", stylers: [ { saturation: 40 }, { lightness: 40 } ] },{ featureType: "road.highway", elementType: "labels", stylers: [ { visibility: "on" }, { saturation: 98 } ] },{ featureType: "administrative.locality", elementType: "labels", stylers: [ { hue: "#0022ff" }, { saturation: 50 }, { lightness: -10 }, { gamma: 0.9 } ] },{ featureType: "transit.line", elementType: "geometry", stylers: [ { hue: "#ff0000" }, { visibility: "on" }, { lightness: -70 } ] } ]; var mapOptions = { zoom: 12, center: chicago, mapTypeControlOptions: { mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'usroadatlas'] } }; map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); var styledMapOptions = { name: "US Road Atlas" } var usRoadMapType = new google.maps.StyledMapType( roadAtlasStyles, styledMapOptions); map.mapTypes.set('usroadatlas', usRoadMapType); map.setMapTypeId('usroadatlas'); }
查看示例 (maptype-styled-complex.html)
自己动手创建样式并测试其代码以查看它们的显示情况可能会耗费您很多时间。这时,您可以借助下列样式化地图向导为自己的 StyledMapStyle
设置 JSON。该向导可让您选择地图项内的地图项和元素,然后向这些地图项应用操作并将样式保存为
JSON,最后复制这些样式并将其粘贴到自己的应用程序中。
自定义地图类型
注意:这属于高级知识主题
现在,Google Maps JavaScript API V3 支持自定义地图类型的显示和管理,可让您实现自己的地图图像或图块叠加层。
V3 API 中提供了以下几种可能的地图类型实现:
- 标准图块集,其中所包含的图片共同构成了完整的制图地图。这些图块集也称为基本地图类型。这些地图类型的行为和表现类似于现有的默认地图类型:
ROADMAP
、SATELLITE
、HYBRID
和TERRAIN
。您可以在地图的mapTypes
数组中添加自定义地图类型,以允许 Google Maps API 中的用户界面将您的自定义地图类型视为标准地图类型(例如,将自定义地图类型包括在
MapType 控件中)。 - 图片图块叠加层,显示在现有基本地图类型之上。通常,这些地图类型用于扩展现有地图类型以显示更多信息,并往往受限于特定位置和/或缩放级别。请注意,这些图块可以是透明的,以便您将地图项添加到现有地图中。
- 非图片的地图类型,可让您在最基础的地图级别处理地图信息的显示。
以上每个选项均依赖于创建一个类以实现 MapType
接口。此外, ImageMapType
类提供了某些内置行为以简化图像 MapType
的创建过程。
在我们解释用于实现 MapType
的类之前,应当先了解 Google Maps 是如何确定坐标以及要显示的地图部分的。对于任何基本或叠加层 MapType
,您需要实现类似的逻辑。
地图坐标
Google Maps API 使用以下几种坐标系:
- 纬度和经度值,对应地球上唯一的一个点。(Google 使用世界测地系统 WGS84 标准。)
- 世界坐标,对应地图上唯一的一个点。
- 图块坐标,对应特定缩放级别地图上的特定图块。
世界坐标
每当 Google Maps API 需要将世界位置转换为地图(屏幕)上的位置时,首先需要将纬度和经度值转换为世界坐标。此转换过程使用地图投影来完成。为此,Google Maps 使用墨卡托投影。您也可以定义自己的投影以实现google.maps.Projection
接口。(请注意,V3
中的接口并非您“分类”的类,而是您自己定义的类的简单规范。)
为便于计算像素坐标(如下所示),我们假定缩放级别为 0 的地图为具有基本图块尺寸的单个图块。然后,我们在缩放级别 0 定义像素坐标对应的世界坐标,使用投影将纬度和经度值转换为此基本图块上的像素位置。该世界坐标为从地图投影原点到特定位置测量的浮点值。请注意,该值为浮点值,因此可能比显示的地图图片的当前分辨率更精确。换言之,世界坐标与当前缩放级别无关。
Google Maps 中的世界坐标是以墨卡托投影的原点(即地图西北角,经度为 180 度,纬度约 85 度)为起点测量的,在 x
方向上朝东(向右)增大,在 y
方向上朝南(向下)增大。由于基本的墨卡托 Google Maps 图块为 256x256 像素,因此可用的世界坐标空间为 {0-256}, {0-256}
(如下所示)。
请注意,墨卡托投影在经度方向上具有有限宽度,但在纬度方向上具有无限高度。我们利用约 +/- 85 度的墨卡托投影“剪切”基本地图图像,使生成的地图为方形,从而更便于选择图块。请注意,投影可能在基本地图的可用坐标空间之外生成世界坐标,例如,如果您在离极点非常近的地方绘制。
像素坐标
世界坐标表示的是指定投影上的绝对位置,但我们需要将该坐标转换为像素坐标,以确定指定缩放级别的“像素”偏移量。像素坐标采用以下公式进行计算:
pixelCoordinate = worldCoordinate * 2<span class="superscript">zoomLevel</span>
请注意,根据上述公式,每个增大的缩放级别在 x
和 y
方向上均为原来的两倍大。因此,缩放级别每增大一级,分辨率为前一个级别的四倍。例如,在缩放级别 1,地图包含 4 个 256x256 像素图块,因而像素空间为 512x512。在缩放级别 19,地图上的每个 x 和 y 像素可使用 0 到 256 * 219 之间的值进行引用。
由于世界坐标是建立在地图的图块尺寸基础上的,因此像素坐标的整数部分起着标识当前缩放级别位置确切像素的作用。请注意,对于缩放级别 0,像素坐标等于世界坐标。
现在,我们在每个缩放级别都能精确表示地图上的每个位置。Google Maps API 在地图中心构造指定缩放级别的可视区域(如 LatLng
),以及包含的 DOM 元素的大小,并将此边框转换为像素坐标。然后,API 从逻辑上确定位于指定像素边界内的所有地图图块。每个地图图块均使用图块坐标引用,该坐标大大简化了地图图像的显示。
图块坐标
Google Maps API 可能无法载入最有用的较高缩放级别的所有地图图像。相反,Google Maps API 将每个缩放级别的图像分割为一组地图图块,这些图块逻辑上按照应用程序能识别的次序排列。当地图滚动到新位置或新的缩放级别时,Google Maps API 会使用像素坐标确定所需的图块,然后将这些值转换为一组要检索的图块。这些图块坐标采用从逻辑上而言易于确定哪些图块包含任何指定点的图像的方案进行分配。
Google Maps 中的图块从与像素原点相同的位置进行编号。对于 Google 的墨卡托投影实现,图块原点始终位于地图的西北角,x
值从西向东逐步增大,y
值从北向南逐步增大。图块使用相对于该原点的 x,y
坐标进行索引。例如,在缩放级别 2,如果地球被分割为 16 个图块,则每个图块都可通过唯一的 x,y
对引用。
请注意,您可以通过按图块大小划分像素坐标并取结果的整数部分,生成当前缩放级别的图块坐标,这属于副产品。
下例显示伊利诺州芝加哥在不同缩放级别的坐标 - LatLng
值、世界坐标、像素坐标以及图块坐标:
MapType
接口
自定义地图类型必须实现 MapType
接口。此接口指定某些属性和方法,以允许 API 当确定需要在当前可视区域和缩放级别中显示地图图块时可以发起对地图类型的请求。您可处理这些请求,以确定要载入的图块。
(注意:您可以创建自己的类以实现此接口,或者如果您有兼容的图像,则可以使用已实现此接口的ImageMapType
类。)
实现 MapType
接口的类要求您定义和填充以下属性:
tileSize
(必需)指定图块(类型为google.maps.Size
)的大小。图块大小必须为矩形,但不一定为正方形。maxZoom
(必需)指定显示该地图类型图块的最大缩放级别。minZoom
(可选)指定显示该地图类型图块的最小缩放级别。该值默认为0
,表示不存在最小缩放级别。name
(可选)指定该地图类型的名称。只有当您希望在 MapType 控件中可选择此地图类型时,该属性才是必需的。(请参见下面的添加MapType
控件。)alt
(可选)指定该地图类型的替换文本,该替换文本将以悬停文本的形式显示。只有当您希望在 MapType 控件中可选择此地图类型时,该属性才是必需的。(请参见下面的添加MapType
控件。)
此外,实现 MapType
接口的类还必须实现以下方法:
-
getTile()
(必需):对于指定可视区域,每当 API 确定地图需要显示新的图块,调用此方法。getTile()
方法必须拥有以下签名:getTile(tileCoord:Point,zoom:number,ownerDocument:Document):Node
API 会根据
MapType
的tileSize
、minZoom
和maxZoom
属性以及地图的当前视口和缩放级别来决定是否需要调用getTile()
。在已传递坐标、缩放级别和要附加图块图片的 DOM 元素的情况下,此方法的处理程序应当返回 HTML 元素。 -
releaseTile()
(可选)每当 API 确定地图需要删除不在视图范围内的图块时,调用此方法。该方法必须拥有以下签名:releaseTile(tile:Node)
一般情况下,您应当删除附加到地图图块而非地图中的任何元素。例如,如果您在地图图块叠加层中附加了事件侦听器,则应在此删除这些侦听器。
getTile()
方法在确定指定可视区域内要载入的图块时是主要的控制程序。
基本地图类型
采用此方式构造的地图类型可以单独使用,也可以作为叠加层与其他地图类型结合使用。单独的地图类型称为“基本地图类型”。您可能希望 API 像对待现有的其他任何基本地图类型(如 ROADMAP
、TERRAIN
等)一样对待此类自定义 MapType
。为此,可将您的自定义 MapType
添加到 Map
的 mapTypes
属性中。此属性类型为MapTypeRegistry
。
以下代码创建一个基本 MapType
以显示地图的图块坐标,并绘制图块轮廓:
function CoordMapType() { } CoordMapType.prototype.tileSize = new google.maps.Size(256,256); CoordMapType.prototype.maxZoom = 19; CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) { var div = ownerDocument.createElement('DIV'); div.innerHTML = coord; div.style.width = this.tileSize.width + 'px'; div.style.height = this.tileSize.height + 'px'; div.style.fontSize = '10'; div.style.borderStyle = 'solid'; div.style.borderWidth = '1px'; div.style.borderColor = '#AAAAAA'; return div; }; CoordMapType.prototype.name = "Tile #s"; CoordMapType.prototype.alt = "Tile Coordinate Map Type"; var map; var chicago = new google.maps.LatLng(41.850033,-87.6500523); var coordinateMapType = new CoordMapType(); function initialize() { var mapOptions = { zoom: 10, center: chicago, mapTypeControlOptions: { mapTypeIds: ['coordinate', google.maps.MapTypeId.ROADMAP], style: google.maps.MapTypeControlStyle.DROPDOWN_MENU } }; map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); // Now attach the coordinate map type to the map's registry map.mapTypes.set('coordinate',coordinateMapType); // We can now set the map to use the 'coordinate' map type map.setMapTypeId('coordinate'); }
叠加层地图类型
某些地图类型设计为在现有地图类型上使用。此类地图类型可能具有透明图层,以指示兴趣点或向用户显示其他数据。(Google 的路况图层即属于这种地图类型。)
在这种情况下,您不会希望将地图类型视为单独的实体。相反,您可以使用 Map
的 overlayMapTypes
属性,将地图类型直接添加到现有 MapType
中。该属性包含 MapType
的 MVCArray
。所有地图类型(基本和叠加层)均在mapPane
图层中渲染。叠加层地图类型将按照在 Map.overlayMapTypes
数组中的出现次序,显示在附加的任何基本地图之上。
下例与上例相仿,只是在 ROADMAP
地图类型上创建了一个图块叠加层 MapType
。
function CoordMapType(tileSize) { this.tileSize = tileSize; } CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) { var div = ownerDocument.createElement('DIV'); div.innerHTML = coord; div.style.width = this.tileSize.width + 'px'; div.style.height = this.tileSize.height + 'px'; div.style.fontSize = '10'; div.style.borderStyle = 'solid'; div.style.borderWidth = '1px'; div.style.borderColor = '#AAAAAA'; return div; }; var map; var chicago = new google.maps.LatLng(41.850033,-87.6500523); function initialize() { var mapOptions = { zoom: 10, center: chicago, mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); // Insert this overlay map type as the first overlay map type at // position 0. Note that all overlay map types appear on top of // their parent base map. map.overlayMapTypes.insertAt(0, new CoordMapType(new google.maps.Size(256, 256))); }
图片地图类型
实现 MapType
来充当基本地图类型可能既耗时又耗力。API 为大多数常用的地图类型提供了实现 MapType
接口的特殊类:包含图块的地图类型构成单个图片文件。
此类即 ImageMapType
类,使用 ImageMapTypeOptions
对象规范构造,这些对象定义了如下必需属性:
tileSize
(必需)指定图块(类型为google.maps.Size
)的大小。图块大小必须为矩形,但不一定为正方形。getTileUrl
(必需)指定函数(通常作为内联函数提供),以根据提供的世界坐标和缩放级别选择恰当的图片图块。
以下代码使用 Google 的路况图块实现基本 ImageMapType
。请注意,地图类型将插入地图的 overlayMapTypes
数组中。
var trafficOptions = { getTileUrl: function(coord, zoom) { return "http://mt3.google.com/mapstt?" + "zoom=" + zoom + "&x=" + coord.x + "&y=" + coord.y + "&client=api"; }, tileSize: new google.maps.Size(256, 256), isPng: true }; var trafficMapType = new google.maps.ImageMapType(trafficOptions); var map; function initialize() { map = new google.maps.Map(document.getElementById("map_canvas")); map.setCenter(new google.maps.LatLng(37.76, -122.45)); map.setZoom(12); map.setMapTypeId('satellite'); map.overlayMapTypes.insertAt(0, trafficMapType); }
投影
地球是一个三维球体(近似说法),而地图是二维平面。您在 Google Maps API 内看到的地图与其他的地球平面地图一样,都是地球在平面上的投影。简单而言,投影可定义为纬度/经度值在投影地图的坐标上的映射。
Google Maps API 中的投影必须实现 Projection
接口。Projection
实现必须同时提供坐标系之间的单向映射和双向映射。也就是说,您必须定义将地球坐标 (LatLng
) 转换为 Projection
的世界坐标系的方法,和反向转换方法。Google
Maps 使用了墨卡托投影来根据地理数据创建地图,并将地图上的事件转换为地理坐标。您可以在Map
(或任何标准的基础 MapType
)上调用 getProjection()
以获取该投影。对于大部分使用情况,该标准Projection
已经足够,不过您也可以使用自定义投影。
实现投影
在实现自定义投影时,您需要定义以下内容:
- 用于在经纬度坐标和笛卡尔平面之间进行双向映射的公式(
Projection
接口仅支持向直线坐标的转换)。 - 基本图块大小。所有图块必须为矩形。
- 对于使用基本图块的地图,必须将其“世界大小”的缩放级别设置为 0。请注意:对于缩放级别为 0 且仅由一个图块构成的地图,其世界大小和基本图块大小是相同的。
投影中的坐标转换
每个投影都提供了两种方法,用于在这两个坐标系之间进行转换,您可以使用这些方法在地理坐标和世界坐标之间进行转换:
Projection.fromLatLngToPoint()
方法会将LatLng
值转换为世界坐标。此方法用于在地图上定位叠加层(同时定位地图本身)。Projection.fromPointToLatLng()
方法会将世界坐标转换为LatLng
值。此方法用于将地图上发生的事件(如点击)转换为地理坐标。
Google Maps 假设投影是直线的。
一般来说,您会在两种情况下使用投影:创建世界地图以和创建本地区域地图。在前一种情况下,您应当确保投影在所有经度上都为直线且与经度垂直。某些投影(尤其是圆锥投影)可能为“局部垂直”(即指向北方),但该地图定位相对于某些参考经度较远时,投影就可能会偏离正北(举例而言)。您可以在局部区域使用此类投影,但是请注意该投影肯定存在误差,且偏离参考经度越远,转换错误将越会明显。
投影中的地图图块选择
投影不仅看用于确定位置或叠加层的位置,还可用于定位地图图块本身。Maps API 使用了 MapType
接口来呈现基本地图,该接口必须同时声明 projection
属性(用于识别地图的投影)和 getTile()
方法(用于根据图块坐标值来检索地图图块)。图块坐标是您的基本图块大小(必须为矩形)和地图的“世界大小”(缩放级别为
0 时的地图世界的像素大小)为基础的(对于缩放级别为 0 且仅由一个图块构成的地图,其图块大小和世界大小是相等的)。
您可以在 MapType
的 tileSize
属性内定义基本图块大小,并在投影的 fromLatLngToPoint()
和fromPointToLatLng()
方法中明确定义世界大小。
由于所选择的图片取决于这些传递的值,因此命名用于接收所传递值(如 map_zoom_tileX_tileY.png
)的图片有利于系统通过编程的方式进行选择。
以下示例定义了一个使用盖尔-彼得斯投影的 ImageMapType
:
// Note: this value is exact as the map projects a full 360 degrees of longitude var GALL_PETERS_RANGE_X = 800; // Note: this value is inexact as the map is cut off at ~ +/- 83 degrees. // However, the polar regions produce very little increase in Y range, so // we will use the tile size. var GALL_PETERS_RANGE_Y = 510; function degreesToRadians(deg) { return deg * (Math.PI / 180); } function radiansToDegrees(rad) { return rad / (Math.PI / 180); } function GallPetersProjection() { // Using the base map tile, denote the lat/lon of the equatorial origin. this.worldOrigin_ = new google.maps.Point(GALL_PETERS_RANGE_X * 400 / 800, GALL_PETERS_RANGE_Y / 2); // This projection has equidistant meridians, so each longitude degree is a linear // mapping. this.worldCoordinatePerLonDegree_ = GALL_PETERS_RANGE_X / 360; // This constant merely reflects that latitudes vary from +90 to -90 degrees. this.worldCoordinateLatRange = GALL_PETERS_RANGE_Y / 2; }; GallPetersProjection.prototype.fromLatLngToPoint = function(latLng) { var origin = this.worldOrigin_; var x = origin.x + this.worldCoordinatePerLonDegree_ * latLng.lng(); // Note that latitude is measured from the world coordinate origin // at the top left of the map. var latRadians = degreesToRadians(latLng.lat()); var y = origin.y - this.worldCoordinateLatRange * Math.sin(latRadians); return new google.maps.Point(x, y); }; GallPetersProjection.prototype.fromPointToLatLng = function(point, noWrap) { var y = point.y; var x = point.x; if (y < 0) { y = 0; } if (y >= GALL_PETERS_RANGE_Y) { y = GALL_PETERS_RANGE_Y; } var origin = this.worldOrigin_; var lng = (x - origin.x) / this.worldCoordinatePerLonDegree_; var latRadians = Math.asin((origin.y - y) / this.worldCoordinateLatRange); var lat = radiansToDegrees(latRadians); return new google.maps.LatLng(lat, lng, noWrap); }; function initialize() { var gallPetersMap; var gallPetersMapType = new google.maps.ImageMapType({ getTileUrl: function(coord, zoom) { var numTiles = 1 << zoom; // Don't wrap tiles vertically. if (coord.y < 0 || coord.y >= numTiles) { return null; } // Wrap tiles horizontally. var x = ((coord.x % numTiles) + numTiles) % numTiles; // For simplicity, we use a tileset consisting of 1 tile at zoom level 0 // and 4 tiles at zoom level 1. var baseURL = 'images/'; baseURL += 'gall-peters_' + zoom + '_' + x + '_' + coord.y + '.png'; return baseURL; }, tileSize: new google.maps.Size(800, 512), isPng: true, minZoom: 0, maxZoom: 1, name: 'Gall-Peters' }); gallPetersMapType.projection = new GallPetersProjection(); var mapOptions = { zoom: 0, center: new google.maps.LatLng(0,0) }; gallPetersMap = new google.maps.Map(document.getElementById("gallPetersMap"), mapOptions); gallPetersMap.mapTypes.set('gallPetersMap', gallPetersMapType); gallPetersMap.setMapTypeId('gallPetersMap'); gallPetersMap.overlayMapTypes.insertAt(0, gallPetersMapType); }b