前提:需要对网络地图服务WMS有一定的了解,了解其方法、参数等。
官网例子https://openlayers.org/en/v4.6.5/examples/wms-image.html?q=wms
new ol.layer.Image({
extent: [-13884991, 2870341, -7455066, 6338219],
source: new ol.source.ImageWMS({
url: 'https://ahocevar.com/geoserver/wms',
params: {'LAYERS': 'topp:states'},
ratio: 1,
serverType: 'geoserver'
})
})
官网例子https://openlayers.org/en/v4.6.5/examples/wms-tiled.html?q=wms
new ol.layer.Tile({
extent: [-13884991, 2870341, -7455066, 6338219],
source: new ol.source.TileWMS({
url: 'https://ahocevar.com/geoserver/wms',
params: {'LAYERS': 'topp:states', 'TILED': true},
serverType: 'geoserver',
// Countries have transparency, so do not fade tiles:
transition: 0
})
})
一般情况下,ImageWMS、TileWMS在使用上基本差不多,但在网络请求上,ImageWMS为一次请求(一张图片),TileWMS多次请求(分为多个小图片请求)。
重点关注一下几个属性:
serverType:服务类型,主要有mapserver、geoserver、qgis
params:标准的OGC WMS请求参数,其中,LAYERS 为必参
projection:坐标系,默认与view的坐标系一致
url:wms服务
重点关注一下几个属性:
tileGrid:瓦片格网,
优先级:
1、自定义的格网
2、采用坐标系的格网
3、无坐标系,采用基于全球范围,原点为[0,0]
相对于ImageWMS,TileWMS具有TileImage的特有属性——tileGrid。
https://github.com/openlayers/openlayers/blob/v4.6.5/src/ol/source/imagewms.js
默认参数设置
// 定义版本 v1.3.0
this.v13_ = true;
this.updateV13_();
/**
* @private
*/
ol.source.ImageWMS.prototype.updateV13_ = function() {
var version = this.params_['VERSION'] || ol.DEFAULT_WMS_VERSION;
this.v13_ = ol.string.compareVersions(version, '1.3') >= 0;
};
// 定义getFeatureInfo时,鼠标所在的像素范围大小
/**
* @const
* @type {ol.Size}
* @private
*/
ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_ = [101, 101];
关键函数 getGetFeatureInfoUrl、getImageInternal、getRequestUrl_
流程:
/**
* Return the GetFeatureInfo URL for the passed coordinate, resolution, and
* projection. Return `undefined` if the GetFeatureInfo URL cannot be
* constructed.
* @param {ol.Coordinate} coordinate Coordinate.
* @param {number} resolution Resolution.
* @param {ol.ProjectionLike} projection Projection.
* @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
* be provided. If `QUERY_LAYERS` is not provided then the layers specified
* in the `LAYERS` parameter will be used. `VERSION` should not be
* specified here.
* @return {string|undefined} GetFeatureInfo URL.
* @api
*/
ol.source.ImageWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {
if (this.url_ === undefined) {
return undefined;
}
var projectionObj = ol.proj.get(projection);
var sourceProjectionObj = this.getProjection();
// 根据坐标系重新计算coordinate和resolution
if (sourceProjectionObj && sourceProjectionObj !== projectionObj) {
resolution = ol.reproj.calculateSourceResolution(sourceProjectionObj, projectionObj, coordinate, resolution);
coordinate = ol.proj.transform(coordinate, projectionObj, sourceProjectionObj);
}
// 计算中心点周边50.5像素的范围
var extent = ol.extent.getForViewAndSize(
coordinate, resolution, 0,
ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_);
var baseParams = {
'SERVICE': 'WMS',
'VERSION': ol.DEFAULT_WMS_VERSION,
'REQUEST': 'GetFeatureInfo',
'FORMAT': 'image/png',
'TRANSPARENT': true,
'QUERY_LAYERS': this.params_['LAYERS']
};
ol.obj.assign(baseParams, this.params_, params);
// 根据版本确定参数
var x = Math.floor((coordinate[0] - extent[0]) / resolution);
var y = Math.floor((extent[3] - coordinate[1]) / resolution);
baseParams[this.v13_ ? 'I' : 'X'] = x;
baseParams[this.v13_ ? 'J' : 'Y'] = y;
return this.getRequestUrl_(
extent, ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_,
1, sourceProjectionObj || projectionObj, baseParams);
};
/**
* @inheritDoc
*/
ol.source.ImageWMS.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
if (this.url_ === undefined) {
return null;
}
// 找到最接近的分辨率
resolution = this.findNearestResolution(resolution);
if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {
pixelRatio = 1;
}
var imageResolution = resolution / pixelRatio;
var center = ol.extent.getCenter(extent);
var viewWidth = Math.ceil(ol.extent.getWidth(extent) / imageResolution);
var viewHeight = Math.ceil(ol.extent.getHeight(extent) / imageResolution);
var viewExtent = ol.extent.getForViewAndSize(center, imageResolution, 0,
[viewWidth, viewHeight]);
var requestWidth = Math.ceil(this.ratio_ * ol.extent.getWidth(extent) / imageResolution);
var requestHeight = Math.ceil(this.ratio_ * ol.extent.getHeight(extent) / imageResolution);
var requestExtent = ol.extent.getForViewAndSize(center, imageResolution, 0,
[requestWidth, requestHeight]);
// 判断图片是否存在,根据分辨率、像素比率、范围,存在则返回图片
var image = this.image_;
if (image &&
this.renderedRevision_ == this.getRevision() &&
image.getResolution() == resolution &&
image.getPixelRatio() == pixelRatio &&
ol.extent.containsExtent(image.getExtent(), viewExtent)) {
return image;
}
// 不存在,则发送请求
var params = {
'SERVICE': 'WMS',
'VERSION': ol.DEFAULT_WMS_VERSION,
'REQUEST': 'GetMap',
'FORMAT': 'image/png',
'TRANSPARENT': true
};
ol.obj.assign(params, this.params_);
this.imageSize_[0] = Math.round(ol.extent.getWidth(requestExtent) / imageResolution);
this.imageSize_[1] = Math.round(ol.extent.getHeight(requestExtent) / imageResolution);
var url = this.getRequestUrl_(requestExtent, this.imageSize_, pixelRatio,
projection, params);
this.image_ = new ol.Image(requestExtent, resolution, pixelRatio,
url, this.crossOrigin_, this.imageLoadFunction_);
this.renderedRevision_ = this.getRevision();
ol.events.listen(this.image_, ol.events.EventType.CHANGE,
this.handleImageChange, this);
return this.image_;
};
/**
* @param {ol.Extent} extent Extent.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {ol.proj.Projection} projection Projection.
* @param {Object} params Params.
* @return {string} Request URL.
* @private
*/
ol.source.ImageWMS.prototype.getRequestUrl_ = function(extent, size, pixelRatio, projection, params) {
ol.asserts.assert(this.url_ !== undefined, 9); // `url` must be configured or set using `#setUrl()`
// 根据坐标系编码,确定wms版本是否为v1.3.0
params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();
if (!('STYLES' in this.params_)) {
params['STYLES'] = '';
}
// 根据serverType确定dpi
if (pixelRatio != 1) {
switch (this.serverType_) {
case ol.source.WMSServerType.GEOSERVER:
var dpi = (90 * pixelRatio + 0.5) | 0; // 取整
if ('FORMAT_OPTIONS' in params) {
params['FORMAT_OPTIONS'] += ';dpi:' + dpi;
} else {
params['FORMAT_OPTIONS'] = 'dpi:' + dpi;
}
break;
case ol.source.WMSServerType.MAPSERVER:
params['MAP_RESOLUTION'] = 90 * pixelRatio;
break;
case ol.source.WMSServerType.CARMENTA_SERVER:
case ol.source.WMSServerType.QGIS:
params['DPI'] = 90 * pixelRatio;
break;
default:
ol.asserts.assert(false, 8); // Unknown `serverType` configured
break;
}
}
params['WIDTH'] = size[0];
params['HEIGHT'] = size[1];
var axisOrientation = projection.getAxisOrientation();
var bbox;
// 根据版本,确定bbox传值方式
if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {
bbox = [extent[1], extent[0], extent[3], extent[2]];
} else {
bbox = extent;
}
params['BBOX'] = bbox.join(',');
return ol.uri.appendParams(/** @type {string} */ (this.url_), params);
};
关键函数 getGetFeatureInfoUrl、fixedTileUrlFunction、getRequestUrl_(基本同上)
流程:
/**
* Return the GetFeatureInfo URL for the passed coordinate, resolution, and
* projection. Return `undefined` if the GetFeatureInfo URL cannot be
* constructed.
* @param {ol.Coordinate} coordinate Coordinate.
* @param {number} resolution Resolution.
* @param {ol.ProjectionLike} projection Projection.
* @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
* be provided. If `QUERY_LAYERS` is not provided then the layers specified
* in the `LAYERS` parameter will be used. `VERSION` should not be
* specified here.
* @return {string|undefined} GetFeatureInfo URL.
* @api
*/
ol.source.TileWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {
var projectionObj = ol.proj.get(projection);
var sourceProjectionObj = this.getProjection();
var tileGrid = this.getTileGrid();
if (!tileGrid) {
tileGrid = this.getTileGridForProjection(projectionObj);
}
var tileCoord = tileGrid.getTileCoordForCoordAndResolution(coordinate, resolution);
if (tileGrid.getResolutions().length <= tileCoord[0]) {
return undefined;
}
// 根据tileCoord确定tileResolution 、tileExtent 、tileSize
var tileResolution = tileGrid.getResolution(tileCoord[0]);
var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
var tileSize = ol.size.toSize(tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
var gutter = this.gutter_;
if (gutter !== 0) {
tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);
tileExtent = ol.extent.buffer(tileExtent, tileResolution * gutter, tileExtent);
}
if (sourceProjectionObj && sourceProjectionObj !== projectionObj) {
tileResolution = ol.reproj.calculateSourceResolution(sourceProjectionObj, projectionObj, coordinate, tileResolution);
tileExtent = ol.proj.transformExtent(tileExtent, projectionObj, sourceProjectionObj);
coordinate = ol.proj.transform(coordinate, projectionObj, sourceProjectionObj);
}
var baseParams = {
'SERVICE': 'WMS',
'VERSION': ol.DEFAULT_WMS_VERSION,
'REQUEST': 'GetFeatureInfo',
'FORMAT': 'image/png',
'TRANSPARENT': true,
'QUERY_LAYERS': this.params_['LAYERS']
};
ol.obj.assign(baseParams, this.params_, params);
var x = Math.floor((coordinate[0] - tileExtent[0]) / tileResolution);
var y = Math.floor((tileExtent[3] - coordinate[1]) / tileResolution);
baseParams[this.v13_ ? 'I' : 'X'] = x;
baseParams[this.v13_ ? 'J' : 'Y'] = y;
return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
1, sourceProjectionObj || projectionObj, baseParams);
};
/**
* @inheritDoc
*/
ol.source.TileWMS.prototype.fixedTileUrlFunction = function(tileCoord, pixelRatio, projection) {
var tileGrid = this.getTileGrid();
if (!tileGrid) {
tileGrid = this.getTileGridForProjection(projection);
}
if (tileGrid.getResolutions().length <= tileCoord[0]) {
return undefined;
}
if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {
pixelRatio = 1;
}
// 根据tileCoord确定tileResolution 、tileExtent 、tileSize
var tileResolution = tileGrid.getResolution(tileCoord[0]);
var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
var tileSize = ol.size.toSize(
tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
var gutter = this.gutter_;
if (gutter !== 0) {
tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);
tileExtent = ol.extent.buffer(tileExtent,
tileResolution * gutter, tileExtent);
}
if (pixelRatio != 1) {
tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize);
}
var baseParams = {
'SERVICE': 'WMS',
'VERSION': ol.DEFAULT_WMS_VERSION,
'REQUEST': 'GetMap',
'FORMAT': 'image/png',
'TRANSPARENT': true
};
ol.obj.assign(baseParams, this.params_);
return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
pixelRatio, projection, baseParams);
};
相同点:两者在实现逻辑上,基本一样,根据范围计算出分辨率、图片大小,然后再拼接参数发送请求。
不同点:ImageWMS根据view的范围求出,而TileWMS根据tileCoord计算出瓦片范围再求出。
1、在实际对WMS服务调用过程中,一般ImageWMS和TileWMS都可以,并无很大的区别。而两者的区别,主要是在大数据量的请求上。如果一次请求数据过大并感觉渲染明显出现停顿的现象,则推荐使用TileWMS调用。
2、ImageArcGISRest和TileArcGISRest的关系,和上述的两者的关系类似。