mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-25 06:36:11 +03:00
Merge branch 'master' into hotfix/minimapClick
This commit is contained in:
commit
9c2211f93c
@ -50,6 +50,7 @@
|
||||
"no-multi-spaces": [
|
||||
"error",
|
||||
{
|
||||
"ignoreEOLComments": true,
|
||||
"exceptions": {
|
||||
"Property": true,
|
||||
"VariableDeclarator": true,
|
||||
@ -259,7 +260,7 @@
|
||||
"space-unary-ops": [
|
||||
"error",
|
||||
{
|
||||
"words": false,
|
||||
"words": true,
|
||||
"nonwords": false
|
||||
}
|
||||
],
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@ instrumented/
|
||||
.idea
|
||||
/nbproject/private/
|
||||
.directory
|
||||
test/demo/temp
|
||||
|
@ -4,11 +4,18 @@ OPENSEADRAGON CHANGELOG
|
||||
2.4.0: (In Progress)
|
||||
|
||||
* BREAKING CHANGE: Viewer's canvas-double-click event is now fired before it initiates the zoom (#1288)
|
||||
* You can now flip the viewport to get a mirror image of the original (#1441)
|
||||
* You can now prevent canvas-double-click events from zooming on a per-event basis (#1288)
|
||||
* Fixed: Opacity 0 images were causing unnecessary redraws (#1319)
|
||||
* The "page" event is now fired after the page index has been updated (#1330)
|
||||
* Added option pixelsPerArrowPress that sets the speed of arrow keys (#1364)
|
||||
* Improved IIIF options.maxLevel calculation (#1401)
|
||||
* Added canvas-key events, along with the ability to cancel key actions (#1414)
|
||||
* Added optional zoom in the middle of the image instead of pointer position (#1423)
|
||||
* Now supporting square edge tiles that are padded rather than cropped (#1426)
|
||||
* Fixed an issue causing the simple image tileSource to sometimes show duplicate copies (#1370)
|
||||
* Fixed an issue causing seams to appear in semi-transparent PNG tiled images (#1470)
|
||||
* Added visual customization options for the navigator (#1480)
|
||||
|
||||
2.3.1:
|
||||
|
||||
|
BIN
images/flip_grouphover.png
Normal file
BIN
images/flip_grouphover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
images/flip_hover.png
Normal file
BIN
images/flip_hover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
images/flip_pressed.png
Normal file
BIN
images/flip_pressed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
images/flip_rest.png
Normal file
BIN
images/flip_rest.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
7638
package-lock.json
generated
Normal file
7638
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -28,16 +28,16 @@
|
||||
"url": "https://github.com/openseadragon/openseadragon.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "^1.0.1",
|
||||
"grunt": "^1.0.2",
|
||||
"grunt-contrib-clean": "^1.1.0",
|
||||
"grunt-contrib-compress": "^1.4.3",
|
||||
"grunt-contrib-concat": "^1.0.1",
|
||||
"grunt-contrib-connect": "^1.0.2",
|
||||
"grunt-contrib-qunit": "^2.0.0",
|
||||
"grunt-contrib-uglify": "^3.2.1",
|
||||
"grunt-contrib-watch": "^1.0.0",
|
||||
"grunt-eslint": "^19.0.0",
|
||||
"grunt-git-describe": "^2.3.2",
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"grunt-eslint": "^20.1.0",
|
||||
"grunt-git-describe": "^2.4.4",
|
||||
"grunt-istanbul": "^0.8.0",
|
||||
"grunt-text-replace": "^0.4.0",
|
||||
"qunitjs": "2.4.1"
|
||||
|
@ -500,6 +500,10 @@ $.Drawer.prototype = {
|
||||
|
||||
if ( this.viewport.degrees !== 0 ) {
|
||||
this._offsetForRotation({degrees: this.viewport.degrees});
|
||||
} else{
|
||||
if(this.viewer.viewport.flipped) {
|
||||
this._flip();
|
||||
}
|
||||
}
|
||||
if (tiledImage.getRotation(true) % 360 !== 0) {
|
||||
this._offsetForRotation({
|
||||
@ -620,10 +624,28 @@ $.Drawer.prototype = {
|
||||
context.save();
|
||||
|
||||
context.translate(point.x, point.y);
|
||||
context.rotate(Math.PI / 180 * options.degrees);
|
||||
if(this.viewer.viewport.flipped){
|
||||
context.rotate(Math.PI / 180 * -options.degrees);
|
||||
context.scale(-1, 1);
|
||||
} else{
|
||||
context.rotate(Math.PI / 180 * options.degrees);
|
||||
}
|
||||
context.translate(-point.x, -point.y);
|
||||
},
|
||||
|
||||
// private
|
||||
_flip: function(options) {
|
||||
options = options || {};
|
||||
var point = options.point ?
|
||||
options.point.times($.pixelDensityRatio) :
|
||||
this.getCanvasCenter();
|
||||
var context = this._getContext(options.useSketch);
|
||||
|
||||
context.translate(point.x, 0);
|
||||
context.scale(-1, 1);
|
||||
context.translate(-point.x, 0);
|
||||
},
|
||||
|
||||
// private
|
||||
_restoreRotationChanges: function(useSketch) {
|
||||
var context = this._getContext(useSketch);
|
||||
|
@ -110,7 +110,11 @@ $.Navigator = function( options ){
|
||||
animationTime: 0,
|
||||
autoResize: options.autoResize,
|
||||
// prevent resizing the navigator from adding unwanted space around the image
|
||||
minZoomImageRatio: 1.0
|
||||
minZoomImageRatio: 1.0,
|
||||
background: options.background,
|
||||
opacity: options.opacity,
|
||||
borderColor: options.borderColor,
|
||||
displayRegionColor: options.displayRegionColor
|
||||
});
|
||||
|
||||
options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;
|
||||
@ -127,10 +131,10 @@ $.Navigator = function( options ){
|
||||
if ( options.controlOptions.anchor != $.ControlAnchor.NONE ) {
|
||||
(function( style, borderWidth ){
|
||||
style.margin = '0px';
|
||||
style.border = borderWidth + 'px solid #555';
|
||||
style.border = borderWidth + 'px solid ' + options.borderColor;
|
||||
style.padding = '0px';
|
||||
style.background = '#000';
|
||||
style.opacity = 0.8;
|
||||
style.background = options.background;
|
||||
style.opacity = options.opacity;
|
||||
style.overflow = 'hidden';
|
||||
}( this.element.style, this.borderWidth));
|
||||
}
|
||||
@ -145,7 +149,7 @@ $.Navigator = function( options ){
|
||||
style.left = '0px';
|
||||
style.fontSize = '0px';
|
||||
style.overflow = 'hidden';
|
||||
style.border = borderWidth + 'px solid #900';
|
||||
style.border = borderWidth + 'px solid ' + options.displayRegionColor;
|
||||
style.margin = '0px';
|
||||
style.padding = '0px';
|
||||
//TODO: IE doesnt like this property being set
|
||||
@ -208,12 +212,14 @@ $.Navigator = function( options ){
|
||||
var degrees = options.viewer.viewport ?
|
||||
options.viewer.viewport.getRotation() :
|
||||
options.viewer.degrees || 0;
|
||||
|
||||
rotate(degrees);
|
||||
options.viewer.addHandler("rotate", function (args) {
|
||||
rotate(args.degrees);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Remove the base class' (Viewer's) innerTracker and replace it with our own
|
||||
this.innerTracker.destroy();
|
||||
this.innerTracker = new $.MouseTracker({
|
||||
@ -271,6 +277,22 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
/* Flip navigator element
|
||||
* @param {Boolean} state - Flip state to set.
|
||||
*/
|
||||
setFlip: function(state) {
|
||||
this.viewport.setFlip(state);
|
||||
|
||||
this.setDisplayTransform(this.viewer.viewport.getFlip() ? "scale(-1,1)" : "scale(1,1)");
|
||||
return this;
|
||||
},
|
||||
|
||||
setDisplayTransform: function(rule) {
|
||||
setElementTransform(this.displayRegion, rule);
|
||||
setElementTransform(this.canvas, rule);
|
||||
setElementTransform(this.element, rule);
|
||||
},
|
||||
|
||||
/**
|
||||
* Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs.
|
||||
@ -399,6 +421,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
@ -432,6 +455,9 @@ function onCanvasClick( event ) {
|
||||
this.viewer.raiseEvent('navigator-click', canvasClickEventArgs);
|
||||
|
||||
if ( !canvasClickEventArgs.preventDefaultAction && event.quick && this.viewer.viewport && (this.panVertical || this.panHorizontal)) {
|
||||
if(this.viewer.viewport.flipped) {
|
||||
event.position.x = this.viewport.getContainerSize().x - event.position.x;
|
||||
}
|
||||
var target = this.viewport.pointFromPixel(event.position);
|
||||
if (!this.panVertical) {
|
||||
// perform only horizonal pan
|
||||
@ -459,6 +485,11 @@ function onCanvasDrag( event ) {
|
||||
if( !this.panVertical ){
|
||||
event.delta.y = 0;
|
||||
}
|
||||
|
||||
if(this.viewer.viewport.flipped){
|
||||
event.delta.x = -event.delta.x;
|
||||
}
|
||||
|
||||
this.viewer.viewport.panBy(
|
||||
this.viewport.deltaPointsFromPixels(
|
||||
event.delta
|
||||
@ -522,12 +553,16 @@ function onCanvasScroll( event ) {
|
||||
* @param {Object} element
|
||||
* @param {Number} degrees
|
||||
*/
|
||||
function _setTransformRotate (element, degrees) {
|
||||
element.style.webkitTransform = "rotate(" + degrees + "deg)";
|
||||
element.style.mozTransform = "rotate(" + degrees + "deg)";
|
||||
element.style.msTransform = "rotate(" + degrees + "deg)";
|
||||
element.style.oTransform = "rotate(" + degrees + "deg)";
|
||||
element.style.transform = "rotate(" + degrees + "deg)";
|
||||
function _setTransformRotate( element, degrees ) {
|
||||
setElementTransform(element, "rotate(" + degrees + "deg)");
|
||||
}
|
||||
|
||||
function setElementTransform( element, rule ) {
|
||||
element.style.webkitTransform = rule;
|
||||
element.style.mozTransform = rule;
|
||||
element.style.msTransform = rule;
|
||||
element.style.oTransform = rule;
|
||||
element.style.transform = rule;
|
||||
}
|
||||
|
||||
}( OpenSeadragon ));
|
||||
|
@ -206,6 +206,9 @@
|
||||
* @property {Number} [degrees=0]
|
||||
* Initial rotation.
|
||||
*
|
||||
* @property {Boolean} [flipped=false]
|
||||
* Initial flip state.
|
||||
*
|
||||
* @property {Number} [minZoomLevel=null]
|
||||
*
|
||||
* @property {Number} [maxZoomLevel=null]
|
||||
@ -314,6 +317,8 @@
|
||||
* @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true
|
||||
* then clickToZoom should be set to false to prevent multiple zooms.
|
||||
* @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture
|
||||
* @property {Boolean} [gestureSettingsMouse.zoomToRefPoint=true] - If zoomToRefPoint is true, the zoom is centered at the pointer position. Otherwise,
|
||||
* the zoom is centered at the canvas center.
|
||||
* @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture
|
||||
* @property {Number} [gestureSettingsMouse.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
|
||||
* @property {Number} [gestureSettingsMouse.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture
|
||||
@ -326,6 +331,8 @@
|
||||
* @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true
|
||||
* then clickToZoom should be set to false to prevent multiple zooms.
|
||||
* @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture
|
||||
* @property {Boolean} [gestureSettingsTouch.zoomToRefPoint=true] - If zoomToRefPoint is true, the zoom is centered at the pointer position. Otherwise,
|
||||
* the zoom is centered at the canvas center.
|
||||
* @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture
|
||||
* @property {Number} [gestureSettingsTouch.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
|
||||
* @property {Number} [gestureSettingsTouch.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture
|
||||
@ -338,6 +345,8 @@
|
||||
* @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true
|
||||
* then clickToZoom should be set to false to prevent multiple zooms.
|
||||
* @property {Boolean} [gestureSettingsPen.pinchToZoom=false] - Zoom on pinch gesture
|
||||
* @property {Boolean} [gestureSettingsPan.zoomToRefPoint=true] - If zoomToRefPoint is true, the zoom is centered at the pointer position. Otherwise,
|
||||
* the zoom is centered at the canvas center.
|
||||
* @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture
|
||||
* @property {Number} [gestureSettingsPen.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
|
||||
* @property {Number} [gestureSettingsPen.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture
|
||||
@ -350,6 +359,8 @@
|
||||
* @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true
|
||||
* then clickToZoom should be set to false to prevent multiple zooms.
|
||||
* @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture
|
||||
* @property {Boolean} [gestureSettingsUnknown.zoomToRefPoint=true] - If zoomToRefPoint is true, the zoom is centered at the pointer position. Otherwise,
|
||||
* the zoom is centered at the canvas center.
|
||||
* @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture
|
||||
* @property {Number} [gestureSettingsUnknown.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
|
||||
* @property {Number} [gestureSettingsUnknown.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture
|
||||
@ -408,6 +419,18 @@
|
||||
* @property {Boolean} [navigatorRotate=true]
|
||||
* If true, the navigator will be rotated together with the viewer.
|
||||
*
|
||||
* @property {String} [navigatorBackground='#000']
|
||||
* Specifies the background color of the navigator minimap
|
||||
*
|
||||
* @property {Number} [navigatorOpacity=0.8]
|
||||
* Specifies the opacity of the navigator minimap.
|
||||
*
|
||||
* @property {String} [navigatorBorderColor='#555']
|
||||
* Specifies the border color of the navigator minimap
|
||||
*
|
||||
* @property {String} [navigatorDisplayRegionColor='#900']
|
||||
* Specifies the border color of the display region rectangle of the navigator minimap
|
||||
*
|
||||
* @property {Number} [controlsFadeDelay=2000]
|
||||
* The number of milliseconds to wait once the user has stopped interacting
|
||||
* with the interface before begining to fade the controls. Assumes
|
||||
@ -470,6 +493,10 @@
|
||||
* Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding
|
||||
* this setting when set to false.
|
||||
*
|
||||
* @property {Boolean} [showFlipControl=false]
|
||||
* If true then the flip controls will be displayed as part of the
|
||||
* standard controls.
|
||||
*
|
||||
* @property {Boolean} [showSequenceControl=true]
|
||||
* If sequenceMode is true, then provide buttons for navigating forward and
|
||||
* backward through the images.
|
||||
@ -680,6 +707,12 @@
|
||||
* @property {String} rotateright.HOVER
|
||||
* @property {String} rotateright.DOWN
|
||||
*
|
||||
* @property {Object} flip - Images for the flip button.
|
||||
* @property {String} flip.REST
|
||||
* @property {String} flip.GROUP
|
||||
* @property {String} flip.HOVER
|
||||
* @property {String} flip.DOWN
|
||||
*
|
||||
* @property {Object} previous - Images for the previous button.
|
||||
* @property {String} previous.REST
|
||||
* @property {String} previous.GROUP
|
||||
@ -1044,6 +1077,7 @@ function OpenSeadragon( options ){
|
||||
clickToZoom: true,
|
||||
dblClickToZoom: false,
|
||||
pinchToZoom: false,
|
||||
zoomToRefPoint: true,
|
||||
flickEnabled: false,
|
||||
flickMinSpeed: 120,
|
||||
flickMomentum: 0.25,
|
||||
@ -1054,6 +1088,7 @@ function OpenSeadragon( options ){
|
||||
clickToZoom: false,
|
||||
dblClickToZoom: true,
|
||||
pinchToZoom: true,
|
||||
zoomToRefPoint: true,
|
||||
flickEnabled: true,
|
||||
flickMinSpeed: 120,
|
||||
flickMomentum: 0.25,
|
||||
@ -1064,6 +1099,7 @@ function OpenSeadragon( options ){
|
||||
clickToZoom: true,
|
||||
dblClickToZoom: false,
|
||||
pinchToZoom: false,
|
||||
zoomToRefPoint: true,
|
||||
flickEnabled: false,
|
||||
flickMinSpeed: 120,
|
||||
flickMomentum: 0.25,
|
||||
@ -1074,6 +1110,7 @@ function OpenSeadragon( options ){
|
||||
clickToZoom: false,
|
||||
dblClickToZoom: true,
|
||||
pinchToZoom: true,
|
||||
zoomToRefPoint: true,
|
||||
flickEnabled: true,
|
||||
flickMinSpeed: 120,
|
||||
flickMomentum: 0.25,
|
||||
@ -1108,6 +1145,7 @@ function OpenSeadragon( options ){
|
||||
showHomeControl: true, //HOME
|
||||
showFullPageControl: true, //FULL
|
||||
showRotationControl: false, //ROTATION
|
||||
showFlipControl: false, //FLIP
|
||||
controlsFadeDelay: 2000, //ZOOM/HOME/FULL/SEQUENCE
|
||||
controlsFadeLength: 1500, //ZOOM/HOME/FULL/SEQUENCE
|
||||
mouseNavEnabled: true, //GENERAL MOUSE INTERACTIVITY
|
||||
@ -1125,10 +1163,17 @@ function OpenSeadragon( options ){
|
||||
navigatorAutoResize: true,
|
||||
navigatorAutoFade: true,
|
||||
navigatorRotate: true,
|
||||
navigatorBackground: '#000',
|
||||
navigatorOpacity: 0.8,
|
||||
navigatorBorderColor: '#555',
|
||||
navigatorDisplayRegionColor: '#900',
|
||||
|
||||
// INITIAL ROTATION
|
||||
degrees: 0,
|
||||
|
||||
// INITIAL FLIP STATE
|
||||
flipped: false,
|
||||
|
||||
// APPEARANCE
|
||||
opacity: 1,
|
||||
preload: false,
|
||||
@ -1197,6 +1242,12 @@ function OpenSeadragon( options ){
|
||||
HOVER: 'rotateright_hover.png',
|
||||
DOWN: 'rotateright_pressed.png'
|
||||
},
|
||||
flip: { // Flip icon designed by Yaroslav Samoylov from the Noun Project and modified by Nelson Campos ncampos@criteriamarathon.com, https://thenounproject.com/term/flip/136289/
|
||||
REST: 'flip_rest.png',
|
||||
GROUP: 'flip_grouphover.png',
|
||||
HOVER: 'flip_hover.png',
|
||||
DOWN: 'flip_pressed.png'
|
||||
},
|
||||
previous: {
|
||||
REST: 'previous_rest.png',
|
||||
GROUP: 'previous_grouphover.png',
|
||||
@ -1487,7 +1538,7 @@ function OpenSeadragon( options ){
|
||||
*/
|
||||
getMousePosition: function( event ) {
|
||||
|
||||
if ( typeof( event.pageX ) == "number" ) {
|
||||
if ( typeof ( event.pageX ) == "number" ) {
|
||||
$.getMousePosition = function( event ){
|
||||
var result = new $.Point();
|
||||
|
||||
@ -1497,7 +1548,7 @@ function OpenSeadragon( options ){
|
||||
|
||||
return result;
|
||||
};
|
||||
} else if ( typeof( event.clientX ) == "number" ) {
|
||||
} else if ( typeof ( event.clientX ) == "number" ) {
|
||||
$.getMousePosition = function( event ){
|
||||
var result = new $.Point();
|
||||
|
||||
@ -1532,7 +1583,7 @@ function OpenSeadragon( options ){
|
||||
var docElement = document.documentElement || {},
|
||||
body = document.body || {};
|
||||
|
||||
if ( typeof( window.pageXOffset ) == "number" ) {
|
||||
if ( typeof ( window.pageXOffset ) == "number" ) {
|
||||
$.getPageScroll = function(){
|
||||
return new $.Point(
|
||||
window.pageXOffset,
|
||||
@ -1621,7 +1672,7 @@ function OpenSeadragon( options ){
|
||||
var docElement = document.documentElement || {},
|
||||
body = document.body || {};
|
||||
|
||||
if ( typeof( window.innerWidth ) == 'number' ) {
|
||||
if ( typeof ( window.innerWidth ) == 'number' ) {
|
||||
$.getWindowSize = function(){
|
||||
return new $.Point(
|
||||
window.innerWidth,
|
||||
@ -2221,7 +2272,7 @@ function OpenSeadragon( options ){
|
||||
error messages are localized.
|
||||
*/
|
||||
var oldIE = $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 10;
|
||||
if ( oldIE && typeof( e.number ) != "undefined" && e.number == -2147024891 ) {
|
||||
if ( oldIE && typeof ( e.number ) != "undefined" && e.number == -2147024891 ) {
|
||||
msg += "\nSee http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx#xdomain";
|
||||
}
|
||||
|
||||
|
@ -58,27 +58,27 @@ $.Rect = function(x, y, width, height, degrees) {
|
||||
* @member {Number} x
|
||||
* @memberof OpenSeadragon.Rect#
|
||||
*/
|
||||
this.x = typeof(x) === "number" ? x : 0;
|
||||
this.x = typeof (x) === "number" ? x : 0;
|
||||
/**
|
||||
* The vector component 'y'.
|
||||
* @member {Number} y
|
||||
* @memberof OpenSeadragon.Rect#
|
||||
*/
|
||||
this.y = typeof(y) === "number" ? y : 0;
|
||||
this.y = typeof (y) === "number" ? y : 0;
|
||||
/**
|
||||
* The vector component 'width'.
|
||||
* @member {Number} width
|
||||
* @memberof OpenSeadragon.Rect#
|
||||
*/
|
||||
this.width = typeof(width) === "number" ? width : 0;
|
||||
this.width = typeof (width) === "number" ? width : 0;
|
||||
/**
|
||||
* The vector component 'height'.
|
||||
* @member {Number} height
|
||||
* @memberof OpenSeadragon.Rect#
|
||||
*/
|
||||
this.height = typeof(height) === "number" ? height : 0;
|
||||
this.height = typeof (height) === "number" ? height : 0;
|
||||
|
||||
this.degrees = typeof(degrees) === "number" ? degrees : 0;
|
||||
this.degrees = typeof (degrees) === "number" ? degrees : 0;
|
||||
|
||||
// Normalizes the rectangle.
|
||||
this.degrees = $.positiveModulo(this.degrees, 360);
|
||||
|
@ -50,7 +50,7 @@
|
||||
$.Spring = function( options ) {
|
||||
var args = arguments;
|
||||
|
||||
if( typeof( options ) != 'object' ){
|
||||
if( typeof ( options ) != 'object' ){
|
||||
//allows backward compatible use of ( initialValue, config ) as
|
||||
//constructor parameters
|
||||
options = {
|
||||
|
@ -57,7 +57,8 @@ var I18N = {
|
||||
NextPage: "Next page",
|
||||
PreviousPage: "Previous page",
|
||||
RotateLeft: "Rotate left",
|
||||
RotateRight: "Rotate right"
|
||||
RotateRight: "Rotate right",
|
||||
Flip: "Flip Horizontally"
|
||||
}
|
||||
};
|
||||
|
||||
@ -81,7 +82,7 @@ $.extend( $, /** @lends OpenSeadragon */{
|
||||
}
|
||||
string = container[ props[ i ] ];
|
||||
|
||||
if ( typeof( string ) != "string" ) {
|
||||
if ( typeof ( string ) != "string" ) {
|
||||
$.console.log( "Untranslated source string:", prop );
|
||||
string = ""; // FIXME: this breaks gettext()-style convention, which would return source
|
||||
}
|
||||
|
35
src/tile.js
35
src/tile.js
@ -40,7 +40,7 @@
|
||||
* @param {Number} level The zoom level this tile belongs to.
|
||||
* @param {Number} x The vector component 'x'.
|
||||
* @param {Number} y The vector component 'y'.
|
||||
* @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized
|
||||
* @param {OpenSeadragon.Rect} bounds Where this tile fits, in normalized
|
||||
* coordinates.
|
||||
* @param {Boolean} exists Is this tile a part of a sparse image? ( Also has
|
||||
* this tile failed to load? )
|
||||
@ -49,8 +49,11 @@
|
||||
* is provided directly by the tile source.
|
||||
* @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request .
|
||||
* @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable).
|
||||
* @param {OpenSeadragon.Rect} sourceBounds The portion of the tile to use as the source of the
|
||||
* drawing operation, in pixels. Note that this only works when drawing with canvas; when drawing
|
||||
* with HTML the entire tile is always used.
|
||||
*/
|
||||
$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders) {
|
||||
$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders, sourceBounds) {
|
||||
/**
|
||||
* The zoom level this tile belongs to.
|
||||
* @member {Number} level
|
||||
@ -75,6 +78,13 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.bounds = bounds;
|
||||
/**
|
||||
* The portion of the tile to use as the source of the drawing operation, in pixels. Note that
|
||||
* this only works when drawing with canvas; when drawing with HTML the entire tile is always used.
|
||||
* @member {OpenSeadragon.Rect} sourceBounds
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.sourceBounds = sourceBounds;
|
||||
/**
|
||||
* Is this tile a part of a sparse image? Also has this tile failed to load?
|
||||
* @member {Boolean} exists
|
||||
@ -346,10 +356,10 @@ $.Tile.prototype = {
|
||||
//clearing only the inside of the rectangle occupied
|
||||
//by the png prevents edge flikering
|
||||
context.clearRect(
|
||||
position.x + 1,
|
||||
position.y + 1,
|
||||
size.x - 2,
|
||||
size.y - 2
|
||||
position.x,
|
||||
position.y,
|
||||
size.x,
|
||||
size.y
|
||||
);
|
||||
}
|
||||
|
||||
@ -357,12 +367,21 @@ $.Tile.prototype = {
|
||||
// changes as we are rendering the image
|
||||
drawingHandler({context: context, tile: this, rendered: rendered});
|
||||
|
||||
var sourceWidth, sourceHeight;
|
||||
if (this.sourceBounds) {
|
||||
sourceWidth = Math.min(this.sourceBounds.width, rendered.canvas.width);
|
||||
sourceHeight = Math.min(this.sourceBounds.height, rendered.canvas.height);
|
||||
} else {
|
||||
sourceWidth = rendered.canvas.width;
|
||||
sourceHeight = rendered.canvas.height;
|
||||
}
|
||||
|
||||
context.drawImage(
|
||||
rendered.canvas,
|
||||
0,
|
||||
0,
|
||||
rendered.canvas.width,
|
||||
rendered.canvas.height,
|
||||
sourceWidth,
|
||||
sourceHeight,
|
||||
position.x,
|
||||
position.y,
|
||||
size.x,
|
||||
|
@ -85,7 +85,11 @@
|
||||
*/
|
||||
$.TiledImage = function( options ) {
|
||||
var _this = this;
|
||||
|
||||
/**
|
||||
* The {@link OpenSeadragon.TileSource} that defines this TiledImage.
|
||||
* @member {OpenSeadragon.TileSource} source
|
||||
* @memberof OpenSeadragon.TiledImage#
|
||||
*/
|
||||
$.console.assert( options.tileCache, "[TiledImage] options.tileCache is required" );
|
||||
$.console.assert( options.drawer, "[TiledImage] options.drawer is required" );
|
||||
$.console.assert( options.viewer, "[TiledImage] options.viewer is required" );
|
||||
@ -1372,6 +1376,7 @@ function getTile(
|
||||
var xMod,
|
||||
yMod,
|
||||
bounds,
|
||||
sourceBounds,
|
||||
exists,
|
||||
url,
|
||||
ajaxHeaders,
|
||||
@ -1389,6 +1394,7 @@ function getTile(
|
||||
xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x;
|
||||
yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;
|
||||
bounds = tileSource.getTileBounds( level, xMod, yMod );
|
||||
sourceBounds = tileSource.getTileBounds( level, xMod, yMod, true );
|
||||
exists = tileSource.tileExists( level, xMod, yMod );
|
||||
url = tileSource.getTileUrl( level, xMod, yMod );
|
||||
|
||||
@ -1418,7 +1424,8 @@ function getTile(
|
||||
url,
|
||||
context2D,
|
||||
tiledImage.loadTilesWithAjax,
|
||||
ajaxHeaders
|
||||
ajaxHeaders,
|
||||
sourceBounds
|
||||
);
|
||||
|
||||
if (xMod === numTiles.x - 1) {
|
||||
@ -1883,6 +1890,10 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
degrees: tiledImage.viewport.degrees,
|
||||
useSketch: useSketch
|
||||
});
|
||||
} else {
|
||||
if(tiledImage._drawer.viewer.viewport.flipped) {
|
||||
tiledImage._drawer._flip({});
|
||||
}
|
||||
}
|
||||
if (tiledImage.getRotation(true) % 360 !== 0) {
|
||||
tiledImage._drawer._offsetForRotation({
|
||||
@ -1966,6 +1977,10 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
}
|
||||
if (tiledImage.viewport.degrees !== 0) {
|
||||
tiledImage._drawer._restoreRotationChanges(useSketch);
|
||||
} else{
|
||||
if(tiledImage._drawer.viewer.viewport.flipped) {
|
||||
tiledImage._drawer._flip({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,7 +360,7 @@ $.TileSource.prototype = {
|
||||
if (point.x >= 1) {
|
||||
x = this.getNumTiles(level).x - 1;
|
||||
}
|
||||
var EPSILON = 1e-16;
|
||||
var EPSILON = 1e-15;
|
||||
if (point.y >= 1 / this.aspectRatio - EPSILON) {
|
||||
y = this.getNumTiles(level).y - 1;
|
||||
}
|
||||
@ -373,8 +373,12 @@ $.TileSource.prototype = {
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Boolean} [isSource=false] Whether to return the source bounds of the tile.
|
||||
* @returns {OpenSeadragon.Rect} Either where this tile fits (in normalized coordinates) or the
|
||||
* portion of the tile to use as the source of the drawing operation (in pixels), depending on
|
||||
* the isSource parameter.
|
||||
*/
|
||||
getTileBounds: function( level, x, y ) {
|
||||
getTileBounds: function( level, x, y, isSource ) {
|
||||
var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
||||
tileWidth = this.getTileWidth(level),
|
||||
tileHeight = this.getTileHeight(level),
|
||||
@ -387,6 +391,10 @@ $.TileSource.prototype = {
|
||||
sx = Math.min( sx, dimensionsScaled.x - px );
|
||||
sy = Math.min( sy, dimensionsScaled.y - py );
|
||||
|
||||
if (isSource) {
|
||||
return new $.Rect(0, 0, sx, sy);
|
||||
}
|
||||
|
||||
return new $.Rect( px * scale, py * scale, sx * scale, sy * scale );
|
||||
},
|
||||
|
||||
@ -419,7 +427,7 @@ $.TileSource.prototype = {
|
||||
}
|
||||
|
||||
callback = function( data ){
|
||||
if( typeof(data) === "string" ) {
|
||||
if( typeof (data) === "string" ) {
|
||||
data = $.parseXml( data );
|
||||
}
|
||||
var $TileSource = $.TileSource.determineType( _this, data, url );
|
||||
@ -492,7 +500,7 @@ $.TileSource.prototype = {
|
||||
msg = "HTTP " + xhr.status + " attempting to load TileSource";
|
||||
} catch ( e ) {
|
||||
var formattedExc;
|
||||
if ( typeof( exc ) == "undefined" || !exc.toString ) {
|
||||
if ( typeof ( exc ) == "undefined" || !exc.toString ) {
|
||||
formattedExc = "Unknown error";
|
||||
} else {
|
||||
formattedExc = exc.toString();
|
||||
|
206
src/viewer.js
206
src/viewer.js
@ -145,6 +145,8 @@ $.Viewer = function( options ) {
|
||||
|
||||
//These are originally not part options but declared as members
|
||||
//in initialize. It's still considered idiomatic to put them here
|
||||
//source is here for backwards compatibility. It is not an official
|
||||
//part of the API and should not be relied upon.
|
||||
source: null,
|
||||
/**
|
||||
* Handles rendering of tiles in the viewer. Created for each TileSource opened.
|
||||
@ -152,6 +154,11 @@ $.Viewer = function( options ) {
|
||||
* @memberof OpenSeadragon.Viewer#
|
||||
*/
|
||||
drawer: null,
|
||||
/**
|
||||
* Keeps track of all of the tiled images in the scene.
|
||||
* @member {OpenSeadragon.Drawer} world
|
||||
* @memberof OpenSeadragon.Viewer#
|
||||
*/
|
||||
world: null,
|
||||
/**
|
||||
* Handles coordinate-related functionality - zoom, pan, rotation, etc. Created for each TileSource opened.
|
||||
@ -182,10 +189,10 @@ $.Viewer = function( options ) {
|
||||
|
||||
}, $.DEFAULT_SETTINGS, options );
|
||||
|
||||
if ( typeof( this.hash) === "undefined" ) {
|
||||
if ( typeof ( this.hash) === "undefined" ) {
|
||||
throw new Error("A hash must be defined, either by specifying options.id or options.hash.");
|
||||
}
|
||||
if ( typeof( THIS[ this.hash ] ) !== "undefined" ) {
|
||||
if ( typeof ( THIS[ this.hash ] ) !== "undefined" ) {
|
||||
// We don't want to throw an error here, as the user might have discarded
|
||||
// the previous viewer with the same hash and now want to recreate it.
|
||||
$.console.warn("Hash " + this.hash + " has already been used.");
|
||||
@ -367,6 +374,7 @@ $.Viewer = function( options ) {
|
||||
maxZoomLevel: this.maxZoomLevel,
|
||||
viewer: this,
|
||||
degrees: this.degrees,
|
||||
flipped: this.flipped,
|
||||
navigatorRotate: this.navigatorRotate,
|
||||
homeFillsViewer: this.homeFillsViewer,
|
||||
margins: this.viewportMargins
|
||||
@ -428,6 +436,10 @@ $.Viewer = function( options ) {
|
||||
prefixUrl: this.prefixUrl,
|
||||
viewer: this,
|
||||
navigatorRotate: this.navigatorRotate,
|
||||
background: this.navigatorBackground,
|
||||
opacity: this.navigatorOpacity,
|
||||
borderColor: this.navigatorBorderColor,
|
||||
displayRegionColor: this.navigatorDisplayRegionColor,
|
||||
crossOriginPolicy: this.crossOriginPolicy
|
||||
});
|
||||
}
|
||||
@ -1674,6 +1686,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
onFullScreenHandler = $.delegate( this, onFullScreen ),
|
||||
onRotateLeftHandler = $.delegate( this, onRotateLeft ),
|
||||
onRotateRightHandler = $.delegate( this, onRotateRight ),
|
||||
onFlipHandler = $.delegate( this, onFlip),
|
||||
onFocusHandler = $.delegate( this, onFocus ),
|
||||
onBlurHandler = $.delegate( this, onBlur ),
|
||||
navImages = this.navImages,
|
||||
@ -1685,7 +1698,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
|
||||
if( this.zoomInButton || this.zoomOutButton ||
|
||||
this.homeButton || this.fullPageButton ||
|
||||
this.rotateLeftButton || this.rotateRightButton ) {
|
||||
this.rotateLeftButton || this.rotateRightButton ||
|
||||
this.flipButton ) {
|
||||
//if we are binding to custom buttons then layout and
|
||||
//grouping is the responsibility of the page author
|
||||
useGroup = false;
|
||||
@ -1789,7 +1803,22 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
onFocus: onFocusHandler,
|
||||
onBlur: onBlurHandler
|
||||
}));
|
||||
}
|
||||
|
||||
if ( this.showFlipControl ) {
|
||||
buttons.push( this.flipButton = new $.Button({
|
||||
element: this.flipButton ? $.getElement( this.flipButton ) : null,
|
||||
clickTimeThreshold: this.clickTimeThreshold,
|
||||
clickDistThreshold: this.clickDistThreshold,
|
||||
tooltip: $.getString( "Tooltips.Flip" ),
|
||||
srcRest: resolveUrl( this.prefixUrl, navImages.flip.REST ),
|
||||
srcGroup: resolveUrl( this.prefixUrl, navImages.flip.GROUP ),
|
||||
srcHover: resolveUrl( this.prefixUrl, navImages.flip.HOVER ),
|
||||
srcDown: resolveUrl( this.prefixUrl, navImages.flip.DOWN ),
|
||||
onRelease: onFlipHandler,
|
||||
onFocus: onFocusHandler,
|
||||
onBlur: onBlurHandler
|
||||
}));
|
||||
}
|
||||
|
||||
if ( useGroup ) {
|
||||
@ -2477,31 +2506,62 @@ function onBlur(){
|
||||
}
|
||||
|
||||
function onCanvasKeyDown( event ) {
|
||||
if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {
|
||||
var canvasKeyDownEventArgs = {
|
||||
originalEvent: event.originalEvent,
|
||||
preventDefaultAction: event.preventDefaultAction,
|
||||
preventVerticalPan: event.preventVerticalPan,
|
||||
preventHorizontalPan: event.preventHorizontalPan
|
||||
};
|
||||
|
||||
/**
|
||||
* Raised when a keyboard key is pressed and the focus is on the {@link OpenSeadragon.Viewer#canvas} element.
|
||||
*
|
||||
* @event canvas-key
|
||||
* @memberof OpenSeadragon.Viewer
|
||||
* @type {object}
|
||||
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
|
||||
* @property {Object} originalEvent - The original DOM event.
|
||||
* @property {Boolean} preventDefaultAction - Set to true to prevent default keyboard behaviour. Default: false.
|
||||
* @property {Boolean} preventVerticalPan - Set to true to prevent keyboard vertical panning. Default: false.
|
||||
* @property {Boolean} preventHorizontalPan - Set to true to prevent keyboard horizontal panning. Default: false.
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
*/
|
||||
|
||||
this.raiseEvent('canvas-key', canvasKeyDownEventArgs);
|
||||
|
||||
if ( !canvasKeyDownEventArgs.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {
|
||||
switch( event.keyCode ){
|
||||
case 38://up arrow
|
||||
if ( event.shift ) {
|
||||
if (!canvasKeyDownEventArgs.preventVerticalPan) {
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(1.1);
|
||||
} else {
|
||||
} else {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -this.pixelsPerArrowPress)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 40://down arrow
|
||||
if ( event.shift ) {
|
||||
if (!canvasKeyDownEventArgs.preventVerticalPan) {
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(0.9);
|
||||
} else {
|
||||
} else {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, this.pixelsPerArrowPress)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 37://left arrow
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-this.pixelsPerArrowPress, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
if (!canvasKeyDownEventArgs.preventHorizontalPan) {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-this.pixelsPerArrowPress, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
return false;
|
||||
case 39://right arrow
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(this.pixelsPerArrowPress, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
if (!canvasKeyDownEventArgs.preventHorizontalPan) {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(this.pixelsPerArrowPress, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
//console.log( 'navigator keycode %s', event.keyCode );
|
||||
@ -2511,9 +2571,18 @@ function onCanvasKeyDown( event ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function onCanvasKeyPress( event ) {
|
||||
if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {
|
||||
var canvasKeyPressEventArgs = {
|
||||
originalEvent: event.originalEvent,
|
||||
preventDefaultAction: event.preventDefaultAction,
|
||||
preventVerticalPan: event.preventVerticalPan,
|
||||
preventHorizontalPan: event.preventHorizontalPan
|
||||
};
|
||||
|
||||
// This event is documented in onCanvasKeyDown
|
||||
this.raiseEvent('canvas-key', canvasKeyPressEventArgs);
|
||||
|
||||
if ( !canvasKeyPressEventArgs.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {
|
||||
switch( event.keyCode ){
|
||||
case 43://=|+
|
||||
case 61://=|+
|
||||
@ -2530,32 +2599,59 @@ function onCanvasKeyPress( event ) {
|
||||
return false;
|
||||
case 119://w
|
||||
case 87://W
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(1.1);
|
||||
} else {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
if (!canvasKeyPressEventArgs.preventVerticalPan) {
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(1.1);
|
||||
} else {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
return false;
|
||||
case 115://s
|
||||
case 83://S
|
||||
if ( event.shift ) {
|
||||
if (!canvasKeyPressEventArgs.preventVerticalPan) {
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(0.9);
|
||||
} else {
|
||||
} else {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 97://a
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
if (!canvasKeyPressEventArgs.preventHorizontalPan) {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
return false;
|
||||
case 100://d
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
if (!canvasKeyPressEventArgs.preventHorizontalPan) {
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
return false;
|
||||
case 114: //r - 90 degrees clockwise rotation
|
||||
if(this.viewport.flipped){
|
||||
this.viewport.setRotation(this.viewport.degrees - 90);
|
||||
} else{
|
||||
this.viewport.setRotation(this.viewport.degrees + 90);
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 82: //R - 90 degrees counterclockwise rotation
|
||||
if(this.viewport.flipped){
|
||||
this.viewport.setRotation(this.viewport.degrees + 90);
|
||||
} else{
|
||||
this.viewport.setRotation(this.viewport.degrees - 90);
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 102: //f
|
||||
this.viewport.toggleFlip();
|
||||
return false;
|
||||
default:
|
||||
//console.log( 'navigator keycode %s', event.keyCode );
|
||||
// console.log( 'navigator keycode %s', event.keyCode );
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@ -2572,6 +2668,9 @@ function onCanvasClick( event ) {
|
||||
if ( !haveKeyboardFocus ) {
|
||||
this.canvas.focus();
|
||||
}
|
||||
if(this.viewport.flipped){
|
||||
event.position.x = this.viewport.getContainerSize().x - event.position.x;
|
||||
}
|
||||
|
||||
var canvasClickEventArgs = {
|
||||
tracker: event.eventSource,
|
||||
@ -2604,7 +2703,7 @@ function onCanvasClick( event ) {
|
||||
if ( gestureSettings.clickToZoom ) {
|
||||
this.viewport.zoomBy(
|
||||
event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick,
|
||||
this.viewport.pointFromPixel( event.position, true )
|
||||
gestureSettings.zoomToRefPoint ? this.viewport.pointFromPixel( event.position, true ) : null
|
||||
);
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
@ -2643,7 +2742,7 @@ function onCanvasDblClick( event ) {
|
||||
if ( gestureSettings.dblClickToZoom ) {
|
||||
this.viewport.zoomBy(
|
||||
event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick,
|
||||
this.viewport.pointFromPixel( event.position, true )
|
||||
gestureSettings.zoomToRefPoint ? this.viewport.pointFromPixel( event.position, true ) : null
|
||||
);
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
@ -2691,6 +2790,9 @@ function onCanvasDrag( event ) {
|
||||
if( !this.panVertical ){
|
||||
event.delta.y = 0;
|
||||
}
|
||||
if(this.viewport.flipped){
|
||||
event.delta.x = -event.delta.x;
|
||||
}
|
||||
|
||||
if( this.constrainDuringPan ){
|
||||
var delta = this.viewport.deltaPointsFromPixels( event.delta.negate() );
|
||||
@ -2957,7 +3059,9 @@ function onCanvasPinch( event ) {
|
||||
panByPt.y = 0;
|
||||
}
|
||||
this.viewport.zoomBy( event.distance / event.lastDistance, centerPt, true );
|
||||
this.viewport.panBy( panByPt, true );
|
||||
if ( gestureSettings.zoomToRefPoint ) {
|
||||
this.viewport.panBy(panByPt, true);
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
if ( gestureSettings.pinchRotate ) {
|
||||
@ -3014,13 +3118,17 @@ function onCanvasScroll( event ) {
|
||||
if (deltaScrollTime > this.minScrollDeltaTime) {
|
||||
this._lastScrollTime = thisScrollTime;
|
||||
|
||||
if(this.viewport.flipped){
|
||||
event.position.x = this.viewport.getContainerSize().x - event.position.x;
|
||||
}
|
||||
|
||||
if ( !event.preventDefaultAction && this.viewport ) {
|
||||
gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );
|
||||
if ( gestureSettings.scrollToZoom ) {
|
||||
factor = Math.pow( this.zoomPerScroll, event.scroll );
|
||||
this.viewport.zoomBy(
|
||||
factor,
|
||||
this.viewport.pointFromPixel( event.position, true )
|
||||
gestureSettings.zoomToRefPoint ? this.viewport.pointFromPixel( event.position, true ) : null
|
||||
);
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
@ -3209,7 +3317,7 @@ function updateOnce( viewer ) {
|
||||
drawWorld( viewer );
|
||||
viewer._drawOverlays();
|
||||
if( viewer.navigator ){
|
||||
viewer.navigator.update( viewer.viewport );
|
||||
viewer.navigator.update( viewer.viewport );
|
||||
}
|
||||
|
||||
THIS[ viewer.hash ].forceRedraw = false;
|
||||
@ -3379,11 +3487,11 @@ function onFullScreen() {
|
||||
function onRotateLeft() {
|
||||
if ( this.viewport ) {
|
||||
var currRotation = this.viewport.getRotation();
|
||||
if (currRotation === 0) {
|
||||
currRotation = 270;
|
||||
}
|
||||
else {
|
||||
currRotation -= 90;
|
||||
|
||||
if ( this.viewport.flipped ){
|
||||
currRotation = $.positiveModulo(currRotation + 90, 360);
|
||||
} else {
|
||||
currRotation = $.positiveModulo(currRotation - 90, 360);
|
||||
}
|
||||
this.viewport.setRotation(currRotation);
|
||||
}
|
||||
@ -3395,16 +3503,22 @@ function onRotateLeft() {
|
||||
function onRotateRight() {
|
||||
if ( this.viewport ) {
|
||||
var currRotation = this.viewport.getRotation();
|
||||
if (currRotation === 270) {
|
||||
currRotation = 0;
|
||||
}
|
||||
else {
|
||||
currRotation += 90;
|
||||
|
||||
if ( this.viewport.flipped ){
|
||||
currRotation = $.positiveModulo(currRotation - 90, 360);
|
||||
} else {
|
||||
currRotation = $.positiveModulo(currRotation + 90, 360);
|
||||
}
|
||||
this.viewport.setRotation(currRotation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: When pressed flip control button
|
||||
*/
|
||||
function onFlip() {
|
||||
this.viewport.toggleFlip();
|
||||
}
|
||||
|
||||
function onPrevious(){
|
||||
var previous = this._sequenceIndex - 1;
|
||||
|
@ -107,6 +107,7 @@ $.Viewport = function( options ) {
|
||||
minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,
|
||||
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel,
|
||||
degrees: $.DEFAULT_SETTINGS.degrees,
|
||||
flipped: $.DEFAULT_SETTINGS.flipped,
|
||||
homeFillsViewer: $.DEFAULT_SETTINGS.homeFillsViewer
|
||||
|
||||
}, options );
|
||||
@ -880,7 +881,6 @@ $.Viewport.prototype = {
|
||||
if (!this.viewer || !this.viewer.drawer.canRotate()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.degrees = $.positiveModulo(degrees, 360);
|
||||
this._setContentBounds(
|
||||
this.viewer.world.getHomeBounds(),
|
||||
@ -1518,7 +1518,58 @@ $.Viewport.prototype = {
|
||||
var scale = this._contentBoundsNoRotate.width;
|
||||
var viewportToImageZoomRatio = (imageWidth / containerWidth) / scale;
|
||||
return imageZoom * viewportToImageZoomRatio;
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles flip state and demands a new drawing on navigator and viewer objects.
|
||||
* @function
|
||||
* @return {OpenSeadragon.Viewport} Chainable.
|
||||
*/
|
||||
toggleFlip: function() {
|
||||
this.setFlip(!this.getFlip());
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets flip state stored on viewport.
|
||||
* @function
|
||||
* @return {Boolean} Flip state.
|
||||
*/
|
||||
getFlip: function() {
|
||||
return this.flipped;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets flip state according to the state input argument.
|
||||
* @function
|
||||
* @param {Boolean} state - Flip state to set.
|
||||
* @return {OpenSeadragon.Viewport} Chainable.
|
||||
*/
|
||||
setFlip: function( state ) {
|
||||
if ( this.flipped === state ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.flipped = state;
|
||||
if(this.viewer.navigator){
|
||||
this.viewer.navigator.setFlip(this.getFlip());
|
||||
}
|
||||
this.viewer.forceRedraw();
|
||||
|
||||
/**
|
||||
* Raised when flip state has been changed.
|
||||
*
|
||||
* @event flip
|
||||
* @memberof OpenSeadragon.Viewer
|
||||
* @type {object}
|
||||
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
|
||||
* @property {Number} flipped - The flip state after this change.
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
*/
|
||||
this.viewer.raiseEvent('flip', {"flipped": state});
|
||||
return this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}( OpenSeadragon ));
|
||||
|
@ -107,6 +107,17 @@
|
||||
maxLevel: 0,
|
||||
});
|
||||
assertTileAtPoint(0, new OpenSeadragon.Point(1, 1239 / 4036), new OpenSeadragon.Point(0, 0));
|
||||
|
||||
// Test for issue #1362
|
||||
tileSource = new OpenSeadragon.TileSource({
|
||||
width: 2000,
|
||||
height: 3033,
|
||||
tileWidth: 2000,
|
||||
tileHeight: 3033,
|
||||
tileOverlap: 0,
|
||||
maxLevel: 0,
|
||||
});
|
||||
assertTileAtPoint(0, new OpenSeadragon.Point(1, 3033 / 2000), new OpenSeadragon.Point(0, 0));
|
||||
});
|
||||
|
||||
}());
|
||||
|
@ -118,6 +118,7 @@
|
||||
assert,
|
||||
actual,
|
||||
expected,
|
||||
1e-15,
|
||||
"Correctly converted coordinates " + orig
|
||||
);
|
||||
} else {
|
||||
@ -136,8 +137,8 @@
|
||||
viewer.open(DZI_PATH);
|
||||
};
|
||||
|
||||
function assertPointsEquals(assert, actual, expected, message) {
|
||||
Util.assertPointsEquals(assert, actual, expected, 1e-15, message);
|
||||
function assertPointsEquals(assert, actual, expected, variance, message) {
|
||||
Util.assertPointsEquals(assert, actual, expected, variance, message);
|
||||
}
|
||||
|
||||
// Tests start here.
|
||||
@ -470,6 +471,32 @@
|
||||
bounds,
|
||||
EPSILON,
|
||||
"Viewport.applyConstraints should move viewport.");
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('applyConstraints flipped', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function() {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
viewport.setFlip(true);
|
||||
|
||||
viewport.fitBounds(new OpenSeadragon.Rect(1, 1, 1, 1), true);
|
||||
viewport.visibilityRatio = 0.3;
|
||||
viewport.applyConstraints(true);
|
||||
var bounds = viewport.getBounds();
|
||||
Util.assertRectangleEquals(
|
||||
assert,
|
||||
new OpenSeadragon.Rect(0.7, 0.7, 1, 1),
|
||||
bounds,
|
||||
EPSILON,
|
||||
"Viewport.applyConstraints should move flipped viewport.");
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
@ -514,6 +541,32 @@
|
||||
new OpenSeadragon.Rect(1, 0, Math.sqrt(2), Math.sqrt(2), 45),
|
||||
EPSILON,
|
||||
"Viewport.applyConstraints with rotation should move viewport.");
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('applyConstraints flipped with rotation', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function() {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
viewport.setFlip(true);
|
||||
viewport.setRotation(45);
|
||||
|
||||
viewport.fitBounds(new OpenSeadragon.Rect(1, 1, 1, 1), true);
|
||||
viewport.applyConstraints(true);
|
||||
var bounds = viewport.getBounds();
|
||||
Util.assertRectangleEquals(
|
||||
assert,
|
||||
bounds,
|
||||
new OpenSeadragon.Rect(1, 0, Math.sqrt(2), Math.sqrt(2), 45),
|
||||
EPSILON,
|
||||
"Viewport.applyConstraints flipped and with rotation should move viewport.");
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
@ -742,6 +795,30 @@
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('panBy flipped', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
viewport.setFlip(true);
|
||||
|
||||
for (var i = 0; i < testPoints.length; i++){
|
||||
var expected = viewport.getCenter().plus(testPoints[i]);
|
||||
viewport.panBy(testPoints[i], true);
|
||||
assert.propEqual(
|
||||
viewport.getCenter(),
|
||||
expected,
|
||||
"Panned flipped by the correct amount."
|
||||
);
|
||||
}
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('panTo', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
@ -763,6 +840,29 @@
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('panTo flipped', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
viewport.setFlip(true);
|
||||
|
||||
for (var i = 0; i < testPoints.length; i++){
|
||||
viewport.panTo(testPoints[i], true);
|
||||
assert.propEqual(
|
||||
viewport.getCenter(),
|
||||
testPoints[i],
|
||||
"Panned flipped to the correct location."
|
||||
);
|
||||
}
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('zoomBy no ref point', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
@ -821,6 +921,45 @@
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('zoomBy flipped with ref point', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
viewport.setFlip(true);
|
||||
|
||||
var expectedFlippedCenters = [
|
||||
new OpenSeadragon.Point(5, 5),
|
||||
new OpenSeadragon.Point(6.996, 6.996),
|
||||
new OpenSeadragon.Point(7.246, 6.996),
|
||||
new OpenSeadragon.Point(7.246, 6.996),
|
||||
new OpenSeadragon.Point(7.621, 7.371),
|
||||
new OpenSeadragon.Point(7.621, 7.371),
|
||||
];
|
||||
|
||||
for (var i = 0; i < testZoomLevels.length; i++) {
|
||||
viewport.zoomBy(testZoomLevels[i], testPoints[i], true);
|
||||
assert.propEqual(
|
||||
testZoomLevels[i],
|
||||
viewport.getZoom(),
|
||||
"Zoomed flipped by the correct amount."
|
||||
);
|
||||
assertPointsEquals(
|
||||
assert,
|
||||
expectedFlippedCenters[i],
|
||||
viewport.getCenter(),
|
||||
1e-6,
|
||||
"Panned flipped to the correct location."
|
||||
);
|
||||
}
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('zoomTo no ref point', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
@ -866,8 +1005,8 @@
|
||||
);
|
||||
assertPointsEquals(
|
||||
assert,
|
||||
viewport.getCenter(),
|
||||
expectedCenters[i],
|
||||
viewport.getCenter(),
|
||||
1e-14,
|
||||
"Panned to the correct location."
|
||||
);
|
||||
@ -879,6 +1018,45 @@
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('zoomTo flipped with ref point', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
viewport.setFlip(true);
|
||||
|
||||
var expectedFlippedCenters = [
|
||||
new OpenSeadragon.Point(5, 5),
|
||||
new OpenSeadragon.Point(4.7505, 4.7505),
|
||||
new OpenSeadragon.Point(4.6005, 4.7505),
|
||||
new OpenSeadragon.Point(4.8455, 4.9955),
|
||||
new OpenSeadragon.Point(5.2205, 5.3705),
|
||||
new OpenSeadragon.Point(5.2205, 5.3705),
|
||||
];
|
||||
|
||||
for (var i = 0; i < testZoomLevels.length; i++) {
|
||||
viewport.zoomTo(testZoomLevels[i], testPoints[i], true);
|
||||
assert.propEqual(
|
||||
viewport.getZoom(),
|
||||
testZoomLevels[i],
|
||||
"Zoomed flipped to the correct level."
|
||||
);
|
||||
assertPointsEquals(
|
||||
assert,
|
||||
expectedFlippedCenters[i],
|
||||
viewport.getCenter(),
|
||||
1e-14,
|
||||
"Panned flipped to the correct location."
|
||||
);
|
||||
}
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('rotation', function(assert){
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
@ -890,6 +1068,28 @@
|
||||
assert.propEqual(viewport.getRotation, 90, "Rotation should be 90 degrees");
|
||||
viewport.setRotation(-75);
|
||||
assert.propEqual(viewport.getRotation, -75, "Rotation should be -75 degrees");
|
||||
|
||||
done();
|
||||
};
|
||||
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('rotation (flipped)', function(assert){
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
viewport.setFlip(true);
|
||||
|
||||
assert.propEqual(viewport.getRotation, 0, "Original flipped rotation should be 0 degrees");
|
||||
viewport.setRotation(90);
|
||||
assert.propEqual(viewport.getRotation, 90, "Flipped rotation should be 90 degrees");
|
||||
viewport.setRotation(-75);
|
||||
assert.propEqual(viewport.getRotation, -75, "Flipped rotation should be -75 degrees");
|
||||
|
||||
done();
|
||||
};
|
||||
|
||||
@ -1140,4 +1340,44 @@
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('toggleFlipState', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
assert.deepEqual(viewport.getFlip(), false, "Get original flip state should be false");
|
||||
|
||||
viewport.toggleFlip();
|
||||
assert.deepEqual(viewport.getFlip(), true, "Toggling flip state variable, viewport should be true");
|
||||
|
||||
viewport.toggleFlip();
|
||||
assert.deepEqual(viewport.getFlip(), false, "Toggling back flip state variable, viewport should be false again");
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
QUnit.test('setFlipState', function(assert) {
|
||||
var done = assert.async();
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
assert.deepEqual(viewport.getFlip(), false, "Get original flip state should be false");
|
||||
|
||||
viewport.setFlip(true);
|
||||
assert.deepEqual(viewport.getFlip(), true, "Setting flip state variable should be true");
|
||||
|
||||
viewport.setFlip(false);
|
||||
assert.deepEqual(viewport.getFlip(), false, "Unsetting flip state variable, viewport should be false again");
|
||||
|
||||
done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user