mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-22 21:26:10 +03:00
Extends the fix for seams in transparent images to any browsers, making it configurable
This commit is contained in:
parent
c8f4934c8a
commit
e5b608d86a
@ -352,7 +352,7 @@ $.Drawer.prototype = {
|
|||||||
if (this.useCanvas) {
|
if (this.useCanvas) {
|
||||||
var context = this._getContext(useSketch);
|
var context = this._getContext(useSketch);
|
||||||
scale = scale || 1;
|
scale = scale || 1;
|
||||||
tile.drawCanvas(context, drawingHandler, scale, translate);
|
tile.drawCanvas(context, drawingHandler, scale, translate, this._shouldRoundPositionAndSize);
|
||||||
} else {
|
} else {
|
||||||
tile.drawHTML( this.canvas );
|
tile.drawHTML( this.canvas );
|
||||||
}
|
}
|
||||||
|
@ -209,6 +209,13 @@
|
|||||||
* You can pass a CSS color value like "#FF8800".
|
* You can pass a CSS color value like "#FF8800".
|
||||||
* When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern.
|
* When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern.
|
||||||
*
|
*
|
||||||
|
* @property {Object} [subPixelRounding=null]
|
||||||
|
* Determines when subpixel rounding should be applied for tiles rendering.
|
||||||
|
* This property is a subpixel rounding enum values dictionary [number] --> string.
|
||||||
|
* The key is a $.BROWSERS value, and the value is one of 'ALWAYS', 'ONLY_AT_REST' or 'NEVER',
|
||||||
|
* indicating, for a given browser, when to apply subpixel rounding.
|
||||||
|
* Key '' is the fallback value for any browser not specified in the dictionary.
|
||||||
|
*
|
||||||
* @property {Number} [degrees=0]
|
* @property {Number} [degrees=0]
|
||||||
* Initial rotation.
|
* Initial rotation.
|
||||||
*
|
*
|
||||||
@ -1263,6 +1270,7 @@ function OpenSeadragon( options ){
|
|||||||
compositeOperation: null,
|
compositeOperation: null,
|
||||||
imageSmoothingEnabled: true,
|
imageSmoothingEnabled: true,
|
||||||
placeholderFillStyle: null,
|
placeholderFillStyle: null,
|
||||||
|
subPixelRounding: null,
|
||||||
|
|
||||||
//REFERENCE STRIP SETTINGS
|
//REFERENCE STRIP SETTINGS
|
||||||
showReferenceStrip: false,
|
showReferenceStrip: false,
|
||||||
|
13
src/tile.js
13
src/tile.js
@ -318,8 +318,11 @@ $.Tile.prototype = {
|
|||||||
* where <code>rendered</code> is the context with the pre-drawn image.
|
* where <code>rendered</code> is the context with the pre-drawn image.
|
||||||
* @param {Number} [scale=1] - Apply a scale to position and size
|
* @param {Number} [scale=1] - Apply a scale to position and size
|
||||||
* @param {OpenSeadragon.Point} [translate] - A translation vector
|
* @param {OpenSeadragon.Point} [translate] - A translation vector
|
||||||
|
* @param {Boolean} [shouldRoundPositionAndSize] - Tells whether to round
|
||||||
|
* position and size of tiles supporting alpha channel in non-transparency
|
||||||
|
* context.
|
||||||
*/
|
*/
|
||||||
drawCanvas: function( context, drawingHandler, scale, translate ) {
|
drawCanvas: function( context, drawingHandler, scale, translate, shouldRoundPositionAndSize ) {
|
||||||
|
|
||||||
var position = this.position.times($.pixelDensityRatio),
|
var position = this.position.times($.pixelDensityRatio),
|
||||||
size = this.size.times($.pixelDensityRatio),
|
size = this.size.times($.pixelDensityRatio),
|
||||||
@ -363,6 +366,14 @@ $.Tile.prototype = {
|
|||||||
//an image with an alpha channel, then the only way
|
//an image with an alpha channel, then the only way
|
||||||
//to avoid seeing the tile underneath is to clear the rectangle
|
//to avoid seeing the tile underneath is to clear the rectangle
|
||||||
if (context.globalAlpha === 1 && this._hasTransparencyChannel()) {
|
if (context.globalAlpha === 1 && this._hasTransparencyChannel()) {
|
||||||
|
if (shouldRoundPositionAndSize) {
|
||||||
|
// Round to the nearest whole pixel so we don't get seams from overlap.
|
||||||
|
position.x = Math.round(position.x);
|
||||||
|
position.y = Math.round(position.y);
|
||||||
|
size.x = Math.round(size.x);
|
||||||
|
size.y = Math.round(size.y);
|
||||||
|
}
|
||||||
|
|
||||||
//clearing only the inside of the rectangle occupied
|
//clearing only the inside of the rectangle occupied
|
||||||
//by the png prevents edge flikering
|
//by the png prevents edge flikering
|
||||||
context.clearRect(
|
context.clearRect(
|
||||||
|
@ -177,7 +177,8 @@ $.TiledImage = function( options ) {
|
|||||||
placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,
|
placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,
|
||||||
opacity: $.DEFAULT_SETTINGS.opacity,
|
opacity: $.DEFAULT_SETTINGS.opacity,
|
||||||
preload: $.DEFAULT_SETTINGS.preload,
|
preload: $.DEFAULT_SETTINGS.preload,
|
||||||
compositeOperation: $.DEFAULT_SETTINGS.compositeOperation
|
compositeOperation: $.DEFAULT_SETTINGS.compositeOperation,
|
||||||
|
subPixelRounding: $.DEFAULT_SETTINGS.subPixelRounding
|
||||||
}, options );
|
}, options );
|
||||||
|
|
||||||
this._preload = this.preload;
|
this._preload = this.preload;
|
||||||
@ -1951,6 +1952,111 @@ function compareTiles( previousBest, tile ) {
|
|||||||
return previousBest;
|
return previousBest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @inner
|
||||||
|
* Defines the value for subpixel rounding to fallback to in case of missing or
|
||||||
|
* invalid value.
|
||||||
|
*/
|
||||||
|
var DEFAULT_SUBPIXEL_ROUNDING_RULE = 'NEVER';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @inner
|
||||||
|
* Determines whether the subpixel rounding enum value is 'ALWAYS' or not.
|
||||||
|
*
|
||||||
|
* @param {string} value - The subpixel rounding enum value to check, case sensitive.
|
||||||
|
* @returns {Boolean} True if input value is 'ALWAYS', false otherwise.
|
||||||
|
*/
|
||||||
|
function isSubPixelRoundingRuleAlways(value) {
|
||||||
|
return value === 'ALWAYS';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @inner
|
||||||
|
* Determines whether the subpixel rounding enum value is 'ONLY_AT_REST' or not.
|
||||||
|
*
|
||||||
|
* @param {string} value - The subpixel rounding enum value to check, case sensitive.
|
||||||
|
* @returns {Boolean} True if input value is 'ONLY_AT_REST', false otherwise.
|
||||||
|
*/
|
||||||
|
function isSubPixelRoundingRuleOnlyAtRest(value) {
|
||||||
|
return value === 'ONLY_AT_REST';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @inner
|
||||||
|
* Determines whether the subpixel rounding enum value is 'NEVER' or not.
|
||||||
|
*
|
||||||
|
* @param {string} value - The subpixel rounding enum value to check, case sensitive.
|
||||||
|
* @returns {Boolean} True if input value is 'NEVER', false otherwise.
|
||||||
|
*/
|
||||||
|
function isSubPixelRoundingRuleNever(value) {
|
||||||
|
return value === DEFAULT_SUBPIXEL_ROUNDING_RULE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @inner
|
||||||
|
* Checks whether the input value is an invalid subpixel rounding enum value.
|
||||||
|
*
|
||||||
|
* @param {string} value - The subpixel rounding enum value to check, case sensitive.
|
||||||
|
* @returns {Boolean} Returns true if the input value is none of the expected
|
||||||
|
* 'ALWAYS', 'ONLY_AT_REST' or 'NEVER' value.
|
||||||
|
* Note that if passed a valid value but with the incorrect casing, the return
|
||||||
|
* value will be true. If input is 'always', then true is returned, indicating
|
||||||
|
* it is an unknown value.
|
||||||
|
*/
|
||||||
|
function isSubPixelRoundingRuleUnknown(value) {
|
||||||
|
return !isSubPixelRoundingRuleAlways(value) &&
|
||||||
|
!isSubPixelRoundingRuleOnlyAtRest(value) &&
|
||||||
|
!isSubPixelRoundingRuleNever(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @inner
|
||||||
|
* Ensures the returned value is always a valid subpixel rounding enum value,
|
||||||
|
* defaulting to 'NEVER' if input is missing or invalid.
|
||||||
|
*
|
||||||
|
* @param {string} value - The subpixel rounding enum value to normalize, case sensitive.
|
||||||
|
* @returns {string} Returns a valid subpixel rounding enum value.
|
||||||
|
* Note that if passed a valid value but with the incorrect casing, the return
|
||||||
|
* value will be the default 'NEVER'. If input is 'always', then 'NEVER' is
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
function normalizeSubPixelRoundingRule(value) {
|
||||||
|
if (isSubPixelRoundingRuleUnknown(value)) {
|
||||||
|
return DEFAULT_SUBPIXEL_ROUNDING_RULE;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @inner
|
||||||
|
* Ensures the returned value is always a valid subpixel rounding enum value,
|
||||||
|
* defaulting to 'NEVER' if input is missing or invalid.
|
||||||
|
*
|
||||||
|
* @param {Object} subPixelRoundingRules - A subpixel rounding enum values dictionary [number] --> string.
|
||||||
|
* @returns {string} Returns the determined subpixel rounding enum value for the
|
||||||
|
* current browser.
|
||||||
|
*/
|
||||||
|
function determineSubPixelRoundingRule(subPixelRoundingRules) {
|
||||||
|
if (!subPixelRoundingRules || !$.Browser) {
|
||||||
|
return DEFAULT_SUBPIXEL_ROUNDING_RULE;
|
||||||
|
}
|
||||||
|
|
||||||
|
var subPixelRoundingRule = subPixelRoundingRules[$.Browser.vendor];
|
||||||
|
|
||||||
|
if (!subPixelRoundingRule || isSubPixelRoundingRuleUnknown(subPixelRoundingRule)) {
|
||||||
|
subPixelRoundingRule = subPixelRoundingRules[''];
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizeSubPixelRoundingRule(subPixelRoundingRule);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @inner
|
* @inner
|
||||||
@ -2099,6 +2205,19 @@ function drawTiles( tiledImage, lastDrawn ) {
|
|||||||
tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch);
|
tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var subPixelRoundingRule = determineSubPixelRoundingRule(tiledImage.subPixelRounding);
|
||||||
|
|
||||||
|
var shouldRoundPositionAndSize = false;
|
||||||
|
|
||||||
|
if (isSubPixelRoundingRuleAlways(subPixelRoundingRule)) {
|
||||||
|
shouldRoundPositionAndSize = true;
|
||||||
|
} else if (isSubPixelRoundingRuleOnlyAtRest(subPixelRoundingRule)) {
|
||||||
|
var isAnimating = tiledImage.viewer && tiledImage.viewer.isAnimating();
|
||||||
|
shouldRoundPositionAndSize = !isAnimating;
|
||||||
|
}
|
||||||
|
|
||||||
|
tiledImage._drawer._shouldRoundPositionAndSize = shouldRoundPositionAndSize;
|
||||||
|
|
||||||
for (var i = lastDrawn.length - 1; i >= 0; i--) {
|
for (var i = lastDrawn.length - 1; i >= 0; i--) {
|
||||||
tile = lastDrawn[ i ];
|
tile = lastDrawn[ i ];
|
||||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate );
|
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate );
|
||||||
|
@ -1494,7 +1494,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
|||||||
ajaxWithCredentials: queueItem.options.ajaxWithCredentials,
|
ajaxWithCredentials: queueItem.options.ajaxWithCredentials,
|
||||||
loadTilesWithAjax: queueItem.options.loadTilesWithAjax,
|
loadTilesWithAjax: queueItem.options.loadTilesWithAjax,
|
||||||
ajaxHeaders: queueItem.options.ajaxHeaders,
|
ajaxHeaders: queueItem.options.ajaxHeaders,
|
||||||
debugMode: _this.debugMode
|
debugMode: _this.debugMode,
|
||||||
|
subPixelRounding: _this.subPixelRounding
|
||||||
});
|
});
|
||||||
|
|
||||||
if (_this.collectionMode) {
|
if (_this.collectionMode) {
|
||||||
@ -2348,6 +2349,10 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
|||||||
}
|
}
|
||||||
this.goToPage( next );
|
this.goToPage( next );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isAnimating: function () {
|
||||||
|
return THIS[ this.hash ].animating;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -3494,7 +3499,9 @@ function updateOnce( viewer ) {
|
|||||||
animated = viewer.referenceStrip.update( viewer.viewport ) || animated;
|
animated = viewer.referenceStrip.update( viewer.viewport ) || animated;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !THIS[ viewer.hash ].animating && animated ) {
|
var currentAnimating = THIS[ viewer.hash ].animating;
|
||||||
|
|
||||||
|
if ( !currentAnimating && animated ) {
|
||||||
/**
|
/**
|
||||||
* Raised when any spring animation starts (zoom, pan, etc.).
|
* Raised when any spring animation starts (zoom, pan, etc.).
|
||||||
*
|
*
|
||||||
@ -3532,7 +3539,7 @@ function updateOnce( viewer ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( THIS[ viewer.hash ].animating && !animated ) {
|
if ( currentAnimating && !animated ) {
|
||||||
/**
|
/**
|
||||||
* Raised when any spring animation ends (zoom, pan, etc.).
|
* Raised when any spring animation ends (zoom, pan, etc.).
|
||||||
*
|
*
|
||||||
@ -3551,6 +3558,13 @@ function updateOnce( viewer ) {
|
|||||||
|
|
||||||
THIS[ viewer.hash ].animating = animated;
|
THIS[ viewer.hash ].animating = animated;
|
||||||
|
|
||||||
|
// Intentionally use currentAnimating as the value at the current frame,
|
||||||
|
// regardless of THIS[ viewer.hash ].animating being updated.
|
||||||
|
if (currentAnimating && !animated) {
|
||||||
|
// Ensure a draw occurs once animation is over.
|
||||||
|
drawWorld( viewer );
|
||||||
|
}
|
||||||
|
|
||||||
//viewer.profiler.endUpdate();
|
//viewer.profiler.endUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user