diff --git a/examples/wmts-hidpi.html b/examples/wmts-hidpi.html
new file mode 100644
index 0000000000..71f31e5648
--- /dev/null
+++ b/examples/wmts-hidpi.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+ WMTS HiDPI example
+
+
+
+
+
+
+
+
+
+
+
+
+
WMTS HiDPI example
+
Example of a WMTS based HiDPI layer.
+
+
hidpi, retina, wmts
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/wmts-hidpi.js b/examples/wmts-hidpi.js
new file mode 100644
index 0000000000..a89a1fbe5a
--- /dev/null
+++ b/examples/wmts-hidpi.js
@@ -0,0 +1,75 @@
+goog.require('ol.BrowserFeature');
+goog.require('ol.Map');
+goog.require('ol.View2D');
+goog.require('ol.layer.Tile');
+goog.require('ol.source.WMTS');
+goog.require('ol.tilegrid.WMTS');
+
+
+var template =
+ '{Layer}/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.jpeg';
+var urls = [
+ 'http://maps1.wien.gv.at/basemap/' + template,
+ 'http://maps2.wien.gv.at/basemap/' + template,
+ 'http://maps3.wien.gv.at/basemap/' + template,
+ 'http://maps4.wien.gv.at/basemap/' + template,
+ 'http://maps.wien.gv.at/basemap/' + template
+];
+
+
+// HiDPI support:
+// * Use 'bmaphidpi' layer (pixel ratio 2) for device pixel ratio > 1
+// * Use 'geolandbasemap' layer (pixel ratio 1) for device pixel ratio == 1
+var hiDPI = ol.BrowserFeature.DEVICE_PIXEL_RATIO > 1;
+
+var source = new ol.source.WMTS({
+ extent: [977844.377599999, 5837774.6617, 1915609.8654, 6295560.8122],
+ projection: 'EPSG:3857',
+ layer: hiDPI ? 'bmaphidpi' : 'geolandbasemap',
+ tilePixelRatio: hiDPI ? 2 : 1,
+ style: 'normal',
+ matrixSet: 'google3857',
+ urls: urls,
+ requestEncoding: /** @type {ol.source.WMTSRequestEncoding} */ ('REST'),
+ tileGrid: new ol.tilegrid.WMTS({
+ origin: [-20037508.3428, 20037508.3428],
+ resolutions: [
+ 559082264.029 * 0.28E-3,
+ 279541132.015 * 0.28E-3,
+ 139770566.007 * 0.28E-3,
+ 69885283.0036 * 0.28E-3,
+ 34942641.5018 * 0.28E-3,
+ 17471320.7509 * 0.28E-3,
+ 8735660.37545 * 0.28E-3,
+ 4367830.18773 * 0.28E-3,
+ 2183915.09386 * 0.28E-3,
+ 1091957.54693 * 0.28E-3,
+ 545978.773466 * 0.28E-3,
+ 272989.386733 * 0.28E-3,
+ 136494.693366 * 0.28E-3,
+ 68247.3466832 * 0.28E-3,
+ 34123.6733416 * 0.28E-3,
+ 17061.8366708 * 0.28E-3,
+ 8530.91833540 * 0.28E-3,
+ 4265.45916770 * 0.28E-3,
+ 2132.72958385 * 0.28E-3,
+ 1066.36479193 * 0.28E-3
+ ],
+ matrixIds: [
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
+ ]
+ })
+});
+
+var map = new ol.Map({
+ layers: [
+ new ol.layer.Tile({
+ source: source
+ })
+ ],
+ target: 'map',
+ view: new ol.View2D({
+ center: [1823849, 6143760],
+ zoom: 11
+ })
+});
diff --git a/externs/olx.js b/externs/olx.js
index 7c87c7bfdf..7efe62290f 100644
--- a/externs/olx.js
+++ b/externs/olx.js
@@ -2751,6 +2751,7 @@ olx.source.GPXOptions.prototype.urls;
* ol.TileLoadFunctionType)|undefined),
* tileGrid: (ol.tilegrid.TileGrid|undefined),
* tileLoadFunction: (ol.TileLoadFunctionType|undefined),
+ * tilePixelRatio: (number|undefined),
* tileUrlFunction: (ol.TileUrlFunctionType|undefined)}}
* @todo api
*/
@@ -2822,6 +2823,16 @@ olx.source.TileImageOptions.prototype.tileGrid;
olx.source.TileImageOptions.prototype.tileLoadFunction;
+/**
+ * The pixel ratio used by the tile service. For example, if the tile
+ * service advertizes 256px by 256px tiles but actually sends 512px
+ * by 512px images (for retina/hidpi devices) then `tilePixelRatio`
+ * should be set to `2`. Default is `1`.
+ * @type {number|undefined}
+ */
+olx.source.TileImageOptions.prototype.tilePixelRatio;
+
+
/**
* Optional function to get tile URL given a tile coordinate and the projection.
* @type {ol.TileUrlFunctionType|undefined}
@@ -4176,6 +4187,7 @@ olx.source.StaticVectorOptions.prototype.urls;
* requestEncoding: (ol.source.WMTSRequestEncoding|undefined),
* layer: string,
* style: string,
+ * tilePixelRatio: (number|undefined),
* version: (string|undefined),
* format: (string|undefined),
* matrixSet: string,
@@ -4252,6 +4264,16 @@ olx.source.WMTSOptions.prototype.layer;
olx.source.WMTSOptions.prototype.style;
+/**
+ * The pixel ratio used by the tile service. For example, if the tile
+ * service advertizes 256px by 256px tiles but actually sends 512px
+ * by 512px images (for retina/hidpi devices) then `tilePixelRatio`
+ * should be set to `2`. Default is `1`.
+ * @type {number|undefined}
+ */
+olx.source.WMTSOptions.prototype.tilePixelRatio;
+
+
/**
* WMTS version. Default to `1.0.0`.
* @type {string|undefined}
diff --git a/src/ol/source/tileimagesource.js b/src/ol/source/tileimagesource.js
index e66c4115fd..66de03572d 100644
--- a/src/ol/source/tileimagesource.js
+++ b/src/ol/source/tileimagesource.js
@@ -30,7 +30,8 @@ ol.source.TileImage = function(options) {
logo: options.logo,
opaque: options.opaque,
projection: options.projection,
- tileGrid: options.tileGrid
+ tileGrid: options.tileGrid,
+ tilePixelRatio: options.tilePixelRatio
});
/**
diff --git a/src/ol/source/tilesource.js b/src/ol/source/tilesource.js
index dcf6d2c6aa..0e31459b27 100644
--- a/src/ol/source/tilesource.js
+++ b/src/ol/source/tilesource.js
@@ -16,6 +16,7 @@ goog.require('ol.tilegrid.TileGrid');
* extent: (ol.Extent|undefined),
* logo: (string|undefined),
* opaque: (boolean|undefined),
+ * tilePixelRatio: (number|undefined),
* projection: ol.proj.ProjectionLike,
* tileGrid: (ol.tilegrid.TileGrid|undefined)}}
*/
@@ -48,6 +49,13 @@ ol.source.Tile = function(options) {
*/
this.opaque_ = goog.isDef(options.opaque) ? options.opaque : false;
+ /**
+ * @private
+ * @type {number}
+ */
+ this.tilePixelRatio_ = goog.isDef(options.tilePixelRatio) ?
+ options.tilePixelRatio : 1;
+
/**
* @protected
* @type {ol.tilegrid.TileGrid}
@@ -185,7 +193,7 @@ ol.source.Tile.prototype.getTileGridForProjection = function(projection) {
ol.source.Tile.prototype.getTilePixelSize =
function(z, pixelRatio, projection) {
var tileGrid = this.getTileGridForProjection(projection);
- return tileGrid.getTileSize(z);
+ return tileGrid.getTileSize(z) * this.tilePixelRatio_;
};
diff --git a/src/ol/source/wmtssource.js b/src/ol/source/wmtssource.js
index 975039994a..5eb8fe3662 100644
--- a/src/ol/source/wmtssource.js
+++ b/src/ol/source/wmtssource.js
@@ -186,6 +186,7 @@ ol.source.WMTS = function(options) {
projection: options.projection,
tileGrid: tileGrid,
tileLoadFunction: options.tileLoadFunction,
+ tilePixelRatio: options.tilePixelRatio,
tileUrlFunction: tileUrlFunction
});