Compare commits

...

4 Commits

Author SHA1 Message Date
Andreas Hocevar
b4c4a81afb Update package version to 3.14.1 2016-03-01 10:10:41 +01:00
Andreas Hocevar
7478e82b9a Changelog for v3.14.1 2016-03-01 10:10:06 +01:00
Andreas Hocevar
4b586df2b5 Merge pull request #4939 from ahocevar/clip-opacity
Fix rendering of opaque layers with opacity != 1
2016-03-01 10:05:07 +01:00
Andreas Hocevar
ed62203527 Merge pull request #4921 from ahocevar/unlisten-earlier-and-bind-to-target
Unlisten before calling listener and bind to target by default
2016-03-01 10:03:51 +01:00
5 changed files with 83 additions and 63 deletions

10
changelog/v3.14.1.md Normal file
View File

@@ -0,0 +1,10 @@
# v3.14.1
## Summary
The v3.14.1 release is a patch release that addresses a few regressions in the v3.14.0 release. See the [v3.14.0 release notes](https://github.com/openlayers/ol3/releases/tag/v3.14.0) for details on upgrading from v3.13.x.
## Fixes
* [#4939](https://github.com/openlayers/ol3/pull/4939) - Fix rendering of opaque layers with opacity != 1 ([@ahocevar](https://github.com/ahocevar))
* [#4921](https://github.com/openlayers/ol3/pull/4921) - Unlisten before calling listener and bind to target by default ([@ahocevar](https://github.com/ahocevar))

View File

@@ -1,6 +1,6 @@
{ {
"name": "openlayers", "name": "openlayers",
"version": "3.14.0", "version": "3.14.1",
"description": "Build tools and sources for developing OpenLayers based mapping applications", "description": "Build tools and sources for developing OpenLayers based mapping applications",
"keywords": [ "keywords": [
"map", "map",

View File

@@ -107,11 +107,12 @@ ol.events.ListenerObjType;
*/ */
ol.events.bindListener_ = function(listenerObj) { ol.events.bindListener_ = function(listenerObj) {
var boundListener = function(evt) { var boundListener = function(evt) {
var rv = listenerObj.listener.call(listenerObj.bindTo, evt); var listener = listenerObj.listener;
var bindTo = listenerObj.bindTo || listenerObj.target;
if (listenerObj.callOnce) { if (listenerObj.callOnce) {
ol.events.unlistenByKey(listenerObj); ol.events.unlistenByKey(listenerObj);
} }
return rv; return listener.call(bindTo, evt);
} }
listenerObj.boundListener = boundListener; listenerObj.boundListener = boundListener;
return boundListener; return boundListener;

View File

@@ -9,6 +9,7 @@ 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.object');
goog.require('ol.render.EventType'); goog.require('ol.render.EventType');
goog.require('ol.renderer.canvas.Layer'); goog.require('ol.renderer.canvas.Layer');
goog.require('ol.source.Tile'); goog.require('ol.source.Tile');
@@ -25,9 +26,9 @@ ol.renderer.canvas.TileLayer = function(tileLayer) {
/** /**
* @private * @private
* @type {Object.<string, Array.<ol.Extent>>} * @type {!Object.<string, Array.<ol.TileCoord>>}
*/ */
this.clipExtents_ = null; this.clipTileCoords_ = {};
/** /**
* @private * @private
@@ -68,7 +69,6 @@ ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
goog.asserts.assertInstanceof(source, ol.source.Tile, goog.asserts.assertInstanceof(source, ol.source.Tile,
'source is an ol.source.Tile'); 'source is an ol.source.Tile');
var tileGutter = source.getGutter(projection); var tileGutter = source.getGutter(projection);
var opaque = source.getOpaque(projection);
var transform = this.getTransform(frameState, 0); var transform = this.getTransform(frameState, 0);
@@ -95,60 +95,60 @@ ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
var tileGrid = source.getTileGridForProjection(projection); var tileGrid = source.getTileGridForProjection(projection);
var tilesToDraw = this.renderedTiles_; var tilesToDraw = this.renderedTiles_;
var clipExtents, clipExtent, currentZ, i, ii, j, jj, insertPoint; var clipExtent, clipH, clipLeft, clipOrigin, clipTileCoord, clipTileCoords;
var origin, tile, tileExtent, tileHeight, tileOffsetX, tileOffsetY; var clipTop, clipW, currentZ, h, i, ii, j, jj, left, origin, tile, tileExtent;
var tilePixelSize, tileWidth; var tilePixelSize, top, w;
for (i = 0, ii = tilesToDraw.length; i < ii; ++i) { for (i = 0, ii = tilesToDraw.length; i < ii; ++i) {
tile = tilesToDraw[i]; tile = tilesToDraw[i];
tileExtent = tileGrid.getTileCoordExtent( tileExtent = tileGrid.getTileCoordExtent(
tile.getTileCoord(), this.tmpExtent_); tile.getTileCoord(), this.tmpExtent_);
clipExtents = !opaque && this.clipExtents_[tile.tileCoord.toString()]; currentZ = tile.getTileCoord()[0];
if (clipExtents) { // Calculate all insert points by tile widths from a common origin to avoid
// gaps caused by rounding
origin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent(
tileGrid.getTileCoordForCoordAndZ(center, currentZ)));
w = Math.round(ol.extent.getWidth(tileExtent) * pixelScale);
h = Math.round(ol.extent.getHeight(tileExtent) * pixelScale);
left = Math.round((tileExtent[0] - origin[0]) * pixelScale / w) * w +
offsetX + Math.round((origin[0] - center[0]) * pixelScale);
top = Math.round((origin[1] - tileExtent[3]) * pixelScale / h) * h +
offsetY + Math.round((center[1] - origin[1]) * pixelScale);
clipTileCoords = this.clipTileCoords_[tile.tileCoord.toString()];
if (clipTileCoords) {
// Create a clip mask for regions in this low resolution tile that will be // Create a clip mask for regions in this low resolution tile that will be
// filled by a higher resolution tile // filled by a higher resolution tile
renderContext.save(); renderContext.save();
renderContext.beginPath(); renderContext.beginPath();
renderContext.moveTo((tileExtent[0] - center[0]) * pixelScale + offsetX, // counter-clockwise (outer ring) for current tile
(center[1] - tileExtent[1]) * pixelScale + offsetY); renderContext.moveTo(left + w, top);
renderContext.lineTo((tileExtent[2] - center[0]) * pixelScale + offsetX, renderContext.lineTo(left, top);
(center[1] - tileExtent[1]) * pixelScale + offsetY); renderContext.lineTo(left, top + h);
renderContext.lineTo((tileExtent[2] - center[0]) * pixelScale + offsetX, renderContext.lineTo(left + w, top + h);
(center[1] - tileExtent[3]) * pixelScale + offsetY);
renderContext.lineTo((tileExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[3]) * pixelScale + offsetY);
renderContext.closePath(); renderContext.closePath();
for (j = 0, jj = clipExtents.length; j < jj; ++j) { // clockwise (inner rings) for lower resolution tiles
clipExtent = clipExtents[j]; for (j = 0, jj = clipTileCoords.length; j < jj; ++j) {
renderContext.moveTo((clipExtent[0] - center[0]) * pixelScale + offsetX, clipTileCoord = clipTileCoords[j];
(center[1] - clipExtent[1]) * pixelScale + offsetY); clipExtent = tileGrid.getTileCoordExtent(clipTileCoord);
renderContext.lineTo((clipExtent[0] - center[0]) * pixelScale + offsetX, clipOrigin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent(
(center[1] - clipExtent[3]) * pixelScale + offsetY); tileGrid.getTileCoordForCoordAndZ(center, clipTileCoord[0])));
renderContext.lineTo((clipExtent[2] - center[0]) * pixelScale + offsetX, clipW = Math.round(ol.extent.getWidth(clipExtent) * pixelScale);
(center[1] - clipExtent[3]) * pixelScale + offsetY); clipH = Math.round(ol.extent.getHeight(clipExtent) * pixelScale);
renderContext.lineTo((clipExtent[2] - center[0]) * pixelScale + offsetX, clipLeft = Math.round((clipExtent[0] - clipOrigin[0]) * pixelScale / clipW) * clipW +
(center[1] - clipExtent[1]) * pixelScale + offsetY); offsetX + Math.round((clipOrigin[0] - center[0]) * pixelScale);
clipTop = Math.round((clipOrigin[1] - clipExtent[3]) * pixelScale / clipH) * clipH +
offsetY + Math.round((center[1] - clipOrigin[1]) * pixelScale);
renderContext.moveTo(clipLeft, clipTop + clipH);
renderContext.lineTo(clipLeft, clipTop);
renderContext.lineTo(clipLeft + clipW, clipTop);
renderContext.lineTo(clipLeft + clipW, clipTop + clipH);
renderContext.closePath(); renderContext.closePath();
} }
renderContext.clip(); renderContext.clip();
} }
currentZ = tile.getTileCoord()[0];
tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection); 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, renderContext.drawImage(tile.getImage(), tileGutter, tileGutter,
tilePixelSize[0], tilePixelSize[1], tilePixelSize[0], tilePixelSize[1], left, top, w, h);
Math.round((insertPoint[0] - origin[0]) * pixelScale / tileWidth) * if (clipTileCoords) {
tileWidth + tileOffsetX,
Math.round((origin[1] - insertPoint[1]) * pixelScale / tileHeight) *
tileHeight + tileOffsetY, tileWidth, tileHeight);
if (clipExtents) {
renderContext.restore(); renderContext.restore();
} }
} }
@@ -266,8 +266,9 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
} }
} }
this.renderedTiles_ = renderables; this.renderedTiles_ = renderables;
if (!tileSource.getOpaque(projection)) { ol.object.clear(this.clipTileCoords_);
var clipExtents = {}; if (!(tileSource.getOpaque(projection) && layerState.opacity == 1)) {
var clipTileCoords = this.clipTileCoords_;
var tileCoord; var tileCoord;
for (i = renderables.length - 1; i >= 0; --i) { for (i = renderables.length - 1; i >= 0; --i) {
tileCoord = renderables[i].getTileCoord(); tileCoord = renderables[i].getTileCoord();
@@ -280,10 +281,10 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
tile = tiles[key]; tile = tiles[key];
if (tileRange.contains(tile.getTileCoord()) && if (tileRange.contains(tile.getTileCoord()) &&
tile.getState() == ol.TileState.LOADED) { tile.getState() == ol.TileState.LOADED) {
if (!(key in clipExtents)) { if (!(key in clipTileCoords)) {
clipExtents[key] = []; clipTileCoords[key] = [];
} }
clipExtents[key].push(tileGrid.getTileCoordExtent(tileCoord)); clipTileCoords[key].push(tileCoord);
return true; return true;
} }
} }
@@ -291,7 +292,6 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
return false; return false;
}, this, tmpTileRange, tmpExtent); }, this, tmpTileRange, tmpExtent);
} }
this.clipExtents_ = clipExtents;
} }
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);

View File

@@ -24,23 +24,32 @@ describe('ol.events', function() {
boundListener(); boundListener();
expect(listenerObj.listener.thisValues[0]).to.equal(listenerObj.bindTo); expect(listenerObj.listener.thisValues[0]).to.equal(listenerObj.bindTo);
}); });
it('binds a self-unregistering listener when callOnce is true', function() { it('binds to the target when bindTo is not provided', function() {
var bindTo = {id: 1};
var listener = sinon.spy();
target.removeEventListener = function() {};
var listenerObj = { var listenerObj = {
type: 'foo', listener: sinon.spy(),
target: target, target: {id: 1}
listener: listener,
bindTo: bindTo,
callOnce: true
}; };
var boundListener = ol.events.bindListener_(listenerObj); var boundListener = ol.events.bindListener_(listenerObj);
expect(listenerObj.boundListener).to.equal(boundListener); expect(listenerObj.boundListener).to.equal(boundListener);
var spy = sinon.spy(ol.events, 'unlistenByKey');
boundListener(); boundListener();
expect(listener.thisValues[0]).to.equal(bindTo); expect(listenerObj.listener.thisValues[0]).to.equal(listenerObj.target);
expect(spy.firstCall.args[0]).to.eql(listenerObj); });
it('binds a self-unregistering listener when callOnce is true', function() {
var bindTo = {id: 1};
var listenerObj = {
type: 'foo',
target: target,
bindTo: bindTo,
callOnce: true
};
var unlistenSpy = sinon.spy(ol.events, 'unlistenByKey');
listenerObj.listener = function() {
expect(this).to.equal(bindTo);
expect(unlistenSpy.firstCall.args[0]).to.eql(listenerObj);
}
var boundListener = ol.events.bindListener_(listenerObj);
expect(listenerObj.boundListener).to.equal(boundListener);
boundListener();
ol.events.unlistenByKey.restore(); ol.events.unlistenByKey.restore();
}); });
}); });