410 lines
14 KiB
Markdown
410 lines
14 KiB
Markdown
---
|
||
title: Openlayers投影与坐标转换
|
||
date: 2020-12-25
|
||
author: ac
|
||
sidebar: false
|
||
tags:
|
||
- Openlayers
|
||
categories:
|
||
- GIS
|
||
---
|
||
|
||
## 投影
|
||
|
||
在初始化`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()`方法添加:
|
||
|
||
```javascript
|
||
proj4.defs('urn:x-ogc:def:crs:EPSG:4326', proj4.defs('EPSG:4326'));
|
||
```
|
||
|
||
|
||
|
||
`ol`对于其他空间参考,可以使用`proj4js`进行自定义。`defs()`方法定义,`register()`方法进行注册。
|
||
|
||
> `proj4js`是一个JavaScript库,是一个强大的通用坐标转换引擎,可以同时进行大规模地图投影和高精密度的坐标转换。
|
||
|
||
```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/](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`的空间参考。
|
||
|
||
```html
|
||
<!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`命名空间下的方法,在客户端进行坐标转换,如:
|
||
|
||
```javascript
|
||
//将坐标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`类型的文件可以选择在解析器解析完成得到要素集合后,对每个要素进行转化。
|
||
|
||
示例:
|
||
|
||
```html
|
||
<!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`数据文件
|
||
|
||
```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`参数指定返回要素的空间参考,将坐标转换的工作在服务端完成。
|
||
|
||
示例:
|
||
|
||
```html
|
||
<!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>
|
||
```
|
||
|
||

|
||
|
||
```javascript
|
||
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
|
||
})
|
||
});
|
||
```
|
||
|
||

|
||
|