14 KiB
title | date | author | sidebar | tags | categories | ||
---|---|---|---|---|---|---|---|
Openlayers投影与坐标转换 | 2020-12-25 | ac | false |
|
|
投影
在初始化map
实例时,如果不在view
中用projection
参数指定投影坐标系,则将会使用默认的空间参考EPSG:3857
(Web 墨卡托投影)。后续叠加的图层,都会将数据进行投影转换,确保map
在同一个空间参考内。
EPSG
(European Petroleum Survey Group,欧洲石油调查组织)负责维护并发布坐标参照系统的数据集参数,以及坐标转换描述。它将已有的椭球体,投影坐标系等及其不同组合都对应着不同的ID号,这个号在EPSG
中被称为EPSG code
,它代表特定的椭球体、单位、地理坐标系或投影坐标系等信息。
Openlayers
中的指定空间参考可以直接使用EPSG code
指定,如EPSG:4326
,因为ol.proj.Projection
已经帮我们定义好EPSG:4326
和EPSG:3857
这两个空间参考的参数,同时也为这两个空间参考定义了一些别名,如EPSG:3857
的EPSG:102100
、EPSG:102113
、EPSG:900913
这些曾用名,也有用于识别GML
要素的 http://www.opengis.net/gml/srs/epsg.xml#3857
和urn:ogc:def:crs:EPSG:6.18:3:3857
。
空间参考的别名可以使用proj4js
的defs()
方法添加:
proj4.defs('urn:x-ogc:def:crs:EPSG:4326', proj4.defs('EPSG:4326'));
ol
对于其他空间参考,可以使用proj4js
进行自定义。defs()
方法定义,register()
方法进行注册。
proj4js
是一个JavaScript库,是一个强大的通用坐标转换引擎,可以同时进行大规模地图投影和高精密度的坐标转换。
proj4.defs(
'EPSG:21781',
'+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 ' +
'+x_0=600000 +y_0=200000 +ellps=bessel ' +
'+towgs84=660.077,13.551,369.344,2.484,1.783,2.939,5.66 +units=m +no_defs'
);
register(proj4);
自定义的投影必须是在https://epsg.io/可以找到的才有效。
常用参数列表:
参数 | 描述 |
---|---|
+proj | 投影名称,安装proj 后可以使用proj - l 命令查看支持的投影名称 |
+lat_0 | 维度起点 |
+lon_0 | 中央经线 |
+x_0 | 东(伪)偏移量 |
+y_0 | 北(伪)偏移量 |
+ellps | 椭球体名称,使用proj -le 命令查看支持哪些椭球体 |
+units | 水平单位,meters(米)。使用proj -lu 命令查看PROJ 支持的单位 |
+lat_ts | 有效纬度范围 |
+a | 椭球体长半轴长度 |
+b | 椭球体短半轴长度 |
+k | 比例系数(比例因子),旧版本,不赞成使用 |
+k_0 | 比例系数(比例因子) |
+vunits | 垂直单位 |
+datum | 基准面名称,使用proj -ld 命令查看支持的基准面 |
+towgs84 | 3参数或7参数基面转换 |
+to_meter | 将水平单位转换为米计算输出转换参数,如:1英尺= |
+no_defs | 不要使用proj 库中的缺省定义文件。 |
下面使用OSM
地图作为示例图层,定义CGCS2000
的空间参考。
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="css/ol.css" type="text/css">
<style>
.map {
height: 85vh;
width: 100%;
}
</style>
<script src="lib/ol.js"></script>
<!--引入proj4.js-->
<script src="lib/proj4.js"></script>
<title>OpenLayers example</title>
<meta charset="UTF-8">
</head>
<body>
<h2>Projection CGCS2000(EPSG:4490)</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var shenzhen = [113.958334, 22.535640];
//使用proj4.defs()定义投影
proj4.defs("EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs");
//使proj4中定义的投影在OpenLayers中可用。
ol.proj.proj4.register(proj4);
//创建"EPSG:4490"的Projection实例,Openlayers将可以从Peoj4js中获取转换函数。
var cgcs2000 = new ol.proj.Projection({
code: "EPSG:4490",//EPSG code
extent:[-180,-90,180,90],
worldExtent:[-180,-90,180,90],
units:"degrees"//Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or `'us-ft'.
});
ol.proj.addProjection(cgcs2000);
var map = new ol.Map({
target: "map",
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center:ol.proj.fromLonLat(shenzhen,cgcs2000),
zoom: 11,
projection: cgcs2000
})
})
</script>
</body>
</html>
可以将瓦片图层SOM
当做底图,再往上叠加图层。
坐标转换
对于矢量数据可以使用ol.proj
命名空间下的方法,在客户端进行坐标转换,如:
//将坐标coordinate从“EPSG:3857”转换到“EPSG:4490”
ol.proj.transform([12686109.88955285,2572810.705991532],"EPSG:3857","EPSG:4490");
//添加坐标转换函数
ol.proj.addCoordinateTransforms("EPSG:3857","EPSG:4490",function (coordinate) {
return proj4("EPSG:3857","EPSG:4490",coordinate);
},function (coordinate) {
return proj4("EPSG:4490","EPSG:3857",coordinate);
})
//将经纬度的coordinate转换到目标空间参考下的坐标,默认是EPSG:3857
ol.proj.fromLonLat([113.958334, 22.535640],cgcs2000)
//将coordinate转换成经纬度
ol.proj.toLonLat([12686109.88955285,2572810.705991532])
上述是对单个coordinate的转换,对于几何要素Geometry及其子类(点、线、面等)可以使用ol.geom.Geometry
中的transform()
方法转换几何对象中的每组坐标。像GeoJSON
、KML
、gpx
类型的文件可以选择在解析器解析完成得到要素集合后,对每个要素进行转化。
示例:
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="css/ol.css" type="text/css">
<style>
.map {
height: 85vh;
width: 100%;
}
</style>
<script src="lib/ol.js"></script>
<!--引入proj4.js-->
<script src="lib/proj4.js"></script>
<title>OpenLayers example</title>
<meta charset="UTF-8">
</head>
<body>
<h2>Projection CGCS2000(EPSG:4490)</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var shenzhen = [113.958334, 22.535640];
//使用proj4.defs()定义投影
proj4.defs("EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs");
//使proj4中定义的投影在OpenLayers中可用。
ol.proj.proj4.register(proj4);
//创建"EPSG:4490"的Projection实例,Openlayers将可以从Peoj4js中获取转换函数。
var cgcs2000 = new ol.proj.Projection({
code: "EPSG:4490",//EPSG code
extent:[-180,-90,180,90],
worldExtent:[-180,-90,180,90],
units:"degrees"//Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or `'us-ft'.
});
var map = new ol.Map({
target: "map",
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center:ol.proj.fromLonLat(shenzhen,cgcs2000),
zoom: 11,
projection: cgcs2000
})
})
var geojson = new ol.source.Vector();
fetch("data/geojson/test.json").then(function(response){
return response.json();
}).then(function (value) {
var features = (new ol.format.GeoJSON()).readFeatures(value);
for(var i=0;i<features.length;i++){
features[i].getGeometry().transform("EPSG:3857","EPSG:4490");
}
geojson.addFeatures(features);
})
var testLayer = new ol.layer.Vector({
source: geojson
});
map.addLayer(testLayer);
</script>
</body>
</html>
test.json
数据文件
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:EPSG:3857"
}
},
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
12686109.88955285,
2572810.705991532
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
12683644.795390654,
2568835.9805207034
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[
12673134.704001442,
2577473.364716928
],
[
12671453.089379169,
2571625.932053112
],
[
12689186.479941329,
2580358.8625346934
],
[
12677606.270156125,
2580435.2995629786
]
]
}
}
]
}
对于服务类型的数据,像WFS
、WMS
服务可以在请求中使用srsname
或CRS
参数指定返回要素的空间参考,将坐标转换的工作在服务端完成。
示例:
<!doctype html>
<html >
<head>
<link rel="stylesheet" href="css/ol.css" type="text/css">
<style>
.map {
height: 85vh;
width: 100%;
}
</style>
<script src="lib/ol.js"></script>
<script src="lib/proj4.js"></script>
<title>OpenLayers example</title>
<meta charset="UTF-8">
</head>
<body>
<h2>Projection:加载GeoServer的WFS服务</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
//使用proj4.defs()定义投影
proj4.defs("EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs");
//使proj4中定义的投影在OpenLayers中可用。
ol.proj.proj4.register(proj4);
//创建"EPSG:4490"的Projection实例,Openlayers将可以从Peoj4js中获取转换函数。
var cgcs2000 = new ol.proj.Projection({
code: "EPSG:4490",//EPSG code
extent:[-180,-90,180,90],
worldExtent:[-180,-90,180,90],
units:"degrees"//Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or `'us-ft'.
});
var nyc = [-73.92722,40.774221];
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: new ol.source.Vector({
format: new ol.format.GeoJSON(),
url: function(extent) {
//直接返回WFS的GetFeature接口访问地址,设置outputFormat为json格式和format中的解析器一致
//使用srsname指定返回要素的空间参考:srsname=EPSG:4490
return 'http://localhost:8080/geoserver/wfs?service=WFS&' +
'version=1.1.0&request=GetFeature&typename=tiger:tiger_roads&' +
'outputFormat=application/json&srsname=EPSG:4490&' +
'bbox=' + extent.join(',') + ',EPSG:4490';
},
/*
* 加载策略,可选值:
* all,一次性加载所有的要素;
* bbox,加载地图当前视图范围内的要素;
* tile,基于瓦片格网加载要素
*/
strategy: ol.loadingstrategy.bbox
})
}),
vecLayer
],
target: document.getElementById('map'),
view: new ol.View({
center: nyc,
maxZoom: 19,
zoom: 12,
projection: cgcs2000
})
});
</script>
</body>
</html>
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://localhost:8080/geoserver/tiger/ows',
params: {
//WIDTH, HEIGHT, BBOX and CRS (SRS for WMS version < 1.3.0) 将被动态设置.
'LAYERS': 'tiger:tiger_roads',
'TILED': false,
'VERSION':'1.1.0',
'TRANSPARENT':true,//
'CRS':"EPSG:4490"
},
//远程WMS服务器的类型
serverType: 'geoserver',
// 用于渲染的不透明度过渡的持续时间。要禁用不透明过渡,设置transition为: 0
transition: 0
})
})
],
target: document.getElementById('map'),
view: new ol.View({
center: nyc,
maxZoom: 19,
zoom: 12,
projection: cgcs2000
})
});