no longer rely on the transitionend event, unwanted flashes are avoid using a timer

This commit is contained in:
Éric Lemoine
2012-01-02 22:53:53 +01:00
parent aeccee865c
commit eb924c8f77
3 changed files with 38 additions and 103 deletions
+30 -4
View File
@@ -138,6 +138,14 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
*/ */
backBufferLonLat: null, backBufferLonLat: null,
/**
* Property; backBufferTimerId
* {Number} The id of the back buffer timer. This timer is used to
* delay the removal of the back buffer, thereby preventing
* flash effects caused by tile animation.
*/
backBufferTimerId: null,
/** /**
* Register a listener for a particular event with the following syntax: * Register a listener for a particular event with the following syntax:
* (code) * (code)
@@ -190,6 +198,10 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
window.clearTimeout(this.timerId); window.clearTimeout(this.timerId);
this.timerId = null; this.timerId = null;
} }
if(this.backBufferTimerId !== null) {
window.clearTimeout(this.backBufferTimerId);
this.backBufferTimerId = null;
}
}, },
/** /**
@@ -197,9 +209,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* Deconstruct the layer and clear the grid. * Deconstruct the layer and clear the grid.
*/ */
destroy: function() { destroy: function() {
this.removeBackBuffer();
this.clearGrid(); this.clearGrid();
// clearGrid should remove any back buffer from the layer,
// so no need to call removeBackBuffer here
this.grid = null; this.grid = null;
this.tileSize = null; this.tileSize = null;
@@ -530,6 +541,17 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
} }
}, },
/**
* Method: scheduleBackBufferRemoval
*/
scheduleBackBufferRemoval: function() {
if(this.backBufferTimerId !== null) {
window.clearTimeout(this.backBufferTimerId);
}
this.backBufferTimerId = window.setTimeout(
OpenLayers.Function.bind(this.removeBackBuffer, this), 800);
},
/** /**
* Method: moveByPx * Method: moveByPx
* Move the layer based on pixel vector. * Move the layer based on pixel vector.
@@ -930,8 +952,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
//if that was the last tile, then trigger a 'loadend' on the layer //if that was the last tile, then trigger a 'loadend' on the layer
if (this.numLoadingTiles == 0) { if (this.numLoadingTiles == 0) {
this.events.triggerEvent("loadend"); this.events.triggerEvent("loadend");
this.removeBackBuffer(); if(this.backBuffer) {
} // the removal of the back buffer is delayed to prevent flash
// effects due to the animation of tile displaying
this.scheduleBackBufferRemoval();
}
}
}; };
tile.events.register("loadend", this, tile.onLoadEnd); tile.events.register("loadend", this, tile.onLoadEnd);
tile.events.register("unload", this, tile.onLoadEnd); tile.events.register("unload", this, tile.onLoadEnd);
+4 -50
View File
@@ -359,27 +359,12 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
var img = this.imgDiv; var img = this.imgDiv;
OpenLayers.Event.stopObservingElement(img); OpenLayers.Event.stopObservingElement(img);
var opacity = this.layer.opacity,
tileAnimation = this.layer.map.tileAnimation;
if (OpenLayers.Tile.Image.TRANSITION && tileAnimation && opacity) {
// if the displaying of the tile is animated we delay the
// loadend event until after the end of the transition, this
// to avoid flash effects because the backbuffer is removed
// before the tile is actually displayed
OpenLayers.Event.observe(img, OpenLayers.Tile.Image.TRANSITION_END,
OpenLayers.Function.bind(this.onTransitionEnd, this)
);
}
img.style.visibility = 'inherit'; img.style.visibility = 'inherit';
img.style.opacity = opacity; img.style.opacity = this.layer.opacity;
img.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'; img.style.filter = 'alpha(opacity=' + (this.layer.opacity * 100) + ')';
if (!OpenLayers.Tile.Image.TRANSITION || !tileAnimation || !opacity) { this.isLoading = false;
this.isLoading = false; this.events.triggerEvent("loadend");
this.events.triggerEvent("loadend");
}
// IE<7 needs a reflow when the tiles are loaded because of the // IE<7 needs a reflow when the tiles are loaded because of the
// percentage based positioning. Otherwise nothing is shown // percentage based positioning. Otherwise nothing is shown
@@ -432,34 +417,3 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
CLASS_NAME: "OpenLayers.Tile.Image" CLASS_NAME: "OpenLayers.Tile.Image"
}); });
// Test for support of CSS transitions and store appropriate property names
(function() {
function testProp(props) {
var style = document.documentElement.style;
for (var i=0; i<props.length; i++) {
if(props[i] in style) {
return props[i];
}
}
return false;
}
var TRANSITION = testProp([
'transition', 'webkitTransition', 'MozTransition'
]);
var TRANSITION_END = TRANSITION === 'webkitTransition' ?
TRANSITION + 'End' : 'transitionend';
/**
* Constant: OpenLayers.Tile.Image.TRANSITION
*/
OpenLayers.Tile.Image.TRANSITION = TRANSITION;
/**
* Constant: OpenLayers.Tile.Image.TRANSITION_END
*/
OpenLayers.Tile.Image.TRANSITION_END = TRANSITION_END;
})();
+4 -49
View File
@@ -344,7 +344,7 @@
} }
function test_onImageLoad(t) { function test_onImageLoad(t) {
t.plan(12); t.plan(3);
var map = new OpenLayers.Map('map'); var map = new OpenLayers.Map('map');
var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
@@ -357,61 +357,16 @@
var log; var log;
tile.events.on({loadend: function() { log++; }}); tile.events.on({loadend: function() { log++; }});
var T = OpenLayers.Tile.Image.TRANSITION;
var TE = OpenLayers.Tile.Image.TRANSITION_END;
OpenLayers.Tile.Image.TRANSITION_END = 'transitionend';
function firstObserverName() {
var cacheID = tile.imgDiv._eventCacheID,
observers = OpenLayers.Event.observers[cacheID];
return observers && observers.length > 0 ? observers[0].name : undefined;
}
OpenLayers.Tile.Image.TRANSITION = true;
map.tileAnimation = true;
log = 0; log = 0;
tile.onImageLoad(); tile.onImageLoad();
t.eq(tile.imgDiv.style.visibility, 'inherit', t.eq(tile.imgDiv.style.visibility, 'inherit',
'[a] onImageLoad makes the image visible'); 'onImageLoad makes the image visible');
t.eq(parseFloat(tile.imgDiv.style.opacity), 0.5, t.eq(parseFloat(tile.imgDiv.style.opacity), 0.5,
'[a] onImageLoad sets the expected opacity for the image'); 'onImageLoad sets the expected opacity for the image');
t.eq(log, 0,
'[a] onImageLoad does not trigger loadend');
t.eq(firstObserverName(), 'transitionend',
'[a] onImageLoad registers a transitionend observer');
OpenLayers.Event.stopObservingElement(tile.imgDiv);
OpenLayers.Tile.Image.TRANSITION = true;
map.tileAnimation = false;
log = 0;
tile.onImageLoad();
t.eq(tile.imgDiv.style.visibility, 'inherit',
'[b] onImageLoad makes the image visible');
t.eq(parseFloat(tile.imgDiv.style.opacity), 0.5,
'[b] onImageLoad sets the expected opacity for the image');
t.eq(log, 1, t.eq(log, 1,
'[b] onImageLoad does trigger loadend'); 'onImageLoad does not trigger loadend');
t.eq(firstObserverName(), undefined,
'[b] onImageLoad does not register a transitionend observer');
OpenLayers.Event.stopObservingElement(tile.imgDiv);
OpenLayers.Tile.Image.TRANSITION = false;
map.tileAnimation = true;
log = 0;
tile.onImageLoad();
t.eq(tile.imgDiv.style.visibility, 'inherit',
'[c] onImageLoad makes the image visible');
t.eq(parseFloat(tile.imgDiv.style.opacity), 0.5,
'[c] onImageLoad sets the expected opacity for the image');
t.eq(log, 1,
'[c] onImageLoad does trigger loadend');
t.eq(firstObserverName(), undefined,
'[c] onImageLoad does not register a transitionend observer');
OpenLayers.Event.stopObservingElement(tile.imgDiv);
map.destroy(); map.destroy();
OpenLayers.Tile.Image.TRANSITION = T;
OpenLayers.Tile.Image.TRANSITION_END = TE;
} }
</script> </script>