Merge branch 'master' into set-multi

This commit is contained in:
Björn Harrtell
2016-02-22 09:30:25 +01:00
35 changed files with 529 additions and 478 deletions
+1
View File
@@ -2,6 +2,7 @@
[![Travis CI Status](https://secure.travis-ci.org/openlayers/ol3.svg)](http://travis-ci.org/#!/openlayers/ol3) [![Travis CI Status](https://secure.travis-ci.org/openlayers/ol3.svg)](http://travis-ci.org/#!/openlayers/ol3)
[![Coverage Status](https://coveralls.io/repos/openlayers/ol3/badge.svg?branch=master)](https://coveralls.io/r/openlayers/ol3?branch=master) [![Coverage Status](https://coveralls.io/repos/openlayers/ol3/badge.svg?branch=master)](https://coveralls.io/r/openlayers/ol3?branch=master)
[![OSGeo Project](https://img.shields.io/badge/OSGeo-Project-brightgreen.svg)](http://osgeo.org/)
[OpenLayers 3](http://openlayers.org/) is a high-performance, feature-packed library for creating interactive maps on the web. [OpenLayers 3](http://openlayers.org/) is a high-performance, feature-packed library for creating interactive maps on the web.
+38
View File
@@ -2,6 +2,44 @@
### v3.14.0 ### v3.14.0
#### Layer pre-/postcompose event changes
It is the responsibility of the application to undo any canvas transform changes at the end of a layer 'precompose' or 'postcompose' handler. Previously, it was ok to set a null transform. The API now guarantees a device pixel coordinate system on the canvas with its origin in the top left corner of the map. However, applications should not rely on the underlying canvas being the same size as the visible viewport.
Old code:
```js
layer.on('precompose', function(e) {
// rely on canvas dimensions to move coordinate origin to center
e.context.translate(e.context.canvas.width / 2, e.context.canvas.height / 2);
e.context.scale(3, 3);
// draw an x in the center of the viewport
e.context.moveTo(-20, -20);
e.context.lineTo(20, 20);
e.context.moveTo(-20, 20);
e.context.lineTo(20, -20);
// rely on the canvas having a null transform
e.context.setTransform(1, 0, 0, 1, 0, 0);
});
```
New code:
```js
layer.on('precompose', function(e) {
// use map size and pixel ratio to move coordinate origin to center
var size = map.getSize();
var pixelRatio = e.frameState.pixelRatio;
e.context.translate(size[0] / 2 * pixelRatio, size[1] / 2 * pixelRatio);
e.context.scale(3, 3);
// draw an x in the center of the viewport
e.context.moveTo(-20, -20);
e.context.lineTo(20, 20);
e.context.moveTo(-20, 20);
e.context.lineTo(20, -20);
// undo all transforms
e.context.scale(1 / 3, 1 / 3);
e.context.translate(-size[0] / 2 * pixelRatio, -size[1] / 2 * pixelRatio);
});
```
### v3.13.0 ### v3.13.0
#### `proj4js` integration #### `proj4js` integration
+1 -1
View File
@@ -11,7 +11,7 @@
<link rel="stylesheet" href="./resources/layout.css" type="text/css"> <link rel="stylesheet" href="./resources/layout.css" type="text/css">
{{{ extraHead.local }}} {{{ extraHead.local }}}
{{{ css.tag }}} {{{ css.tag }}}
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch"></script> <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,requestAnimationFrame"></script>
<script src="./resources/zeroclipboard/ZeroClipboard.min.js"></script> <script src="./resources/zeroclipboard/ZeroClipboard.min.js"></script>
<title>{{ title }}</title> <title>{{ title }}</title>
</head> </head>
+7 -3
View File
@@ -25,8 +25,10 @@ var map = new ol.Map({
osm.on('precompose', function(event) { osm.on('precompose', function(event) {
var ctx = event.context; var ctx = event.context;
ctx.save(); ctx.save();
ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); var pixelRatio = event.frameState.pixelRatio;
ctx.scale(3, 3); var size = map.getSize();
ctx.translate(size[0] / 2 * pixelRatio, size[1] / 2 * pixelRatio);
ctx.scale(3 * pixelRatio, 3 * pixelRatio);
ctx.translate(-75, -80); ctx.translate(-75, -80);
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(75, 40); ctx.moveTo(75, 40);
@@ -37,7 +39,9 @@ osm.on('precompose', function(event) {
ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25); ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25);
ctx.bezierCurveTo(85, 25, 75, 37, 75, 40); ctx.bezierCurveTo(85, 25, 75, 37, 75, 40);
ctx.clip(); ctx.clip();
ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.translate(75, 80);
ctx.scale(1 / 3 / pixelRatio, 1 / 3 / pixelRatio);
ctx.translate(-size[0] / 2 * pixelRatio, -size[1] / 2 * pixelRatio);
}); });
osm.on('postcompose', function(event) { osm.on('postcompose', function(event) {
+1 -1
View File
@@ -54,7 +54,7 @@
"clean-css": "3.4.9", "clean-css": "3.4.9",
"coveralls": "2.11.6", "coveralls": "2.11.6",
"debounce": "^1.0.0", "debounce": "^1.0.0",
"eslint": "2.1.0", "eslint": "2.2.0",
"eslint-config-openlayers": "4.0.0", "eslint-config-openlayers": "4.0.0",
"expect.js": "0.3.1", "expect.js": "0.3.1",
"gaze": "^0.5.1", "gaze": "^0.5.1",
+18 -12
View File
@@ -575,18 +575,24 @@ ol.extent.getForViewAndSize = function(center, resolution, rotation, size, opt_e
var dy = resolution * size[1] / 2; var dy = resolution * size[1] / 2;
var cosRotation = Math.cos(rotation); var cosRotation = Math.cos(rotation);
var sinRotation = Math.sin(rotation); var sinRotation = Math.sin(rotation);
/** @type {Array.<number>} */ var xCos = dx * cosRotation;
var xs = [-dx, -dx, dx, dx]; var xSin = dx * sinRotation;
/** @type {Array.<number>} */ var yCos = dy * cosRotation;
var ys = [-dy, dy, -dy, dy]; var ySin = dy * sinRotation;
var i, x, y; var x = center[0];
for (i = 0; i < 4; ++i) { var y = center[1];
x = xs[i]; var x0 = x - xCos + ySin;
y = ys[i]; var x1 = x - xCos - ySin;
xs[i] = center[0] + x * cosRotation - y * sinRotation; var x2 = x + xCos - ySin;
ys[i] = center[1] + x * sinRotation + y * cosRotation; var x3 = x + xCos + ySin;
} var y0 = y - xSin - yCos;
return ol.extent.boundingExtentXYs_(xs, ys, opt_extent); var y1 = y - xSin + yCos;
var y2 = y + xSin + yCos;
var y3 = y + xSin - yCos;
return ol.extent.createOrUpdate(
Math.min(x0, x1, x2, x3), Math.min(y0, y1, y2, y3),
Math.max(x0, x1, x2, x3), Math.max(y0, y1, y2, y3),
opt_extent);
}; };
+4 -2
View File
@@ -411,6 +411,7 @@ ol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) {
ol.format.WFS.writeDelete_ = function(node, feature, objectStack) { ol.format.WFS.writeDelete_ = function(node, feature, objectStack) {
var context = objectStack[objectStack.length - 1]; var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context), 'context should be an Object'); goog.asserts.assert(goog.isObject(context), 'context should be an Object');
goog.asserts.assert(feature.getId() !== undefined, 'feature should have an id');
var featureType = context['featureType']; var featureType = context['featureType'];
var featurePrefix = context['featurePrefix']; var featurePrefix = context['featurePrefix'];
featurePrefix = featurePrefix ? featurePrefix : featurePrefix = featurePrefix ? featurePrefix :
@@ -420,7 +421,7 @@ ol.format.WFS.writeDelete_ = function(node, feature, objectStack) {
ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
featureNS); featureNS);
var fid = feature.getId(); var fid = feature.getId();
if (fid) { if (fid !== undefined) {
ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack); ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
} }
}; };
@@ -435,6 +436,7 @@ ol.format.WFS.writeDelete_ = function(node, feature, objectStack) {
ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) { ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) {
var context = objectStack[objectStack.length - 1]; var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context), 'context should be an Object'); goog.asserts.assert(goog.isObject(context), 'context should be an Object');
goog.asserts.assert(feature.getId() !== undefined, 'feature should have an id');
var featureType = context['featureType']; var featureType = context['featureType'];
var featurePrefix = context['featurePrefix']; var featurePrefix = context['featurePrefix'];
featurePrefix = featurePrefix ? featurePrefix : featurePrefix = featurePrefix ? featurePrefix :
@@ -444,7 +446,7 @@ ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) {
ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
featureNS); featureNS);
var fid = feature.getId(); var fid = feature.getId();
if (fid) { if (fid !== undefined) {
var keys = feature.getKeys(); var keys = feature.getKeys();
var values = []; var values = [];
for (var i = 0, ii = keys.length; i < ii; i++) { for (var i = 0, ii = keys.length; i < ii; i++) {
+18 -16
View File
@@ -147,16 +147,10 @@ ol.MapBrowserEventHandler = function(map) {
this.dragging_ = false; this.dragging_ = false;
/** /**
* @type {Array.<ol.events.Key>} * @type {!Array.<ol.events.Key>}
* @private * @private
*/ */
this.dragListenerKeys_ = null; this.dragListenerKeys_ = [];
/**
* @type {?ol.events.Key}
* @private
*/
this.pointerdownListenerKey_ = null;
/** /**
* The most recent "down" type event (or null if none have occurred). * The most recent "down" type event (or null if none have occurred).
@@ -198,10 +192,18 @@ ol.MapBrowserEventHandler = function(map) {
*/ */
this.documentPointerEventHandler_ = null; this.documentPointerEventHandler_ = null;
/**
* @type {?ol.events.Key}
* @private
*/
this.pointerdownListenerKey_ = ol.events.listen(this.pointerEventHandler_, this.pointerdownListenerKey_ = ol.events.listen(this.pointerEventHandler_,
ol.pointer.EventType.POINTERDOWN, ol.pointer.EventType.POINTERDOWN,
this.handlePointerDown_, this); this.handlePointerDown_, this);
/**
* @type {?ol.events.Key}
* @private
*/
this.relayedListenerKey_ = ol.events.listen(this.pointerEventHandler_, this.relayedListenerKey_ = ol.events.listen(this.pointerEventHandler_,
ol.pointer.EventType.POINTERMOVE, ol.pointer.EventType.POINTERMOVE,
this.relayEvent_, this); this.relayEvent_, this);
@@ -280,7 +282,7 @@ ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) {
'this.activePointers_ should be equal to or larger than 0'); 'this.activePointers_ should be equal to or larger than 0');
if (this.activePointers_ === 0) { if (this.activePointers_ === 0) {
this.dragListenerKeys_.forEach(ol.events.unlistenByKey); this.dragListenerKeys_.forEach(ol.events.unlistenByKey);
this.dragListenerKeys_ = null; this.dragListenerKeys_.length = 0;
this.dragging_ = false; this.dragging_ = false;
this.down_ = null; this.down_ = null;
goog.dispose(this.documentPointerEventHandler_); goog.dispose(this.documentPointerEventHandler_);
@@ -311,7 +313,7 @@ ol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent)
this.down_ = pointerEvent; this.down_ = pointerEvent;
if (!this.dragListenerKeys_) { if (this.dragListenerKeys_.length === 0) {
/* Set up a pointer event handler on the `document`, /* Set up a pointer event handler on the `document`,
* which is required when the pointer is moved outside * which is required when the pointer is moved outside
* the viewport when dragging. * the viewport when dragging.
@@ -319,7 +321,7 @@ ol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent)
this.documentPointerEventHandler_ = this.documentPointerEventHandler_ =
new ol.pointer.PointerEventHandler(document); new ol.pointer.PointerEventHandler(document);
this.dragListenerKeys_ = [ this.dragListenerKeys_.push(
ol.events.listen(this.documentPointerEventHandler_, ol.events.listen(this.documentPointerEventHandler_,
ol.MapBrowserEvent.EventType.POINTERMOVE, ol.MapBrowserEvent.EventType.POINTERMOVE,
this.handlePointerMove_, this), this.handlePointerMove_, this),
@@ -342,7 +344,7 @@ ol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent)
ol.events.listen(this.pointerEventHandler_, ol.events.listen(this.pointerEventHandler_,
ol.MapBrowserEvent.EventType.POINTERCANCEL, ol.MapBrowserEvent.EventType.POINTERCANCEL,
this.handlePointerUp_, this) this.handlePointerUp_, this)
]; );
} }
}; };
@@ -409,10 +411,10 @@ ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
ol.events.unlistenByKey(this.pointerdownListenerKey_); ol.events.unlistenByKey(this.pointerdownListenerKey_);
this.pointerdownListenerKey_ = null; this.pointerdownListenerKey_ = null;
} }
if (this.dragListenerKeys_) {
this.dragListenerKeys_.forEach(ol.events.unlistenByKey); this.dragListenerKeys_.forEach(ol.events.unlistenByKey);
this.dragListenerKeys_ = null; this.dragListenerKeys_.length = 0;
}
if (this.documentPointerEventHandler_) { if (this.documentPointerEventHandler_) {
goog.dispose(this.documentPointerEventHandler_); goog.dispose(this.documentPointerEventHandler_);
this.documentPointerEventHandler_ = null; this.documentPointerEventHandler_ = null;
+15
View File
@@ -94,3 +94,18 @@ ol.render.canvas.defaultTextBaseline = 'middle';
* @type {number} * @type {number}
*/ */
ol.render.canvas.defaultLineWidth = 1; ol.render.canvas.defaultLineWidth = 1;
/**
* @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation.
* @param {number} offsetX X offset.
* @param {number} offsetY Y offset.
*/
ol.render.canvas.rotateAtOffset = function(context, rotation, offsetX, offsetY) {
if (rotation !== 0) {
context.translate(offsetX, offsetY);
context.rotate(rotation);
context.translate(-offsetX, -offsetY);
}
};
@@ -147,7 +147,6 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
var viewState = frameState.viewState; var viewState = frameState.viewState;
var viewCenter = viewState.center; var viewCenter = viewState.center;
var viewResolution = viewState.resolution; var viewResolution = viewState.resolution;
var viewRotation = viewState.rotation;
var image; var image;
var imageLayer = this.getLayer(); var imageLayer = this.getLayer();
@@ -195,7 +194,7 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
pixelRatio * frameState.size[0] / 2, pixelRatio * frameState.size[0] / 2,
pixelRatio * frameState.size[1] / 2, pixelRatio * frameState.size[1] / 2,
scale, scale, scale, scale,
viewRotation, 0,
imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution, imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution,
imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution); imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution);
this.imageTransformInv_ = null; this.imageTransformInv_ = null;
+17 -63
View File
@@ -2,12 +2,11 @@ goog.provide('ol.renderer.canvas.Layer');
goog.require('goog.asserts'); goog.require('goog.asserts');
goog.require('goog.vec.Mat4'); goog.require('goog.vec.Mat4');
goog.require('ol.array');
goog.require('ol.dom');
goog.require('ol.extent'); goog.require('ol.extent');
goog.require('ol.layer.Layer'); goog.require('ol.layer.Layer');
goog.require('ol.render.Event'); goog.require('ol.render.Event');
goog.require('ol.render.EventType'); goog.require('ol.render.EventType');
goog.require('ol.render.canvas');
goog.require('ol.render.canvas.Immediate'); goog.require('ol.render.canvas.Immediate');
goog.require('ol.renderer.Layer'); goog.require('ol.renderer.Layer');
goog.require('ol.vec.Mat4'); goog.require('ol.vec.Mat4');
@@ -51,6 +50,9 @@ ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerStat
goog.asserts.assert(extent !== undefined, goog.asserts.assert(extent !== undefined,
'layerState extent is defined'); 'layerState extent is defined');
var pixelRatio = frameState.pixelRatio; var pixelRatio = frameState.pixelRatio;
var width = frameState.size[0] * pixelRatio;
var height = frameState.size[1] * pixelRatio;
var rotation = frameState.viewState.rotation;
var topLeft = ol.extent.getTopLeft(extent); var topLeft = ol.extent.getTopLeft(extent);
var topRight = ol.extent.getTopRight(extent); var topRight = ol.extent.getTopRight(extent);
var bottomRight = ol.extent.getBottomRight(extent); var bottomRight = ol.extent.getBottomRight(extent);
@@ -66,12 +68,14 @@ ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerStat
bottomLeft, bottomLeft); bottomLeft, bottomLeft);
context.save(); context.save();
ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);
context.beginPath(); context.beginPath();
context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio); context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio);
context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio); context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio);
context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio); context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio);
context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio); context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio);
context.clip(); context.clip();
ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);
} }
var imageTransform = this.getImageTransform(); var imageTransform = this.getImageTransform();
@@ -83,24 +87,12 @@ ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerStat
// for performance reasons, context.setTransform is only used // for performance reasons, context.setTransform is only used
// when the view is rotated. see http://jsperf.com/canvas-transform // when the view is rotated. see http://jsperf.com/canvas-transform
if (frameState.viewState.rotation === 0) { var dx = goog.vec.Mat4.getElement(imageTransform, 0, 3);
var dx = goog.vec.Mat4.getElement(imageTransform, 0, 3); var dy = goog.vec.Mat4.getElement(imageTransform, 1, 3);
var dy = goog.vec.Mat4.getElement(imageTransform, 1, 3); var dw = image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0);
var dw = image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0); var dh = image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1);
var dh = image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1); context.drawImage(image, 0, 0, +image.width, +image.height,
context.drawImage(image, 0, 0, +image.width, +image.height, Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));
Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));
} else {
context.setTransform(
goog.vec.Mat4.getElement(imageTransform, 0, 0),
goog.vec.Mat4.getElement(imageTransform, 1, 0),
goog.vec.Mat4.getElement(imageTransform, 0, 1),
goog.vec.Mat4.getElement(imageTransform, 1, 1),
goog.vec.Mat4.getElement(imageTransform, 0, 3),
goog.vec.Mat4.getElement(imageTransform, 1, 3));
context.drawImage(image, 0, 0);
context.setTransform(1, 0, 0, 1, 0, 0);
}
context.globalAlpha = alpha; context.globalAlpha = alpha;
if (clipped) { if (clipped) {
@@ -123,6 +115,10 @@ ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerStat
ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState, opt_transform) { ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState, opt_transform) {
var layer = this.getLayer(); var layer = this.getLayer();
if (layer.hasListener(type)) { if (layer.hasListener(type)) {
var width = frameState.size[0] * frameState.pixelRatio;
var height = frameState.size[1] * frameState.pixelRatio;
var rotation = frameState.viewState.rotation;
ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);
var transform = opt_transform !== undefined ? var transform = opt_transform !== undefined ?
opt_transform : this.getTransform(frameState, 0); opt_transform : this.getTransform(frameState, 0);
var render = new ol.render.canvas.Immediate( var render = new ol.render.canvas.Immediate(
@@ -132,6 +128,7 @@ ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = function(type, contex
context, null); context, null);
layer.dispatchEvent(composeEvent); layer.dispatchEvent(composeEvent);
render.flush(); render.flush();
ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);
} }
}; };
@@ -224,46 +221,3 @@ ol.renderer.canvas.Layer.prototype.getPixelOnCanvas = function(pixelOnMap, image
ol.vec.Mat4.multVec2(imageTransformInv, pixelOnMap, pixelOnCanvas); ol.vec.Mat4.multVec2(imageTransformInv, pixelOnMap, pixelOnCanvas);
return pixelOnCanvas; return pixelOnCanvas;
}; };
/**
* @param {ol.Size} size Size.
* @return {boolean} True when the canvas with the current size does not exceed
* the maximum dimensions.
*/
ol.renderer.canvas.Layer.testCanvasSize = (function() {
/**
* @type {CanvasRenderingContext2D}
*/
var context = null;
/**
* @type {ImageData}
*/
var imageData = null;
return function(size) {
if (!context) {
context = ol.dom.createCanvasContext2D(1, 1);
imageData = context.createImageData(1, 1);
var data = imageData.data;
data[0] = 42;
data[1] = 84;
data[2] = 126;
data[3] = 255;
}
var canvas = context.canvas;
var good = size[0] <= canvas.width && size[1] <= canvas.height;
if (!good) {
canvas.width = size[0];
canvas.height = size[1];
var x = size[0] - 1;
var y = size[1] - 1;
context.putImageData(imageData, x, y);
var result = context.getImageData(x, y, 1, 1);
good = ol.array.equals(imageData.data, result.data);
}
return good;
};
})();
+54 -7
View File
@@ -11,6 +11,7 @@ goog.require('ol.RendererType');
goog.require('ol.array'); goog.require('ol.array');
goog.require('ol.css'); goog.require('ol.css');
goog.require('ol.dom'); goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.layer.Image'); goog.require('ol.layer.Image');
goog.require('ol.layer.Layer'); goog.require('ol.layer.Layer');
goog.require('ol.layer.Tile'); goog.require('ol.layer.Tile');
@@ -45,6 +46,12 @@ ol.renderer.canvas.Map = function(container, map) {
*/ */
this.context_ = ol.dom.createCanvasContext2D(); this.context_ = ol.dom.createCanvasContext2D();
/**
* @private
* @type {CanvasRenderingContext2D}
*/
this.renderContext_ = ol.dom.createCanvasContext2D();
/** /**
* @private * @private
* @type {HTMLCanvasElement} * @type {HTMLCanvasElement}
@@ -56,6 +63,24 @@ ol.renderer.canvas.Map = function(container, map) {
this.canvas_.className = ol.css.CLASS_UNSELECTABLE; this.canvas_.className = ol.css.CLASS_UNSELECTABLE;
goog.dom.insertChildAt(container, this.canvas_, 0); goog.dom.insertChildAt(container, this.canvas_, 0);
/**
* @private
* @type {HTMLCanvasElement}
*/
this.renderCanvas_ = this.renderContext_.canvas;
/**
* @private
* @type {ol.Coordinate}
*/
this.pixelCenter_ = [0, 0];
/**
* @private
* @type {ol.Extent}
*/
this.pixelExtent_ = ol.extent.createEmpty();
/** /**
* @private * @private
* @type {boolean} * @type {boolean}
@@ -156,14 +181,27 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
return; return;
} }
var context = this.context_; var context;
var width = frameState.size[0] * frameState.pixelRatio; var pixelRatio = frameState.pixelRatio;
var height = frameState.size[1] * frameState.pixelRatio; var width = frameState.size[0] * pixelRatio;
if (this.canvas_.width != width || this.canvas_.height != height) { var height = frameState.size[1] * pixelRatio;
this.canvas_.width = width; this.canvas_.width = width;
this.canvas_.height = height; this.canvas_.height = height;
var rotation = frameState.viewState.rotation;
var pixelExtent;
if (rotation) {
context = this.renderContext_;
pixelExtent = ol.extent.getForViewAndSize(this.pixelCenter_, pixelRatio,
rotation, frameState.size, this.pixelExtent_);
var renderWidth = ol.extent.getWidth(pixelExtent);
var renderHeight = ol.extent.getHeight(pixelExtent);
this.renderCanvas_.width = renderWidth + 0.5;
this.renderCanvas_.height = renderHeight + 0.5;
this.renderContext_.translate(Math.round((renderWidth - width) / 2),
Math.round((renderHeight - height) / 2));
} else { } else {
context.clearRect(0, 0, this.canvas_.width, this.canvas_.height); context = this.context_;
} }
this.calculateMatrices2D(frameState); this.calculateMatrices2D(frameState);
@@ -190,6 +228,15 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
} }
} }
if (rotation) {
this.context_.translate(width / 2, height / 2);
this.context_.rotate(rotation);
this.context_.drawImage(this.renderCanvas_,
Math.round(pixelExtent[0]), Math.round(pixelExtent[1]));
this.context_.rotate(-rotation);
this.context_.translate(-width / 2, -height / 2);
}
this.dispatchComposeEvent_( this.dispatchComposeEvent_(
ol.render.EventType.POSTCOMPOSE, frameState); ol.render.EventType.POSTCOMPOSE, frameState);
+157 -311
View File
@@ -1,20 +1,17 @@
// FIXME find correct globalCompositeOperation // FIXME find correct globalCompositeOperation
// FIXME optimize :-)
goog.provide('ol.renderer.canvas.TileLayer'); goog.provide('ol.renderer.canvas.TileLayer');
goog.require('goog.asserts'); goog.require('goog.asserts');
goog.require('goog.vec.Mat4');
goog.require('ol.Size');
goog.require('ol.TileRange'); goog.require('ol.TileRange');
goog.require('ol.TileState'); goog.require('ol.TileState');
goog.require('ol.array'); goog.require('ol.array');
goog.require('ol.dom'); goog.require('ol.dom');
goog.require('ol.extent'); goog.require('ol.extent');
goog.require('ol.layer.Tile'); goog.require('ol.layer.Tile');
goog.require('ol.render.EventType');
goog.require('ol.renderer.canvas.Layer'); goog.require('ol.renderer.canvas.Layer');
goog.require('ol.size'); goog.require('ol.source.Tile');
goog.require('ol.vec.Mat4');
/** /**
@@ -28,63 +25,15 @@ ol.renderer.canvas.TileLayer = function(tileLayer) {
/** /**
* @private * @private
* @type {HTMLCanvasElement} * @type {Object.<string, Array.<ol.Extent>>}
*/ */
this.canvas_ = null; this.clipExtents_ = null;
/**
* @private
* @type {ol.Size}
*/
this.canvasSize_ = null;
/**
* @private
* @type {boolean}
*/
this.canvasTooBig_ = false;
/** /**
* @private * @private
* @type {CanvasRenderingContext2D} * @type {CanvasRenderingContext2D}
*/ */
this.context_ = null; this.context_ = ol.dom.createCanvasContext2D();
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.imageTransform_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {?goog.vec.Mat4.Number}
*/
this.imageTransformInv_ = null;
/**
* @private
* @type {number}
*/
this.renderedCanvasZ_ = NaN;
/**
* @private
* @type {number}
*/
this.renderedTileWidth_ = NaN;
/**
* @private
* @type {number}
*/
this.renderedTileHeight_ = NaN;
/**
* @private
* @type {ol.TileRange}
*/
this.renderedCanvasTileRange_ = null;
/** /**
* @private * @private
@@ -94,9 +43,9 @@ ol.renderer.canvas.TileLayer = function(tileLayer) {
/** /**
* @private * @private
* @type {ol.Size} * @type {ol.Extent}
*/ */
this.tmpSize_ = [0, 0]; this.tmpExtent_ = ol.extent.createEmpty();
}; };
goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer); goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer);
@@ -105,86 +54,120 @@ goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer);
/** /**
* @inheritDoc * @inheritDoc
*/ */
ol.renderer.canvas.TileLayer.prototype.getImage = function() { ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
return this.canvas_; frameState, layerState, context) {
var pixelRatio = frameState.pixelRatio;
var viewState = frameState.viewState;
var center = viewState.center;
var projection = viewState.projection;
var resolution = viewState.resolution;
var size = frameState.size;
var pixelScale = pixelRatio / resolution;
var layer = this.getLayer();
var source = layer.getSource();
goog.asserts.assertInstanceof(source, ol.source.Tile,
'source is an ol.source.Tile');
var tileGutter = source.getGutter(projection);
var opaque = source.getOpaque(projection);
var transform = this.getTransform(frameState, 0);
this.dispatchPreComposeEvent(context, frameState, transform);
var renderContext;
if (layer.hasListener(ol.render.EventType.RENDER)) {
// resize and clear
this.context_.canvas.width = context.canvas.width;
this.context_.canvas.height = context.canvas.height;
renderContext = this.context_;
} else {
renderContext = context;
}
var offsetX = Math.round(pixelRatio * size[0] / 2);
var offsetY = Math.round(pixelRatio * size[1] / 2);
// for performance reasons, context.save / context.restore is not used
// to save and restore the transformation matrix and the opacity.
// see http://jsperf.com/context-save-restore-versus-variable
var alpha = renderContext.globalAlpha;
renderContext.globalAlpha = layerState.opacity;
var tileGrid = source.getTileGridForProjection(projection);
var tilesToDraw = this.renderedTiles_;
var clipExtents, clipExtent, currentZ, i, ii, j, jj, insertPoint;
var origin, tile, tileExtent, tileHeight, tileOffsetX, tileOffsetY;
var tilePixelSize, tileWidth;
for (i = 0, ii = tilesToDraw.length; i < ii; ++i) {
tile = tilesToDraw[i];
tileExtent = tileGrid.getTileCoordExtent(
tile.getTileCoord(), this.tmpExtent_);
clipExtents = !opaque && this.clipExtents_[tile.tileCoord.toString()];
if (clipExtents) {
// Create a clip mask for regions in this low resolution tile that will be
// filled by a higher resolution tile
renderContext.save();
renderContext.beginPath();
renderContext.moveTo((tileExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[1]) * pixelScale + offsetY);
renderContext.lineTo((tileExtent[2] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[1]) * pixelScale + offsetY);
renderContext.lineTo((tileExtent[2] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[3]) * pixelScale + offsetY);
renderContext.lineTo((tileExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[3]) * pixelScale + offsetY);
renderContext.closePath();
for (j = 0, jj = clipExtents.length; j < jj; ++j) {
clipExtent = clipExtents[j];
renderContext.moveTo((clipExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - clipExtent[1]) * pixelScale + offsetY);
renderContext.lineTo((clipExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - clipExtent[3]) * pixelScale + offsetY);
renderContext.lineTo((clipExtent[2] - center[0]) * pixelScale + offsetX,
(center[1] - clipExtent[3]) * pixelScale + offsetY);
renderContext.lineTo((clipExtent[2] - center[0]) * pixelScale + offsetX,
(center[1] - clipExtent[1]) * pixelScale + offsetY);
renderContext.closePath();
}
renderContext.clip();
}
currentZ = tile.getTileCoord()[0];
tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection);
insertPoint = ol.extent.getTopLeft(tileExtent);
tileWidth = Math.round(ol.extent.getWidth(tileExtent) * pixelScale);
tileHeight = Math.round(ol.extent.getHeight(tileExtent) * pixelScale);
// Calculate all insert points from a common origin and tile widths to avoid
// gaps caused by rounding
origin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent(
tileGrid.getTileCoordForCoordAndZ(center, currentZ)));
tileOffsetX = offsetX + Math.round((origin[0] - center[0]) * pixelScale);
tileOffsetY = offsetY + Math.round((center[1] - origin[1]) * pixelScale);
renderContext.drawImage(tile.getImage(), tileGutter, tileGutter,
tilePixelSize[0], tilePixelSize[1],
Math.round((insertPoint[0] - origin[0]) * pixelScale / tileWidth) *
tileWidth + tileOffsetX,
Math.round((origin[1] - insertPoint[1]) * pixelScale / tileHeight) *
tileHeight + tileOffsetY, tileWidth, tileHeight);
if (clipExtents) {
renderContext.restore();
}
}
if (renderContext != context) {
this.dispatchRenderEvent(renderContext, frameState, transform);
context.drawImage(renderContext.canvas, 0, 0);
}
renderContext.globalAlpha = alpha;
this.dispatchPostComposeEvent(context, frameState, transform);
}; };
/** /**
* @inheritDoc * @inheritDoc
*/ */
ol.renderer.canvas.TileLayer.prototype.getImageTransform = function() { ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
return this.imageTransform_; frameState, layerState) {
};
/**
* @inheritDoc
*/
ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layerState) {
//
// Warning! You're entering a dangerous zone!
//
// The canvas tile layer renderering is highly optimized, hence
// the complexity of this function. For best performance we try
// to minimize the number of pixels to update on the canvas. This
// includes:
//
// - Only drawing pixels that will be visible.
// - Not re-drawing pixels/tiles that are already correct.
// - Minimizing calls to clearRect.
// - Never shrink the canvas. Just make it bigger when necessary.
// Re-sizing the canvas also clears it, which further means
// re-creating it (expensive).
//
// The various steps performed by this functions:
//
// - Create a canvas element if none has been created yet.
//
// - Make the canvas bigger if it's too small. Note that we never shrink
// the canvas, we just make it bigger when necessary, when rotating for
// example. Note also that the canvas always contains a whole number
// of tiles.
//
// - Invalidate the canvas tile range (renderedCanvasTileRange_ = null)
// if (1) the canvas has been enlarged, or (2) the zoom level changes,
// or (3) the canvas tile range doesn't contain the required tile
// range. This canvas tile range invalidation thing is related to
// an optimization where we attempt to redraw as few pixels as
// possible on each prepareFrame call.
//
// - If the canvas tile range has been invalidated we reset
// renderedCanvasTileRange_ and reset the renderedTiles_ array.
// The renderedTiles_ array is the structure used to determine
// the canvas pixels that need not be redrawn from one prepareFrame
// call to another. It records while tile has been rendered at
// which position in the canvas.
//
// - We then determine the tiles to draw on the canvas. Tiles for
// the target resolution may not be loaded yet. In that case we
// use low-resolution/interim tiles if loaded already. And, if
// for a non-yet-loaded tile we haven't found a corresponding
// low-resolution tile we indicate that the pixels for that
// tile must be cleared on the canvas. Note: determining the
// interim tiles is based on tile extents instead of tile
// coords, this is to be able to handler irregular tile grids.
//
// - We're now ready to render. We start by calling clearRect
// for the tiles that aren't loaded yet and are not fully covered
// by a low-resolution tile (if they're loaded, we'll draw them;
// if they're fully covered by a low-resolution tile then there's
// no need to clear). We then render the tiles "back to front",
// i.e. starting with the low-resolution tiles.
//
// - After rendering some bookkeeping is performed (updateUsedTiles,
// etc.). manageTilePyramid is what enqueue tiles in the tile
// queue for loading.
//
// - The last step involves updating the image transform matrix,
// which will be used by the map renderer for the final
// composition and positioning.
//
var pixelRatio = frameState.pixelRatio; var pixelRatio = frameState.pixelRatio;
var viewState = frameState.viewState; var viewState = frameState.viewState;
@@ -195,14 +178,8 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layer
'layer is an instance of ol.layer.Tile'); 'layer is an instance of ol.layer.Tile');
var tileSource = tileLayer.getSource(); var tileSource = tileLayer.getSource();
var tileGrid = tileSource.getTileGridForProjection(projection); var tileGrid = tileSource.getTileGridForProjection(projection);
var tileGutter = tileSource.getGutter();
var z = tileGrid.getZForResolution(viewState.resolution); var z = tileGrid.getZForResolution(viewState.resolution);
var tilePixelSize =
tileSource.getTilePixelSize(z, frameState.pixelRatio, projection);
var tilePixelRatio = tilePixelSize[0] /
ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0];
var tileResolution = tileGrid.getResolution(z); var tileResolution = tileGrid.getResolution(z);
var tilePixelResolution = tileResolution / tilePixelRatio;
var center = viewState.center; var center = viewState.center;
var extent; var extent;
if (tileResolution == viewState.resolution) { if (tileResolution == viewState.resolution) {
@@ -224,87 +201,11 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layer
var tileRange = tileGrid.getTileRangeForExtentAndResolution( var tileRange = tileGrid.getTileRangeForExtentAndResolution(
extent, tileResolution); extent, tileResolution);
var canvasWidth = tilePixelSize[0] * tileRange.getWidth();
var canvasHeight = tilePixelSize[1] * tileRange.getHeight();
var canvas, context;
if (!this.canvas_) {
goog.asserts.assert(!this.canvasSize_,
'canvasSize is null (because canvas is null)');
goog.asserts.assert(!this.context_,
'context is null (because canvas is null)');
goog.asserts.assert(!this.renderedCanvasTileRange_,
'renderedCanvasTileRange is null (because canvas is null)');
context = ol.dom.createCanvasContext2D(canvasWidth, canvasHeight);
this.canvas_ = context.canvas;
this.canvasSize_ = [canvasWidth, canvasHeight];
this.context_ = context;
this.canvasTooBig_ =
!ol.renderer.canvas.Layer.testCanvasSize(this.canvasSize_);
} else {
goog.asserts.assert(this.canvasSize_,
'non-null canvasSize (because canvas is not null)');
goog.asserts.assert(this.context_,
'non-null context (because canvas is not null)');
canvas = this.canvas_;
context = this.context_;
if (this.canvasSize_[0] < canvasWidth ||
this.canvasSize_[1] < canvasHeight ||
this.renderedTileWidth_ !== tilePixelSize[0] ||
this.renderedTileHeight_ !== tilePixelSize[1] ||
(this.canvasTooBig_ && (this.canvasSize_[0] > canvasWidth ||
this.canvasSize_[1] > canvasHeight))) {
// Canvas is too small or tileSize has changed, resize it.
// We never shrink the canvas, unless
// we know that the current canvas size exceeds the maximum size
canvas.width = canvasWidth;
canvas.height = canvasHeight;
this.canvasSize_ = [canvasWidth, canvasHeight];
this.canvasTooBig_ =
!ol.renderer.canvas.Layer.testCanvasSize(this.canvasSize_);
this.renderedCanvasTileRange_ = null;
} else {
canvasWidth = this.canvasSize_[0];
canvasHeight = this.canvasSize_[1];
if (z != this.renderedCanvasZ_ ||
!this.renderedCanvasTileRange_.containsTileRange(tileRange)) {
this.renderedCanvasTileRange_ = null;
}
}
}
var canvasTileRange, canvasTileRangeWidth, minX, minY;
if (!this.renderedCanvasTileRange_) {
canvasTileRangeWidth = canvasWidth / tilePixelSize[0];
var canvasTileRangeHeight = canvasHeight / tilePixelSize[1];
minX = tileRange.minX -
Math.floor((canvasTileRangeWidth - tileRange.getWidth()) / 2);
minY = tileRange.minY -
Math.floor((canvasTileRangeHeight - tileRange.getHeight()) / 2);
this.renderedCanvasZ_ = z;
this.renderedTileWidth_ = tilePixelSize[0];
this.renderedTileHeight_ = tilePixelSize[1];
this.renderedCanvasTileRange_ = new ol.TileRange(
minX, minX + canvasTileRangeWidth - 1,
minY, minY + canvasTileRangeHeight - 1);
this.renderedTiles_ =
new Array(canvasTileRangeWidth * canvasTileRangeHeight);
canvasTileRange = this.renderedCanvasTileRange_;
} else {
canvasTileRange = this.renderedCanvasTileRange_;
canvasTileRangeWidth = canvasTileRange.getWidth();
}
goog.asserts.assert(canvasTileRange.containsTileRange(tileRange),
'tileRange is contained in canvasTileRange');
/** /**
* @type {Object.<number, Object.<string, ol.Tile>>} * @type {Object.<number, Object.<string, ol.Tile>>}
*/ */
var tilesToDrawByZ = {}; var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {}; tilesToDrawByZ[z] = {};
/** @type {Array.<ol.Tile>} */
var tilesToClear = [];
var findLoadedTiles = this.createLoadedTileFinder( var findLoadedTiles = this.createLoadedTileFinder(
tileSource, projection, tilesToDrawByZ); tileSource, projection, tilesToDrawByZ);
@@ -339,9 +240,6 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layer
fullyLoaded = tileGrid.forEachTileCoordParentTileRange( fullyLoaded = tileGrid.forEachTileCoordParentTileRange(
tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);
if (!fullyLoaded) { if (!fullyLoaded) {
// FIXME we do not need to clear the tile if it is fully covered by its
// children
tilesToClear.push(tile);
childTileRange = tileGrid.getTileCoordChildTileRange( childTileRange = tileGrid.getTileCoordChildTileRange(
tile.tileCoord, tmpTileRange, tmpExtent); tile.tileCoord, tmpTileRange, tmpExtent);
if (childTileRange) { if (childTileRange) {
@@ -352,86 +250,49 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layer
} }
} }
var i, ii;
for (i = 0, ii = tilesToClear.length; i < ii; ++i) {
tile = tilesToClear[i];
x = tilePixelSize[0] * (tile.tileCoord[1] - canvasTileRange.minX);
y = tilePixelSize[1] * (canvasTileRange.maxY - tile.tileCoord[2]);
context.clearRect(x, y, tilePixelSize[0], tilePixelSize[1]);
}
/** @type {Array.<number>} */ /** @type {Array.<number>} */
var zs = Object.keys(tilesToDrawByZ).map(Number); var zs = Object.keys(tilesToDrawByZ).map(Number);
zs.sort(ol.array.numberSafeCompareFunction); zs.sort(ol.array.numberSafeCompareFunction);
var opaque = tileSource.getOpaque(projection); var renderables = [];
var origin = ol.extent.getTopLeft(tileGrid.getTileCoordExtent( var i, ii, currentZ, tileCoordKey, tilesToDraw;
[z, canvasTileRange.minX, canvasTileRange.maxY],
tmpExtent));
var currentZ, index, scale, tileCoordKey, tileExtent, tileState, tilesToDraw;
var ix, iy, interimTileRange, maxX, maxY;
var height, width;
for (i = 0, ii = zs.length; i < ii; ++i) { for (i = 0, ii = zs.length; i < ii; ++i) {
currentZ = zs[i]; currentZ = zs[i];
tilePixelSize =
tileSource.getTilePixelSize(currentZ, pixelRatio, projection);
tilesToDraw = tilesToDrawByZ[currentZ]; tilesToDraw = tilesToDrawByZ[currentZ];
if (currentZ == z) { for (tileCoordKey in tilesToDraw) {
for (tileCoordKey in tilesToDraw) { tile = tilesToDraw[tileCoordKey];
tile = tilesToDraw[tileCoordKey]; if (tile.getState() == ol.TileState.LOADED) {
index = renderables.push(tile);
(tile.tileCoord[2] - canvasTileRange.minY) * canvasTileRangeWidth +
(tile.tileCoord[1] - canvasTileRange.minX);
if (this.renderedTiles_[index] != tile) {
x = tilePixelSize[0] * (tile.tileCoord[1] - canvasTileRange.minX);
y = tilePixelSize[1] * (canvasTileRange.maxY - tile.tileCoord[2]);
tileState = tile.getState();
if (tileState == ol.TileState.EMPTY ||
(tileState == ol.TileState.ERROR && !useInterimTilesOnError) ||
!opaque) {
context.clearRect(x, y, tilePixelSize[0], tilePixelSize[1]);
}
if (tileState == ol.TileState.LOADED) {
context.drawImage(tile.getImage(),
tileGutter, tileGutter, tilePixelSize[0], tilePixelSize[1],
x, y, tilePixelSize[0], tilePixelSize[1]);
}
this.renderedTiles_[index] = tile;
}
}
} else {
scale = tileGrid.getResolution(currentZ) / tileResolution;
for (tileCoordKey in tilesToDraw) {
tile = tilesToDraw[tileCoordKey];
tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent);
x = (tileExtent[0] - origin[0]) / tilePixelResolution;
y = (origin[1] - tileExtent[3]) / tilePixelResolution;
width = scale * tilePixelSize[0];
height = scale * tilePixelSize[1];
tileState = tile.getState();
if (tileState == ol.TileState.EMPTY || !opaque) {
context.clearRect(x, y, width, height);
}
if (tileState == ol.TileState.LOADED) {
context.drawImage(tile.getImage(),
tileGutter, tileGutter, tilePixelSize[0], tilePixelSize[1],
x, y, width, height);
}
interimTileRange =
tileGrid.getTileRangeForExtentAndZ(tileExtent, z, tmpTileRange);
minX = Math.max(interimTileRange.minX, canvasTileRange.minX);
maxX = Math.min(interimTileRange.maxX, canvasTileRange.maxX);
minY = Math.max(interimTileRange.minY, canvasTileRange.minY);
maxY = Math.min(interimTileRange.maxY, canvasTileRange.maxY);
for (ix = minX; ix <= maxX; ++ix) {
for (iy = minY; iy <= maxY; ++iy) {
index = (iy - canvasTileRange.minY) * canvasTileRangeWidth +
(ix - canvasTileRange.minX);
this.renderedTiles_[index] = undefined;
}
}
} }
} }
} }
this.renderedTiles_ = renderables;
if (!tileSource.getOpaque(projection)) {
var clipExtents = {};
var tileCoord;
for (i = renderables.length - 1; i >= 0; --i) {
tileCoord = renderables[i].getTileCoord();
tileGrid.forEachTileCoordParentTileRange(tileCoord,
function(z, tileRange) {
var tiles = tilesToDrawByZ[z];
if (tiles) {
var key, tile;
for (key in tiles) {
tile = tiles[key];
if (tileRange.contains(tile.getTileCoord()) &&
tile.getState() == ol.TileState.LOADED) {
if (!(key in clipExtents)) {
clipExtents[key] = [];
}
clipExtents[key].push(tileGrid.getTileCoordExtent(tileCoord));
return true;
}
}
}
return false;
}, this, tmpTileRange, tmpExtent);
}
this.clipExtents_ = clipExtents;
}
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio, this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio,
@@ -439,16 +300,6 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layer
this.scheduleExpireCache(frameState, tileSource); this.scheduleExpireCache(frameState, tileSource);
this.updateLogos(frameState, tileSource); this.updateLogos(frameState, tileSource);
ol.vec.Mat4.makeTransform2D(this.imageTransform_,
pixelRatio * frameState.size[0] / 2,
pixelRatio * frameState.size[1] / 2,
pixelRatio * tilePixelResolution / viewState.resolution,
pixelRatio * tilePixelResolution / viewState.resolution,
viewState.rotation,
(origin[0] - center[0]) / tilePixelResolution,
(center[1] - origin[1]) / tilePixelResolution);
this.imageTransformInv_ = null;
return true; return true;
}; };
@@ -456,21 +307,16 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layer
/** /**
* @inheritDoc * @inheritDoc
*/ */
ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) { ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function(
if (!this.context_) { pixel, frameState, callback, thisArg) {
return undefined; var canvas = this.context_.canvas;
} var size = frameState.size;
canvas.width = size[0];
if (!this.imageTransformInv_) { canvas.height = size[1];
this.imageTransformInv_ = goog.vec.Mat4.createNumber(); this.composeFrame(frameState, this.getLayer().getLayerState(), this.context_);
goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_);
}
var pixelOnCanvas =
this.getPixelOnCanvas(pixel, this.imageTransformInv_);
var imageData = this.context_.getImageData( var imageData = this.context_.getImageData(
pixelOnCanvas[0], pixelOnCanvas[1], 1, 1).data; pixel[0], pixel[1], 1, 1).data;
if (imageData[3] > 0) { if (imageData[3] > 0) {
return callback.call(thisArg, this.getLayer()); return callback.call(thisArg, this.getLayer());
@@ -7,6 +7,7 @@ goog.require('ol.dom');
goog.require('ol.extent'); goog.require('ol.extent');
goog.require('ol.layer.Vector'); goog.require('ol.layer.Vector');
goog.require('ol.render.EventType'); goog.require('ol.render.EventType');
goog.require('ol.render.canvas');
goog.require('ol.render.canvas.ReplayGroup'); goog.require('ol.render.canvas.ReplayGroup');
goog.require('ol.renderer.canvas.Layer'); goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.vector'); goog.require('ol.renderer.vector');
@@ -106,6 +107,10 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
var alpha = replayContext.globalAlpha; var alpha = replayContext.globalAlpha;
replayContext.globalAlpha = layerState.opacity; replayContext.globalAlpha = layerState.opacity;
var width = frameState.size[0] * pixelRatio;
var height = frameState.size[1] * pixelRatio;
ol.render.canvas.rotateAtOffset(replayContext, -rotation,
width / 2, height / 2);
replayGroup.replay(replayContext, pixelRatio, transform, rotation, replayGroup.replay(replayContext, pixelRatio, transform, rotation,
skippedFeatureUids); skippedFeatureUids);
if (vectorSource.getWrapX() && projection.canWrapX() && if (vectorSource.getWrapX() && projection.canWrapX() &&
@@ -135,6 +140,8 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
// restore original transform for render and compose events // restore original transform for render and compose events
transform = this.getTransform(frameState, 0); transform = this.getTransform(frameState, 0);
} }
ol.render.canvas.rotateAtOffset(replayContext, rotation,
width / 2, height / 2);
if (replayContext != context) { if (replayContext != context) {
this.dispatchRenderEvent(replayContext, frameState, transform); this.dispatchRenderEvent(replayContext, frameState, transform);
@@ -183,12 +183,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function(frameState,
0, 0, pixelScale, -pixelScale, 0, -center[0], -center[1]); 0, 0, pixelScale, -pixelScale, 0, -center[0], -center[1]);
insertPoint = ol.geom.flat.transform.transform2D( insertPoint = ol.geom.flat.transform.transform2D(
ol.extent.getTopLeft(tileExtent), 0, 1, 2, insertTransform); ol.extent.getTopLeft(tileExtent), 0, 1, 2, insertTransform);
replayContext.translate(offsetX, offsetY);
replayContext.rotate(rotation);
replayContext.drawImage(tileContext.canvas, replayContext.drawImage(tileContext.canvas,
Math.round(insertPoint[0]), Math.round(insertPoint[1])); Math.round(insertPoint[0] + offsetX),
replayContext.rotate(-rotation); Math.round(insertPoint[1]) + offsetY);
replayContext.translate(-offsetX, -offsetY);
} }
} }
+1 -1
View File
@@ -94,7 +94,7 @@ ol.renderer.dom.TileLayer.prototype.prepareFrame = function(frameState, layerSta
'layer is an instance of ol.layer.Tile'); 'layer is an instance of ol.layer.Tile');
var tileSource = tileLayer.getSource(); var tileSource = tileLayer.getSource();
var tileGrid = tileSource.getTileGridForProjection(projection); var tileGrid = tileSource.getTileGridForProjection(projection);
var tileGutter = tileSource.getGutter(); var tileGutter = tileSource.getGutter(projection);
var z = tileGrid.getZForResolution(viewState.resolution); var z = tileGrid.getZForResolution(viewState.resolution);
var tileResolution = tileGrid.getResolution(z); var tileResolution = tileGrid.getResolution(z);
var center = viewState.center; var center = viewState.center;
@@ -169,7 +169,7 @@ ol.renderer.webgl.TileLayer.prototype.prepareFrame = function(frameState, layerS
var pixelRatio = tilePixelSize[0] / var pixelRatio = tilePixelSize[0] /
ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0]; ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0];
var tilePixelResolution = tileResolution / pixelRatio; var tilePixelResolution = tileResolution / pixelRatio;
var tileGutter = tileSource.getGutter(); var tileGutter = tileSource.getGutter(projection);
var center = viewState.center; var center = viewState.center;
var extent; var extent;
+1 -1
View File
@@ -163,7 +163,7 @@ ol.reproj.Image.prototype.reproject_ = function() {
this.targetResolution_, this.targetExtent_, this.triangulation_, [{ this.targetResolution_, this.targetExtent_, this.triangulation_, [{
extent: this.sourceImage_.getExtent(), extent: this.sourceImage_.getExtent(),
image: this.sourceImage_.getImage() image: this.sourceImage_.getImage()
}]); }], 0);
} }
this.state = sourceState; this.state = sourceState;
this.changed(); this.changed();
+11 -7
View File
@@ -101,12 +101,13 @@ ol.reproj.enlargeClipPoint_ = function(centroidX, centroidY, x, y) {
* @param {Array.<{extent: ol.Extent, * @param {Array.<{extent: ol.Extent,
* image: (HTMLCanvasElement|Image|HTMLVideoElement)}>} sources * image: (HTMLCanvasElement|Image|HTMLVideoElement)}>} sources
* Array of sources. * Array of sources.
* @param {number} gutter Gutter of the sources.
* @param {boolean=} opt_renderEdges Render reprojection edges. * @param {boolean=} opt_renderEdges Render reprojection edges.
* @return {HTMLCanvasElement} Canvas with reprojected data. * @return {HTMLCanvasElement} Canvas with reprojected data.
*/ */
ol.reproj.render = function(width, height, pixelRatio, ol.reproj.render = function(width, height, pixelRatio,
sourceResolution, sourceExtent, targetResolution, targetExtent, sourceResolution, sourceExtent, targetResolution, targetExtent,
triangulation, sources, opt_renderEdges) { triangulation, sources, gutter, opt_renderEdges) {
var context = ol.dom.createCanvasContext2D(Math.round(pixelRatio * width), var context = ol.dom.createCanvasContext2D(Math.round(pixelRatio * width),
Math.round(pixelRatio * height)); Math.round(pixelRatio * height));
@@ -128,17 +129,20 @@ ol.reproj.render = function(width, height, pixelRatio,
Math.round(pixelRatio * canvasWidthInUnits / sourceResolution), Math.round(pixelRatio * canvasWidthInUnits / sourceResolution),
Math.round(pixelRatio * canvasHeightInUnits / sourceResolution)); Math.round(pixelRatio * canvasHeightInUnits / sourceResolution));
stitchContext.scale(pixelRatio / sourceResolution, var stitchScale = pixelRatio / sourceResolution;
pixelRatio / sourceResolution);
stitchContext.translate(-sourceDataExtent[0], sourceDataExtent[3]);
sources.forEach(function(src, i, arr) { sources.forEach(function(src, i, arr) {
var xPos = src.extent[0]; var xPos = src.extent[0] - sourceDataExtent[0];
var yPos = -src.extent[3]; var yPos = -(src.extent[3] - sourceDataExtent[3]);
var srcWidth = ol.extent.getWidth(src.extent); var srcWidth = ol.extent.getWidth(src.extent);
var srcHeight = ol.extent.getHeight(src.extent); var srcHeight = ol.extent.getHeight(src.extent);
stitchContext.drawImage(src.image, xPos, yPos, srcWidth, srcHeight); stitchContext.drawImage(
src.image,
gutter, gutter,
src.image.width - 2 * gutter, src.image.height - 2 * gutter,
xPos * stitchScale, yPos * stitchScale,
srcWidth * stitchScale, srcHeight * stitchScale);
}); });
var targetTopLeft = ol.extent.getTopLeft(targetExtent); var targetTopLeft = ol.extent.getTopLeft(targetExtent);
+9 -2
View File
@@ -35,6 +35,7 @@ ol.reproj.TileFunctionType;
* @param {ol.TileCoord} tileCoord Coordinate of the tile. * @param {ol.TileCoord} tileCoord Coordinate of the tile.
* @param {ol.TileCoord} wrappedTileCoord Coordinate of the tile wrapped in X. * @param {ol.TileCoord} wrappedTileCoord Coordinate of the tile wrapped in X.
* @param {number} pixelRatio Pixel ratio. * @param {number} pixelRatio Pixel ratio.
* @param {number} gutter Gutter of the source tiles.
* @param {ol.reproj.TileFunctionType} getTileFunction * @param {ol.reproj.TileFunctionType} getTileFunction
* Function returning source tiles (z, x, y, pixelRatio). * Function returning source tiles (z, x, y, pixelRatio).
* @param {number=} opt_errorThreshold Acceptable reprojection error (in px). * @param {number=} opt_errorThreshold Acceptable reprojection error (in px).
@@ -42,7 +43,7 @@ ol.reproj.TileFunctionType;
*/ */
ol.reproj.Tile = function(sourceProj, sourceTileGrid, ol.reproj.Tile = function(sourceProj, sourceTileGrid,
targetProj, targetTileGrid, tileCoord, wrappedTileCoord, targetProj, targetTileGrid, tileCoord, wrappedTileCoord,
pixelRatio, getTileFunction, pixelRatio, gutter, getTileFunction,
opt_errorThreshold, opt_errorThreshold,
opt_renderEdges) { opt_renderEdges) {
goog.base(this, tileCoord, ol.TileState.IDLE); goog.base(this, tileCoord, ol.TileState.IDLE);
@@ -59,6 +60,12 @@ ol.reproj.Tile = function(sourceProj, sourceTileGrid,
*/ */
this.pixelRatio_ = pixelRatio; this.pixelRatio_ = pixelRatio;
/**
* @private
* @type {number}
*/
this.gutter_ = gutter;
/** /**
* @private * @private
* @type {HTMLCanvasElement} * @type {HTMLCanvasElement}
@@ -269,7 +276,7 @@ ol.reproj.Tile.prototype.reproject_ = function() {
this.canvas_ = ol.reproj.render(width, height, this.pixelRatio_, this.canvas_ = ol.reproj.render(width, height, this.pixelRatio_,
sourceResolution, this.sourceTileGrid_.getExtent(), sourceResolution, this.sourceTileGrid_.getExtent(),
targetResolution, targetExtent, this.triangulation_, sources, targetResolution, targetExtent, this.triangulation_, sources,
this.renderEdges_); this.gutter_, this.renderEdges_);
this.state = ol.TileState.LOADED; this.state = ol.TileState.LOADED;
} }
+8 -27
View File
@@ -344,39 +344,20 @@ ol.source.Raster.prototype.onWorkerComplete_ = function(frameState, callback, er
*/ */
ol.source.Raster.getImageData_ = function(renderer, frameState, layerState) { ol.source.Raster.getImageData_ = function(renderer, frameState, layerState) {
renderer.prepareFrame(frameState, layerState); renderer.prepareFrame(frameState, layerState);
// We should be able to call renderer.composeFrame(), but this is inefficient
// for tiled sources (we've already rendered to an intermediate canvas in the
// prepareFrame call and we don't need to render again to the output canvas).
// TODO: make all canvas renderers render to a single canvas
var image = renderer.getImage();
if (!image) {
return null;
}
var imageTransform = renderer.getImageTransform();
var dx = Math.round(goog.vec.Mat4.getElement(imageTransform, 0, 3));
var dy = Math.round(goog.vec.Mat4.getElement(imageTransform, 1, 3));
var width = frameState.size[0]; var width = frameState.size[0];
var height = frameState.size[1]; var height = frameState.size[1];
if (image instanceof Image) { if (!ol.source.Raster.context_) {
if (!ol.source.Raster.context_) { ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
} else {
var canvas = ol.source.Raster.context_.canvas;
if (canvas.width !== width || canvas.height !== height) {
ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height); ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
} else { } else {
var canvas = ol.source.Raster.context_.canvas; ol.source.Raster.context_.clearRect(0, 0, width, height);
if (canvas.width !== width || canvas.height !== height) {
ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
} else {
ol.source.Raster.context_.clearRect(0, 0, width, height);
}
} }
var dw = Math.round(
image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0));
var dh = Math.round(
image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1));
ol.source.Raster.context_.drawImage(image, dx, dy, dw, dh);
return ol.source.Raster.context_.getImageData(0, 0, width, height);
} else {
return image.getContext('2d').getImageData(-dx, -dy, width, height);
} }
renderer.composeFrame(frameState, layerState, ol.source.Raster.context_);
return ol.source.Raster.context_.getImageData(0, 0, width, height);
}; };
+24
View File
@@ -120,6 +120,29 @@ ol.source.TileImage.prototype.expireCache = function(projection, usedTiles) {
}; };
/**
* @inheritDoc
*/
ol.source.TileImage.prototype.getGutter = function(projection) {
if (ol.ENABLE_RASTER_REPROJECTION &&
this.getProjection() && projection &&
!ol.proj.equivalent(this.getProjection(), projection)) {
return 0;
} else {
return this.getGutterInternal();
}
};
/**
* @protected
* @return {number} Gutter.
*/
ol.source.TileImage.prototype.getGutterInternal = function() {
return 0;
};
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -230,6 +253,7 @@ ol.source.TileImage.prototype.getTile = function(z, x, y, pixelRatio, projection
sourceProjection, sourceTileGrid, sourceProjection, sourceTileGrid,
projection, targetTileGrid, projection, targetTileGrid,
tileCoord, wrappedTileCoord, this.getTilePixelRatio(pixelRatio), tileCoord, wrappedTileCoord, this.getTilePixelRatio(pixelRatio),
this.getGutterInternal(),
function(z, x, y, pixelRatio) { function(z, x, y, pixelRatio) {
return this.getTileInternal(z, x, y, pixelRatio, sourceProjection); return this.getTileInternal(z, x, y, pixelRatio, sourceProjection);
}.bind(this), this.reprojectionErrorThreshold_, }.bind(this), this.reprojectionErrorThreshold_,
+2 -1
View File
@@ -147,9 +147,10 @@ ol.source.Tile.prototype.forEachLoadedTile = function(projection, z, tileRange,
/** /**
* @param {ol.proj.Projection} projection Projection.
* @return {number} Gutter. * @return {number} Gutter.
*/ */
ol.source.Tile.prototype.getGutter = function() { ol.source.Tile.prototype.getGutter = function(projection) {
return 0; return 0;
}; };
+1 -1
View File
@@ -177,7 +177,7 @@ ol.source.TileWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resoluti
/** /**
* @inheritDoc * @inheritDoc
*/ */
ol.source.TileWMS.prototype.getGutter = function() { ol.source.TileWMS.prototype.getGutterInternal = function() {
return this.gutter_; return this.gutter_;
}; };
@@ -25,8 +25,7 @@ describe('ol.control.ZoomSlider', function() {
describe('DOM creation', function() { describe('DOM creation', function() {
it('creates the expected DOM elements', function() { it('creates the expected DOM elements', function() {
var zoomSliderContainers = goog.dom.getElementsByClass( var zoomSliderContainers = target.querySelectorAll('.ol-zoomslider');
'ol-zoomslider', target);
expect(zoomSliderContainers.length).to.be(1); expect(zoomSliderContainers.length).to.be(1);
@@ -37,8 +36,7 @@ describe('ol.control.ZoomSlider', function() {
'ol-unselectable'); 'ol-unselectable');
expect(hasUnselectableCls).to.be(true); expect(hasUnselectableCls).to.be(true);
var zoomSliderThumbs = goog.dom.getElementsByClass('ol-zoomslider-thumb', var zoomSliderThumbs = zoomSliderContainer.querySelectorAll('.ol-zoomslider-thumb');
zoomSliderContainer);
expect(zoomSliderThumbs.length).to.be(1); expect(zoomSliderThumbs.length).to.be(1);
var zoomSliderThumb = zoomSliderThumbs[0]; var zoomSliderThumb = zoomSliderThumbs[0];
@@ -180,7 +178,6 @@ describe('ol.control.ZoomSlider', function() {
goog.require('goog.Disposable'); goog.require('goog.Disposable');
goog.require('goog.dispose'); goog.require('goog.dispose');
goog.require('goog.dom');
goog.require('goog.dom.classlist'); goog.require('goog.dom.classlist');
goog.require('goog.math.Rect'); goog.require('goog.math.Rect');
goog.require('ol.Map'); goog.require('ol.Map');
+1 -2
View File
@@ -3,7 +3,7 @@ goog.provide('ol.test.format.GML');
var readGeometry = function(format, text, opt_options) { var readGeometry = function(format, text, opt_options) {
var doc = ol.xml.parse(text); var doc = ol.xml.parse(text);
// we need an intermediate node for testing purposes // we need an intermediate node for testing purposes
var node = goog.dom.createElement('PRE'); var node = document.createElement('PRE');
node.appendChild(doc.documentElement); node.appendChild(doc.documentElement);
return format.readGeometryFromNode(node, opt_options); return format.readGeometryFromNode(node, opt_options);
}; };
@@ -1256,7 +1256,6 @@ describe('ol.format.GML3', function() {
}); });
goog.require('goog.dom');
goog.require('ol.format.GML'); goog.require('ol.format.GML');
goog.require('ol.format.GML2'); goog.require('ol.format.GML2');
goog.require('ol.format.GML3'); goog.require('ol.format.GML3');
+27
View File
@@ -328,6 +328,33 @@ describe('ol.format.WFS', function() {
}); });
}); });
describe('when writing out a Transaction request', function() {
it('does not create an update if no fid', function() {
var format = new ol.format.WFS();
var updateFeature = new ol.Feature();
updateFeature.setGeometryName('the_geom');
updateFeature.setGeometry(new ol.geom.MultiLineString([[
[-12279454, 6741885],
[-12064207, 6732101],
[-11941908, 6595126],
[-12240318, 6507071],
[-12416429, 6604910]
]]));
var error = false;
try {
format.writeTransaction(null, [updateFeature], null, {
featureNS: 'http://foo',
featureType: 'FAULTS',
featurePrefix: 'foo',
gmlOptions: {srsName: 'EPSG:900913'}
});
} catch (e) {
error = true;
}
expect(error).to.be(true);
});
});
describe('when writing out a Transaction request', function() { describe('when writing out a Transaction request', function() {
var text, filename = 'spec/ol/format/wfs/TransactionUpdateMultiGeoms.xml'; var text, filename = 'spec/ol/format/wfs/TransactionUpdateMultiGeoms.xml';
+1 -2
View File
@@ -11,7 +11,7 @@ describe('ol.MapBrowserEventHandler', function() {
beforeEach(function() { beforeEach(function() {
clock = sinon.useFakeTimers(); clock = sinon.useFakeTimers();
target = goog.dom.createElement('DIV'); target = document.createElement('DIV');
handler = new ol.MapBrowserEventHandler(new ol.Map({ handler = new ol.MapBrowserEventHandler(new ol.Map({
target: target target: target
})); }));
@@ -111,7 +111,6 @@ describe('ol.MapBrowserEventHandler', function() {
}); });
}); });
goog.require('goog.dom');
goog.require('ol.events'); goog.require('ol.events');
goog.require('ol.Map'); goog.require('ol.Map');
goog.require('ol.MapBrowserEventHandler'); goog.require('ol.MapBrowserEventHandler');
+25
View File
@@ -0,0 +1,25 @@
goog.provide('ol.test.render.canvas');
describe('ol.render.canvas', function() {
describe('rotateAtOffset', function() {
it('rotates a canvas at an offset point', function() {
var context = {
translate: sinon.spy(),
rotate: sinon.spy()
};
ol.render.canvas.rotateAtOffset(context, Math.PI, 10, 10);
expect(context.translate.callCount).to.be(2);
expect(context.translate.firstCall.args).to.eql([10, 10]);
expect(context.translate.secondCall.args).to.eql([-10, -10]);
expect(context.rotate.callCount).to.be(1);
expect(context.rotate.firstCall.args).to.eql([Math.PI]);
});
});
});
goog.require('ol.render');
goog.require('ol.render.canvas');
@@ -0,0 +1,68 @@
goog.provide('ol.test.renderer.canvas.Layer');
describe('ol.renderer.canvas.Layer', function() {
describe('#composeFrame()', function() {
it('clips to layer extent and draws image', function() {
var layer = new ol.layer.Image({
extent: [1, 2, 3, 4]
});
var renderer = new ol.renderer.canvas.Layer(layer);
var image = new Image();
image.width = 3;
image.height = 3;
renderer.getImage = function() {
return image;
};
var frameState = {
viewState: {
center: [2, 3],
resolution: 1,
rotation: 0
},
size: [10, 10],
pixelRatio: 1,
coordinateToPixelMatrix: goog.vec.Mat4.createNumber(),
pixelToCoordinateMatrix: goog.vec.Mat4.createNumber()
};
renderer.getImageTransform = function() {
return goog.vec.Mat4.createNumberIdentity();
}
ol.renderer.Map.prototype.calculateMatrices2D(frameState);
var layerState = layer.getLayerState();
var context = {
save: sinon.spy(),
restore: sinon.spy(),
translate: sinon.spy(),
rotate: sinon.spy(),
beginPath: sinon.spy(),
moveTo: sinon.spy(),
lineTo: sinon.spy(),
clip: sinon.spy(),
drawImage: sinon.spy()
}
renderer.composeFrame(frameState, layerState, context);
expect(context.save.callCount).to.be(1);
expect(context.translate.callCount).to.be(0);
expect(context.rotate.callCount).to.be(0);
expect(context.beginPath.callCount).to.be(1);
expect(context.moveTo.firstCall.args).to.eql([4, 4]);
expect(context.lineTo.firstCall.args).to.eql([6, 4]);
expect(context.lineTo.secondCall.args).to.eql([6, 6]);
expect(context.lineTo.thirdCall.args).to.eql([4, 6]);
expect(context.clip.callCount).to.be(1);
expect(context.drawImage.firstCall.args).to.eql(
[renderer.getImage(), 0, 0, 3, 3, 0, 0, 3, 3]);
expect(context.restore.callCount).to.be(1);
});
});
});
goog.require('ol.render.canvas');
goog.require('goog.vec.Mat4');
goog.require('ol.layer.Image');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.canvas.Layer');
+3 -3
View File
@@ -21,7 +21,7 @@ describe('ol.reproj.Tile', function() {
return new ol.reproj.Tile( return new ol.reproj.Tile(
proj3857, ol.tilegrid.createForProjection(proj3857), proj4326, proj3857, ol.tilegrid.createForProjection(proj3857), proj4326,
ol.tilegrid.createForProjection(proj4326, 3, opt_tileSize), ol.tilegrid.createForProjection(proj4326, 3, opt_tileSize),
[3, 2, -2], null, pixelRatio, function(z, x, y, pixelRatio) { [3, 2, -2], null, pixelRatio, 0, function(z, x, y, pixelRatio) {
return new ol.ImageTile([z, x, y], ol.TileState.IDLE, return new ol.ImageTile([z, x, y], ol.TileState.IDLE,
'data:image/gif;base64,' + 'data:image/gif;base64,' +
'R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=', null, 'R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=', null,
@@ -48,7 +48,7 @@ describe('ol.reproj.Tile', function() {
var tile = new ol.reproj.Tile( var tile = new ol.reproj.Tile(
proj3857, ol.tilegrid.createForProjection(proj3857), proj3857, ol.tilegrid.createForProjection(proj3857),
proj4326, ol.tilegrid.createForProjection(proj4326), proj4326, ol.tilegrid.createForProjection(proj4326),
[0, -1, 0], null, 1, function() { [0, -1, 0], null, 1, 0, function() {
expect().fail('No tiles should be required'); expect().fail('No tiles should be required');
}); });
expect(tile.getState()).to.be(ol.TileState.EMPTY); expect(tile.getState()).to.be(ol.TileState.EMPTY);
@@ -60,7 +60,7 @@ describe('ol.reproj.Tile', function() {
var tile = new ol.reproj.Tile( var tile = new ol.reproj.Tile(
proj27700, ol.tilegrid.createForProjection(proj27700), proj27700, ol.tilegrid.createForProjection(proj27700),
proj4326, ol.tilegrid.createForProjection(proj4326), proj4326, ol.tilegrid.createForProjection(proj4326),
[3, 2, -2], null, 1, function() { [3, 2, -2], null, 1, 0, function() {
expect().fail('No tiles should be required'); expect().fail('No tiles should be required');
}); });
expect(tile.getState()).to.be(ol.TileState.EMPTY); expect(tile.getState()).to.be(ol.TileState.EMPTY);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

+1 -1
View File
@@ -78,7 +78,7 @@ describe('ol.rendering.Map', function() {
map.getView().setRotation(90); map.getView().setRotation(90);
map.getView().setCenter([10, 10]); map.getView().setCenter([10, 10]);
expectResemble( expectResemble(
map, 'spec/ol/expected/rotate-canvas.png', IMAGE_TOLERANCE, done); map, 'spec/ol/expected/rotate-canvas.png', 2.8, done);
}); });
it('tests the WebGL renderer', function(done) { it('tests the WebGL renderer', function(done) {
+2 -1
View File
@@ -5,12 +5,13 @@ describe('ol.rendering.reproj.Tile', function() {
function testSingleTile(source, targetProjection, targetTileGrid, z, x, y, function testSingleTile(source, targetProjection, targetTileGrid, z, x, y,
pixelRatio, expectedUrl, expectedRequests, done) { pixelRatio, expectedUrl, expectedRequests, done) {
var sourceProjection = source.getProjection(); var sourceProjection = source.getProjection();
var sourceGutter = source.getGutter(sourceProjection);
var tilesRequested = 0; var tilesRequested = 0;
var tile = new ol.reproj.Tile(sourceProjection, source.getTileGrid(), var tile = new ol.reproj.Tile(sourceProjection, source.getTileGrid(),
ol.proj.get(targetProjection), targetTileGrid, ol.proj.get(targetProjection), targetTileGrid,
[z, x, y], null, pixelRatio, [z, x, y], null, pixelRatio, sourceGutter,
function(z, x, y, pixelRatio) { function(z, x, y, pixelRatio) {
tilesRequested++; tilesRequested++;
return source.getTile(z, x, y, pixelRatio, sourceProjection); return source.getTile(z, x, y, pixelRatio, sourceProjection);