在使用OpenLayers4获得GeoServer数据时出现的一个问题:
if (currentSource.getGetFeatureInfoUrl) {
url = currentSource.getGetFeatureInfoUrl(evt.coordinate, viewResolution, viewProjection, {
'INFO_FORMAT': 'application/json'//vnd.ogc.gml
});
//向服务器发送请求,获得返回数据
$.get(url, function (data) {
var geoJSONReader = new ol.format.GeoJSON();
var feature = geoJSONReader.readFeatures(data)[0];
......
GeoServer连接的MySql数据库,空间数据包含Date类型的属性(如:'2017-11-2')。
获得的feature的Date属性产生了错误:'2017-11-2Z',多了一个Z。
经过检查,发现get到的data中已经产生了该错误。
既然json格式对Date的支持不好,那就改变数据格式。查询GeoServer官网,发现getFeatureInfo方法支持的格式有:
经过测试GML2支持Date类型数据(GML3出现同样的错误)。因此改为使用GML2:
if (currentSource.getGetFeatureInfoUrl) {
url = currentSource.getGetFeatureInfoUrl(evt.coordinate, viewResolution, viewProjection, {
'INFO_FORMAT': 'application/vnd.ogc.gml'//vnd.ogc.gml
});
//向服务器发送请求,获得返回数据
$.get(url, function (data) {
var gml2Reader = new ol.format.GML2();
var feature = gml2Reader.readFeatures(data)[0];
......
获取的data没有问题,但是经过ol.format.GML2解析后的feature出现了经纬度颠倒的情况:
查看OL4中有关ol.format.GML2读取数据的源码:
https://github.com/openlayers/openlayers/blob/2eea8df75af5f548cad4e8e0d0597e487d90a06b/src/ol/format/gml2.js#L59
https://github.com/openlayers/openlayers/blob/2eea8df75af5f548cad4e8e0d0597e487d90a06b/src/ol/format/gml2.js#L59
ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, '');
var context = /** @type {ol.XmlNodeStackItem} */ (objectStack[0]);
var containerSrs = context['srsName'];
var axisOrientation = 'enu';
if (containerSrs) {
var proj = ol.proj.get(containerSrs);
if (proj) {
axisOrientation = proj.getAxisOrientation();
}
}
var coordsGroups = s.trim().split(/\s+/);
var x, y, z;
var flatCoordinates = [];
for (var i = 0, ii = coordsGroups.length; i < ii; i++) {
var coords = coordsGroups[i].split(/,+/);
x = parseFloat(coords[0]);
y = parseFloat(coords[1]);
z = (coords.length === 3) ? parseFloat(coords[2]) : 0;
if (axisOrientation.substr(0, 2) === 'en') {
flatCoordinates.push(x, y, z);
} else {
flatCoordinates.push(y, x, z);
}
}
return flatCoordinates;
};
enu';
if (containerSrs) {
var proj = ol.proj.get(containerSrs);
if (proj) {
axisOrientation = proj.getAxisOrientation();
}
}
var coordsGroups = s.trim().split(/\s+/);
var x, y, z;
var flatCoordinates = [];
for (var i = 0, ii = coordsGroups.length; i < ii; i++) {
var coords = coordsGroups[i].split(/,+/);
x = parseFloat(coords[0]);
y = parseFloat(coords[1]);
z = (coords.length === 3) ? parseFloat(coords[2]) : 0;
if (axisOrientation.substr(0, 2) === 'en') {
flatCoordinates.push(x, y, z);
} else {
flatCoordinates.push(y, x, z);
}
}
return flatCoordinates;
};
可以看到,在使用ol.format.GML2解析gml数据时,OL会优先使用gml数据携带的坐标系统的axis(坐标顺序)。那么再查看一下待解析的gml数据是什么样子:
unknown
JS
320100
南京0860
03
4G
118.53192755,31.99111585
可以看到,gml数据的坐标系统的名称(code)是http://www.opengis.net/gml/srs/epsg.xml#4326。这是WGS84坐标系统的code,意味着数据的坐标系统是WGS84(这与GeoServer发布的图层坐标系统吻合)。OL中默认包含该坐标系统。并且可以看到,该feature是一个点类型,其坐标顺序是(经度,纬度)。
那么再看一下OL中有关WGS84坐标系统的定义:
ol.proj.EPSG4326.PROJECTIONS = [
new ol.proj.EPSG4326.Projection_('CRS:84'),
new ol.proj.EPSG4326.Projection_('EPSG:4326', 'neu'),
new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:EPSG::4326', 'neu'),
new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'),
new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:OGC:1.3:CRS84'),
new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:OGC:2:84'),
new ol.proj.EPSG4326.Projection_('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),
new ol.proj.EPSG4326.Projection_('urn:x-ogc:def:crs:EPSG:4326', 'neu')
];
同一个坐标系统可以有许多不同的code代号,以上列出的是OL中有关WGS84的所有默认code。可以看到code为http://www.opengis.net/gml/srs/epsg.xml#4326的坐标系统带了一个参数:'neu'。该参数指明了数据的坐标顺序为(纬度,经度,高度)。
可以看出这和gml中数据的坐标顺序不一样!
下面捋一捋:使用OL的getGetFeatureInfoUrl获得的gml数据,携带有坐标系统,code为http://www.opengis.net/gml/srs/epsg.xml#4326;另外,gml数据中坐标的顺序是(经度,纬度)。
之后使用ol.format.GML2对象读取该gml数据:OL在解析的过程中,检测到了gml数据的坐标系统,因此使用了该坐标系统,即code为http://www.opengis.net/gml/srs/epsg.xml#4326的WGS84坐标系统,其axis为'neu'(纬度,经度,高度),如此,OL把gml的坐标数据(经度,纬度)当成了(纬度,经度,高度)进行处理!这导致OL最终解析出的feature的坐标出现了经纬度颠倒的情况。
参考github上大神的方法:
it is neu according to the EPSG database
you will need to override the axis order, code sample I've used before:
// override the axis orientation for WMS GetFeatureInfo
var proj = new ol.proj.Projection({
code: 'http://www.opengis.net/gml/srs/epsg.xml#4326',
axis: 'enu'
});
ol.proj.addEquivalentProjections([ol.proj.get('EPSG:4326'), proj]);//也可以使用ol.proj.addProjection(proj)将新的坐标系统添加进来即可,会自动覆盖原坐标系统
解决思路就是重写(override)坐标系统的axis属性。但是需要注意的是覆盖的一定得是与gml具有相同code的坐标系统,即code为http://www.opengis.net/gml/srs/epsg.xml#4326的坐标系统。
这里附上axis的可能值及其含义:
axis可能值:enu,qnu,neu。
含义如下:
> The +axis switch takes three character arguments defining the axis
> orientation of the coordinate system. The possible values are:
>
> 'e' - easting
> 'w' - westing - an x/longitude with the opposite sign to normal.
> 'n' - northing
> 's' - southing - a y/latitude with the opposite sign to the normal.
> 'u' - up - normal z
> 'd' - down - a z/elevation with the opposite sign to the normal.