Merge pull request #1389 from twpayne/vector-api-hdpi
[vector-api] High DPI (Retina) support for vector layers
This commit is contained in:
@@ -40,7 +40,7 @@ var map = new ol.Map({
|
||||
target: 'map',
|
||||
view: new ol.View2D({
|
||||
center: [0, 0],
|
||||
zoom: 2
|
||||
zoom: 1
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
* @typedef {Object} olx.MapOptions
|
||||
* @property {ol.Collection|Array.<ol.control.Control>|undefined} controls
|
||||
* Controls initially added to the map.
|
||||
* @property {number|undefined} devicePixelRatio The ratio between physical
|
||||
* pixels and device-independent pixels (dips) on the device. If `undefined`
|
||||
* then it gets set by using `window.devicePixelRatio`.
|
||||
* @property {ol.Collection|Array.<ol.interaction.Interaction>|undefined} interactions
|
||||
* Interactions that are initially added to the map.
|
||||
* @property {Array.<ol.layer.Base>|ol.Collection|undefined} layers Layers.
|
||||
|
||||
@@ -20,6 +20,7 @@ goog.require('ol.layer.LayerState');
|
||||
* @typedef {{animate: boolean,
|
||||
* attributions: Object.<string, ol.Attribution>,
|
||||
* coordinateToPixelMatrix: goog.vec.Mat4.Number,
|
||||
* devicePixelRatio: number,
|
||||
* extent: (null|ol.Extent),
|
||||
* focus: ol.Coordinate,
|
||||
* index: number,
|
||||
|
||||
@@ -157,6 +157,13 @@ ol.Map = function(options) {
|
||||
|
||||
var optionsInternal = ol.Map.createOptionsInternal(options);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.devicePixelRatio_ = goog.isDef(options.devicePixelRatio) ?
|
||||
options.devicePixelRatio : ol.BrowserFeature.DEVICE_PIXEL_RATIO;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {goog.async.AnimationDelay}
|
||||
@@ -1069,6 +1076,7 @@ ol.Map.prototype.renderFrame_ = function(time) {
|
||||
animate: false,
|
||||
attributions: {},
|
||||
coordinateToPixelMatrix: this.coordinateToPixelMatrix_,
|
||||
devicePixelRatio: this.devicePixelRatio_,
|
||||
extent: null,
|
||||
focus: goog.isNull(this.focus_) ? view2DState.center : this.focus_,
|
||||
index: this.frameIndex_++,
|
||||
|
||||
@@ -17,11 +17,12 @@ goog.require('ol.style.Text');
|
||||
* @constructor
|
||||
* @implements {ol.render.IRender}
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {goog.vec.Mat4.AnyType} transform Transform.
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.Immediate = function(context, extent, transform) {
|
||||
ol.render.canvas.Immediate = function(context, pixelRatio, extent, transform) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -29,6 +30,12 @@ ol.render.canvas.Immediate = function(context, extent, transform) {
|
||||
*/
|
||||
this.context_ = context;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.pixelRatio_ = pixelRatio;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Extent}
|
||||
@@ -385,8 +392,8 @@ ol.render.canvas.Immediate.prototype.setFillStrokeStyle =
|
||||
strokeStyle.lineDash : ol.render.canvas.defaultLineDash;
|
||||
state.lineJoin = goog.isDef(strokeStyle.lineJoin) ?
|
||||
strokeStyle.lineJoin : ol.render.canvas.defaultLineJoin;
|
||||
state.lineWidth = goog.isDef(strokeStyle.width) ?
|
||||
strokeStyle.width : ol.render.canvas.defaultLineWidth;
|
||||
state.lineWidth = this.pixelRatio_ * (goog.isDef(strokeStyle.width) ?
|
||||
strokeStyle.width : ol.render.canvas.defaultLineWidth);
|
||||
state.miterLimit = goog.isDef(strokeStyle.miterLimit) ?
|
||||
strokeStyle.miterLimit : ol.render.canvas.defaultMiterLimit;
|
||||
} else {
|
||||
|
||||
@@ -41,10 +41,17 @@ ol.render.canvas.Instruction = {
|
||||
/**
|
||||
* @constructor
|
||||
* @implements {ol.render.IRender}
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.Replay = function() {
|
||||
ol.render.canvas.Replay = function(pixelRatio) {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
*/
|
||||
this.pixelRatio = pixelRatio;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -430,12 +437,13 @@ ol.render.canvas.Replay.prototype.setTextStyle = goog.abstractMethod;
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.render.canvas.Replay}
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.ImageReplay = function() {
|
||||
ol.render.canvas.ImageReplay = function(pixelRatio) {
|
||||
|
||||
goog.base(this);
|
||||
goog.base(this, pixelRatio);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -588,12 +596,13 @@ ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) {
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.render.canvas.Replay}
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.LineStringReplay = function() {
|
||||
ol.render.canvas.LineStringReplay = function(pixelRatio) {
|
||||
|
||||
goog.base(this);
|
||||
goog.base(this, pixelRatio);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -779,8 +788,8 @@ ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle =
|
||||
strokeStyle.lineDash : ol.render.canvas.defaultLineDash;
|
||||
this.state_.lineJoin = goog.isDef(strokeStyle.lineJoin) ?
|
||||
strokeStyle.lineJoin : ol.render.canvas.defaultLineJoin;
|
||||
this.state_.lineWidth = goog.isDef(strokeStyle.width) ?
|
||||
strokeStyle.width : ol.render.canvas.defaultLineWidth;
|
||||
this.state_.lineWidth = this.pixelRatio * (goog.isDef(strokeStyle.width) ?
|
||||
strokeStyle.width : ol.render.canvas.defaultLineWidth);
|
||||
this.state_.miterLimit = goog.isDef(strokeStyle.miterLimit) ?
|
||||
strokeStyle.miterLimit : ol.render.canvas.defaultMiterLimit;
|
||||
};
|
||||
@@ -790,12 +799,13 @@ ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle =
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.render.canvas.Replay}
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.PolygonReplay = function() {
|
||||
ol.render.canvas.PolygonReplay = function(pixelRatio) {
|
||||
|
||||
goog.base(this);
|
||||
goog.base(this, pixelRatio);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -990,8 +1000,8 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle =
|
||||
strokeStyle.lineDash : ol.render.canvas.defaultLineDash;
|
||||
state.lineJoin = goog.isDef(strokeStyle.lineJoin) ?
|
||||
strokeStyle.lineJoin : ol.render.canvas.defaultLineJoin;
|
||||
state.lineWidth = goog.isDef(strokeStyle.width) ?
|
||||
strokeStyle.width : ol.render.canvas.defaultLineWidth;
|
||||
state.lineWidth = this.pixelRatio * (goog.isDef(strokeStyle.width) ?
|
||||
strokeStyle.width : ol.render.canvas.defaultLineWidth);
|
||||
state.miterLimit = goog.isDef(strokeStyle.miterLimit) ?
|
||||
strokeStyle.miterLimit : ol.render.canvas.defaultMiterLimit;
|
||||
} else {
|
||||
@@ -1052,9 +1062,16 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() {
|
||||
/**
|
||||
* @constructor
|
||||
* @implements {ol.render.IReplayGroup}
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.ReplayGroup = function() {
|
||||
ol.render.canvas.ReplayGroup = function(pixelRatio) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.pixelRatio_ = pixelRatio;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -1248,7 +1265,7 @@ ol.render.canvas.ReplayGroup.prototype.getReplay =
|
||||
if (!goog.isDef(replay)) {
|
||||
var constructor = ol.render.canvas.BATCH_CONSTRUCTORS_[replayType];
|
||||
goog.asserts.assert(goog.isDef(constructor));
|
||||
replay = new constructor();
|
||||
replay = new constructor(this.pixelRatio_);
|
||||
replayes[replayType] = replay;
|
||||
}
|
||||
return replay;
|
||||
@@ -1266,7 +1283,8 @@ ol.render.canvas.ReplayGroup.prototype.isEmpty = function() {
|
||||
/**
|
||||
* @const
|
||||
* @private
|
||||
* @type {Object.<ol.render.ReplayType, function(new: ol.render.canvas.Replay)>}
|
||||
* @type {Object.<ol.render.ReplayType,
|
||||
* function(new: ol.render.canvas.Replay, number)>}
|
||||
*/
|
||||
ol.render.canvas.BATCH_CONSTRUCTORS_ = {
|
||||
'Image': ol.render.canvas.ImageReplay,
|
||||
|
||||
@@ -96,9 +96,12 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame =
|
||||
image = this.image_;
|
||||
var imageExtent = image.getExtent();
|
||||
var imageResolution = image.getResolution();
|
||||
var devicePixelRatio = frameState.devicePixelRatio;
|
||||
ol.vec.Mat4.makeTransform2D(this.imageTransform_,
|
||||
frameState.size[0] / 2, frameState.size[1] / 2,
|
||||
imageResolution / viewResolution, imageResolution / viewResolution,
|
||||
devicePixelRatio * frameState.size[0] / 2,
|
||||
devicePixelRatio * frameState.size[1] / 2,
|
||||
devicePixelRatio * imageResolution / viewResolution,
|
||||
devicePixelRatio * imageResolution / viewResolution,
|
||||
viewRotation,
|
||||
(imageExtent[0] - viewCenter[0]) / imageResolution,
|
||||
(viewCenter[1] - imageExtent[3]) / imageResolution);
|
||||
|
||||
@@ -85,8 +85,8 @@ ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ =
|
||||
if (layer.hasListener(type)) {
|
||||
var transform = goog.isDef(opt_transform) ?
|
||||
opt_transform : this.getTransform(frameState);
|
||||
var render = new ol.render.canvas.Immediate(context, frameState.extent,
|
||||
transform);
|
||||
var render = new ol.render.canvas.Immediate(
|
||||
context, frameState.devicePixelRatio, frameState.extent, transform);
|
||||
var composeEvent = new ol.render.Event(type, layer, render, frameState,
|
||||
context, null);
|
||||
layer.dispatchEvent(composeEvent);
|
||||
@@ -139,9 +139,12 @@ ol.renderer.canvas.Layer.prototype.getImageTransform = goog.abstractMethod;
|
||||
*/
|
||||
ol.renderer.canvas.Layer.prototype.getTransform = function(frameState) {
|
||||
var view2DState = frameState.view2DState;
|
||||
var devicePixelRatio = frameState.devicePixelRatio;
|
||||
return ol.vec.Mat4.makeTransform2D(this.transform_,
|
||||
frameState.size[0] / 2, frameState.size[1] / 2,
|
||||
1 / view2DState.resolution, -1 / view2DState.resolution,
|
||||
devicePixelRatio * frameState.size[0] / 2,
|
||||
devicePixelRatio * frameState.size[1] / 2,
|
||||
devicePixelRatio / view2DState.resolution,
|
||||
-devicePixelRatio / view2DState.resolution,
|
||||
-view2DState.rotation,
|
||||
-view2DState.center[0], -view2DState.center[1]);
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.style');
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('ol.css');
|
||||
goog.require('ol.layer.Image');
|
||||
goog.require('ol.layer.Tile');
|
||||
@@ -19,6 +20,7 @@ goog.require('ol.renderer.canvas.Layer');
|
||||
goog.require('ol.renderer.canvas.TileLayer');
|
||||
goog.require('ol.renderer.canvas.VectorLayer');
|
||||
goog.require('ol.source.State');
|
||||
goog.require('ol.vec.Mat4');
|
||||
|
||||
|
||||
|
||||
@@ -56,6 +58,12 @@ ol.renderer.canvas.Map = function(container, map) {
|
||||
this.context_ = /** @type {CanvasRenderingContext2D} */
|
||||
(this.canvas_.getContext('2d'));
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!goog.vec.Mat4.Number}
|
||||
*/
|
||||
this.transform_ = goog.vec.Mat4.createNumber();
|
||||
|
||||
};
|
||||
goog.inherits(ol.renderer.canvas.Map, ol.renderer.Map);
|
||||
|
||||
@@ -87,8 +95,17 @@ ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ =
|
||||
var map = this.getMap();
|
||||
var context = this.context_;
|
||||
if (map.hasListener(type)) {
|
||||
var view2DState = frameState.view2DState;
|
||||
var devicePixelRatio = frameState.devicePixelRatio;
|
||||
ol.vec.Mat4.makeTransform2D(this.transform_,
|
||||
this.canvas_.width / 2,
|
||||
this.canvas_.height / 2,
|
||||
devicePixelRatio / view2DState.resolution,
|
||||
-devicePixelRatio / view2DState.resolution,
|
||||
-view2DState.rotation,
|
||||
-view2DState.center[0], -view2DState.center[1]);
|
||||
var render = new ol.render.canvas.Immediate(
|
||||
context, frameState.extent, frameState.coordinateToPixelMatrix);
|
||||
context, devicePixelRatio, frameState.extent, this.transform_);
|
||||
var composeEvent = new ol.render.Event(type, map, render, frameState,
|
||||
context, null);
|
||||
map.dispatchEvent(composeEvent);
|
||||
@@ -121,11 +138,12 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
|
||||
}
|
||||
|
||||
var context = this.context_;
|
||||
|
||||
var size = frameState.size;
|
||||
if (this.canvas_.width != size[0] || this.canvas_.height != size[1]) {
|
||||
this.canvas_.width = size[0];
|
||||
this.canvas_.height = size[1];
|
||||
var ratio = frameState.devicePixelRatio;
|
||||
var width = frameState.size[0] * ratio;
|
||||
var height = frameState.size[1] * ratio;
|
||||
if (this.canvas_.width != width || this.canvas_.height != height) {
|
||||
this.canvas_.width = width;
|
||||
this.canvas_.height = height;
|
||||
} else {
|
||||
context.clearRect(0, 0, this.canvas_.width, this.canvas_.height);
|
||||
}
|
||||
|
||||
@@ -382,10 +382,12 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame =
|
||||
this.scheduleExpireCache(frameState, tileSource);
|
||||
this.updateLogos(frameState, tileSource);
|
||||
|
||||
var devicePixelRatio = frameState.devicePixelRatio;
|
||||
ol.vec.Mat4.makeTransform2D(this.imageTransform_,
|
||||
frameState.size[0] / 2, frameState.size[1] / 2,
|
||||
tileResolution / view2DState.resolution,
|
||||
tileResolution / view2DState.resolution,
|
||||
devicePixelRatio * frameState.size[0] / 2,
|
||||
devicePixelRatio * frameState.size[1] / 2,
|
||||
devicePixelRatio * tileResolution / view2DState.resolution,
|
||||
devicePixelRatio * tileResolution / view2DState.resolution,
|
||||
view2DState.rotation,
|
||||
(origin[0] - center[0]) / tileResolution,
|
||||
(center[1] - origin[1]) / tileResolution);
|
||||
|
||||
@@ -172,6 +172,7 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
|
||||
var vectorSource = vectorLayer.getVectorSource();
|
||||
var frameStateExtent = frameState.extent;
|
||||
var frameStateResolution = frameState.view2DState.resolution;
|
||||
var pixelRatio = frameState.devicePixelRatio;
|
||||
|
||||
if (!this.dirty_ &&
|
||||
this.renderedResolution_ == frameStateResolution &&
|
||||
@@ -198,15 +199,15 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
|
||||
if (!goog.isDef(styleFunction)) {
|
||||
styleFunction = ol.layer.Vector.defaultStyleFunction;
|
||||
}
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup();
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup(pixelRatio);
|
||||
vectorSource.forEachFeatureInExtent(extent,
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature.
|
||||
*/
|
||||
function(feature) {
|
||||
this.dirty_ = this.dirty_ ||
|
||||
this.renderFeature(feature, frameStateResolution, styleFunction,
|
||||
replayGroup);
|
||||
this.renderFeature(feature, frameStateResolution, pixelRatio,
|
||||
styleFunction, replayGroup);
|
||||
}, this);
|
||||
replayGroup.finish();
|
||||
|
||||
@@ -223,20 +224,22 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {ol.style.StyleFunction} styleFunction Style function.
|
||||
* @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
|
||||
* @return {boolean} `true` if an image is loading.
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.renderFeature =
|
||||
function(feature, resolution, styleFunction, replayGroup) {
|
||||
function(feature, resolution, pixelRatio, styleFunction, replayGroup) {
|
||||
var loading = false;
|
||||
var styles = styleFunction(feature, resolution);
|
||||
// FIXME if styles is null, should we use the default style?
|
||||
if (!goog.isDefAndNotNull(styles)) {
|
||||
return false;
|
||||
}
|
||||
// simplify to a tolerance of half a CSS pixel
|
||||
var squaredTolerance = resolution * resolution / 4;
|
||||
// simplify to a tolerance of half a device pixel
|
||||
var squaredTolerance =
|
||||
resolution * resolution / (4 * pixelRatio * pixelRatio);
|
||||
var i, ii, style, imageStyle, imageState;
|
||||
for (i = 0, ii = styles.length; i < ii; ++i) {
|
||||
style = styles[i];
|
||||
|
||||
Reference in New Issue
Block a user