Merge pull request #927 from avandecreme/perf

Optimize sketch canvas clearing and blending.
This commit is contained in:
Ian Gilman 2016-04-29 10:08:47 -07:00
commit 07429f5890
4 changed files with 105 additions and 39 deletions

View File

@ -259,13 +259,17 @@ $.Drawer.prototype = {
}
},
_clear: function ( useSketch ) {
if ( !this.useCanvas ) {
_clear: function (useSketch, bounds) {
if (!this.useCanvas) {
return;
}
var context = this._getContext( useSketch );
var canvas = context.canvas;
context.clearRect( 0, 0, canvas.width, canvas.height );
var context = this._getContext(useSketch);
if (bounds) {
context.clearRect(bounds.x, bounds.y, bounds.width, bounds.height);
} else {
var canvas = context.canvas;
context.clearRect(0, 0, canvas.width, canvas.height);
}
},
/**
@ -382,47 +386,80 @@ $.Drawer.prototype = {
/**
* Blends the sketch canvas in the main canvas.
* @param {Float} opacity The opacity of the blending.
* @param {Float} [scale=1] The scale at which tiles were drawn on the sketch. Default is 1.
* Use scale to draw at a lower scale and then enlarge onto the main canvas.
* @param {OpenSeadragon.Point} [translate] A translation vector that was used to draw the tiles
* @param {String} [options.compositeOperation] - How the image is composited onto other images; see compositeOperation in {@link OpenSeadragon.Options} for possible values.
* @returns {undefined}
* @param {Object} options The options
* @param {Float} options.opacity The opacity of the blending.
* @param {Float} [options.scale=1] The scale at which tiles were drawn on
* the sketch. Default is 1.
* Use scale to draw at a lower scale and then enlarge onto the main canvas.
* @param {OpenSeadragon.Point} [options.translate] A translation vector
* that was used to draw the tiles
* @param {String} [options.compositeOperation] - How the image is
* composited onto other images; see compositeOperation in
* {@link OpenSeadragon.Options} for possible values.
* @param {OpenSeadragon.Rect} [options.bounds] The part of the sketch
* canvas to blend in the main canvas. If specified, options.scale and
* options.translate get ignored.
*/
blendSketch: function(opacity, scale, translate, compositeOperation) {
var options = opacity;
if (!$.isPlainObject(options)) {
options = {
opacity: opacity,
scale: scale,
translate: translate,
compositeOperation: compositeOperation
};
}
if (!this.useCanvas || !this.sketchCanvas) {
return;
}
scale = scale || 1;
var position = translate instanceof $.Point ?
translate :
new $.Point(0, 0);
var widthExt = 0;
var heightExt = 0;
if (translate) {
var widthDiff = this.sketchCanvas.width - this.canvas.width;
var heightDiff = this.sketchCanvas.height - this.canvas.height;
widthExt = Math.round(widthDiff / 2);
heightExt = Math.round(heightDiff / 2);
}
opacity = options.opacity;
compositeOperation = options.compositeOperation;
var bounds = options.bounds;
this.context.save();
this.context.globalAlpha = opacity;
if (compositeOperation) {
this.context.globalCompositeOperation = compositeOperation;
}
this.context.drawImage(
this.sketchCanvas,
position.x - widthExt * scale,
position.y - heightExt * scale,
(this.canvas.width + 2 * widthExt) * scale,
(this.canvas.height + 2 * heightExt) * scale,
-widthExt,
-heightExt,
this.canvas.width + 2 * widthExt,
this.canvas.height + 2 * heightExt
);
if (bounds) {
this.context.drawImage(
this.sketchCanvas,
bounds.x,
bounds.y,
bounds.width,
bounds.height,
bounds.x,
bounds.y,
bounds.width,
bounds.height
);
} else {
scale = options.scale || 1;
translate = options.translate;
var position = translate instanceof $.Point ?
translate : new $.Point(0, 0);
var widthExt = 0;
var heightExt = 0;
if (translate) {
var widthDiff = this.sketchCanvas.width - this.canvas.width;
var heightDiff = this.sketchCanvas.height - this.canvas.height;
widthExt = Math.round(widthDiff / 2);
heightExt = Math.round(heightDiff / 2);
}
this.context.drawImage(
this.sketchCanvas,
position.x - widthExt * scale,
position.y - heightExt * scale,
(this.canvas.width + 2 * widthExt) * scale,
(this.canvas.height + 2 * heightExt) * scale,
-widthExt,
-heightExt,
this.canvas.width + 2 * widthExt,
this.canvas.height + 2 * heightExt
);
}
this.context.restore();
},

View File

@ -367,6 +367,20 @@ $.Rect.prototype = {
maxY - minY);
},
/**
* Retrieves the smallest horizontal (degrees=0) rectangle which contains
* this rectangle and has integers x, y, width and height
* @returns {OpenSeadragon.Rect}
*/
getIntegerBoundingBox: function() {
var boundingBox = this.getBoundingBox();
var x = Math.floor(boundingBox.x);
var y = Math.floor(boundingBox.y);
var width = Math.ceil(boundingBox.width + boundingBox.x - x);
var height = Math.ceil(boundingBox.height + boundingBox.y - y);
return new $.Rect(x, y, width, height);
},
/**
* Provides a string representation of the rectangle which is useful for
* debugging.

View File

@ -195,7 +195,7 @@ $.Tile.prototype = {
// private
_hasTransparencyChannel: function() {
return this.context2D || this.url.match('.png');
return !!this.context2D || this.url.match('.png');
},
/**

View File

@ -1448,8 +1448,17 @@ function drawTiles( tiledImage, lastDrawn ) {
tiledImage._drawer.getCanvasSize(true));
}
if ( useSketch ) {
tiledImage._drawer._clear( true );
var bounds;
if (useSketch) {
if (!sketchScale) {
// Except when edge smoothing, we only clean the part of the
// sketch canvas we are going to use for performance reasons.
bounds = tiledImage.viewport.viewportToViewerElementRectangle(
tiledImage.getClippedBounds(true))
.getIntegerBoundingBox()
.times($.pixelDensityRatio);
}
tiledImage._drawer._clear(true, bounds);
}
// When scaling, we must rotate only when blending the sketch canvas to avoid
@ -1532,7 +1541,13 @@ function drawTiles( tiledImage, lastDrawn ) {
if (offsetForRotation) {
tiledImage._drawer._offsetForRotation(tiledImage.viewport.degrees, false);
}
tiledImage._drawer.blendSketch(tiledImage.opacity, sketchScale, sketchTranslate, tiledImage.compositeOperation);
tiledImage._drawer.blendSketch({
opacity: tiledImage.opacity,
scale: sketchScale,
translate: sketchTranslate,
compositeOperation: tiledImage.compositeOperation,
bounds: bounds
});
if (offsetForRotation) {
tiledImage._drawer._restoreRotationChanges(false);
}