mirror of
https://github.com/openseadragon/openseadragon.git
synced 2025-01-19 17:21:50 +03:00
Add opacity support.
This commit is contained in:
parent
5b64beab61
commit
44395662d1
182
src/drawer.js
182
src/drawer.js
@ -96,6 +96,13 @@ $.Drawer = function( options ) {
|
||||
*/
|
||||
this.context = this.useCanvas ? this.canvas.getContext( "2d" ) : null;
|
||||
|
||||
/**
|
||||
* Sketch canvas used to temporarily draw tiles which cannot be drawn directly
|
||||
* to the main canvas due to opacity.
|
||||
*/
|
||||
this.sketchCanvas = this.useCanvas ? document.createElement( "canvas" ) : null;
|
||||
this.sketchContext = this.useCanvas ? this.sketchCanvas.getContext( "2d" ) : null;
|
||||
|
||||
/**
|
||||
* @member {Element} element
|
||||
* @memberof OpenSeadragon.Drawer#
|
||||
@ -111,8 +118,8 @@ $.Drawer = function( options ) {
|
||||
// check canvas available width and height, set canvas width and height such that the canvas backing store is set to the proper pixel density
|
||||
if (this.useCanvas) {
|
||||
var viewportSize = this._calculateCanvasSize();
|
||||
this.canvas.width = viewportSize.x;
|
||||
this.canvas.height = viewportSize.y;
|
||||
this.canvas.width = this.sketchCanvas.width = viewportSize.x;
|
||||
this.canvas.height = this.sketchCanvas.height = viewportSize.y;
|
||||
}
|
||||
|
||||
this.canvas.style.width = "100%";
|
||||
@ -254,21 +261,23 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
* @param {OpenSeadragon.Tile} tile - The tile to draw.
|
||||
* @param {Function} drawingHandler - Method for firing the drawing event if using canvas.
|
||||
* drawingHandler({context, tile, rendered})
|
||||
* @param {Boolean} useSketch - Whether to use the sketch canvas or not.
|
||||
* where <code>rendered</code> is the context with the pre-drawn image.
|
||||
*/
|
||||
drawTile: function( tile, drawingHandler ) {
|
||||
drawTile: function( tile, drawingHandler, useSketch ) {
|
||||
$.console.assert(tile, '[Drawer.drawTile] tile is required');
|
||||
$.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');
|
||||
|
||||
if ( this.useCanvas ) {
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
// TODO do this in a more performant way
|
||||
// specifically, don't save,rotate,restore every time we draw a tile
|
||||
if( this.viewport.degrees !== 0 ) {
|
||||
this._offsetForRotation( tile, this.viewport.degrees );
|
||||
tile.drawCanvas( this.context, drawingHandler );
|
||||
this._restoreRotationChanges( tile );
|
||||
this._offsetForRotation( tile, this.viewport.degrees, useSketch );
|
||||
tile.drawCanvas( context, drawingHandler );
|
||||
this._restoreRotationChanges( tile, useSketch );
|
||||
} else {
|
||||
tile.drawCanvas( this.context, drawingHandler );
|
||||
tile.drawCanvas( context, drawingHandler );
|
||||
}
|
||||
} else {
|
||||
tile.drawHTML( this.canvas );
|
||||
@ -276,63 +285,87 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
},
|
||||
|
||||
// private
|
||||
saveContext: function() {
|
||||
saveContext: function(useSketch) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
context.save();
|
||||
},
|
||||
|
||||
// private
|
||||
restoreContext: function(useSketch) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
context.restore();
|
||||
},
|
||||
|
||||
// private
|
||||
setClip: function(rect, useSketch) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
context.beginPath();
|
||||
context.rect(rect.x, rect.y, rect.width, rect.height);
|
||||
context.clip();
|
||||
},
|
||||
|
||||
// private
|
||||
drawRectangle: function(rect, fillStyle, useSketch) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
context.save();
|
||||
context.fillStyle = fillStyle;
|
||||
context.fillRect(rect.x, rect.y, rect.width, rect.height);
|
||||
context.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* Blends the sketch canvas in the main canvas.
|
||||
* The sketch canvas is then cleared.
|
||||
* @param {Float} opacity The opacity of the blending.
|
||||
* @returns {undefined}
|
||||
*/
|
||||
blendSketch: function(opacity) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.save();
|
||||
},
|
||||
|
||||
// private
|
||||
restoreContext: function() {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.globalAlpha = opacity;
|
||||
this.context.drawImage(this.sketchCanvas, 0, 0);
|
||||
this.context.restore();
|
||||
this.sketchContext.clearRect(0, 0,
|
||||
this.sketchCanvas.width, this.sketchCanvas.height);
|
||||
},
|
||||
|
||||
// private
|
||||
setClip: function(rect) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.rect(rect.x, rect.y, rect.width, rect.height);
|
||||
this.context.clip();
|
||||
},
|
||||
|
||||
// private
|
||||
drawRectangle: function(rect, fillStyle) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.save();
|
||||
this.context.fillStyle = fillStyle;
|
||||
this.context.fillRect(rect.x, rect.y, rect.width, rect.height);
|
||||
this.context.restore();
|
||||
},
|
||||
|
||||
// private
|
||||
drawDebugInfo: function( tile, count, i ){
|
||||
drawDebugInfo: function( tile, count, i, useSketch ){
|
||||
if ( !this.useCanvas ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.save();
|
||||
this.context.lineWidth = 2 * $.pixelDensityRatio;
|
||||
this.context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';
|
||||
this.context.strokeStyle = this.debugGridColor;
|
||||
this.context.fillStyle = this.debugGridColor;
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
context.save();
|
||||
context.lineWidth = 2 * $.pixelDensityRatio;
|
||||
context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';
|
||||
context.strokeStyle = this.debugGridColor;
|
||||
context.fillStyle = this.debugGridColor;
|
||||
|
||||
if ( this.viewport.degrees !== 0 ) {
|
||||
this._offsetForRotation( tile, this.canvas, this.context, this.viewport.degrees );
|
||||
this._offsetForRotation( tile, this.viewport.degrees, useSketch );
|
||||
}
|
||||
|
||||
this.context.strokeRect(
|
||||
context.strokeRect(
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
tile.position.y * $.pixelDensityRatio,
|
||||
tile.size.x * $.pixelDensityRatio,
|
||||
@ -343,95 +376,97 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
var tileCenterY = (tile.position.y + (tile.size.y / 2)) * $.pixelDensityRatio;
|
||||
|
||||
// Rotate the text the right way around.
|
||||
this.context.translate( tileCenterX, tileCenterY );
|
||||
this.context.rotate( Math.PI / 180 * -this.viewport.degrees );
|
||||
this.context.translate( -tileCenterX, -tileCenterY );
|
||||
context.translate( tileCenterX, tileCenterY );
|
||||
context.rotate( Math.PI / 180 * -this.viewport.degrees );
|
||||
context.translate( -tileCenterX, -tileCenterY );
|
||||
|
||||
if( tile.x === 0 && tile.y === 0 ){
|
||||
this.context.fillText(
|
||||
context.fillText(
|
||||
"Zoom: " + this.viewport.getZoom(),
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
(tile.position.y - 30) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
context.fillText(
|
||||
"Pan: " + this.viewport.getBounds().toString(),
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
(tile.position.y - 20) * $.pixelDensityRatio
|
||||
);
|
||||
}
|
||||
this.context.fillText(
|
||||
context.fillText(
|
||||
"Level: " + tile.level,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 20) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
context.fillText(
|
||||
"Column: " + tile.x,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 30) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
context.fillText(
|
||||
"Row: " + tile.y,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 40) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
context.fillText(
|
||||
"Order: " + i + " of " + count,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 50) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
context.fillText(
|
||||
"Size: " + tile.size.toString(),
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 60) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
context.fillText(
|
||||
"Position: " + tile.position.toString(),
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 70) * $.pixelDensityRatio
|
||||
);
|
||||
|
||||
if ( this.viewport.degrees !== 0 ) {
|
||||
this._restoreRotationChanges( tile, this.canvas, this.context );
|
||||
this._restoreRotationChanges( tile, useSketch );
|
||||
}
|
||||
this.context.restore();
|
||||
context.restore();
|
||||
},
|
||||
|
||||
// private
|
||||
debugRect: function(rect) {
|
||||
debugRect: function(rect, useSketch) {
|
||||
if ( this.useCanvas ) {
|
||||
this.context.save();
|
||||
this.context.lineWidth = 2 * $.pixelDensityRatio;
|
||||
this.context.strokeStyle = this.debugGridColor;
|
||||
this.context.fillStyle = this.debugGridColor;
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
context.save();
|
||||
context.lineWidth = 2 * $.pixelDensityRatio;
|
||||
context.strokeStyle = this.debugGridColor;
|
||||
context.fillStyle = this.debugGridColor;
|
||||
|
||||
this.context.strokeRect(
|
||||
context.strokeRect(
|
||||
rect.x * $.pixelDensityRatio,
|
||||
rect.y * $.pixelDensityRatio,
|
||||
rect.width * $.pixelDensityRatio,
|
||||
rect.height * $.pixelDensityRatio
|
||||
);
|
||||
|
||||
this.context.restore();
|
||||
context.restore();
|
||||
}
|
||||
},
|
||||
|
||||
// private
|
||||
_offsetForRotation: function( tile, degrees ){
|
||||
_offsetForRotation: function( tile, degrees, useSketch ){
|
||||
var cx = this.canvas.width / 2,
|
||||
cy = this.canvas.height / 2,
|
||||
px = tile.position.x - cx,
|
||||
py = tile.position.y - cy;
|
||||
|
||||
this.context.save();
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
context.save();
|
||||
|
||||
this.context.translate(cx, cy);
|
||||
this.context.rotate( Math.PI / 180 * degrees);
|
||||
context.translate(cx, cy);
|
||||
context.rotate( Math.PI / 180 * degrees);
|
||||
tile.position.x = px;
|
||||
tile.position.y = py;
|
||||
},
|
||||
|
||||
// private
|
||||
_restoreRotationChanges: function( tile ){
|
||||
_restoreRotationChanges: function( tile, useSketch ){
|
||||
var cx = this.canvas.width / 2,
|
||||
cy = this.canvas.height / 2,
|
||||
px = tile.position.x + cx,
|
||||
@ -440,7 +475,8 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
tile.position.x = px;
|
||||
tile.position.y = py;
|
||||
|
||||
this.context.restore();
|
||||
var context = useSketch ? this.sketchContext : this.context;
|
||||
context.restore();
|
||||
},
|
||||
|
||||
// private
|
||||
|
@ -67,7 +67,7 @@ $.Tile = function(level, x, y, bounds, exists, url) {
|
||||
this.y = y;
|
||||
/**
|
||||
* Where this tile fits, in normalized coordinates
|
||||
* @member {OpenSeadragon.Point} bounds
|
||||
* @member {OpenSeadragon.Rect} bounds
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.bounds = bounds;
|
||||
|
@ -119,6 +119,12 @@ $.TiledImage = function( options ) {
|
||||
delete options.height;
|
||||
}
|
||||
|
||||
this.opacity = 1;
|
||||
if ( options.opacity ) {
|
||||
this.opacity = options.opacity;
|
||||
delete options.opacity;
|
||||
}
|
||||
|
||||
$.extend( true, this, {
|
||||
|
||||
//internal state properties
|
||||
@ -1152,20 +1158,20 @@ function compareTiles( previousBest, tile ) {
|
||||
|
||||
function drawTiles( tiledImage, lastDrawn ) {
|
||||
var i,
|
||||
tile,
|
||||
tileKey,
|
||||
viewer,
|
||||
viewport,
|
||||
position,
|
||||
tileSource;
|
||||
tile;
|
||||
|
||||
if ( tiledImage.opacity <= 0 ) {
|
||||
return;
|
||||
}
|
||||
var useSketch = tiledImage.opacity < 1;
|
||||
|
||||
var usedClip = false;
|
||||
if ( tiledImage._clip ) {
|
||||
tiledImage._drawer.saveContext();
|
||||
tiledImage._drawer.saveContext(useSketch);
|
||||
|
||||
var box = tiledImage.imageToViewportRectangle(tiledImage._clip, true);
|
||||
var clipRect = tiledImage._drawer.viewportToDrawerRectangle(box);
|
||||
tiledImage._drawer.setClip(clipRect);
|
||||
tiledImage._drawer.setClip(clipRect, useSketch);
|
||||
|
||||
usedClip = true;
|
||||
}
|
||||
@ -1181,17 +1187,17 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
fillStyle = tiledImage.placeholderFillStyle;
|
||||
}
|
||||
|
||||
tiledImage._drawer.drawRectangle(placeholderRect, fillStyle);
|
||||
tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch);
|
||||
}
|
||||
|
||||
for ( i = lastDrawn.length - 1; i >= 0; i-- ) {
|
||||
tile = lastDrawn[ i ];
|
||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler );
|
||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch );
|
||||
tile.beingDrawn = true;
|
||||
|
||||
if( tiledImage.debugMode ) {
|
||||
try {
|
||||
tiledImage._drawer.drawDebugInfo( tile, lastDrawn.length, i );
|
||||
tiledImage._drawer.drawDebugInfo( tile, lastDrawn.length, i, useSketch );
|
||||
} catch(e) {
|
||||
$.console.error(e);
|
||||
}
|
||||
@ -1217,7 +1223,11 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
}
|
||||
|
||||
if ( usedClip ) {
|
||||
tiledImage._drawer.restoreContext();
|
||||
tiledImage._drawer.restoreContext( useSketch );
|
||||
}
|
||||
|
||||
if ( useSketch ) {
|
||||
tiledImage._drawer.blendSketch( tiledImage.opacity );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1290,6 +1290,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
height: queueItem.options.height,
|
||||
clip: queueItem.options.clip,
|
||||
placeholderFillStyle: queueItem.options.placeholderFillStyle,
|
||||
opacity: queueItem.options.opacity,
|
||||
springStiffness: _this.springStiffness,
|
||||
animationTime: _this.animationTime,
|
||||
minZoomImageRatio: _this.minZoomImageRatio,
|
||||
|
Loading…
x
Reference in New Issue
Block a user