原文链接及内容
当用户寻求帮助时,某些问题比其他问题更容易出现。本文档尝试列出在Stack Overflow上经常提问的一些问题。
如果你认为应该在此处添加一个问题(以及它的答案),请随时联系我们或在Github上提交一个pr(Pull Request)以增强本文档。
注:额外地,这里用一张图来解释一下上述Pull Request的意思:
OpenLayers使用的是什么投影?
使用OpenLayers创建的每个地图都将有一个地图视图(View),每个视图都将有一个投影,这是因为地球是三维的和圆形的,但地图是2D视图,因此我们需要一个数学表达式来呈现它,这便是投影。
实际上不只是有一种投影,而是有许多常见的投影,每个投影都有不同的属性,因为它可以准确地表示距离、角度或面积。某些投影可能更适合世界的不同地区(区域)。
回到最初的问题:OpenLayers能够处理大多数投影。如果你没有明确设置投影,那么地图将使用Openlayers的默认设置,即Web墨卡托投影
(EPSG:3857
)。同样地,投影也用于OpenStreetMap项目的地图,以及商业化产品像必应地图或谷歌地图。
如果你想要一张显示整个世界的地图,上述Web墨卡托投影
是一个很好的选择,如果你想使用OpenStreetMap或Bing瓦片地图,也同样需要使用这个投影。
如何更改地图的投影?
实际上,你很有可能希望将OpenLayers的默认投影更改为更适合你所在地区的投影,或着是特定数据的投影。
地图的投影可以通过View
对象属性进行设置,以下是一些例子:
1 | import Map from 'ol/Map.js'; |
1 | import Map from 'ol/Map.js'; |
我们建议在epsg.io上查找投影的参数(如有效性范围)。
为什么我的地图以几内亚湾(或非洲、海洋、空岛)为中心?
如果你在地图视图中设置了一个中心(center),但在视觉输出中没有看到真正的变化,那么很可能你在错误的投影中提供了地图中心的坐标(即坐标不匹配当前投影)。
由于OpenLayers中的默认投影是Web墨卡托(如上所述),因此必须提供在该投影下的中心的坐标,你的地图很可能如下所示:
1 | import Map from 'ol/Map.js'; |
这里提供了[-77.036667,38.895]作为视图的中心,但由于Web墨卡托是公制投影(以米为单位),因此这么设置会告诉OpenLayers,中心应该距离[0,0]几米(分别为-77m
和-39m
)而在Web墨卡托投影中,坐标正好在几内亚湾。
解决方法很简单:提供投影到Web墨卡托的坐标。OpenLayers提供了一些有用的方法来帮助你:
1 | import Map from 'ol/Map.js'; |
fromLonLat()
方法从Openlayers的3.5版开始可用。
如果你在Openlayers中注册一个自定义投影(见上面),你可以使用下面的方法将一个坐标从WGS84转换到你的投影:
1 | import {transform} from 'ol/proj.js'; |
为什么坐标顺序是[经度,纬度],而不是[纬度,经度]?
因为有两种不同且互不相容的约定。坐标通常是按纬度和经度这个顺序给出的。地图是地球表面的二维投影,坐标使用的笛卡尔坐标系的x,y网格表示,因为按照惯例,它们是在左边画西边,在上面画北边,这意味着x代表经度,y代表纬度。如上所述,OpenLayers旨在处理所有投影,但默认视图是在投影的笛卡尔坐标中。在笛卡尔x,y坐标系和经纬度系统中没有必要使用重复函数来处理坐标,因此输入纬度和经度时应将它们视为笛卡尔坐标,换句话说,书写顺序是lon,lat
。
如果你记不住是哪个方向,可以使用英语的语言代码en
作为助记符:先东(east)后北(north)。
一个实际的例子
倘若你想要将你的地图放在地球上的某个地方,显然你需要有它的坐标。假设你希望地图以奥地利一个美丽的地方Schladming为中心,打开维基百科的这个页面:https://zh.wikipedia.org/wiki/%E6%96%BD%E6%8B%89%E5%BE%B7%E6%98%8E ,如下图在右上角有这个地方的坐标:
上述坐标如下:
WGS84:
47° 23′ 39″ N, 13° 41′ 21″ E
47.394167, 13.689167
因此,下一步是将转换后的小数坐标放入一个数组中,并将其用作地图视图的中心坐标:
1 | import Map from 'ol/Map.js'; |
运行上面的例子可能会让你大吃一惊,因为我们的中心不是奥地利的施拉德明,而是也门的一个地区阿比扬(可能也是一个好地方)。那到底发生了什么?
许多人混淆了坐标数组中的经度和纬度的顺序,如果你一开始弄错了也不用担心,许多OpenLayers开发者在尝试改变地图中心的时候,不得不再三考虑是先放经度还是先放纬度。那么,让我们反转一下坐标:
1 | const schladming = [13.689167, 47.394167]; |
现在,Schladming现在正确地显示在地图的中央。
因此,当你在OpenLayers中处理EPSG:4326
坐标时,请将经度放在前面,然后是纬度。这种行为与我们在OpenLayers 2中所看到的是一样的,因为按照WGS84坐标轴顺序还真说的通(上述的先东后北)。
如果你实在记不住正确的顺序,只需看看我们使用的方法名:fromLonLat
,暗示我们需要先写经度,后写纬度。
为什么我的数据源中没有任何要素?
假设你要加载KML文件并在地图上显示包含的要素,可以使用如下代码:
1 | import VectorLayer from 'ol/layer/Vector.js'; |
你可能会问自己该KML文件中有多少个要素,并尝试如下所示:
1 | import VectorLayer from 'ol/layer/Vector.js'; |
这将在控制台的日志中记录0个要素的计数。这是因为KML文件的加载将以异步方式进行。要尽快获得计数(就在提取文件并且在数据源对象中添加要素之后),你应该在数据源上使用事件侦听器函数:
1 | vector.getSource().on('change', function(evt){ |
这时才能获取正确的要素数量,不出意外的话结果应为1119。
如何强制重新渲染地图?
通常,一旦数据源对象发生更改(例如,当远程数据源已加载时),就会自动重新渲染地图。
若要手动触发渲染,则可以使用:
1 | map.render(); |
或者上述方法的伴随方法(companion method):
1 | map.renderSync(); |
为什么找不到我加载的要素?
在使用Map的forEachFeatureAtPixel
或hasFeatureAtPixel
方法时,会发现它们有时不适用于大图标或标签,命中检测仅检查在给定位置的特定距离内的要素。针对大图标,要素的实际几何形状可能由于太远而不会被考虑。
在这种情况下,设置VectorLayer的renderBuffer属性(默认值是100px):
1 | import VectorLayer from 'ol/layer/Vector.js'; |
推荐值为最大符号、线宽或标签的大小。
为什么在地图上进行缩放或单击时会被关闭(或译为不起作用)或变得不准确?
在调整地图容器元素的大小时,若OpenLayers没有更新地图,这可能是由渐进式更新CSS样式或手动调整地图大小引起的。当这种情况发生时,任何交互都将会变得不准确: 地图将放大和缩小,并最终不在指针(鼠标指针)上居中。这使得很难进行某些交互,例如选择所需的要素。
目前没有内置的方法来对元素的大小变化做出反应,因为Resize Observer API只在Chrome中实现。
然而有一种简单解决办法,那便是使用polyfill:
1 | import Map from 'ol/Map.js'; |