mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-21 20:56:09 +03:00
Merge branch 'master' into ig-seams
This commit is contained in:
commit
2a84ce365e
@ -278,8 +278,9 @@
|
||||
]
|
||||
},
|
||||
"globals": {
|
||||
"OpenSeadragon": true,
|
||||
"define": false,
|
||||
"module": false
|
||||
"OpenSeadragon": "writable",
|
||||
"define": "readonly",
|
||||
"module": "readonly",
|
||||
"Map": "readonly"
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,34 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"eslint:recommended"
|
||||
],
|
||||
"env": {
|
||||
"es6": false,
|
||||
"browser": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 5,
|
||||
"sourceType": "script",
|
||||
"ecmaFeatures": {
|
||||
"globalReturn": false,
|
||||
"impliedStrict": false,
|
||||
"jsx": false
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"OpenSeadragon": "writable",
|
||||
"define": "readonly",
|
||||
"module": "readonly",
|
||||
"Map": "readonly"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"args": "none"
|
||||
}
|
||||
],
|
||||
"indent": [
|
||||
"off",
|
||||
4
|
||||
@ -16,24 +41,18 @@
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"args": "none"
|
||||
}
|
||||
],
|
||||
"block-scoped-var": [
|
||||
"error"
|
||||
],
|
||||
"consistent-return": [
|
||||
"off"
|
||||
"error"
|
||||
],
|
||||
"curly": [
|
||||
"error",
|
||||
"all"
|
||||
],
|
||||
"eqeqeq": [
|
||||
"off"
|
||||
"error"
|
||||
],
|
||||
"no-eval": [
|
||||
"error"
|
||||
@ -83,7 +102,7 @@
|
||||
"error"
|
||||
],
|
||||
"no-useless-escape": [
|
||||
"off"
|
||||
"error"
|
||||
],
|
||||
"no-useless-return": [
|
||||
"error"
|
||||
@ -103,7 +122,9 @@
|
||||
"no-use-before-define": [
|
||||
"error",
|
||||
{
|
||||
"functions": false
|
||||
"functions": false,
|
||||
"classes": true,
|
||||
"variables": true
|
||||
}
|
||||
],
|
||||
"array-bracket-spacing": [
|
||||
@ -237,7 +258,7 @@
|
||||
"after"
|
||||
],
|
||||
"quote-props": [
|
||||
"off",
|
||||
"error",
|
||||
"as-needed"
|
||||
],
|
||||
"semi-spacing": [
|
||||
@ -273,10 +294,5 @@
|
||||
"no-loop-func": [
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"globals": {
|
||||
"OpenSeadragon": true,
|
||||
"define": false,
|
||||
"module": false
|
||||
}
|
||||
}
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # iangilman
|
||||
patreon: # iangilman
|
||||
open_collective: openseadragon
|
||||
ko_fi: # iangilman
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,4 +7,4 @@ instrumented/
|
||||
.idea
|
||||
/nbproject/private/
|
||||
.directory
|
||||
test/demo/temp
|
||||
local-test
|
||||
|
21
.vscode/tasks.json
vendored
21
.vscode/tasks.json
vendored
@ -1,25 +1,26 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "0.1.0",
|
||||
"version": "2.0.0",
|
||||
"command": "grunt",
|
||||
"isShellCommand": true,
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "build",
|
||||
"args": [],
|
||||
"isBuildCommand": true,
|
||||
"isWatching": false,
|
||||
"label": "build",
|
||||
"type": "grunt",
|
||||
"task": "build",
|
||||
"problemMatcher": [
|
||||
"$lessCompile",
|
||||
"$tsc",
|
||||
"$jshint"
|
||||
]
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"taskName": "test",
|
||||
"args": [],
|
||||
"isTestCommand": true
|
||||
"label": "test",
|
||||
"type": "grunt",
|
||||
"task": "test",
|
||||
"problemMatcher": [],
|
||||
"group": "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
25
.vscode/tasks.json.old
vendored
Normal file
25
.vscode/tasks.json.old
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "0.1.0",
|
||||
"command": "grunt",
|
||||
"isShellCommand": true,
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "build",
|
||||
"args": [],
|
||||
"isBuildCommand": true,
|
||||
"isWatching": false,
|
||||
"problemMatcher": [
|
||||
"$lessCompile",
|
||||
"$tsc",
|
||||
"$jshint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"taskName": "test",
|
||||
"args": [],
|
||||
"isTestCommand": true
|
||||
}
|
||||
]
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
/* eslint-disable no-redeclare */
|
||||
/* global module */
|
||||
|
||||
module.exports = function(grunt) {
|
||||
/* eslint-disable no-undef */
|
||||
var dateFormat = require('dateformat');
|
||||
|
||||
// ----------
|
||||
@ -123,6 +125,7 @@ module.exports = function(grunt) {
|
||||
banner: banner,
|
||||
compress: {
|
||||
sequences: false,
|
||||
/* eslint-disable camelcase */
|
||||
join_vars: false
|
||||
},
|
||||
sourceMap: true,
|
||||
@ -199,7 +202,7 @@ module.exports = function(grunt) {
|
||||
target: sources
|
||||
},
|
||||
"git-describe": {
|
||||
"options": {
|
||||
options: {
|
||||
failOnError: false
|
||||
},
|
||||
build: {}
|
||||
|
@ -1,13 +1,78 @@
|
||||
OPENSEADRAGON CHANGELOG
|
||||
=======================
|
||||
|
||||
2.4.2: (In Progress)
|
||||
3.0.0: (In progress)
|
||||
|
||||
* BREAKING CHANGE: Dropped support for older browsers (IE < 11) (#1872 #1949 #1951 @msalsbery, #1950 @rmontroy)
|
||||
* BREAKING CHANGE: Removed deprecated OpenSeadragon.getEvent function (#1949 @msalsbery)
|
||||
* DEPRECATION: MouseTracker exitHandler deprecated for name change to leaveHandler for consistency with DOM event names (#1872 @msalsbery)
|
||||
* Now when "simple image" tile sources are removed from the viewer, they free the memory used by the pyramid they create (#1789 @TakumaKira)
|
||||
* Improvements to docs (#1814 @kenanchristian, #1872 @msalsbery, #1996 @tdiprima)
|
||||
* Better cleanup on destruction, to avoid memory leaks (#1832 @JoFrMueller)
|
||||
* Better handle destruction when navigator in custom location (#1884 @woodchuck)
|
||||
* Miscellaneous code cleanup (#1840 @msalsbery)
|
||||
* You can now specify tileSize for the Zoomify Tile Source (#1868 @abrlam)
|
||||
* Better use of IIIF "max" and "full" URL parameters (#1871 @MImranAsghar)
|
||||
* You can now specify the file format of the tiles in the Zoomify tile source (#1889 @abrlam)
|
||||
* Improved browser sniffing - detect EDGE and CHROMEEDGE browsers (#1872 @msalsbery)
|
||||
* Improved DOM event model feature detection (#1872 @msalsbery)
|
||||
* Added support for options parameter on addEvent()/removeEvent (to support passive option) (#1872 @msalsbery)
|
||||
* Added OpenSeadragon.eventIsCanceled() function for defaultPrevented detection on DOM events (#1872 @msalsbery)
|
||||
* MouseTracker: better PointerEvent model detection - removed use of deprecated window.navigator.pointerEnabled (#1872 @msalsbery)
|
||||
* MouseTracker: added overHandler/outHandler options for handling corresponding pointerover/pointerout events (#1872 @msalsbery)
|
||||
* MouseTracker: changed enterHandler/leaveHandler to use DOM pointerenter/pointerleave events instead of simulating using pointerover/pointerout (#1872 @msalsbery)
|
||||
* All internal uses of MouseTracker use pointerenter/pointerleave events instead of pointerover/pointerout events for more consistent pointer tracking (#1872 @msalsbery)
|
||||
* Fixed bug in Button class where two MouseTracker event handlers used an invalid "this" causing issues in some browsers (#1872 @msalsbery)
|
||||
* Added pointerType property to Viewer container-enter, container-exit, canvas-drag, canvas-drag-end, canvas-pinch events (#1872 @msalsbery)
|
||||
* MouseTracker: Fire dragEndHandler event even if release point same as initial contact point (#1872 @msalsbery)
|
||||
* MouseTracker: Pointer capture implemented with capture APIs where available. Only fallback to emulated capture on extremely old browsers (#1872 @msalsbery)
|
||||
* MouseTracker: Added preProcessEventHandler option to allow MouseTracker instances to control bubbling and default behavior of events on their associated element (#1872 @msalsbery)
|
||||
* MouseTracker: Improved handling of canceled events (#1872 @msalsbery)
|
||||
* MouseTracker: Improved releasing of tracked pointers on destroy()/stopTracking() (#1872 @msalsbery)
|
||||
* Updated Viewer, Button, Drawer, Navigator, ReferenceStrip DOM for proper DOM event handling (#1872 @msalsbery)
|
||||
* Added OpenSeadragon.setElementPointerEventsNone() for setting pointer-events:'none' on DOM elements (#1872 @msalsbery)
|
||||
* MouseTracker: added contextMenuHandler option for handling contextmenu events (#1872 @msalsbery)
|
||||
* Viewer: added a canvas-contextmenu event (#1872 @msalsbery)
|
||||
* Fixed simulated drag events in navigator tests (#1949 @msalsbery)
|
||||
* Added preventDefault option to MouseTracker.contextMenuHandler and Viewer 'canvas-contextmenu' event args (#1951 @msalsbery)
|
||||
* MouseTracker: Added preProcessEventHandler for keydown, keyup, keypress, focus, blur Events (#1951 @msalsbery)
|
||||
* Fixed preventDefaultAction functionality in viewer events (#1953 @msalsbery)
|
||||
* Added setImageFormatsSupported function (#1954 @pandaxtc)
|
||||
* Added dragToPan to the GestureSettings class, implemented in Viewer (#1956 @msalsbery)
|
||||
* Added preventDefault option to MouseTracker handlers: scrollHandler, keyDownHandler, keyUpHandler, keyHandler (#1957 @msalsbery)
|
||||
* Fixed test "Events: Viewer: preventDefaultAction in dblClickHandler". Fixes #1372 (#1960 @msalsbery)
|
||||
* ReferenceStrip: Fixed issue where its element was being removed from its parent element twice on destroy, causing an exception (#1958 @msalsbery)
|
||||
* ReferenceStrip: Made its element focusable for keyboard navigation (#1958 @msalsbery)
|
||||
* You can now flip individual images (not just the whole viewport) (#1903 @ali1234)
|
||||
* Accessibility: we now take the browser's zoom into account when choosing what detail level to draw (#1937 @ronnymikalsen)
|
||||
* Fixed a bug causing overlays to disappear in Sequence Mode (#1865 @gunmiosb)
|
||||
* Fixed a bug where the ajaxHeaders provided per-image were not being used for image requests (#1968 @maxshuty)
|
||||
* MouseTracker: Added workaround for WebKit Pointer Event Implicit Capture Bug (#1972 @msalsbery)
|
||||
* Removed test for move-leave (fly-over, no enter event)...not a valid, handleable event state, no longer supported (#1972 @msalsbery)
|
||||
* Added OpenSeadragon.setElementPointerEvents() for setting pointer-events to other values besides 'none' on DOM elements (#1972 @msalsbery)
|
||||
* Now ensuring the page body is display:block when in fullscreen (#1995 @thewilkybarkid)
|
||||
* Added a static method in OpenSeadragon to get an existing viewer (#2000 @HerCerM)
|
||||
* Now ensuring that the new item is already in the navigator when the "add-item" event fires (#2005 @RammasEchor)
|
||||
* Added keys to change image in sequence mode (j: previous, k: next) (#2007 @RammasEchor)
|
||||
* Fixed a bug where the navigator wouldn't pick up opacity/composite changes made while it is loading (#2018 @crydell)
|
||||
* Explicitly set passive:false for wheel event handlers to suppress console warnings. Fixes #1669 (#2043 @msalsbery)
|
||||
* Viewer's canvas-click events now include an originalTarget property so you can know which element received the click (#2037 @iangilman)
|
||||
* Added method for getting the size of an image in window coordinates (#2049 @superbland)
|
||||
|
||||
2.4.2:
|
||||
|
||||
* Add support for IIIF Image API 3.0 beta (#1764)
|
||||
* You can now crop an image with arbitrary polygons (#1772)
|
||||
* Improved support for using the Reference Strip in an OpenSeadragon Viewer inside a Web Component (#1676)
|
||||
* Added setWidth and setHeight methods to Navigator (#1686)
|
||||
* Fixed: Navigator was still resizing after you explicitly set its width and height with navigatorWidth and navigatorHeight (#1686)
|
||||
* Improvements to docs (#1696, #1698)
|
||||
* Improvements to docs (#1696, #1698, #1716, #1719)
|
||||
* Now passing Viewer AJAX configs down to ReferenceStrip thumbnails (#1701)
|
||||
* The ReferenceStrip now honors the useCanvas option from the Viewer (#1742)
|
||||
* Fixed: Navigator was still resizing after you explicitly set its width and height with navigatorWidth and navigatorHeight (#1686)
|
||||
* Fixed issues with touches on iOS 13 and iPad (#1754, #1756)
|
||||
* No longer throwing an exception on pages that have malformed URL parameters (#1758)
|
||||
* Fixed an issue with flipping the viewport on high pixel density screens (#1779)
|
||||
* Removed use of deprecated imageSmoothingEnabled prefixes (#1740)
|
||||
|
||||
2.4.1:
|
||||
|
||||
|
7232
package-lock.json
generated
7232
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openseadragon",
|
||||
"version": "2.4.1",
|
||||
"version": "2.4.2",
|
||||
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
|
||||
"keywords": [
|
||||
"image",
|
||||
@ -14,7 +14,8 @@
|
||||
"osm",
|
||||
"tms"
|
||||
],
|
||||
"homepage": "http://openseadragon.github.io/",
|
||||
"homepage": "https://openseadragon.github.io/",
|
||||
"funding": "https://opencollective.com/openseadragon",
|
||||
"bugs": {
|
||||
"url": "https://github.com/openseadragon/openseadragon/issues"
|
||||
},
|
||||
@ -28,15 +29,15 @@
|
||||
"url": "https://github.com/openseadragon/openseadragon.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "^1.0.4",
|
||||
"grunt-contrib-clean": "^1.1.0",
|
||||
"grunt-contrib-compress": "^1.5.0",
|
||||
"grunt": "^1.1.0",
|
||||
"grunt-contrib-clean": "^2.0.0",
|
||||
"grunt-contrib-compress": "^1.6.0",
|
||||
"grunt-contrib-concat": "^1.0.1",
|
||||
"grunt-contrib-connect": "^1.0.2",
|
||||
"grunt-contrib-connect": "^2.1.0",
|
||||
"grunt-contrib-qunit": "^3.1.0",
|
||||
"grunt-contrib-uglify": "^3.4.0",
|
||||
"grunt-contrib-uglify": "^4.0.1",
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"grunt-eslint": "^20.2.0",
|
||||
"grunt-eslint": "^23.0.0",
|
||||
"grunt-git-describe": "^2.4.4",
|
||||
"grunt-istanbul": "^0.8.0",
|
||||
"grunt-text-replace": "^0.4.0",
|
||||
|
@ -77,6 +77,7 @@ $.ButtonState = {
|
||||
* @param {OpenSeadragon.EventHandler} [options.onExit=null] Event handler callback for {@link OpenSeadragon.Button.event:exit}.
|
||||
* @param {OpenSeadragon.EventHandler} [options.onFocus=null] Event handler callback for {@link OpenSeadragon.Button.event:focus}.
|
||||
* @param {OpenSeadragon.EventHandler} [options.onBlur=null] Event handler callback for {@link OpenSeadragon.Button.event:blur}.
|
||||
* @param {Object} [options.userData=null] Arbitrary object to be passed unchanged to any attached handler methods.
|
||||
*/
|
||||
$.Button = function( options ) {
|
||||
|
||||
@ -111,7 +112,8 @@ $.Button = function( options ) {
|
||||
onEnter: null,
|
||||
onExit: null,
|
||||
onFocus: null,
|
||||
onBlur: null
|
||||
onBlur: null,
|
||||
userData: null
|
||||
|
||||
}, options );
|
||||
|
||||
@ -136,6 +138,13 @@ $.Button = function( options ) {
|
||||
this.imgDown.alt =
|
||||
this.tooltip;
|
||||
|
||||
// Allow pointer events to pass through the img elements so implicit
|
||||
// pointer capture works on touch devices
|
||||
$.setElementPointerEventsNone( this.imgRest );
|
||||
$.setElementPointerEventsNone( this.imgGroup );
|
||||
$.setElementPointerEventsNone( this.imgHover );
|
||||
$.setElementPointerEventsNone( this.imgDown );
|
||||
|
||||
this.element.style.position = "relative";
|
||||
$.setElementTouchActionNone( this.element );
|
||||
|
||||
@ -158,7 +167,7 @@ $.Button = function( options ) {
|
||||
this.imgDown.style.visibility =
|
||||
"hidden";
|
||||
|
||||
if ($.Browser.vendor == $.BROWSERS.FIREFOX && $.Browser.version < 3) {
|
||||
if ($.Browser.vendor === $.BROWSERS.FIREFOX && $.Browser.version < 3) {
|
||||
this.imgGroup.style.top =
|
||||
this.imgHover.style.top =
|
||||
this.imgDown.style.top =
|
||||
@ -203,6 +212,7 @@ $.Button = function( options ) {
|
||||
*/
|
||||
this.tracker = new $.MouseTracker({
|
||||
|
||||
userData: 'Button.tracker',
|
||||
element: this.element,
|
||||
clickTimeThreshold: this.clickTimeThreshold,
|
||||
clickDistThreshold: this.clickDistThreshold,
|
||||
@ -227,7 +237,7 @@ $.Button = function( options ) {
|
||||
},
|
||||
|
||||
focusHandler: function ( event ) {
|
||||
this.enterHandler( event );
|
||||
_this.tracker.enterHandler( event );
|
||||
/**
|
||||
* Raised when the Button element receives focus.
|
||||
*
|
||||
@ -241,7 +251,7 @@ $.Button = function( options ) {
|
||||
_this.raiseEvent( "focus", { originalEvent: event.originalEvent } );
|
||||
},
|
||||
|
||||
exitHandler: function( event ) {
|
||||
leaveHandler: function( event ) {
|
||||
outTo( _this, $.ButtonState.GROUP );
|
||||
if ( event.insideElementPressed ) {
|
||||
/**
|
||||
@ -259,7 +269,7 @@ $.Button = function( options ) {
|
||||
},
|
||||
|
||||
blurHandler: function ( event ) {
|
||||
this.exitHandler( event );
|
||||
_this.tracker.leaveHandler( event );
|
||||
/**
|
||||
* Raised when the Button element loses focus.
|
||||
*
|
||||
@ -350,9 +360,11 @@ $.Button = function( options ) {
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
*/
|
||||
_this.raiseEvent( "release", { originalEvent: event.originalEvent } );
|
||||
return false;
|
||||
|
||||
event.preventDefault = true;
|
||||
} else{
|
||||
event.preventDefault = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
@ -363,8 +375,8 @@ $.Button = function( options ) {
|
||||
$.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.Button.prototype */{
|
||||
|
||||
/**
|
||||
* TODO: Determine what this function is intended to do and if it's actually
|
||||
* useful as an API point.
|
||||
* Used by a button container element (e.g. a ButtonGroup) to transition the button state
|
||||
* to ButtonState.GROUP.
|
||||
* @function
|
||||
*/
|
||||
notifyGroupEnter: function() {
|
||||
@ -372,8 +384,8 @@ $.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.
|
||||
},
|
||||
|
||||
/**
|
||||
* TODO: Determine what this function is intended to do and if it's actually
|
||||
* useful as an API point.
|
||||
* Used by a button container element (e.g. a ButtonGroup) to transition the button state
|
||||
* to ButtonState.REST.
|
||||
* @function
|
||||
*/
|
||||
notifyGroupExit: function() {
|
||||
@ -396,6 +408,28 @@ $.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.
|
||||
this.element.disabled = false;
|
||||
$.setElementOpacity( this.element, 1.0, true );
|
||||
this.notifyGroupEnter();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this.imgRest) {
|
||||
this.element.removeChild(this.imgRest);
|
||||
this.imgRest = null;
|
||||
}
|
||||
if (this.imgGroup) {
|
||||
this.element.removeChild(this.imgGroup);
|
||||
this.imgGroup = null;
|
||||
}
|
||||
if (this.imgHover) {
|
||||
this.element.removeChild(this.imgHover);
|
||||
this.imgHover = null;
|
||||
}
|
||||
if (this.imgDown) {
|
||||
this.element.removeChild(this.imgDown);
|
||||
this.imgDown = null;
|
||||
}
|
||||
this.removeAllHandlers();
|
||||
this.tracker.destroy();
|
||||
this.element = null;
|
||||
}
|
||||
|
||||
});
|
||||
@ -451,13 +485,13 @@ function inTo( button, newState ) {
|
||||
}
|
||||
|
||||
if ( newState >= $.ButtonState.GROUP &&
|
||||
button.currentState == $.ButtonState.REST ) {
|
||||
button.currentState === $.ButtonState.REST ) {
|
||||
stopFading( button );
|
||||
button.currentState = $.ButtonState.GROUP;
|
||||
}
|
||||
|
||||
if ( newState >= $.ButtonState.HOVER &&
|
||||
button.currentState == $.ButtonState.GROUP ) {
|
||||
button.currentState === $.ButtonState.GROUP ) {
|
||||
if( button.imgHover ){
|
||||
button.imgHover.style.visibility = "";
|
||||
}
|
||||
@ -465,7 +499,7 @@ function inTo( button, newState ) {
|
||||
}
|
||||
|
||||
if ( newState >= $.ButtonState.DOWN &&
|
||||
button.currentState == $.ButtonState.HOVER ) {
|
||||
button.currentState === $.ButtonState.HOVER ) {
|
||||
if( button.imgDown ){
|
||||
button.imgDown.style.visibility = "";
|
||||
}
|
||||
@ -481,7 +515,7 @@ function outTo( button, newState ) {
|
||||
}
|
||||
|
||||
if ( newState <= $.ButtonState.HOVER &&
|
||||
button.currentState == $.ButtonState.DOWN ) {
|
||||
button.currentState === $.ButtonState.DOWN ) {
|
||||
if( button.imgDown ){
|
||||
button.imgDown.style.visibility = "hidden";
|
||||
}
|
||||
@ -489,7 +523,7 @@ function outTo( button, newState ) {
|
||||
}
|
||||
|
||||
if ( newState <= $.ButtonState.GROUP &&
|
||||
button.currentState == $.ButtonState.HOVER ) {
|
||||
button.currentState === $.ButtonState.HOVER ) {
|
||||
if( button.imgHover ){
|
||||
button.imgHover.style.visibility = "hidden";
|
||||
}
|
||||
@ -497,7 +531,7 @@ function outTo( button, newState ) {
|
||||
}
|
||||
|
||||
if ( newState <= $.ButtonState.REST &&
|
||||
button.currentState == $.ButtonState.GROUP ) {
|
||||
button.currentState === $.ButtonState.GROUP ) {
|
||||
beginFading( button );
|
||||
button.currentState = $.ButtonState.REST;
|
||||
}
|
||||
|
@ -88,6 +88,7 @@ $.ButtonGroup = function( options ) {
|
||||
* @memberof OpenSeadragon.ButtonGroup#
|
||||
*/
|
||||
this.tracker = new $.MouseTracker({
|
||||
userData: 'ButtonGroup.tracker',
|
||||
element: this.element,
|
||||
clickTimeThreshold: this.clickTimeThreshold,
|
||||
clickDistThreshold: this.clickDistThreshold,
|
||||
@ -97,7 +98,7 @@ $.ButtonGroup = function( options ) {
|
||||
_this.buttons[ i ].notifyGroupEnter();
|
||||
}
|
||||
},
|
||||
exitHandler: function ( event ) {
|
||||
leaveHandler: function ( event ) {
|
||||
var i;
|
||||
if ( !event.insideElementPressed ) {
|
||||
for ( i = 0; i < _this.buttons.length; i++ ) {
|
||||
@ -127,8 +128,18 @@ $.ButtonGroup.prototype = {
|
||||
* @function
|
||||
* @private
|
||||
*/
|
||||
emulateExit: function() {
|
||||
this.tracker.exitHandler( { eventSource: this.tracker } );
|
||||
emulateLeave: function() {
|
||||
this.tracker.leaveHandler( { eventSource: this.tracker } );
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
while (this.buttons.length) {
|
||||
var button = this.buttons.pop();
|
||||
this.element.removeChild(button.element);
|
||||
button.destroy();
|
||||
}
|
||||
this.tracker.destroy();
|
||||
this.element = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -112,13 +112,13 @@ $.Control = function ( element, options, container ) {
|
||||
* @member {Element} wrapper
|
||||
* @memberof OpenSeadragon.Control#
|
||||
*/
|
||||
if ( this.anchor == $.ControlAnchor.ABSOLUTE ) {
|
||||
if ( this.anchor === $.ControlAnchor.ABSOLUTE ) {
|
||||
this.wrapper = $.makeNeutralElement( "div" );
|
||||
this.wrapper.style.position = "absolute";
|
||||
this.wrapper.style.top = typeof (options.top) == "number" ? (options.top + 'px') : options.top;
|
||||
this.wrapper.style.left = typeof (options.left) == "number" ? (options.left + 'px') : options.left;
|
||||
this.wrapper.style.height = typeof (options.height) == "number" ? (options.height + 'px') : options.height;
|
||||
this.wrapper.style.width = typeof (options.width) == "number" ? (options.width + 'px') : options.width;
|
||||
this.wrapper.style.top = typeof (options.top) === "number" ? (options.top + 'px') : options.top;
|
||||
this.wrapper.style.left = typeof (options.left) === "number" ? (options.left + 'px') : options.left;
|
||||
this.wrapper.style.height = typeof (options.height) === "number" ? (options.height + 'px') : options.height;
|
||||
this.wrapper.style.width = typeof (options.width) === "number" ? (options.width + 'px') : options.width;
|
||||
this.wrapper.style.margin = "0px";
|
||||
this.wrapper.style.padding = "0px";
|
||||
|
||||
@ -130,7 +130,7 @@ $.Control = function ( element, options, container ) {
|
||||
} else {
|
||||
this.wrapper = $.makeNeutralElement( "div" );
|
||||
this.wrapper.style.display = "inline-block";
|
||||
if ( this.anchor == $.ControlAnchor.NONE ) {
|
||||
if ( this.anchor === $.ControlAnchor.NONE ) {
|
||||
// IE6 fix
|
||||
this.wrapper.style.width = this.wrapper.style.height = "100%";
|
||||
}
|
||||
@ -138,8 +138,8 @@ $.Control = function ( element, options, container ) {
|
||||
this.wrapper.appendChild( this.element );
|
||||
|
||||
if (options.attachToViewer ) {
|
||||
if ( this.anchor == $.ControlAnchor.TOP_RIGHT ||
|
||||
this.anchor == $.ControlAnchor.BOTTOM_RIGHT ) {
|
||||
if ( this.anchor === $.ControlAnchor.TOP_RIGHT ||
|
||||
this.anchor === $.ControlAnchor.BOTTOM_RIGHT ) {
|
||||
this.container.insertBefore(
|
||||
this.wrapper,
|
||||
this.container.firstChild
|
||||
@ -161,7 +161,9 @@ $.Control.prototype = {
|
||||
*/
|
||||
destroy: function() {
|
||||
this.wrapper.removeChild( this.element );
|
||||
if (this.anchor !== $.ControlAnchor.NONE) {
|
||||
this.container.removeChild(this.wrapper);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -170,7 +172,7 @@ $.Control.prototype = {
|
||||
* @return {Boolean} true if currently visible, false otherwise.
|
||||
*/
|
||||
isVisible: function() {
|
||||
return this.wrapper.style.display != "none";
|
||||
return this.wrapper.style.display !== "none";
|
||||
},
|
||||
|
||||
/**
|
||||
@ -180,7 +182,7 @@ $.Control.prototype = {
|
||||
*/
|
||||
setVisible: function( visible ) {
|
||||
this.wrapper.style.display = visible ?
|
||||
( this.anchor == $.ControlAnchor.ABSOLUTE ? 'block' : 'inline-block' ) :
|
||||
( this.anchor === $.ControlAnchor.ABSOLUTE ? 'block' : 'inline-block' ) :
|
||||
"none";
|
||||
},
|
||||
|
||||
@ -190,7 +192,7 @@ $.Control.prototype = {
|
||||
* @param {Number} opactiy - a value between 1 and 0 inclusively.
|
||||
*/
|
||||
setOpacity: function( opacity ) {
|
||||
if ( this.element[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) {
|
||||
if ( this.element[ $.SIGNAL ] && $.Browser.vendor === $.BROWSERS.IE ) {
|
||||
$.setElementOpacity( this.element, opacity, true );
|
||||
} else {
|
||||
$.setElementOpacity( this.wrapper, opacity, true );
|
||||
|
@ -218,7 +218,7 @@
|
||||
i;
|
||||
|
||||
for ( i = controls.length - 1; i >= 0; i-- ) {
|
||||
if ( controls[ i ].element == element ) {
|
||||
if ( controls[ i ].element === element ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +126,10 @@ $.Drawer = function( options ) {
|
||||
this.canvas.style.height = "100%";
|
||||
this.canvas.style.position = "absolute";
|
||||
$.setElementOpacity( this.canvas, this.opacity, true );
|
||||
// Allow pointer events to pass through the canvas element so implicit
|
||||
// pointer capture works on touch devices
|
||||
$.setElementPointerEventsNone( this.canvas );
|
||||
$.setElementTouchActionNone( this.canvas );
|
||||
|
||||
// explicit left-align
|
||||
this.container.style.textAlign = "left";
|
||||
@ -166,6 +170,41 @@ $.Drawer.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* This function converts the given point from to the drawer coordinate by
|
||||
* multiplying it with the pixel density.
|
||||
* This function does not take rotation into account, thus assuming provided
|
||||
* point is at 0 degree.
|
||||
* @param {OpenSeadragon.Point} point - the pixel point to convert
|
||||
*/
|
||||
viewportCoordToDrawerCoord: function(point) {
|
||||
var vpPoint = this.viewport.pixelFromPointNoRotate(point, true);
|
||||
return new $.Point(
|
||||
vpPoint.x * $.pixelDensityRatio,
|
||||
vpPoint.y * $.pixelDensityRatio
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will create multiple polygon paths on the drawing context by provided polygons,
|
||||
* then clip the context to the paths.
|
||||
* @param {OpenSeadragon.Point[][]} polygons - an array of polygons. A polygon is an array of OpenSeadragon.Point
|
||||
* @param {Boolean} useSketch - Whether to use the sketch canvas or not.
|
||||
*/
|
||||
clipWithPolygons: function (polygons, useSketch) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
var context = this._getContext(useSketch);
|
||||
context.beginPath();
|
||||
polygons.forEach(function (polygon) {
|
||||
polygon.forEach(function (coord, i) {
|
||||
context[i === 0 ? 'moveTo' : 'lineTo'](coord.x, coord.y);
|
||||
});
|
||||
});
|
||||
context.clip();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the opacity of the drawer.
|
||||
* @param {Number} opacity
|
||||
@ -249,8 +288,8 @@ $.Drawer.prototype = {
|
||||
this.canvas.innerHTML = "";
|
||||
if ( this.useCanvas ) {
|
||||
var viewportSize = this._calculateCanvasSize();
|
||||
if( this.canvas.width != viewportSize.x ||
|
||||
this.canvas.height != viewportSize.y ) {
|
||||
if( this.canvas.width !== viewportSize.x ||
|
||||
this.canvas.height !== viewportSize.y ) {
|
||||
this.canvas.width = viewportSize.x;
|
||||
this.canvas.height = viewportSize.y;
|
||||
this._updateImageSmoothingEnabled(this.context);
|
||||
@ -633,8 +672,6 @@ $.Drawer.prototype = {
|
||||
|
||||
// private
|
||||
_updateImageSmoothingEnabled: function(context){
|
||||
context.mozImageSmoothingEnabled = this._imageSmoothingEnabled;
|
||||
context.webkitImageSmoothingEnabled = this._imageSmoothingEnabled;
|
||||
context.msImageSmoothingEnabled = this._imageSmoothingEnabled;
|
||||
context.imageSmoothingEnabled = this._imageSmoothingEnabled;
|
||||
},
|
||||
|
@ -108,7 +108,7 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
|
||||
if ( data.Image ) {
|
||||
ns = data.Image.xmlns;
|
||||
} else if ( data.documentElement) {
|
||||
if ("Image" == data.documentElement.localName || "Image" == data.documentElement.tagName) {
|
||||
if ("Image" === data.documentElement.localName || "Image" === data.documentElement.tagName) {
|
||||
ns = data.documentElement.namespaceURI;
|
||||
}
|
||||
}
|
||||
@ -142,9 +142,9 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
|
||||
|
||||
if (url && !options.tilesUrl) {
|
||||
options.tilesUrl = url.replace(
|
||||
/([^\/]+?)(\.(dzi|xml|js)?(\?[^\/]*)?)?\/?$/, '$1_files/');
|
||||
/([^/]+?)(\.(dzi|xml|js)?(\?[^/]*)?)?\/?$/, '$1_files/');
|
||||
|
||||
if (url.search(/\.(dzi|xml|js)\?/) != -1) {
|
||||
if (url.search(/\.(dzi|xml|js)\?/) !== -1) {
|
||||
options.queryParams = url.match(/\?.*/);
|
||||
}else{
|
||||
options.queryParams = '';
|
||||
@ -240,7 +240,7 @@ function configureFromXML( tileSource, xmlDoc ){
|
||||
sizeNode,
|
||||
i;
|
||||
|
||||
if ( rootName == "Image" ) {
|
||||
if ( rootName === "Image" ) {
|
||||
|
||||
try {
|
||||
sizeNode = root.getElementsByTagName("Size" )[ 0 ];
|
||||
@ -304,9 +304,9 @@ function configureFromXML( tileSource, xmlDoc ){
|
||||
e :
|
||||
new Error( $.getString("Errors.Dzi") );
|
||||
}
|
||||
} else if ( rootName == "Collection" ) {
|
||||
} else if ( rootName === "Collection" ) {
|
||||
throw new Error( $.getString( "Errors.Dzc" ) );
|
||||
} else if ( rootName == "Error" ) {
|
||||
} else if ( rootName === "Error" ) {
|
||||
var messageNode = root.getElementsByTagName("Message")[0];
|
||||
var message = messageNode.firstChild.nodeValue;
|
||||
throw new Error(message);
|
||||
|
@ -59,6 +59,8 @@ $.IIIFTileSource = function( options ){
|
||||
|
||||
this.tileFormat = this.tileFormat || 'jpg';
|
||||
|
||||
this.version = options.version;
|
||||
|
||||
// N.B. 2.0 renamed scale_factors to scaleFactors
|
||||
if ( this.tile_width && this.tile_height ) {
|
||||
options.tileWidth = this.tile_width;
|
||||
@ -69,7 +71,7 @@ $.IIIFTileSource = function( options ){
|
||||
options.tileSize = this.tile_height;
|
||||
} else if ( this.tiles ) {
|
||||
// Version 2.0 forwards
|
||||
if ( this.tiles.length == 1 ) {
|
||||
if ( this.tiles.length === 1 ) {
|
||||
options.tileWidth = this.tiles[0].width;
|
||||
// Use height if provided, otherwise assume square tiles and use width.
|
||||
options.tileHeight = this.tiles[0].height || this.tiles[0].width;
|
||||
@ -88,7 +90,7 @@ $.IIIFTileSource = function( options ){
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ( canBeTiled(options.profile) ) {
|
||||
} else if ( canBeTiled(options) ) {
|
||||
// use the largest of tileOptions that is smaller than the short dimension
|
||||
var shortDim = Math.min( this.height, this.width ),
|
||||
tileOptions = [256, 512, 1024],
|
||||
@ -150,12 +152,12 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
|
||||
supports: function( data, url ) {
|
||||
// Version 2.0 and forwards
|
||||
if (data.protocol && data.protocol == 'http://iiif.io/api/image') {
|
||||
if (data.protocol && data.protocol === 'http://iiif.io/api/image') {
|
||||
return true;
|
||||
// Version 1.1
|
||||
} else if ( data['@context'] && (
|
||||
data['@context'] == "http://library.stanford.edu/iiif/image-api/1.1/context.json" ||
|
||||
data['@context'] == "http://iiif.io/api/image/1/context.json") ) {
|
||||
data['@context'] === "http://library.stanford.edu/iiif/image-api/1.1/context.json" ||
|
||||
data['@context'] === "http://iiif.io/api/image/1/context.json") ) {
|
||||
// N.B. the iiif.io context is wrong, but where the representation lives so likely to be used
|
||||
return true;
|
||||
|
||||
@ -166,8 +168,8 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
} else if ( data.identifier && data.width && data.height ) {
|
||||
return true;
|
||||
} else if ( data.documentElement &&
|
||||
"info" == data.documentElement.tagName &&
|
||||
"http://library.stanford.edu/iiif/image-api/ns/" ==
|
||||
"info" === data.documentElement.tagName &&
|
||||
"http://library.stanford.edu/iiif/image-api/ns/" ===
|
||||
data.documentElement.namespaceURI) {
|
||||
return true;
|
||||
|
||||
@ -201,11 +203,42 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
var options = configureFromXml10( data );
|
||||
options['@context'] = "http://iiif.io/api/image/1.0/context.json";
|
||||
options['@id'] = url.replace('/info.xml', '');
|
||||
options.version = 1;
|
||||
return options;
|
||||
} else {
|
||||
if ( !data['@context'] ) {
|
||||
data['@context'] = 'http://iiif.io/api/image/1.0/context.json';
|
||||
data['@id'] = url.replace('/info.json', '');
|
||||
data.version = 1;
|
||||
} else {
|
||||
var context = data['@context'];
|
||||
if (Array.isArray(context)) {
|
||||
for (var i = 0; i < context.length; i++) {
|
||||
if (typeof context[i] === 'string' &&
|
||||
( /^http:\/\/iiif\.io\/api\/image\/[1-3]\/context\.json$/.test(context[i]) ||
|
||||
context[i] === 'http://library.stanford.edu/iiif/image-api/1.1/context.json' ) ) {
|
||||
context = context[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (context) {
|
||||
case 'http://iiif.io/api/image/1/context.json':
|
||||
case 'http://library.stanford.edu/iiif/image-api/1.1/context.json':
|
||||
data.version = 1;
|
||||
break;
|
||||
case 'http://iiif.io/api/image/2/context.json':
|
||||
data.version = 2;
|
||||
break;
|
||||
case 'http://iiif.io/api/image/3/context.json':
|
||||
data.version = 3;
|
||||
break;
|
||||
default:
|
||||
$.console.error('Data has a @context property which contains no known IIIF context URI.');
|
||||
}
|
||||
}
|
||||
if ( !data['@id'] && data['id'] ) {
|
||||
data['@id'] = data['id'];
|
||||
}
|
||||
if(data.preferredFormats) {
|
||||
for (var f = 0; f < data.preferredFormats.length; f++ ) {
|
||||
@ -350,27 +383,28 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
iiifTileH,
|
||||
iiifSize,
|
||||
iiifSizeW,
|
||||
iiifSizeH,
|
||||
iiifQuality,
|
||||
uri,
|
||||
isv1;
|
||||
uri;
|
||||
|
||||
tileWidth = this.getTileWidth(level);
|
||||
tileHeight = this.getTileHeight(level);
|
||||
iiifTileSizeWidth = Math.ceil( tileWidth / scale );
|
||||
iiifTileSizeHeight = Math.ceil( tileHeight / scale );
|
||||
isv1 = ( this['@context'].indexOf('/1.0/context.json') > -1 ||
|
||||
this['@context'].indexOf('/1.1/context.json') > -1 ||
|
||||
this['@context'].indexOf('/1/context.json') > -1 );
|
||||
if (isv1) {
|
||||
if (this.version === 1) {
|
||||
iiifQuality = "native." + this.tileFormat;
|
||||
} else {
|
||||
iiifQuality = "default." + this.tileFormat;
|
||||
}
|
||||
if ( levelWidth < tileWidth && levelHeight < tileHeight ){
|
||||
if ( isv1 || levelWidth !== this.width ) {
|
||||
iiifSize = levelWidth + ",";
|
||||
} else {
|
||||
if ( this.version === 2 && levelWidth === this.width ) {
|
||||
iiifSize = "full";
|
||||
} else if ( this.version === 3 && levelWidth === this.width && levelHeight === this.height ) {
|
||||
iiifSize = "max";
|
||||
} else if ( this.version === 3 ) {
|
||||
iiifSize = levelWidth + "," + levelHeight;
|
||||
} else {
|
||||
iiifSize = levelWidth + ",";
|
||||
}
|
||||
iiifRegion = 'full';
|
||||
} else {
|
||||
@ -384,8 +418,13 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' );
|
||||
}
|
||||
iiifSizeW = Math.ceil( iiifTileW * scale );
|
||||
if ( (!isv1) && iiifSizeW === this.width ) {
|
||||
iiifSizeH = Math.ceil( iiifTileH * scale );
|
||||
if ( this.version === 2 && iiifSizeW === this.width ) {
|
||||
iiifSize = "full";
|
||||
} else if ( this.version === 3 && iiifSizeW === this.width && iiifSizeH === this.height ) {
|
||||
iiifSize = "max";
|
||||
} else if (this.version === 3) {
|
||||
iiifSize = iiifSizeW + "," + iiifSizeH;
|
||||
} else {
|
||||
iiifSize = iiifSizeW + ",";
|
||||
}
|
||||
@ -393,6 +432,11 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
uri = [ this['@id'], iiifRegion, iiifSize, IIIF_ROTATION, iiifQuality ].join( '/' );
|
||||
|
||||
return uri;
|
||||
},
|
||||
|
||||
__testonly__: {
|
||||
canBeTiled: canBeTiled,
|
||||
constructLevels: constructLevels
|
||||
}
|
||||
|
||||
});
|
||||
@ -403,18 +447,24 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
* @param {array} profile - IIIF profile array
|
||||
* @throws {Error}
|
||||
*/
|
||||
function canBeTiled ( profile ) {
|
||||
function canBeTiled ( options ) {
|
||||
var level0Profiles = [
|
||||
"http://library.stanford.edu/iiif/image-api/compliance.html#level0",
|
||||
"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0",
|
||||
"http://iiif.io/api/image/2/level0.json"
|
||||
"http://iiif.io/api/image/2/level0.json",
|
||||
"level0",
|
||||
"https://iiif.io/api/image/3/level0.json"
|
||||
];
|
||||
var isLevel0 = (level0Profiles.indexOf(profile[0]) !== -1);
|
||||
var hasSizeByW = false;
|
||||
if ( profile.length > 1 && profile[1].supports ) {
|
||||
hasSizeByW = profile[1].supports.indexOf( "sizeByW" ) !== -1;
|
||||
var profileLevel = Array.isArray(options.profile) ? options.profile[0] : options.profile;
|
||||
var isLevel0 = (level0Profiles.indexOf(profileLevel) !== -1);
|
||||
var hasCanoncicalSizeFeature = false;
|
||||
if ( options.version === 2 && options.profile.length > 1 && options.profile[1].supports ) {
|
||||
hasCanoncicalSizeFeature = options.profile[1].supports.indexOf( "sizeByW" ) !== -1;
|
||||
}
|
||||
return !isLevel0 || hasSizeByW;
|
||||
if ( options.version === 3 && options.extraFeatures ) {
|
||||
hasCanoncicalSizeFeature = options.extraFeatures.indexOf( "sizeByWh" ) !== -1;
|
||||
}
|
||||
return !isLevel0 || hasCanoncicalSizeFeature;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,7 +477,9 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
var levels = [];
|
||||
for(var i = 0; i < options.sizes.length; i++) {
|
||||
levels.push({
|
||||
url: options['@id'] + '/full/' + options.sizes[i].width + ',/0/default.' + options.tileFormat,
|
||||
url: options['@id'] + '/full/' + options.sizes[i].width + ',' +
|
||||
(options.version === 3 ? options.sizes[i].height : '') +
|
||||
'/0/default.' + options.tileFormat,
|
||||
width: options.sizes[i].width,
|
||||
height: options.sizes[i].height
|
||||
});
|
||||
@ -448,7 +500,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
rootName = root.tagName,
|
||||
configuration = null;
|
||||
|
||||
if ( rootName == "info" ) {
|
||||
if ( rootName === "info" ) {
|
||||
try {
|
||||
configuration = {};
|
||||
parseXML10( root, configuration );
|
||||
@ -466,7 +518,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
function parseXML10( node, configuration, property ) {
|
||||
var i,
|
||||
value;
|
||||
if ( node.nodeType == 3 && property ) {//text node
|
||||
if ( node.nodeType === 3 && property ) {//text node
|
||||
value = node.nodeValue.trim();
|
||||
if( value.match(/^\d*$/)){
|
||||
value = Number( value );
|
||||
@ -479,7 +531,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
}
|
||||
configuration[ property ].push( value );
|
||||
}
|
||||
} else if( node.nodeType == 1 ){
|
||||
} else if( node.nodeType === 1 ){
|
||||
for( i = 0; i < node.childNodes.length; i++ ){
|
||||
parseXML10( node.childNodes[ i ], configuration, node.nodeName );
|
||||
}
|
||||
|
@ -114,9 +114,8 @@
|
||||
}
|
||||
|
||||
$.addEvent(image, 'load', function () {
|
||||
/* IE8 fix since it has no naturalWidth and naturalHeight */
|
||||
_this.width = Object.prototype.hasOwnProperty.call(image, 'naturalWidth') ? image.naturalWidth : image.width;
|
||||
_this.height = Object.prototype.hasOwnProperty.call(image, 'naturalHeight') ? image.naturalHeight : image.height;
|
||||
_this.width = image.naturalWidth;
|
||||
_this.height = image.naturalHeight;
|
||||
_this.aspectRatio = _this.width / _this.height;
|
||||
_this.dimensions = new $.Point(_this.width, _this.height);
|
||||
_this._tileWidth = _this.width;
|
||||
@ -195,6 +194,13 @@
|
||||
}
|
||||
return context;
|
||||
},
|
||||
/**
|
||||
* Destroys ImageTileSource
|
||||
* @function
|
||||
*/
|
||||
destroy: function () {
|
||||
this._freeupCanvasMemory();
|
||||
},
|
||||
|
||||
// private
|
||||
//
|
||||
@ -203,9 +209,8 @@
|
||||
_buildLevels: function () {
|
||||
var levels = [{
|
||||
url: this._image.src,
|
||||
/* IE8 fix since it has no naturalWidth and naturalHeight */
|
||||
width: Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width,
|
||||
height: Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height
|
||||
width: this._image.naturalWidth,
|
||||
height: this._image.naturalHeight
|
||||
}];
|
||||
|
||||
if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) {
|
||||
@ -214,9 +219,8 @@
|
||||
return levels;
|
||||
}
|
||||
|
||||
/* IE8 fix since it has no naturalWidth and naturalHeight */
|
||||
var currentWidth = Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width;
|
||||
var currentHeight = Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height;
|
||||
var currentWidth = this._image.naturalWidth;
|
||||
var currentHeight = this._image.naturalHeight;
|
||||
|
||||
|
||||
var bigCanvas = document.createElement("canvas");
|
||||
@ -258,7 +262,19 @@
|
||||
bigContext = smallContext;
|
||||
}
|
||||
return levels;
|
||||
},
|
||||
/**
|
||||
* Free up canvas memory
|
||||
* (iOS 12 or higher on 2GB RAM device has only 224MB canvas memory,
|
||||
* and Safari keeps canvas until its height and width will be set to 0).
|
||||
* @function
|
||||
*/
|
||||
_freeupCanvasMemory: function () {
|
||||
for (var i = 0; i < this.levels.length; i++) {
|
||||
this.levels[i].context2D.canvas.height = 0;
|
||||
this.levels[i].context2D.canvas.width = 0;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
}(OpenSeadragon));
|
||||
|
@ -109,10 +109,10 @@ $.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenS
|
||||
supports: function( data, url ){
|
||||
return (
|
||||
data.type &&
|
||||
"legacy-image-pyramid" == data.type
|
||||
"legacy-image-pyramid" === data.type
|
||||
) || (
|
||||
data.documentElement &&
|
||||
"legacy-image-pyramid" == data.documentElement.getAttribute('type')
|
||||
"legacy-image-pyramid" === data.documentElement.getAttribute('type')
|
||||
);
|
||||
},
|
||||
|
||||
@ -241,7 +241,7 @@ function configureFromXML( tileSource, xmlDoc ){
|
||||
level,
|
||||
i;
|
||||
|
||||
if ( rootName == "image" ) {
|
||||
if ( rootName === "image" ) {
|
||||
|
||||
try {
|
||||
conf = {
|
||||
@ -267,9 +267,9 @@ function configureFromXML( tileSource, xmlDoc ){
|
||||
e :
|
||||
new Error( 'Unknown error parsing Legacy Image Pyramid XML.' );
|
||||
}
|
||||
} else if ( rootName == "collection" ) {
|
||||
} else if ( rootName === "collection" ) {
|
||||
throw new Error( 'Legacy Image Pyramid Collections not yet supported.' );
|
||||
} else if ( rootName == "error" ) {
|
||||
} else if ( rootName === "error" ) {
|
||||
throw new Error( 'Error: ' + xmlDoc );
|
||||
}
|
||||
|
||||
|
2549
src/mousetracker.js
2549
src/mousetracker.js
File diff suppressed because it is too large
Load Diff
@ -66,15 +66,15 @@ $.Navigator = function( options ){
|
||||
};
|
||||
|
||||
if( options.position ){
|
||||
if( 'BOTTOM_RIGHT' == options.position ){
|
||||
if( 'BOTTOM_RIGHT' === options.position ){
|
||||
options.controlOptions.anchor = $.ControlAnchor.BOTTOM_RIGHT;
|
||||
} else if( 'BOTTOM_LEFT' == options.position ){
|
||||
} else if( 'BOTTOM_LEFT' === options.position ){
|
||||
options.controlOptions.anchor = $.ControlAnchor.BOTTOM_LEFT;
|
||||
} else if( 'TOP_RIGHT' == options.position ){
|
||||
} else if( 'TOP_RIGHT' === options.position ){
|
||||
options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT;
|
||||
} else if( 'TOP_LEFT' == options.position ){
|
||||
} else if( 'TOP_LEFT' === options.position ){
|
||||
options.controlOptions.anchor = $.ControlAnchor.TOP_LEFT;
|
||||
} else if( 'ABSOLUTE' == options.position ){
|
||||
} else if( 'ABSOLUTE' === options.position ){
|
||||
options.controlOptions.anchor = $.ControlAnchor.ABSOLUTE;
|
||||
options.controlOptions.top = options.top;
|
||||
options.controlOptions.left = options.left;
|
||||
@ -128,7 +128,7 @@ $.Navigator = function( options ){
|
||||
this.totalBorderWidths = new $.Point(this.borderWidth * 2, this.borderWidth * 2).minus(this.fudge);
|
||||
|
||||
|
||||
if ( options.controlOptions.anchor != $.ControlAnchor.NONE ) {
|
||||
if ( options.controlOptions.anchor !== $.ControlAnchor.NONE ) {
|
||||
(function( style, borderWidth ){
|
||||
style.margin = '0px';
|
||||
style.border = borderWidth + 'px solid ' + options.borderColor;
|
||||
@ -167,20 +167,24 @@ $.Navigator = function( options ){
|
||||
style.zIndex = 999999999;
|
||||
style.cursor = 'default';
|
||||
}( this.displayRegion.style, this.borderWidth ));
|
||||
$.setElementPointerEventsNone( this.displayRegion );
|
||||
$.setElementTouchActionNone( this.displayRegion );
|
||||
|
||||
this.displayRegionContainer = $.makeNeutralElement("div");
|
||||
this.displayRegionContainer.id = this.element.id + '-displayregioncontainer';
|
||||
this.displayRegionContainer.className = "displayregioncontainer";
|
||||
this.displayRegionContainer.style.width = "100%";
|
||||
this.displayRegionContainer.style.height = "100%";
|
||||
$.setElementPointerEventsNone( this.displayRegionContainer );
|
||||
$.setElementTouchActionNone( this.displayRegionContainer );
|
||||
|
||||
viewer.addControl(
|
||||
this.element,
|
||||
options.controlOptions
|
||||
);
|
||||
|
||||
this._resizeWithViewer = options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE &&
|
||||
options.controlOptions.anchor != $.ControlAnchor.NONE;
|
||||
this._resizeWithViewer = options.controlOptions.anchor !== $.ControlAnchor.ABSOLUTE &&
|
||||
options.controlOptions.anchor !== $.ControlAnchor.NONE;
|
||||
|
||||
if (options.width && options.height) {
|
||||
this.setWidth(options.width);
|
||||
@ -221,12 +225,29 @@ $.Navigator = function( options ){
|
||||
// Remove the base class' (Viewer's) innerTracker and replace it with our own
|
||||
this.innerTracker.destroy();
|
||||
this.innerTracker = new $.MouseTracker({
|
||||
element: this.element,
|
||||
userData: 'Navigator.innerTracker',
|
||||
element: this.element, //this.canvas,
|
||||
dragHandler: $.delegate( this, onCanvasDrag ),
|
||||
clickHandler: $.delegate( this, onCanvasClick ),
|
||||
releaseHandler: $.delegate( this, onCanvasRelease ),
|
||||
scrollHandler: $.delegate( this, onCanvasScroll )
|
||||
scrollHandler: $.delegate( this, onCanvasScroll ),
|
||||
preProcessEventHandler: function (eventInfo) {
|
||||
if (eventInfo.eventType === 'wheel') {
|
||||
//don't scroll the page up and down if the user is scrolling
|
||||
//in the navigator
|
||||
eventInfo.preventDefault = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.outerTracker.userData = 'Navigator.outerTracker';
|
||||
|
||||
// this.innerTracker is attached to this.element...we need to allow pointer
|
||||
// events to pass through this Viewer's canvas/container elements so implicit
|
||||
// pointer capture works on touch devices
|
||||
//TODO an alternative is to attach the new MouseTracker to this.canvas...not
|
||||
// sure why it isn't already (see MouseTracker constructor call above)
|
||||
$.setElementPointerEventsNone( this.canvas );
|
||||
$.setElementPointerEventsNone( this.container );
|
||||
|
||||
this.addHandler("reset-size", function() {
|
||||
if (_this.viewport) {
|
||||
@ -282,7 +303,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
*/
|
||||
setWidth: function(width) {
|
||||
this.width = width;
|
||||
this.element.style.width = typeof (width) == "number" ? (width + 'px') : width;
|
||||
this.element.style.width = typeof (width) === "number" ? (width + 'px') : width;
|
||||
this._resizeWithViewer = false;
|
||||
},
|
||||
|
||||
@ -292,7 +313,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
*/
|
||||
setHeight: function(height) {
|
||||
this.height = height;
|
||||
this.element.style.height = typeof (height) == "number" ? (height + 'px') : height;
|
||||
this.element.style.height = typeof (height) === "number" ? (height + 'px') : height;
|
||||
this._resizeWithViewer = false;
|
||||
},
|
||||
|
||||
@ -383,6 +404,8 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
var myItem = event.item;
|
||||
myItem._originalForNavigator = original;
|
||||
_this._matchBounds(myItem, original, true);
|
||||
_this._matchOpacity(myItem, original);
|
||||
_this._matchCompositeOperation(myItem, original);
|
||||
|
||||
function matchBounds() {
|
||||
_this._matchBounds(myItem, original);
|
||||
@ -406,6 +429,10 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
return $.Viewer.prototype.addTiledImage.apply(this, [optionsClone]);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
return $.Viewer.prototype.destroy.apply(this);
|
||||
},
|
||||
|
||||
// private
|
||||
_getMatchingItem: function(theirItem) {
|
||||
var count = this.world.getItemCount();
|
||||
@ -427,6 +454,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
myItem.setWidth(bounds.width, immediately);
|
||||
myItem.setRotation(theirItem.getRotation(), immediately);
|
||||
myItem.setClip(theirItem.getClip());
|
||||
myItem.setFlip(theirItem.getFlip());
|
||||
},
|
||||
|
||||
// private
|
||||
@ -453,7 +481,7 @@ function onCanvasClick( event ) {
|
||||
quick: event.quick,
|
||||
shift: event.shift,
|
||||
originalEvent: event.originalEvent,
|
||||
preventDefaultAction: event.preventDefaultAction
|
||||
preventDefaultAction: false
|
||||
};
|
||||
/**
|
||||
* Raised when a click event occurs on the {@link OpenSeadragon.Viewer#navigator} element.
|
||||
@ -505,7 +533,7 @@ function onCanvasDrag( event ) {
|
||||
direction: event.direction,
|
||||
shift: event.shift,
|
||||
originalEvent: event.originalEvent,
|
||||
preventDefaultAction: event.preventDefaultAction
|
||||
preventDefaultAction: false
|
||||
};
|
||||
/**
|
||||
* Raised when a drag event occurs on the {@link OpenSeadragon.Viewer#navigator} element.
|
||||
@ -522,7 +550,7 @@ function onCanvasDrag( event ) {
|
||||
* @property {Boolean} shift - True if the shift key was pressed during this event.
|
||||
* @property {Object} originalEvent - The original DOM event.
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
* @property {Boolean} preventDefaultAction - Set to true to prevent default click to zoom behaviour. Default: false.
|
||||
* @property {Boolean} preventDefaultAction - Set to true to prevent default drag to pan behaviour. Default: false.
|
||||
*/
|
||||
this.viewer.raiseEvent('navigator-drag', canvasDragEventArgs);
|
||||
|
||||
@ -568,6 +596,15 @@ function onCanvasRelease( event ) {
|
||||
* @function
|
||||
*/
|
||||
function onCanvasScroll( event ) {
|
||||
var eventArgs = {
|
||||
tracker: event.eventSource,
|
||||
position: event.position,
|
||||
scroll: event.scroll,
|
||||
shift: event.shift,
|
||||
originalEvent: event.originalEvent,
|
||||
preventDefault: event.preventDefault
|
||||
};
|
||||
|
||||
/**
|
||||
* Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#navigator} element (mouse wheel, touch pinch, etc.).
|
||||
*
|
||||
@ -580,19 +617,12 @@ function onCanvasScroll( event ) {
|
||||
* @property {Number} scroll - The scroll delta for the event.
|
||||
* @property {Boolean} shift - True if the shift key was pressed during this event.
|
||||
* @property {Object} originalEvent - The original DOM event.
|
||||
* @property {Boolean} preventDefault - Set to true to prevent the default user-agent's handling of the wheel event.
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
*/
|
||||
this.viewer.raiseEvent( 'navigator-scroll', {
|
||||
tracker: event.eventSource,
|
||||
position: event.position,
|
||||
scroll: event.scroll,
|
||||
shift: event.shift,
|
||||
originalEvent: event.originalEvent
|
||||
});
|
||||
this.viewer.raiseEvent( 'navigator-scroll', eventArgs );
|
||||
|
||||
//don't scroll the page up and down if the user is scrolling
|
||||
//in the navigator
|
||||
return false;
|
||||
event.preventDefault = eventArgs.preventDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -195,8 +195,9 @@
|
||||
*
|
||||
* @property {String} [compositeOperation=null]
|
||||
* Valid values are 'source-over', 'source-atop', 'source-in', 'source-out',
|
||||
* 'destination-over', 'destination-atop', 'destination-in',
|
||||
* 'destination-out', 'lighter', 'copy' or 'xor'
|
||||
* 'destination-over', 'destination-atop', 'destination-in', 'destination-out',
|
||||
* 'lighter', 'difference', 'copy', 'xor', etc.
|
||||
* For complete list of modes, please @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation/ globalCompositeOperation}
|
||||
*
|
||||
* @property {Boolean} [imageSmoothingEnabled=true]
|
||||
* Image smoothing for canvas rendering (only if canvas is used). Note: Ignored
|
||||
@ -320,6 +321,7 @@
|
||||
*
|
||||
* @property {OpenSeadragon.GestureSettings} [gestureSettingsMouse]
|
||||
* Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings})
|
||||
* @property {Boolean} [gestureSettingsMouse.dragToPan=true] - Pan on drag gesture
|
||||
* @property {Boolean} [gestureSettingsMouse.scrollToZoom=true] - Zoom on scroll gesture
|
||||
* @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture
|
||||
* @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true
|
||||
@ -334,6 +336,7 @@
|
||||
*
|
||||
* @property {OpenSeadragon.GestureSettings} [gestureSettingsTouch]
|
||||
* Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings})
|
||||
* @property {Boolean} [gestureSettingsMouse.dragToPan=true] - Pan on drag gesture
|
||||
* @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture
|
||||
* @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture
|
||||
* @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true
|
||||
@ -348,12 +351,13 @@
|
||||
*
|
||||
* @property {OpenSeadragon.GestureSettings} [gestureSettingsPen]
|
||||
* Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings})
|
||||
* @property {Boolean} [gestureSettingsMouse.dragToPan=true] - Pan on drag gesture
|
||||
* @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture
|
||||
* @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture
|
||||
* @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,
|
||||
* @property {Boolean} [gestureSettingsPen.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)
|
||||
@ -362,6 +366,7 @@
|
||||
*
|
||||
* @property {OpenSeadragon.GestureSettings} [gestureSettingsUnknown]
|
||||
* Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings})
|
||||
* @property {Boolean} [gestureSettingsMouse.dragToPan=true] - Pan on drag gesture
|
||||
* @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture
|
||||
* @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture
|
||||
* @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true
|
||||
@ -381,7 +386,11 @@
|
||||
* The "zoom distance" per mouse scroll or touch pinch. <em><strong>Note:</strong> Setting this to 1.0 effectively disables the mouse-wheel zoom feature (also see gestureSettings[Mouse|Touch|Pen].scrollToZoom}).</em>
|
||||
*
|
||||
* @property {Number} [zoomPerSecond=1.0]
|
||||
* The number of seconds to animate a single zoom event over.
|
||||
* Sets the zoom amount per second when zoomIn/zoomOut buttons are pressed and held.
|
||||
* The value is a factor of the current zoom, so 1.0 (the default) disables zooming when the zoomIn/zoomOut buttons
|
||||
* are held. Higher values will increase the rate of zoom when the zoomIn/zoomOut buttons are held. Note that values
|
||||
* < 1.0 will reverse the operation of the zoomIn/zoomOut buttons (zoomIn button will decrease the zoom, zoomOut will
|
||||
* increase the zoom).
|
||||
*
|
||||
* @property {Boolean} [showNavigator=false]
|
||||
* Set to true to make the navigator minimap appear.
|
||||
@ -647,6 +656,9 @@
|
||||
* @typedef {Object} GestureSettings
|
||||
* @memberof OpenSeadragon
|
||||
*
|
||||
* @property {Boolean} dragToPan
|
||||
* Set to false to disable panning on drag gestures.
|
||||
*
|
||||
* @property {Boolean} scrollToZoom
|
||||
* Set to false to disable zooming on scroll gestures.
|
||||
*
|
||||
@ -735,7 +747,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* eslint-disable no-redeclare */
|
||||
function OpenSeadragon( options ){
|
||||
return new OpenSeadragon.Viewer( options );
|
||||
}
|
||||
@ -917,13 +929,65 @@ function OpenSeadragon( options ){
|
||||
return isTainted;
|
||||
};
|
||||
|
||||
/**
|
||||
* True if the browser supports the EventTarget.addEventListener() method
|
||||
* @member {Boolean} supportsAddEventListener
|
||||
* @memberof OpenSeadragon
|
||||
*/
|
||||
$.supportsAddEventListener = (function () {
|
||||
return !!(document.documentElement.addEventListener && document.addEventListener);
|
||||
}());
|
||||
|
||||
/**
|
||||
* True if the browser supports the EventTarget.removeEventListener() method
|
||||
* @member {Boolean} supportsRemoveEventListener
|
||||
* @memberof OpenSeadragon
|
||||
*/
|
||||
$.supportsRemoveEventListener = (function () {
|
||||
return !!(document.documentElement.removeEventListener && document.removeEventListener);
|
||||
}());
|
||||
|
||||
/**
|
||||
* True if the browser supports the newer EventTarget.addEventListener options argument
|
||||
* @member {Boolean} supportsEventListenerOptions
|
||||
* @memberof OpenSeadragon
|
||||
*/
|
||||
$.supportsEventListenerOptions = (function () {
|
||||
var supported = 0;
|
||||
|
||||
if ( $.supportsAddEventListener ) {
|
||||
try {
|
||||
var options = {
|
||||
get capture() {
|
||||
supported++;
|
||||
return false;
|
||||
},
|
||||
get once() {
|
||||
supported++;
|
||||
return false;
|
||||
},
|
||||
get passive() {
|
||||
supported++;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
window.addEventListener("test", null, options);
|
||||
window.removeEventListener("test", null, options);
|
||||
} catch ( e ) {
|
||||
supported = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return supported >= 3;
|
||||
}());
|
||||
|
||||
/**
|
||||
* A ratio comparing the device screen's pixel density to the canvas's backing store pixel density,
|
||||
* clamped to a minimum of 1. Defaults to 1 if canvas isn't supported by the browser.
|
||||
* @member {Number} pixelDensityRatio
|
||||
* @memberof OpenSeadragon
|
||||
*/
|
||||
$.pixelDensityRatio = (function () {
|
||||
$.getCurrentPixelDensityRatio = function() {
|
||||
if ( $.supportsCanvas ) {
|
||||
var context = document.createElement('canvas').getContext('2d');
|
||||
var devicePixelRatio = window.devicePixelRatio || 1;
|
||||
@ -936,13 +1000,19 @@ function OpenSeadragon( options ){
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}());
|
||||
};
|
||||
|
||||
/**
|
||||
* @member {Number} pixelDensityRatio
|
||||
* @memberof OpenSeadragon
|
||||
*/
|
||||
$.pixelDensityRatio = $.getCurrentPixelDensityRatio();
|
||||
|
||||
}( OpenSeadragon ));
|
||||
|
||||
/**
|
||||
* This closure defines all static methods available to the OpenSeadragon
|
||||
* namespace. Many, if not most, are taked directly from jQuery for use
|
||||
* namespace. Many, if not most, are taken directly from jQuery for use
|
||||
* to simplify and reduce common programming patterns. More static methods
|
||||
* from jQuery may eventually make their way into this though we are
|
||||
* attempting to avoid an explicit dependency on jQuery only because
|
||||
@ -1081,6 +1151,7 @@ function OpenSeadragon( options ){
|
||||
springStiffness: 6.5,
|
||||
animationTime: 1.2,
|
||||
gestureSettingsMouse: {
|
||||
dragToPan: true,
|
||||
scrollToZoom: true,
|
||||
clickToZoom: true,
|
||||
dblClickToZoom: false,
|
||||
@ -1092,6 +1163,7 @@ function OpenSeadragon( options ){
|
||||
pinchRotate: false
|
||||
},
|
||||
gestureSettingsTouch: {
|
||||
dragToPan: true,
|
||||
scrollToZoom: false,
|
||||
clickToZoom: false,
|
||||
dblClickToZoom: true,
|
||||
@ -1103,6 +1175,7 @@ function OpenSeadragon( options ){
|
||||
pinchRotate: false
|
||||
},
|
||||
gestureSettingsPen: {
|
||||
dragToPan: true,
|
||||
scrollToZoom: false,
|
||||
clickToZoom: true,
|
||||
dblClickToZoom: false,
|
||||
@ -1114,6 +1187,7 @@ function OpenSeadragon( options ){
|
||||
pinchRotate: false
|
||||
},
|
||||
gestureSettingsUnknown: {
|
||||
dragToPan: true,
|
||||
scrollToZoom: false,
|
||||
clickToZoom: false,
|
||||
dblClickToZoom: true,
|
||||
@ -1315,6 +1389,8 @@ function OpenSeadragon( options ){
|
||||
* @property {Number} SAFARI
|
||||
* @property {Number} CHROME
|
||||
* @property {Number} OPERA
|
||||
* @property {Number} EDGE
|
||||
* @property {Number} CHROMEEDGE
|
||||
*/
|
||||
BROWSERS: {
|
||||
UNKNOWN: 0,
|
||||
@ -1322,9 +1398,31 @@ function OpenSeadragon( options ){
|
||||
FIREFOX: 2,
|
||||
SAFARI: 3,
|
||||
CHROME: 4,
|
||||
OPERA: 5
|
||||
OPERA: 5,
|
||||
EDGE: 6,
|
||||
CHROMEEDGE: 7
|
||||
},
|
||||
|
||||
/**
|
||||
* Keep track of which {@link Viewer}s have been created.
|
||||
* - Key: {@link Element} to which a Viewer is attached.
|
||||
* - Value: {@link Viewer} of the element defined by the key.
|
||||
* @private
|
||||
* @static
|
||||
* @type {Object}
|
||||
*/
|
||||
_viewers: new Map(),
|
||||
|
||||
/**
|
||||
* Returns the {@link Viewer} attached to a given DOM element. If there is
|
||||
* no viewer attached to the provided element, undefined is returned.
|
||||
* @function
|
||||
* @param {String|Element} element Accepts an id or element.
|
||||
* @returns {Viewer} The viewer attached to the given element, or undefined.
|
||||
*/
|
||||
getViewer: function(element) {
|
||||
return $._viewers.get(this.getElement(element));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a DOM Element for the given id or element.
|
||||
@ -1333,7 +1431,7 @@ function OpenSeadragon( options ){
|
||||
* @returns {Element} The element with the given id, null, or the element itself.
|
||||
*/
|
||||
getElement: function( element ) {
|
||||
if ( typeof ( element ) == "string" ) {
|
||||
if ( typeof ( element ) === "string" ) {
|
||||
element = document.getElementById( element );
|
||||
}
|
||||
return element;
|
||||
@ -1352,7 +1450,7 @@ function OpenSeadragon( options ){
|
||||
offsetParent;
|
||||
|
||||
element = $.getElement( element );
|
||||
isFixed = $.getElementStyle( element ).position == "fixed";
|
||||
isFixed = $.getElementStyle( element ).position === "fixed";
|
||||
offsetParent = getOffsetParent( element, isFixed );
|
||||
|
||||
while ( offsetParent ) {
|
||||
@ -1365,7 +1463,7 @@ function OpenSeadragon( options ){
|
||||
}
|
||||
|
||||
element = offsetParent;
|
||||
isFixed = $.getElementStyle( element ).position == "fixed";
|
||||
isFixed = $.getElementStyle( element ).position === "fixed";
|
||||
offsetParent = getOffsetParent( element, isFixed );
|
||||
}
|
||||
|
||||
@ -1397,7 +1495,7 @@ function OpenSeadragon( options ){
|
||||
boundingRect = element.getBoundingClientRect();
|
||||
}
|
||||
|
||||
win = ( doc == doc.window ) ?
|
||||
win = ( doc === doc.window ) ?
|
||||
doc :
|
||||
( doc.nodeType === 9 ) ?
|
||||
doc.defaultView || doc.parentWindow :
|
||||
@ -1517,29 +1615,6 @@ function OpenSeadragon( options ){
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Gets the latest event, really only useful internally since its
|
||||
* specific to IE behavior.
|
||||
* @function
|
||||
* @param {Event} [event]
|
||||
* @returns {Event}
|
||||
* @deprecated For internal use only
|
||||
* @private
|
||||
*/
|
||||
getEvent: function( event ) {
|
||||
if( event ){
|
||||
$.getEvent = function( event ) {
|
||||
return event;
|
||||
};
|
||||
} else {
|
||||
$.getEvent = function() {
|
||||
return window.event;
|
||||
};
|
||||
}
|
||||
return $.getEvent( event );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Gets the position of the mouse on the screen for a given event.
|
||||
* @function
|
||||
@ -1548,21 +1623,19 @@ function OpenSeadragon( options ){
|
||||
*/
|
||||
getMousePosition: function( event ) {
|
||||
|
||||
if ( typeof ( event.pageX ) == "number" ) {
|
||||
if ( typeof ( event.pageX ) === "number" ) {
|
||||
$.getMousePosition = function( event ){
|
||||
var result = new $.Point();
|
||||
|
||||
event = $.getEvent( event );
|
||||
result.x = event.pageX;
|
||||
result.y = event.pageY;
|
||||
|
||||
return result;
|
||||
};
|
||||
} else if ( typeof ( event.clientX ) == "number" ) {
|
||||
} else if ( typeof ( event.clientX ) === "number" ) {
|
||||
$.getMousePosition = function( event ){
|
||||
var result = new $.Point();
|
||||
|
||||
event = $.getEvent( event );
|
||||
result.x =
|
||||
event.clientX +
|
||||
document.body.scrollLeft +
|
||||
@ -1593,7 +1666,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,
|
||||
@ -1670,7 +1743,7 @@ function OpenSeadragon( options ){
|
||||
};
|
||||
}
|
||||
|
||||
return $.setPageScroll( scroll );
|
||||
$.setPageScroll( scroll );
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1682,7 +1755,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,
|
||||
@ -1798,51 +1871,16 @@ function OpenSeadragon( options ){
|
||||
|
||||
/**
|
||||
* Ensures an image is loaded correctly to support alpha transparency.
|
||||
* Generally only IE has issues doing this correctly for formats like
|
||||
* png.
|
||||
* @function
|
||||
* @param {String} src
|
||||
* @returns {Element}
|
||||
*/
|
||||
makeTransparentImage: function( src ) {
|
||||
|
||||
$.makeTransparentImage = function( src ){
|
||||
var img = $.makeNeutralElement( "img" );
|
||||
|
||||
img.src = src;
|
||||
|
||||
return img;
|
||||
};
|
||||
|
||||
if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 7 ) {
|
||||
|
||||
$.makeTransparentImage = function( src ){
|
||||
var img = $.makeNeutralElement( "img" ),
|
||||
element = null;
|
||||
|
||||
element = $.makeNeutralElement("span");
|
||||
element.style.display = "inline-block";
|
||||
|
||||
img.onload = function() {
|
||||
element.style.width = element.style.width || img.width + "px";
|
||||
element.style.height = element.style.height || img.height + "px";
|
||||
|
||||
img.onload = null;
|
||||
img = null; // to prevent memory leaks in IE
|
||||
};
|
||||
|
||||
img.src = src;
|
||||
element.style.filter =
|
||||
"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
|
||||
src +
|
||||
"', sizingMethod='scale')";
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return $.makeTransparentImage( src );
|
||||
},
|
||||
|
||||
|
||||
@ -1893,6 +1931,30 @@ function OpenSeadragon( options ){
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Sets the specified element's pointer-events style attribute to the passed value.
|
||||
* @function
|
||||
* @param {Element|String} element
|
||||
* @param {String} value
|
||||
*/
|
||||
setElementPointerEvents: function( element, value ) {
|
||||
element = $.getElement( element );
|
||||
if ( typeof element.style.pointerEvents !== 'undefined' ) {
|
||||
element.style.pointerEvents = value;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Sets the specified element's pointer-events style attribute to 'none'.
|
||||
* @function
|
||||
* @param {Element|String} element
|
||||
*/
|
||||
setElementPointerEventsNone: function( element ) {
|
||||
$.setElementPointerEvents( element, 'none' );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Add the specified CSS class to the element if not present.
|
||||
* @function
|
||||
@ -1978,6 +2040,34 @@ function OpenSeadragon( options ){
|
||||
element.className = newClasses.join(' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert passed addEventListener() options to boolean or options object,
|
||||
* depending on browser support.
|
||||
* @function
|
||||
* @param {Boolean|Object} [options] Boolean useCapture, or if [supportsEventListenerOptions]{@link OpenSeadragon.supportsEventListenerOptions}, can be an object
|
||||
* @param {Boolean} [options.capture]
|
||||
* @param {Boolean} [options.passive]
|
||||
* @param {Boolean} [options.once]
|
||||
* @return {String} The protocol (http:, https:, file:, ftp: ...)
|
||||
*/
|
||||
normalizeEventListenerOptions: function (options) {
|
||||
var opts;
|
||||
if ( typeof options !== 'undefined' ) {
|
||||
if ( typeof options === 'boolean' ) {
|
||||
// Legacy Boolean useCapture
|
||||
opts = $.supportsEventListenerOptions ? { capture: options } : options;
|
||||
} else {
|
||||
// Options object
|
||||
opts = $.supportsEventListenerOptions ? options :
|
||||
( ( typeof options.capture !== 'undefined' ) ? options.capture : false );
|
||||
}
|
||||
} else {
|
||||
// No options specified - Legacy optional useCapture argument
|
||||
// (for IE, first supported on version 9, so we'll pass a Boolean)
|
||||
opts = $.supportsEventListenerOptions ? { capture: false } : false;
|
||||
}
|
||||
return opts;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an event listener for the given element, eventName and handler.
|
||||
@ -1985,16 +2075,20 @@ function OpenSeadragon( options ){
|
||||
* @param {Element|String} element
|
||||
* @param {String} eventName
|
||||
* @param {Function} handler
|
||||
* @param {Boolean} [useCapture]
|
||||
* @param {Boolean|Object} [options] Boolean useCapture, or if [supportsEventListenerOptions]{@link OpenSeadragon.supportsEventListenerOptions}, can be an object
|
||||
* @param {Boolean} [options.capture]
|
||||
* @param {Boolean} [options.passive]
|
||||
* @param {Boolean} [options.once]
|
||||
*/
|
||||
addEvent: (function () {
|
||||
if ( window.addEventListener ) {
|
||||
return function ( element, eventName, handler, useCapture ) {
|
||||
if ( $.supportsAddEventListener ) {
|
||||
return function ( element, eventName, handler, options ) {
|
||||
options = $.normalizeEventListenerOptions(options);
|
||||
element = $.getElement( element );
|
||||
element.addEventListener( eventName, handler, useCapture );
|
||||
element.addEventListener( eventName, handler, options );
|
||||
};
|
||||
} else if ( window.attachEvent ) {
|
||||
return function ( element, eventName, handler, useCapture ) {
|
||||
} else if ( document.documentElement.attachEvent && document.attachEvent ) {
|
||||
return function ( element, eventName, handler ) {
|
||||
element = $.getElement( element );
|
||||
element.attachEvent( 'on' + eventName, handler );
|
||||
};
|
||||
@ -2011,16 +2105,18 @@ function OpenSeadragon( options ){
|
||||
* @param {Element|String} element
|
||||
* @param {String} eventName
|
||||
* @param {Function} handler
|
||||
* @param {Boolean} [useCapture]
|
||||
* @param {Boolean|Object} [options] Boolean useCapture, or if [supportsEventListenerOptions]{@link OpenSeadragon.supportsEventListenerOptions}, can be an object
|
||||
* @param {Boolean} [options.capture]
|
||||
*/
|
||||
removeEvent: (function () {
|
||||
if ( window.removeEventListener ) {
|
||||
return function ( element, eventName, handler, useCapture ) {
|
||||
if ( $.supportsRemoveEventListener ) {
|
||||
return function ( element, eventName, handler, options ) {
|
||||
options = $.normalizeEventListenerOptions(options);
|
||||
element = $.getElement( element );
|
||||
element.removeEventListener( eventName, handler, useCapture );
|
||||
element.removeEventListener( eventName, handler, options );
|
||||
};
|
||||
} else if ( window.detachEvent ) {
|
||||
return function( element, eventName, handler, useCapture ) {
|
||||
} else if ( document.documentElement.detachEvent && document.detachEvent ) {
|
||||
return function( element, eventName, handler ) {
|
||||
element = $.getElement( element );
|
||||
element.detachEvent( 'on' + eventName, handler );
|
||||
};
|
||||
@ -2037,49 +2133,28 @@ function OpenSeadragon( options ){
|
||||
* @param {Event} [event]
|
||||
*/
|
||||
cancelEvent: function( event ) {
|
||||
event = $.getEvent( event );
|
||||
|
||||
if ( event.preventDefault ) {
|
||||
$.cancelEvent = function( event ){
|
||||
// W3C for preventing default
|
||||
event.preventDefault();
|
||||
};
|
||||
} else {
|
||||
$.cancelEvent = function( event ){
|
||||
event = $.getEvent( event );
|
||||
// legacy for preventing default
|
||||
event.cancel = true;
|
||||
// IE for preventing default
|
||||
event.returnValue = false;
|
||||
};
|
||||
}
|
||||
$.cancelEvent( event );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Stops the propagation of the event up the DOM.
|
||||
* Returns true if {@link OpenSeadragon.cancelEvent|cancelEvent} has been called on
|
||||
* the event, otherwise returns false.
|
||||
* @function
|
||||
* @param {Event} [event]
|
||||
*/
|
||||
eventIsCanceled: function( event ) {
|
||||
return event.defaultPrevented;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Stops the propagation of the event through the DOM in the capturing and bubbling phases.
|
||||
* @function
|
||||
* @param {Event} [event]
|
||||
*/
|
||||
stopEvent: function( event ) {
|
||||
event = $.getEvent( event );
|
||||
|
||||
if ( event.stopPropagation ) {
|
||||
// W3C for stopping propagation
|
||||
$.stopEvent = function( event ){
|
||||
event.stopPropagation();
|
||||
};
|
||||
} else {
|
||||
// IE for stopping propagation
|
||||
$.stopEvent = function( event ){
|
||||
event = $.getEvent( event );
|
||||
event.cancelBubble = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
$.stopEvent( event );
|
||||
},
|
||||
|
||||
|
||||
@ -2227,7 +2302,7 @@ function OpenSeadragon( options ){
|
||||
|
||||
request.onreadystatechange = function() {
|
||||
// 4 = DONE (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Properties)
|
||||
if ( request.readyState == 4 ) {
|
||||
if ( request.readyState === 4 ) {
|
||||
request.onreadystatechange = function(){};
|
||||
|
||||
// With protocols other than http/https, a successful request status is in
|
||||
@ -2256,7 +2331,7 @@ function OpenSeadragon( options ){
|
||||
|
||||
if (headers) {
|
||||
for (var headerName in headers) {
|
||||
if (headers.hasOwnProperty(headerName) && headers[headerName]) {
|
||||
if (Object.prototype.hasOwnProperty.call(headers, headerName) && headers[headerName]) {
|
||||
request.setRequestHeader(headerName, headers[headerName]);
|
||||
}
|
||||
}
|
||||
@ -2268,64 +2343,14 @@ function OpenSeadragon( options ){
|
||||
|
||||
request.send(null);
|
||||
} catch (e) {
|
||||
var msg = e.message;
|
||||
|
||||
/*
|
||||
IE < 10 does not support CORS and an XHR request to a different origin will fail as soon
|
||||
as send() is called. This is particularly easy to miss during development and appear in
|
||||
production if you use a CDN or domain sharding and the security policy is likely to break
|
||||
exception handlers since any attempt to access a property of the request object will
|
||||
raise an access denied TypeError inside the catch block.
|
||||
|
||||
To be friendlier, we'll check for this specific error and add a documentation pointer
|
||||
to point developers in the right direction. We test the exception number because IE's
|
||||
error messages are localized.
|
||||
*/
|
||||
var oldIE = $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 10;
|
||||
if ( oldIE && typeof ( e.number ) != "undefined" && e.number == -2147024891 ) {
|
||||
msg += "\nSee http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx#xdomain";
|
||||
}
|
||||
|
||||
$.console.log( "%s while making AJAX request: %s", e.name, msg );
|
||||
$.console.log( "%s while making AJAX request: %s", e.name, e.message );
|
||||
|
||||
request.onreadystatechange = function(){};
|
||||
|
||||
if (window.XDomainRequest) { // IE9 or IE8 might as well try to use XDomainRequest
|
||||
var xdr = new XDomainRequest();
|
||||
if (xdr) {
|
||||
xdr.onload = function (e) {
|
||||
if ( $.isFunction( onSuccess ) ) {
|
||||
onSuccess({ // Faking an xhr object
|
||||
responseText: xdr.responseText,
|
||||
status: 200, // XDomainRequest doesn't support status codes, so we just fake one! :/
|
||||
statusText: 'OK'
|
||||
});
|
||||
}
|
||||
};
|
||||
xdr.onerror = function (e) {
|
||||
if ($.isFunction(onError)) {
|
||||
onError({ // Faking an xhr object
|
||||
responseText: xdr.responseText,
|
||||
status: 444, // 444 No Response
|
||||
statusText: 'An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser.'
|
||||
});
|
||||
}
|
||||
};
|
||||
try {
|
||||
xdr.open('GET', url);
|
||||
xdr.send();
|
||||
} catch (e2) {
|
||||
if ( $.isFunction( onError ) ) {
|
||||
onError( request, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( $.isFunction( onError ) ) {
|
||||
onError( request, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
},
|
||||
@ -2353,7 +2378,7 @@ function OpenSeadragon( options ){
|
||||
callbackParam = options.param || 'callback',
|
||||
callback = options.callback;
|
||||
|
||||
url = url.replace( /(\=)\?(&|$)|\?\?/i, replace );
|
||||
url = url.replace( /(=)\?(&|$)|\?\?/i, replace );
|
||||
// Add callback manually
|
||||
url += (/\?/.test( url ) ? "&" : "?") + callbackParam + "=" + jsonpCallback;
|
||||
|
||||
@ -2462,16 +2487,7 @@ function OpenSeadragon( options ){
|
||||
* @returns {Object}
|
||||
*/
|
||||
parseJSON: function(string) {
|
||||
if (window.JSON && window.JSON.parse) {
|
||||
$.parseJSON = window.JSON.parse;
|
||||
} else {
|
||||
// Should only be used by IE8 in non standards mode
|
||||
$.parseJSON = function(string) {
|
||||
/*jshint evil:true*/
|
||||
//eslint-disable-next-line no-eval
|
||||
return eval('(' + string + ')');
|
||||
};
|
||||
}
|
||||
return $.parseJSON(string);
|
||||
},
|
||||
|
||||
@ -2486,11 +2502,61 @@ function OpenSeadragon( options ){
|
||||
extension = extension ? extension : "";
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
return !!FILEFORMATS[ extension.toLowerCase() ];
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates supported image formats with user-specified values.
|
||||
* Preexisting formats that are not being updated are left unchanged.
|
||||
* By default, the defined formats are
|
||||
* <pre><code>{
|
||||
* bmp: false,
|
||||
* jpeg: true,
|
||||
* jpg: true,
|
||||
* png: true,
|
||||
* tif: false,
|
||||
* wdp: false
|
||||
* }
|
||||
* </code></pre>
|
||||
* @function
|
||||
* @example
|
||||
* // sets webp as supported and png as unsupported
|
||||
* setImageFormatsSupported({webp: true, png: false});
|
||||
* @param {Object} formats An object containing format extensions as
|
||||
* keys and booleans as values.
|
||||
*/
|
||||
setImageFormatsSupported: function(formats) {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
$.extend(FILEFORMATS, formats);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
//TODO: $.console is often used inside a try/catch block which generally
|
||||
// prevents allowings errors to occur with detection until a debugger
|
||||
// is attached. Although I've been guilty of the same anti-pattern
|
||||
// I eventually was convinced that errors should naturally propagate in
|
||||
// all but the most special cases.
|
||||
/**
|
||||
* A convenient alias for console when available, and a simple null
|
||||
* function when console is unavailable.
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
var nullfunction = function( msg ){
|
||||
//document.location.hash = msg;
|
||||
};
|
||||
|
||||
$.console = window.console || {
|
||||
log: nullfunction,
|
||||
debug: nullfunction,
|
||||
info: nullfunction,
|
||||
warn: nullfunction,
|
||||
error: nullfunction,
|
||||
assert: nullfunction
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The current browser vendor, version, and related information regarding detected features.
|
||||
* @member {Object} Browser
|
||||
@ -2509,12 +2575,12 @@ function OpenSeadragon( options ){
|
||||
|
||||
|
||||
var FILEFORMATS = {
|
||||
"bmp": false,
|
||||
"jpeg": true,
|
||||
"jpg": true,
|
||||
"png": true,
|
||||
"tif": false,
|
||||
"wdp": false
|
||||
bmp: false,
|
||||
jpeg: true,
|
||||
jpg: true,
|
||||
png: true,
|
||||
tif: false,
|
||||
wdp: false
|
||||
},
|
||||
URLPARAMS = {};
|
||||
|
||||
@ -2544,7 +2610,17 @@ function OpenSeadragon( options ){
|
||||
break;
|
||||
case "Netscape":
|
||||
if (window.addEventListener) {
|
||||
if ( ua.indexOf( "Firefox" ) >= 0 ) {
|
||||
if ( ua.indexOf( "Edge" ) >= 0 ) {
|
||||
$.Browser.vendor = $.BROWSERS.EDGE;
|
||||
$.Browser.version = parseFloat(
|
||||
ua.substring( ua.indexOf( "Edge" ) + 5 )
|
||||
);
|
||||
} else if ( ua.indexOf( "Edg" ) >= 0 ) {
|
||||
$.Browser.vendor = $.BROWSERS.CHROMEEDGE;
|
||||
$.Browser.version = parseFloat(
|
||||
ua.substring( ua.indexOf( "Edg" ) + 4 )
|
||||
);
|
||||
} else if ( ua.indexOf( "Firefox" ) >= 0 ) {
|
||||
$.Browser.vendor = $.BROWSERS.FIREFOX;
|
||||
$.Browser.version = parseFloat(
|
||||
ua.substring( ua.indexOf( "Firefox" ) + 8 )
|
||||
@ -2586,56 +2662,30 @@ function OpenSeadragon( options ){
|
||||
sep = part.indexOf( '=' );
|
||||
|
||||
if ( sep > 0 ) {
|
||||
URLPARAMS[ part.substring( 0, sep ) ] =
|
||||
decodeURIComponent( part.substring( sep + 1 ) );
|
||||
var key = part.substring( 0, sep ),
|
||||
value = part.substring( sep + 1 );
|
||||
try {
|
||||
URLPARAMS[ key ] = decodeURIComponent( value );
|
||||
} catch (e) {
|
||||
$.console.error( "Ignoring malformed URL parameter: %s=%s", key, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//determine if this browser supports image alpha transparency
|
||||
$.Browser.alpha = !(
|
||||
(
|
||||
$.Browser.vendor == $.BROWSERS.IE &&
|
||||
$.Browser.version < 9
|
||||
) || (
|
||||
$.Browser.vendor == $.BROWSERS.CHROME &&
|
||||
$.Browser.version < 2
|
||||
)
|
||||
$.Browser.vendor === $.BROWSERS.CHROME && $.Browser.version < 2
|
||||
);
|
||||
|
||||
//determine if this browser supports element.style.opacity
|
||||
$.Browser.opacity = !(
|
||||
$.Browser.vendor == $.BROWSERS.IE &&
|
||||
$.Browser.version < 9
|
||||
);
|
||||
$.Browser.opacity = true;
|
||||
|
||||
if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 11 ) {
|
||||
$.console.error('Internet Explorer versions < 11 are not supported by OpenSeadragon');
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
//TODO: $.console is often used inside a try/catch block which generally
|
||||
// prevents allowings errors to occur with detection until a debugger
|
||||
// is attached. Although I've been guilty of the same anti-pattern
|
||||
// I eventually was convinced that errors should naturally propagate in
|
||||
// all but the most special cases.
|
||||
/**
|
||||
* A convenient alias for console when available, and a simple null
|
||||
* function when console is unavailable.
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
var nullfunction = function( msg ){
|
||||
//document.location.hash = msg;
|
||||
};
|
||||
|
||||
$.console = window.console || {
|
||||
log: nullfunction,
|
||||
debug: nullfunction,
|
||||
info: nullfunction,
|
||||
warn: nullfunction,
|
||||
error: nullfunction,
|
||||
assert: nullfunction
|
||||
};
|
||||
|
||||
|
||||
// Adding support for HTML5's requestAnimationFrame as suggested by acdha.
|
||||
// Implementation taken from matt synder's post here:
|
||||
// http://mattsnider.com/cross-browser-and-legacy-supported-requestframeanimation/
|
||||
@ -2731,7 +2781,7 @@ function OpenSeadragon( options ){
|
||||
* @returns {Element}
|
||||
*/
|
||||
function getOffsetParent( element, isFixed ) {
|
||||
if ( isFixed && element != document.body ) {
|
||||
if ( isFixed && element !== document.body ) {
|
||||
return document.body;
|
||||
} else {
|
||||
return element.offsetParent;
|
||||
|
@ -113,7 +113,7 @@ $.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
|
||||
supports: function( data, url ){
|
||||
return (
|
||||
data.type &&
|
||||
"openstreetmaps" == data.type
|
||||
"openstreetmaps" === data.type
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -288,11 +288,8 @@
|
||||
style[transformProp] = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (style.display !== 'none') {
|
||||
style.display = 'block';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// private
|
||||
|
@ -50,13 +50,13 @@ $.Point = function( x, y ) {
|
||||
* @member {Number} x
|
||||
* @memberof OpenSeadragon.Point#
|
||||
*/
|
||||
this.x = typeof ( x ) == "number" ? x : 0;
|
||||
this.x = typeof ( x ) === "number" ? x : 0;
|
||||
/**
|
||||
* The vector component 'y'.
|
||||
* @member {Number} y
|
||||
* @memberof OpenSeadragon.Point#
|
||||
*/
|
||||
this.y = typeof ( y ) == "number" ? y : 0;
|
||||
this.y = typeof ( y ) === "number" ? y : 0;
|
||||
};
|
||||
|
||||
/** @lends OpenSeadragon.Point.prototype */
|
||||
|
@ -85,24 +85,19 @@ $.ReferenceStrip = function ( options ) {
|
||||
scroll: $.DEFAULT_SETTINGS.referenceStripScroll,
|
||||
clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold
|
||||
}, options, {
|
||||
//required overrides
|
||||
element: this.element,
|
||||
//These need to be overridden to prevent recursion since
|
||||
//the navigator is a viewer and a viewer has a navigator
|
||||
showNavigator: false,
|
||||
mouseNavEnabled: false,
|
||||
showNavigationControl: false,
|
||||
showSequenceControl: false
|
||||
element: this.element
|
||||
} );
|
||||
|
||||
$.extend( this, options );
|
||||
//Private state properties
|
||||
THIS[this.id] = {
|
||||
"animating": false
|
||||
animating: false
|
||||
};
|
||||
|
||||
this.minPixelRatio = this.viewer.minPixelRatio;
|
||||
|
||||
this.element.tabIndex = 0;
|
||||
|
||||
style = this.element.style;
|
||||
style.marginTop = '0px';
|
||||
style.marginRight = '0px';
|
||||
@ -119,14 +114,21 @@ $.ReferenceStrip = function ( options ) {
|
||||
$.setElementOpacity( this.element, 0.8 );
|
||||
|
||||
this.viewer = viewer;
|
||||
this.innerTracker = new $.MouseTracker( {
|
||||
this.tracker = new $.MouseTracker( {
|
||||
userData: 'ReferenceStrip.tracker',
|
||||
element: this.element,
|
||||
clickHandler: $.delegate( this, onStripClick ),
|
||||
dragHandler: $.delegate( this, onStripDrag ),
|
||||
scrollHandler: $.delegate( this, onStripScroll ),
|
||||
enterHandler: $.delegate( this, onStripEnter ),
|
||||
exitHandler: $.delegate( this, onStripExit ),
|
||||
leaveHandler: $.delegate( this, onStripLeave ),
|
||||
keyDownHandler: $.delegate( this, onKeyDown ),
|
||||
keyHandler: $.delegate( this, onKeyPress )
|
||||
keyHandler: $.delegate( this, onKeyPress ),
|
||||
preProcessEventHandler: function (eventInfo) {
|
||||
if (eventInfo.eventType === 'wheel') {
|
||||
eventInfo.preventDefault = true;
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
//Controls the position and orientation of the reference strip and sets the
|
||||
@ -139,7 +141,7 @@ $.ReferenceStrip = function ( options ) {
|
||||
{ anchor: $.ControlAnchor.BOTTOM_LEFT }
|
||||
);
|
||||
} else {
|
||||
if ( "horizontal" == options.scroll ) {
|
||||
if ( "horizontal" === options.scroll ) {
|
||||
this.element.style.width = (
|
||||
viewerSize.x *
|
||||
options.sizeRatio *
|
||||
@ -189,34 +191,12 @@ $.ReferenceStrip = function ( options ) {
|
||||
element.style.width = _this.panelWidth + 'px';
|
||||
element.style.height = _this.panelHeight + 'px';
|
||||
element.style.display = 'inline';
|
||||
element.style.float = 'left'; //Webkit
|
||||
element.style['float'] = 'left'; //Webkit
|
||||
element.style.cssFloat = 'left'; //Firefox
|
||||
element.style.styleFloat = 'left'; //IE
|
||||
element.style.padding = '2px';
|
||||
$.setElementTouchActionNone( element );
|
||||
|
||||
element.innerTracker = new $.MouseTracker( {
|
||||
element: element,
|
||||
clickTimeThreshold: this.clickTimeThreshold,
|
||||
clickDistThreshold: this.clickDistThreshold,
|
||||
pressHandler: function ( event ) {
|
||||
event.eventSource.dragging = $.now();
|
||||
},
|
||||
releaseHandler: function ( event ) {
|
||||
var tracker = event.eventSource,
|
||||
id = tracker.element.id,
|
||||
page = Number( id.split( '-' )[2] ),
|
||||
now = $.now();
|
||||
|
||||
if ( event.insideElementPressed &&
|
||||
event.insideElementReleased &&
|
||||
tracker.dragging &&
|
||||
( now - tracker.dragging ) < tracker.clickTimeThreshold ) {
|
||||
tracker.dragging = null;
|
||||
viewer.goToPage( page );
|
||||
}
|
||||
}
|
||||
} );
|
||||
$.setElementPointerEventsNone( element );
|
||||
|
||||
this.element.appendChild( element );
|
||||
|
||||
@ -225,12 +205,13 @@ $.ReferenceStrip = function ( options ) {
|
||||
this.panels.push( element );
|
||||
|
||||
}
|
||||
loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.x, 0 );
|
||||
loadPanels( this, this.scroll === 'vertical' ? viewerSize.y : viewerSize.x, 0 );
|
||||
this.setFocus( 0 );
|
||||
|
||||
};
|
||||
|
||||
$.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.ReferenceStrip.prototype */{
|
||||
/** @lends OpenSeadragon.ReferenceStrip.prototype */
|
||||
$.ReferenceStrip.prototype = {
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -251,7 +232,7 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
|
||||
this.currentSelected = element;
|
||||
this.currentSelected.style.background = '#999';
|
||||
|
||||
if ( 'horizontal' == this.scroll ) {
|
||||
if ( 'horizontal' === this.scroll ) {
|
||||
//right left
|
||||
offset = ( Number( page ) ) * ( this.panelWidth + 3 );
|
||||
if ( offset > offsetLeft + viewerSize.x - this.panelWidth ) {
|
||||
@ -277,7 +258,7 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
|
||||
}
|
||||
|
||||
this.currentPage = page;
|
||||
onStripEnter.call( this, { eventSource: this.innerTracker } );
|
||||
onStripEnter.call( this, { eventSource: this.tracker } );
|
||||
}
|
||||
},
|
||||
|
||||
@ -292,7 +273,6 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
|
||||
return false;
|
||||
},
|
||||
|
||||
// Overrides Viewer.destroy
|
||||
destroy: function() {
|
||||
if (this.miniViewers) {
|
||||
for (var key in this.miniViewers) {
|
||||
@ -300,14 +280,36 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
|
||||
}
|
||||
}
|
||||
|
||||
this.tracker.destroy();
|
||||
|
||||
if (this.element) {
|
||||
this.element.parentNode.removeChild(this.element);
|
||||
this.viewer.removeControl( this.element );
|
||||
}
|
||||
}
|
||||
|
||||
} );
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* @function
|
||||
*/
|
||||
function onStripClick( event ) {
|
||||
if ( event.quick ) {
|
||||
var page;
|
||||
|
||||
if ( 'horizontal' === this.scroll ) {
|
||||
page = Math.floor(event.position.x / this.panelWidth);
|
||||
} else {
|
||||
page = Math.floor(event.position.y / this.panelHeight);
|
||||
}
|
||||
|
||||
this.viewer.goToPage( page );
|
||||
}
|
||||
|
||||
this.element.focus();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -317,14 +319,15 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
|
||||
*/
|
||||
function onStripDrag( event ) {
|
||||
|
||||
this.dragging = true;
|
||||
if ( this.element ) {
|
||||
var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),
|
||||
offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ),
|
||||
scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),
|
||||
scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),
|
||||
viewerSize = $.getElementSize( this.viewer.canvas );
|
||||
this.dragging = true;
|
||||
if ( this.element ) {
|
||||
if ( 'horizontal' == this.scroll ) {
|
||||
|
||||
if ( 'horizontal' === this.scroll ) {
|
||||
if ( -event.delta.x > 0 ) {
|
||||
//forward
|
||||
if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) {
|
||||
@ -354,7 +357,6 @@ function onStripDrag( event ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@ -366,13 +368,14 @@ function onStripDrag( event ) {
|
||||
* @function
|
||||
*/
|
||||
function onStripScroll( event ) {
|
||||
if ( this.element ) {
|
||||
var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),
|
||||
offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ),
|
||||
scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),
|
||||
scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),
|
||||
viewerSize = $.getElementSize( this.viewer.canvas );
|
||||
if ( this.element ) {
|
||||
if ( 'horizontal' == this.scroll ) {
|
||||
|
||||
if ( 'horizontal' === this.scroll ) {
|
||||
if ( event.scroll > 0 ) {
|
||||
//forward
|
||||
if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) {
|
||||
@ -401,9 +404,9 @@ function onStripScroll( event ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event.preventDefault = true;
|
||||
}
|
||||
//cancels event
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -412,10 +415,9 @@ function loadPanels( strip, viewerSize, scroll ) {
|
||||
activePanelsStart,
|
||||
activePanelsEnd,
|
||||
miniViewer,
|
||||
style,
|
||||
i,
|
||||
element;
|
||||
if ( 'horizontal' == strip.scroll ) {
|
||||
if ( 'horizontal' === strip.scroll ) {
|
||||
panelSize = strip.panelWidth;
|
||||
} else {
|
||||
panelSize = strip.panelHeight;
|
||||
@ -451,36 +453,17 @@ function loadPanels( strip, viewerSize, scroll ) {
|
||||
blendTime: 0,
|
||||
animationTime: 0,
|
||||
loadTilesWithAjax: strip.viewer.loadTilesWithAjax,
|
||||
ajaxHeaders: strip.viewer.ajaxHeaders
|
||||
ajaxHeaders: strip.viewer.ajaxHeaders,
|
||||
useCanvas: strip.useCanvas
|
||||
} );
|
||||
|
||||
miniViewer.displayRegion = $.makeNeutralElement( "div" );
|
||||
miniViewer.displayRegion.id = element.id + '-displayregion';
|
||||
miniViewer.displayRegion.className = 'displayregion';
|
||||
|
||||
style = miniViewer.displayRegion.style;
|
||||
style.position = 'relative';
|
||||
style.top = '0px';
|
||||
style.left = '0px';
|
||||
style.fontSize = '0px';
|
||||
style.overflow = 'hidden';
|
||||
style.float = 'left'; //Webkit
|
||||
style.cssFloat = 'left'; //Firefox
|
||||
style.styleFloat = 'left'; //IE
|
||||
style.zIndex = 999999999;
|
||||
style.cursor = 'default';
|
||||
style.width = ( strip.panelWidth - 4 ) + 'px';
|
||||
style.height = ( strip.panelHeight - 4 ) + 'px';
|
||||
|
||||
// TODO: What is this for? Future keyboard navigation support?
|
||||
miniViewer.displayRegion.innerTracker = new $.MouseTracker( {
|
||||
element: miniViewer.displayRegion,
|
||||
startDisabled: true
|
||||
} );
|
||||
|
||||
element.getElementsByTagName( 'div' )[0].appendChild(
|
||||
miniViewer.displayRegion
|
||||
);
|
||||
// Allow pointer events to pass through miniViewer's canvas/container
|
||||
// elements so implicit pointer capture works on touch devices
|
||||
$.setElementPointerEventsNone( miniViewer.canvas );
|
||||
$.setElementPointerEventsNone( miniViewer.container );
|
||||
// We'll use event delegation from the reference strip element instead of
|
||||
// handling events on every miniViewer
|
||||
miniViewer.innerTracker.setTracking( false );
|
||||
miniViewer.outerTracker.setTracking( false );
|
||||
|
||||
strip.miniViewers[element.id] = miniViewer;
|
||||
|
||||
@ -503,7 +486,7 @@ function onStripEnter( event ) {
|
||||
//element.style.border = '1px solid #555';
|
||||
//element.style.background = '#000';
|
||||
|
||||
if ( 'horizontal' == this.scroll ) {
|
||||
if ( 'horizontal' === this.scroll ) {
|
||||
|
||||
//element.style.paddingTop = "0px";
|
||||
element.style.marginBottom = "0px";
|
||||
@ -514,7 +497,6 @@ function onStripEnter( event ) {
|
||||
element.style.marginLeft = "0px";
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -523,10 +505,10 @@ function onStripEnter( event ) {
|
||||
* @inner
|
||||
* @function
|
||||
*/
|
||||
function onStripExit( event ) {
|
||||
function onStripLeave( event ) {
|
||||
var element = event.eventSource.element;
|
||||
|
||||
if ( 'horizontal' == this.scroll ) {
|
||||
if ( 'horizontal' === this.scroll ) {
|
||||
|
||||
//element.style.paddingTop = "10px";
|
||||
element.style.marginBottom = "-" + ( $.getElementSize( element ).y / 2 ) + "px";
|
||||
@ -537,7 +519,6 @@ function onStripExit( event ) {
|
||||
element.style.marginLeft = "-" + ( $.getElementSize( element ).x / 2 ) + "px";
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -549,26 +530,31 @@ function onStripExit( event ) {
|
||||
function onKeyDown( event ) {
|
||||
//console.log( event.keyCode );
|
||||
|
||||
if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {
|
||||
if ( !event.ctrl && !event.alt && !event.meta ) {
|
||||
switch ( event.keyCode ) {
|
||||
case 38: //up arrow
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
case 40: //down arrow
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
case 37: //left arrow
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
case 39: //right arrow
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
default:
|
||||
//console.log( 'navigator keycode %s', event.keyCode );
|
||||
return true;
|
||||
event.preventDefault = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
event.preventDefault = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -581,35 +567,42 @@ function onKeyDown( event ) {
|
||||
function onKeyPress( event ) {
|
||||
//console.log( event.keyCode );
|
||||
|
||||
if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {
|
||||
if ( !event.ctrl && !event.alt && !event.meta ) {
|
||||
switch ( event.keyCode ) {
|
||||
case 61: //=|+
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
case 45: //-|_
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
case 48: //0|)
|
||||
case 119: //w
|
||||
case 87: //W
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
case 115: //s
|
||||
case 83: //S
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
case 97: //a
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
case 100: //d
|
||||
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );
|
||||
return false;
|
||||
event.preventDefault = true;
|
||||
break;
|
||||
default:
|
||||
//console.log( 'navigator keycode %s', event.keyCode );
|
||||
return true;
|
||||
event.preventDefault = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
event.preventDefault = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,11 +50,11 @@
|
||||
$.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 = {
|
||||
initial: args.length && typeof ( args[ 0 ] ) == "number" ?
|
||||
initial: args.length && typeof ( args[ 0 ] ) === "number" ?
|
||||
args[ 0 ] :
|
||||
undefined,
|
||||
/**
|
||||
@ -96,7 +96,7 @@ $.Spring = function( options ) {
|
||||
* @property {Number} time
|
||||
*/
|
||||
this.current = {
|
||||
value: typeof ( this.initial ) == "number" ?
|
||||
value: typeof ( this.initial ) === "number" ?
|
||||
this.initial :
|
||||
(this._exponential ? 0 : 1),
|
||||
time: $.now() // always work in milliseconds
|
||||
@ -237,7 +237,7 @@ $.Spring.prototype = {
|
||||
this.current.value = currentValue;
|
||||
}
|
||||
|
||||
return oldValue != this.current.value;
|
||||
return oldValue !== this.current.value;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -82,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
|
||||
}
|
||||
|
20
src/tile.js
20
src/tile.js
@ -176,6 +176,12 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.size = null;
|
||||
/**
|
||||
* Whether to flip the tile when rendering.
|
||||
* @member {Boolean} flipped
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.flipped = false;
|
||||
/**
|
||||
* The start time of this tile's blending.
|
||||
* @member {Number} blendStart
|
||||
@ -284,10 +290,10 @@ $.Tile.prototype = {
|
||||
this.style = this.element.style;
|
||||
this.style.position = "absolute";
|
||||
}
|
||||
if ( this.element.parentNode != container ) {
|
||||
if ( this.element.parentNode !== container ) {
|
||||
container.appendChild( this.element );
|
||||
}
|
||||
if ( this.imgElement.parentNode != this.element ) {
|
||||
if ( this.imgElement.parentNode !== this.element ) {
|
||||
this.element.appendChild( this.imgElement );
|
||||
}
|
||||
|
||||
@ -296,6 +302,10 @@ $.Tile.prototype = {
|
||||
this.style.height = this.size.y + "px";
|
||||
this.style.width = this.size.x + "px";
|
||||
|
||||
if (this.flipped) {
|
||||
this.style.transform = "scaleX(-1)";
|
||||
}
|
||||
|
||||
$.setElementOpacity( this.element, this.opacity );
|
||||
},
|
||||
|
||||
@ -383,13 +393,17 @@ $.Tile.prototype = {
|
||||
sourceHeight = rendered.canvas.height;
|
||||
}
|
||||
|
||||
context.translate(position.x + size.x / 2, 0);
|
||||
if (this.flipped) {
|
||||
context.scale(-1, 1);
|
||||
}
|
||||
context.drawImage(
|
||||
rendered.canvas,
|
||||
0,
|
||||
0,
|
||||
sourceWidth,
|
||||
sourceHeight,
|
||||
position.x,
|
||||
-size.x / 2,
|
||||
position.y,
|
||||
size.x,
|
||||
size.y
|
||||
|
@ -196,7 +196,7 @@ $.TileCache.prototype = {
|
||||
worstLevel = worstTile.level;
|
||||
|
||||
if ( prevTime < worstTime ||
|
||||
( prevTime == worstTime && prevLevel > worstLevel ) ) {
|
||||
( prevTime === worstTime && prevLevel > worstLevel ) ) {
|
||||
worstTile = prevTile;
|
||||
worstTileIndex = i;
|
||||
worstTileRecord = prevTileRecord;
|
||||
|
@ -326,6 +326,10 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
*/
|
||||
destroy: function() {
|
||||
this.reset();
|
||||
|
||||
if (this.source.destroy) {
|
||||
this.source.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -388,6 +392,26 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
return bounds.rotate(this.getRotation(current), this._getRotationPoint(current));
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @returns {OpenSeadragon.Rect} Where this tile fits (in normalized coordinates).
|
||||
*/
|
||||
getTileBounds: function( level, x, y ) {
|
||||
var numTiles = this.source.getNumTiles(level);
|
||||
var xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x;
|
||||
var yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;
|
||||
var bounds = this.source.getTileBounds(level, xMod, yMod);
|
||||
if (this.getFlip()) {
|
||||
bounds.x = 1 - bounds.x - bounds.width;
|
||||
}
|
||||
bounds.x += (x - xMod) / numTiles.x;
|
||||
bounds.y += (this._worldHeightCurrent / this._worldWidthCurrent) * ((y - yMod) / numTiles.y);
|
||||
return bounds;
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {OpenSeadragon.Point} This TiledImage's content size, in original pixels.
|
||||
*/
|
||||
@ -395,6 +419,15 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
return new $.Point(this.source.dimensions.x, this.source.dimensions.y);
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {OpenSeadragon.Point} The TiledImage's content size, in window coordinates.
|
||||
*/
|
||||
getSizeInWindowCoordinates: function() {
|
||||
var topLeft = this.imageToWindowCoordinates(new $.Point(0, 0));
|
||||
var bottomRight = this.imageToWindowCoordinates(this.getContentSize());
|
||||
return new $.Point(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
|
||||
},
|
||||
|
||||
// private
|
||||
_viewportToImageDelta: function( viewerX, viewerY, current ) {
|
||||
var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value);
|
||||
@ -674,6 +707,58 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
this._setScale(height / this.normHeight, immediately);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets an array of polygons to crop the TiledImage during draw tiles.
|
||||
* The render function will use the default non-zero winding rule.
|
||||
* @param {OpenSeadragon.Point[][]} polygons - represented in an array of point object in image coordinates.
|
||||
* Example format: [
|
||||
* [{x: 197, y:172}, {x: 226, y:172}, {x: 226, y:198}, {x: 197, y:198}], // First polygon
|
||||
* [{x: 328, y:200}, {x: 330, y:199}, {x: 332, y:201}, {x: 329, y:202}] // Second polygon
|
||||
* [{x: 321, y:201}, {x: 356, y:205}, {x: 341, y:250}] // Third polygon
|
||||
* ]
|
||||
*/
|
||||
setCroppingPolygons: function( polygons ) {
|
||||
|
||||
var isXYObject = function(obj) {
|
||||
return obj instanceof $.Point || (typeof obj.x === 'number' && typeof obj.y === 'number');
|
||||
};
|
||||
|
||||
var objectToSimpleXYObject = function(objs) {
|
||||
return objs.map(function(obj) {
|
||||
try {
|
||||
if (isXYObject(obj)) {
|
||||
return { x: obj.x, y: obj.y };
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
} catch(e) {
|
||||
throw new Error('A Provided cropping polygon point is not supported');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
if (!$.isArray(polygons)) {
|
||||
throw new Error('Provided cropping polygon is not an array');
|
||||
}
|
||||
this._croppingPolygons = polygons.map(function(polygon){
|
||||
return objectToSimpleXYObject(polygon);
|
||||
});
|
||||
} catch (e) {
|
||||
$.console.error('[TiledImage.setCroppingPolygons] Cropping polygon format not supported');
|
||||
$.console.error(e);
|
||||
this._croppingPolygons = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the cropping polygons, thus next render will remove all cropping
|
||||
* polygon effects.
|
||||
*/
|
||||
resetCroppingPolygons: function() {
|
||||
this._croppingPolygons = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Positions and scales the TiledImage to fit in the specified bounds.
|
||||
* Note: this method fires OpenSeadragon.TiledImage.event:bounds-change
|
||||
@ -776,6 +861,23 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
this.raiseEvent('clip-change');
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Boolean} Whether the TiledImage should be flipped before rendering.
|
||||
*/
|
||||
getFlip: function() {
|
||||
return !!this.flipped;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Boolean} flip Whether the TiledImage should be flipped before rendering.
|
||||
* @fires OpenSeadragon.TiledImage.event:bounds-change
|
||||
*/
|
||||
setFlip: function(flip) {
|
||||
this.flipped = !!flip;
|
||||
this._needsDraw = true;
|
||||
this._raiseBoundsChange();
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Number} The TiledImage's current opacity.
|
||||
*/
|
||||
@ -1199,24 +1301,41 @@ function updateLevel(tiledImage, haveDrawn, drawLevel, level, levelOpacity,
|
||||
|
||||
var viewportCenter = tiledImage.viewport.pixelFromPoint(
|
||||
tiledImage.viewport.getCenter());
|
||||
|
||||
if (tiledImage.getFlip()) {
|
||||
// The right-most tile can be narrower than the others. When flipped,
|
||||
// this tile is now on the left. Because it is narrower than the normal
|
||||
// left-most tile, the subsequent tiles may not be wide enough to completely
|
||||
// fill the viewport. Fix this by rendering an extra column of tiles. If we
|
||||
// are not wrapping, make sure we never render more than the number of tiles
|
||||
// in the image.
|
||||
bottomRightTile.x += 1;
|
||||
if (!tiledImage.wrapHorizontal) {
|
||||
bottomRightTile.x = Math.min(bottomRightTile.x, numberOfTiles.x - 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (var x = topLeftTile.x; x <= bottomRightTile.x; x++) {
|
||||
for (var y = topLeftTile.y; y <= bottomRightTile.y; y++) {
|
||||
|
||||
// Optimisation disabled with wrapping because getTileBounds does not
|
||||
// work correctly with x and y outside of the number of tiles
|
||||
if (!tiledImage.wrapHorizontal && !tiledImage.wrapVertical) {
|
||||
var tileBounds = tiledImage.source.getTileBounds(level, x, y);
|
||||
if (drawArea.intersection(tileBounds) === null) {
|
||||
var flippedX;
|
||||
if (tiledImage.getFlip()) {
|
||||
var xMod = ( numberOfTiles.x + ( x % numberOfTiles.x ) ) % numberOfTiles.x;
|
||||
flippedX = x + numberOfTiles.x - xMod - xMod - 1;
|
||||
} else {
|
||||
flippedX = x;
|
||||
}
|
||||
|
||||
if (drawArea.intersection(tiledImage.getTileBounds(level, flippedX, y)) === null) {
|
||||
// This tile is outside of the viewport, no need to draw it
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
best = updateTile(
|
||||
tiledImage,
|
||||
drawLevel,
|
||||
haveDrawn,
|
||||
x, y,
|
||||
flippedX, y,
|
||||
level,
|
||||
levelOpacity,
|
||||
levelVisibility,
|
||||
@ -1391,10 +1510,10 @@ function getTile(
|
||||
tilesMatrix[ level ][ x ] = {};
|
||||
}
|
||||
|
||||
if ( !tilesMatrix[ level ][ x ][ y ] ) {
|
||||
if ( !tilesMatrix[ level ][ x ][ y ] || !tilesMatrix[ level ][ x ][ y ].flipped !== !tiledImage.flipped ) {
|
||||
xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x;
|
||||
yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;
|
||||
bounds = tileSource.getTileBounds( level, xMod, yMod );
|
||||
bounds = tiledImage.getTileBounds( level, x, y );
|
||||
sourceBounds = tileSource.getTileBounds( level, xMod, yMod, true );
|
||||
exists = tileSource.tileExists( level, xMod, yMod );
|
||||
url = tileSource.getTileUrl( level, xMod, yMod );
|
||||
@ -1413,9 +1532,6 @@ function getTile(
|
||||
context2D = tileSource.getContext2D ?
|
||||
tileSource.getContext2D(level, xMod, yMod) : undefined;
|
||||
|
||||
bounds.x += ( x - xMod ) / numTiles.x;
|
||||
bounds.y += (worldHeight / worldWidth) * (( y - yMod ) / numTiles.y);
|
||||
|
||||
tile = new $.Tile(
|
||||
level,
|
||||
x,
|
||||
@ -1429,14 +1545,22 @@ function getTile(
|
||||
sourceBounds
|
||||
);
|
||||
|
||||
if (tiledImage.getFlip()) {
|
||||
if (xMod === 0) {
|
||||
tile.isRightMost = true;
|
||||
}
|
||||
} else {
|
||||
if (xMod === numTiles.x - 1) {
|
||||
tile.isRightMost = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (yMod === numTiles.y - 1) {
|
||||
tile.isBottomMost = true;
|
||||
}
|
||||
|
||||
tile.flipped = tiledImage.flipped;
|
||||
|
||||
tilesMatrix[ level ][ x ][ y ] = tile;
|
||||
}
|
||||
|
||||
@ -1573,7 +1697,7 @@ function setTileLoaded(tiledImage, tile, image, cutoff, tileRequest) {
|
||||
* @property {Image} image - The image of the tile.
|
||||
* @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile.
|
||||
* @property {OpenSeadragon.Tile} tile - The tile which has been loaded.
|
||||
* @property {XMLHttpRequest} tiledImage - The AJAX request that loaded this tile (if applicable).
|
||||
* @property {XMLHttpRequest} tileRequest - The AJAX request that loaded this tile (if applicable).
|
||||
* @property {function} getCompletionCallback - A function giving a callback to call
|
||||
* when the asynchronous processing of the image is done. The image will be
|
||||
* marked as entirely loaded when the callback has been called once for each
|
||||
@ -1714,10 +1838,10 @@ function providesCoverage( coverage, level, x, y ) {
|
||||
if ( x === undefined || y === undefined ) {
|
||||
rows = coverage[ level ];
|
||||
for ( i in rows ) {
|
||||
if ( rows.hasOwnProperty( i ) ) {
|
||||
if ( Object.prototype.hasOwnProperty.call( rows, i ) ) {
|
||||
cols = rows[ i ];
|
||||
for ( j in cols ) {
|
||||
if ( cols.hasOwnProperty( j ) && !cols[ j ] ) {
|
||||
if ( Object.prototype.hasOwnProperty.call( cols, j ) && !cols[ j ] ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1818,7 +1942,7 @@ function compareTiles( previousBest, tile ) {
|
||||
|
||||
if ( tile.visibility > previousBest.visibility ) {
|
||||
return tile;
|
||||
} else if ( tile.visibility == previousBest.visibility ) {
|
||||
} else if ( tile.visibility === previousBest.visibility ) {
|
||||
if ( tile.squaredDistance < previousBest.squaredDistance ) {
|
||||
return tile;
|
||||
}
|
||||
@ -1877,14 +2001,15 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
// sketch canvas we are going to use for performance reasons.
|
||||
bounds = tiledImage.viewport.viewportToViewerElementRectangle(
|
||||
tiledImage.getClippedBounds(true))
|
||||
.getIntegerBoundingBox()
|
||||
.times($.pixelDensityRatio);
|
||||
.getIntegerBoundingBox();
|
||||
|
||||
if(tiledImage._drawer.viewer.viewport.getFlip()) {
|
||||
if (tiledImage.viewport.degrees !== 0 || tiledImage.getRotation(true) % 360 !== 0){
|
||||
bounds.x = tiledImage._drawer.viewer.container.clientWidth - (bounds.x + bounds.width);
|
||||
}
|
||||
}
|
||||
|
||||
bounds = bounds.times($.pixelDensityRatio);
|
||||
}
|
||||
tiledImage._drawer._clear(true, bounds);
|
||||
}
|
||||
@ -1932,6 +2057,28 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
usedClip = true;
|
||||
}
|
||||
|
||||
if (tiledImage._croppingPolygons) {
|
||||
tiledImage._drawer.saveContext(useSketch);
|
||||
try {
|
||||
var polygons = tiledImage._croppingPolygons.map(function (polygon) {
|
||||
return polygon.map(function (coord) {
|
||||
var point = tiledImage
|
||||
.imageToViewportCoordinates(coord.x, coord.y, true)
|
||||
.rotate(-tiledImage.getRotation(true), tiledImage._getRotationPoint(true));
|
||||
var clipPoint = tiledImage._drawer.viewportCoordToDrawerCoord(point);
|
||||
if (sketchScale) {
|
||||
clipPoint = clipPoint.times(sketchScale);
|
||||
}
|
||||
return clipPoint;
|
||||
});
|
||||
});
|
||||
tiledImage._drawer.clipWithPolygons(polygons, useSketch);
|
||||
} catch (e) {
|
||||
$.console.error(e);
|
||||
}
|
||||
usedClip = true;
|
||||
}
|
||||
|
||||
if ( tiledImage.placeholderFillStyle && tiledImage._hasOpaqueTile === false ) {
|
||||
var placeholderRect = tiledImage._drawer.viewportToDrawerRectangle(tiledImage.getBounds(true));
|
||||
if (sketchScale) {
|
||||
|
@ -167,7 +167,7 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
* @memberof OpenSeadragon.TileSource#
|
||||
*/
|
||||
|
||||
if( 'string' == $.type( arguments[ 0 ] ) ){
|
||||
if( 'string' === $.type( arguments[ 0 ] ) ){
|
||||
this.url = arguments[0];
|
||||
}
|
||||
|
||||
@ -313,8 +313,8 @@ $.TileSource.prototype = {
|
||||
*/
|
||||
getPixelRatio: function( level ) {
|
||||
var imageSizeScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
||||
rx = 1.0 / imageSizeScaled.x,
|
||||
ry = 1.0 / imageSizeScaled.y;
|
||||
rx = 1.0 / imageSizeScaled.x * $.pixelDensityRatio,
|
||||
ry = 1.0 / imageSizeScaled.y * $.pixelDensityRatio;
|
||||
|
||||
return new $.Point(rx, ry);
|
||||
},
|
||||
@ -500,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();
|
||||
@ -640,7 +640,7 @@ function processResponse( xhr ){
|
||||
throw new Error( $.getString( "Errors.Security" ) );
|
||||
} else if ( xhr.status !== 200 && xhr.status !== 0 ) {
|
||||
status = xhr.status;
|
||||
statusText = ( status == 404 ) ?
|
||||
statusText = ( status === 404 ) ?
|
||||
"Not Found" :
|
||||
xhr.statusText;
|
||||
throw new Error( $.getString( "Errors.Status", status, statusText ) );
|
||||
@ -654,7 +654,7 @@ function processResponse( xhr ){
|
||||
} catch (e){
|
||||
data = xhr.responseText;
|
||||
}
|
||||
}else if( responseText.match(/\s*[\{\[].*/) ){
|
||||
}else if( responseText.match(/\s*[{[].*/) ){
|
||||
try{
|
||||
data = $.parseJSON(responseText);
|
||||
} catch(e){
|
||||
@ -690,6 +690,8 @@ $.TileSource.determineType = function( tileSource, data, url ){
|
||||
}
|
||||
|
||||
$.console.error( "No TileSource was able to open %s %s", url, data );
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
|
@ -103,7 +103,7 @@ $.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
|
||||
* @param {String} optional - url
|
||||
*/
|
||||
supports: function( data, url ){
|
||||
return ( data.type && "tiledmapservice" == data.type );
|
||||
return ( data.type && "tiledmapservice" === data.type );
|
||||
},
|
||||
|
||||
/**
|
||||
|
562
src/viewer.js
562
src/viewer.js
File diff suppressed because it is too large
Load Diff
@ -898,7 +898,7 @@ $.Viewport.prototype = {
|
||||
* @property {Number} degrees - The number of degrees the rotation was set to.
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
*/
|
||||
this.viewer.raiseEvent('rotate', {"degrees": degrees});
|
||||
this.viewer.raiseEvent('rotate', {degrees: degrees});
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -1567,7 +1567,7 @@ $.Viewport.prototype = {
|
||||
* @property {Number} flipped - The flip state after this change.
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
*/
|
||||
this.viewer.raiseEvent('flip', {"flipped": state});
|
||||
this.viewer.raiseEvent('flip', {flipped: state});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
* tilesUrl: "/test/data/zoomify/"
|
||||
* }
|
||||
*
|
||||
* The tileSize is currently hardcoded to 256 (the usual Zoomify default). The tileUrl must the path to the image _directory_.
|
||||
* The tileSize is set to 256 (the usual Zoomify default) when it is not defined. The tileUrl must the path to the image _directory_.
|
||||
*
|
||||
* 2) Loading image metadata from xml file: (CURRENTLY NOT SUPPORTED)
|
||||
*
|
||||
@ -44,7 +44,14 @@
|
||||
* @param {String} tilesUrl
|
||||
*/
|
||||
$.ZoomifyTileSource = function(options) {
|
||||
if(typeof options.tileSize === 'undefined'){
|
||||
options.tileSize = 256;
|
||||
}
|
||||
|
||||
if(typeof options.fileFormat === 'undefined'){
|
||||
options.fileFormat = 'jpg';
|
||||
this.fileFormat = options.fileFormat;
|
||||
}
|
||||
|
||||
var currentImageSize = {
|
||||
x: options.width,
|
||||
@ -107,7 +114,7 @@
|
||||
* @param {String} optional - url
|
||||
*/
|
||||
supports: function(data, url) {
|
||||
return (data.type && "zoomifytileservice" == data.type);
|
||||
return (data.type && "zoomifytileservice" === data.type);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -133,7 +140,7 @@
|
||||
var result = 0;
|
||||
var num = this._calculateAbsoluteTileNumber(level, x, y);
|
||||
result = Math.floor(num / 256);
|
||||
return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.jpg';
|
||||
return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.' + this.fileFormat;
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -87,6 +87,7 @@
|
||||
<script src="/test/modules/rectangle.js"></script>
|
||||
<script src="/test/modules/ajax-tiles.js"></script>
|
||||
<script src="/test/modules/imageloader.js"></script>
|
||||
<script src="/test/modules/iiif.js"></script>
|
||||
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up)
|
||||
so we put them last. -->
|
||||
<script src="/test/modules/navigator.js"></script>
|
||||
|
165
test/demo/cropping-polygons.html
Normal file
165
test/demo/cropping-polygons.html
Normal file
@ -0,0 +1,165 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OpenSeadragon Cropping PolygonList Demo</title>
|
||||
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
|
||||
<script type="text/javascript" src='../lib/jquery-1.9.1.min.js'></script>
|
||||
<style type="text/css">
|
||||
|
||||
.openseadragon1 {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
background: lightgreen;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 215px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.box-with-title {
|
||||
padding-top: 1em;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.buttons {
|
||||
width: 215px;
|
||||
}
|
||||
|
||||
*:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>
|
||||
Simple demo page to show cropping with polygonList in a OpenSeadragon viewer.
|
||||
</h3>
|
||||
<div id="contentDiv" class="openseadragon1"></div>
|
||||
<span>Click on Viewer to save polygon points</span>
|
||||
<div>
|
||||
<button id='resetBtn'>Reset</button>
|
||||
<button id='exampleBtn'>Load Example</button>
|
||||
</div>
|
||||
<div class='box-with-title'>
|
||||
<div class="buttons">
|
||||
<button id="addPointBtn">Add Points as Polygon</button>
|
||||
<button onclick="emptyElement('polygonPointEl')">Clear</button>
|
||||
</div>
|
||||
<textarea id="polygonPointEl"></textarea>
|
||||
</div>
|
||||
<div class='box-with-title'>
|
||||
<div class="buttons">
|
||||
<button id="cropBtn">Crop With Polygon</button>
|
||||
<button onclick="emptyElement('previewEl')">Clear</button>
|
||||
</div>
|
||||
<textarea id='previewEl'></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Setup Viewer -->
|
||||
<script type="text/javascript">
|
||||
var viewer = OpenSeadragon({
|
||||
// debugMode: true,
|
||||
id: "contentDiv",
|
||||
prefixUrl: "../../build/openseadragon/images/",
|
||||
tileSources: "../data/testpattern.dzi",
|
||||
showNavigator: false,
|
||||
gestureSettingsMouse: {
|
||||
clickToZoom: false
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Global Variables
|
||||
var previewEl = document.getElementById('previewEl');
|
||||
var polygonPointEl = document.getElementById('polygonPointEl');
|
||||
|
||||
var examples = [
|
||||
[{x: 480, y: 300},{x: 300, y: 420},{x: 600, y: 420}], // Triangle
|
||||
[{x: 300, y: 550},{x: 300, y: 750},{x: 600, y: 750},{x: 600, y: 550}] // Rectangle
|
||||
];
|
||||
|
||||
// Load default examples
|
||||
function loadExample(){
|
||||
previewEl.value = JSON.stringify(examples);
|
||||
}
|
||||
loadExample();
|
||||
|
||||
// Set a given element's value to empty string
|
||||
function emptyElement(elementId) {
|
||||
document.getElementById(elementId).value = '';
|
||||
}
|
||||
|
||||
// JSON parse a given object, then insert object assuming parsed value is array.
|
||||
function insertObjectToElement(object, element) {
|
||||
var parsed = []; // Default to empty array
|
||||
try {
|
||||
parsed = JSON.parse(element.value);
|
||||
} catch(error) { }
|
||||
parsed.push(object);
|
||||
element.value = JSON.stringify(parsed)
|
||||
}
|
||||
|
||||
// Add click handler to clicked point tracker
|
||||
viewer.addHandler('canvas-click', function(event) {
|
||||
var viewportPoint = viewer.viewport.pointFromPixel(event.position);
|
||||
var p = viewer.viewport.viewportToImageCoordinates(viewportPoint);
|
||||
p.x = Math.round((p.x + Number.EPSILON) * 100) / 100
|
||||
p.y = Math.round((p.y + Number.EPSILON) * 100) / 100
|
||||
insertObjectToElement({x:p.x, y:p.y}, polygonPointEl);
|
||||
});
|
||||
|
||||
// Evaluate give element in JavaScript variable, default to empty array.
|
||||
function readElementValueDefaultToEmptyArray(elementId) {
|
||||
try {
|
||||
var val = document.getElementById(elementId).value;
|
||||
if (val === '') { return []; }
|
||||
return eval(val); // If using JSON.parse, user must put quotes [{"x": 123, "y":12}]
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Insert value from given element into preview element
|
||||
function insertValueFromElementToPreviewElement(element) {
|
||||
try {
|
||||
if (element.value === '') { return; }
|
||||
var polygon = eval(element.value);
|
||||
var polygonList = readElementValueDefaultToEmptyArray('previewEl');
|
||||
polygonList.push(polygon);
|
||||
element.value = '';
|
||||
previewEl.value = JSON.stringify(polygonList);
|
||||
} catch(error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Add clicked points to polygon tracker variable as point objects
|
||||
document.getElementById('addPointBtn').onclick = function(){
|
||||
insertValueFromElementToPreviewElement(polygonPointEl);
|
||||
};
|
||||
|
||||
// Crop image with value in the preview element
|
||||
document.getElementById('cropBtn').onclick = function(){
|
||||
var polygonList = eval(previewEl.value);
|
||||
var tiledImage = viewer.world.getItemAt(0);
|
||||
tiledImage.setCroppingPolygons(polygonList);
|
||||
viewer.forceRedraw();
|
||||
emptyElement('previewEl');
|
||||
};
|
||||
|
||||
document.getElementById('resetBtn').onclick = function(){
|
||||
emptyElement('polygonPointEl');
|
||||
emptyElement('previewEl');
|
||||
var tiledImage = viewer.world.getItemAt(0);
|
||||
tiledImage.resetCroppingPolygons();
|
||||
viewer.forceRedraw();
|
||||
};
|
||||
|
||||
document.getElementById('exampleBtn').onclick = loadExample;
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
113
test/demo/flipping.html
Normal file
113
test/demo/flipping.html
Normal file
@ -0,0 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OpenSeadragon Flipping Demo</title>
|
||||
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
|
||||
<script type="text/javascript" src='../lib/jquery-1.9.1.min.js'></script>
|
||||
<style type="text/css">
|
||||
|
||||
.openseadragon1 {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.options {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: 0.3em;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Simple demo page to show image flipping.
|
||||
</div>
|
||||
<div id="contentDiv" class="openseadragon1">
|
||||
|
||||
|
||||
</div>
|
||||
<div class="options">
|
||||
First
|
||||
<div class="button">
|
||||
<input type="checkbox" id="ffirst" onchange="flip(0, this.checked)">
|
||||
<label for="ffirst">Flip</label>
|
||||
</div>
|
||||
<div class="button">
|
||||
<input type="checkbox" id="rfirst" onchange="rotate(0, this.checked * 45)">
|
||||
<label for="rfirst">Rotate</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="options">
|
||||
Second
|
||||
<div class="button">
|
||||
<input type="checkbox" id="fsecond" onchange="flip(1, this.checked)" checked>
|
||||
<label for="fsecond">Flip</label>
|
||||
</div>
|
||||
<div class="button">
|
||||
<input type="checkbox" id="rsecond" onchange="rotate(1, this.checked * 45)">
|
||||
<label for="rsecond">Rotate</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="options">
|
||||
Viewport
|
||||
<div class="button">
|
||||
<input type="checkbox" id="fview" onchange="flipViewport(this.checked)">
|
||||
<label for="fview">Flip Viewport</label>
|
||||
</div>
|
||||
|
||||
<div class="button">
|
||||
<input type="checkbox" id="debug" onchange="debug(this.checked)">
|
||||
<label for="debug">Debug Mode</label>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
|
||||
var viewer = OpenSeadragon({
|
||||
// debugMode: true,
|
||||
id: "contentDiv",
|
||||
prefixUrl: "../../build/openseadragon/images/",
|
||||
showNavigator:true,
|
||||
tileSources: [
|
||||
{
|
||||
tileSource: "../data/testpattern.dzi",
|
||||
x: 0,
|
||||
y: 0,
|
||||
flipped: document.getElementById("ffirst").checked,
|
||||
degrees: document.getElementById("rfirst").checked * 45,
|
||||
}, {
|
||||
tileSource: "../data/testpattern.dzi",
|
||||
x: 1,
|
||||
y: 0,
|
||||
flipped: document.getElementById("fsecond").checked,
|
||||
degrees: document.getElementById("rsecond").checked * 45,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
viewer.viewport.setFlip(document.getElementById("fview").checked);
|
||||
|
||||
function debug(v) {
|
||||
viewer.setDebugMode(v);
|
||||
}
|
||||
|
||||
function flip(n, v) {
|
||||
viewer.world.getItemAt(n).setFlip(v);
|
||||
}
|
||||
|
||||
function rotate(n, v) {
|
||||
viewer.world.getItemAt(n).setRotation(v);
|
||||
}
|
||||
|
||||
function flipViewport(v) {
|
||||
viewer.viewport.setFlip(v);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
55
test/demo/memorycheck-with-simple-image.html
Normal file
55
test/demo/memorycheck-with-simple-image.html
Normal file
@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OpenSeadragon Memory Check With Simple Image Demo</title>
|
||||
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
|
||||
<style type="text/css">
|
||||
|
||||
.openseadragon1 {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Simple demo page to monitor OpenSeadragon Memory Usage.
|
||||
</div>
|
||||
<!-- To get "Total canvas memory use exceeds the maximum limit" warning and then "null is not an object (evaluating 'smallContext.drawImage')" error,
|
||||
disable _freeupCanvasMemory method in ImageTileSource,
|
||||
then click Create button below 12 times on "iPad Air (3rd generation) -- 13.3" Simulator on Mac with Web Inspector by Safari. -->
|
||||
<button onclick="createViewer()">Create</button>
|
||||
<button onclick="destroyViewer()">Destroy</button>
|
||||
|
||||
<div id="contentDiv" class="openseadragon1"></div>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _viewer;
|
||||
|
||||
function createViewer() {
|
||||
if ( _viewer ) {
|
||||
destroyViewer();
|
||||
}
|
||||
|
||||
_viewer = OpenSeadragon({
|
||||
element: document.getElementById("contentDiv"),
|
||||
showNavigationControl: false,
|
||||
prefixUrl: "../../build/openseadragon/images/",
|
||||
tileSources: {
|
||||
type: "image",
|
||||
url: "../data/CCyan.png"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function destroyViewer() {
|
||||
if ( _viewer ) {
|
||||
_viewer.destroy();
|
||||
}
|
||||
_viewer = null;
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -6,20 +6,22 @@
|
||||
|
||||
$.MouseTracker.subscribeEvents = [ "click", "dblclick", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ];
|
||||
|
||||
if( $.MouseTracker.wheelEventName == "DOMMouseScroll" ) {
|
||||
if( $.MouseTracker.wheelEventName === "DOMMouseScroll" ) {
|
||||
// Older Firefox
|
||||
$.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" );
|
||||
}
|
||||
|
||||
$.MouseTracker.havePointerEvents = false;
|
||||
if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
|
||||
$.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" );
|
||||
$.MouseTracker.haveMouseEnter = true;
|
||||
} else {
|
||||
$.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" );
|
||||
$.MouseTracker.haveMouseEnter = false;
|
||||
$.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave", "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" );
|
||||
$.MouseTracker.mousePointerId = "legacy-mouse";
|
||||
// Legacy mouse events capture support (IE/Firefox only?)
|
||||
$.MouseTracker.havePointerCapture = (function () {
|
||||
var divElement = document.createElement( 'div' );
|
||||
return $.isFunction( divElement.setCapture ) && $.isFunction( divElement.releaseCapture );
|
||||
}());
|
||||
if ( $.MouseTracker.havePointerCapture ) {
|
||||
$.MouseTracker.subscribeEvents.push( "losecapture" );
|
||||
}
|
||||
$.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" );
|
||||
if ( 'ontouchstart' in window ) {
|
||||
// iOS, Android, and other W3c Touch Event implementations
|
||||
// (see http://www.w3.org/TR/touch-events/)
|
||||
@ -32,8 +34,5 @@
|
||||
// Subscribe to these to prevent default gesture handling
|
||||
$.MouseTracker.subscribeEvents.push( "gesturestart", "gesturechange" );
|
||||
}
|
||||
$.MouseTracker.mousePointerId = "legacy-mouse";
|
||||
$.MouseTracker.maxTouchPoints = 10;
|
||||
|
||||
|
||||
}(OpenSeadragon));
|
||||
|
@ -37,7 +37,7 @@
|
||||
};
|
||||
|
||||
$canvas
|
||||
.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseenter' : 'mouseover', event )
|
||||
.simulate( 'mouseenter', event )
|
||||
.simulate( 'mousedown', event );
|
||||
for ( var i = 0; i < args.dragCount; i++ ) {
|
||||
event.clientX += args.dragDx;
|
||||
@ -47,7 +47,7 @@
|
||||
}
|
||||
$canvas
|
||||
.simulate( 'mouseup', event )
|
||||
.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', event );
|
||||
.simulate( 'mouseleave', event );
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
12
test/modules/controls.js
vendored
12
test/modules/controls.js
vendored
@ -53,9 +53,9 @@
|
||||
assert.ok(viewer.showZoomControl, 'showZoomControl should be on');
|
||||
assert.ok(!!viewer.zoomInButton, "zoomIn button should not be null");
|
||||
assert.ok(!!viewer.zoomOutButton, "zoomOut button should not be null");
|
||||
assert.notEqual(viewer.buttons.buttons.indexOf(viewer.zoomInButton), -1,
|
||||
assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.zoomInButton), -1,
|
||||
"The zoomIn button should be present");
|
||||
assert.notEqual(viewer.buttons.buttons.indexOf(viewer.zoomOutButton), -1,
|
||||
assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.zoomOutButton), -1,
|
||||
"The zoomOut button should be present");
|
||||
|
||||
var oldZoom = viewer.viewport.getZoom();
|
||||
@ -108,7 +108,7 @@
|
||||
viewer.removeHandler('open', openHandler);
|
||||
assert.ok(viewer.showHomeControl, 'showHomeControl should be on');
|
||||
assert.ok(!!viewer.homeButton, "Home button should not be null");
|
||||
assert.notEqual(viewer.buttons.buttons.indexOf(viewer.homeButton), -1,
|
||||
assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.homeButton), -1,
|
||||
"The home button should be present");
|
||||
|
||||
viewer.viewport.zoomBy(1.1);
|
||||
@ -167,7 +167,7 @@
|
||||
viewer.removeHandler('open', openHandler);
|
||||
assert.ok(viewer.showHomeControl, 'showFullPageControl should be on');
|
||||
assert.ok(!!viewer.fullPageButton, "FullPage button should not be null");
|
||||
assert.notEqual(viewer.buttons.buttons.indexOf(viewer.fullPageButton), -1,
|
||||
assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.fullPageButton), -1,
|
||||
"The full page button should be present");
|
||||
|
||||
assert.ok(!viewer.isFullPage(), "OSD should not be in full page.");
|
||||
@ -223,9 +223,9 @@
|
||||
assert.ok(viewer.drawer, 'Drawer exists');
|
||||
assert.ok(viewer.drawer.canRotate(), 'drawer.canRotate needs to be true');
|
||||
assert.ok(viewer.showRotationControl, 'showRotationControl should be true');
|
||||
assert.notEqual(viewer.buttons.buttons.indexOf(viewer.rotateLeftButton), -1,
|
||||
assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.rotateLeftButton), -1,
|
||||
"rotateLeft should be found");
|
||||
assert.notEqual(viewer.buttons.buttons.indexOf(viewer.rotateRightButton), -1,
|
||||
assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.rotateRightButton), -1,
|
||||
"rotateRight should be found");
|
||||
|
||||
// Now simulate the left/right button clicks.
|
||||
|
@ -32,7 +32,7 @@
|
||||
offset = $canvas.offset(),
|
||||
tracker = viewer.innerTracker,
|
||||
origEnterHandler,
|
||||
origExitHandler,
|
||||
origLeaveHandler,
|
||||
origPressHandler,
|
||||
origReleaseHandler,
|
||||
origNonPrimaryPressHandler,
|
||||
@ -43,7 +43,7 @@
|
||||
origDragHandler,
|
||||
origDragEndHandler,
|
||||
enterCount,
|
||||
exitCount,
|
||||
leaveCount,
|
||||
pressCount,
|
||||
releaseCount,
|
||||
rightPressCount,
|
||||
@ -71,11 +71,11 @@
|
||||
return true;
|
||||
}
|
||||
};
|
||||
origExitHandler = tracker.exitHandler;
|
||||
tracker.exitHandler = function ( event ) {
|
||||
exitCount++;
|
||||
if (origExitHandler) {
|
||||
return origExitHandler( event );
|
||||
origLeaveHandler = tracker.leaveHandler;
|
||||
tracker.leaveHandler = function ( event ) {
|
||||
leaveCount++;
|
||||
if (origLeaveHandler) {
|
||||
return origLeaveHandler( event );
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
@ -182,7 +182,7 @@
|
||||
|
||||
var unhookViewerHandlers = function () {
|
||||
tracker.enterHandler = origEnterHandler;
|
||||
tracker.exitHandler = origExitHandler;
|
||||
tracker.leaveHandler = origLeaveHandler;
|
||||
tracker.pressHandler = origPressHandler;
|
||||
tracker.releaseHandler = origReleaseHandler;
|
||||
tracker.moveHandler = origMoveHandler;
|
||||
@ -195,21 +195,21 @@
|
||||
var simulateEnter = function (x, y) {
|
||||
simEvent.clientX = offset.left + x;
|
||||
simEvent.clientY = offset.top + y;
|
||||
$canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseenter' : 'mouseover', simEvent );
|
||||
$canvas.simulate( 'mouseenter', simEvent );
|
||||
};
|
||||
|
||||
var simulateLeave = function (x, y) {
|
||||
simEvent.clientX = offset.left + x;
|
||||
simEvent.clientY = offset.top + y;
|
||||
simEvent.relatedTarget = document.body;
|
||||
$canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent );
|
||||
$canvas.simulate( 'mouseleave', simEvent );
|
||||
};
|
||||
|
||||
//var simulateLeaveFrame = function (x, y) {
|
||||
// simEvent.clientX = offset.left + x;
|
||||
// simEvent.clientY = offset.top + y;
|
||||
// simEvent.relatedTarget = document.getElementsByTagName("html")[0];
|
||||
// $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent );
|
||||
// $canvas.simulate( 'mouseleave', simEvent );
|
||||
//};
|
||||
|
||||
var simulateDown = function (x, y) {
|
||||
@ -256,7 +256,7 @@
|
||||
clientY: offset.top
|
||||
};
|
||||
enterCount = 0;
|
||||
exitCount = 0;
|
||||
leaveCount = 0;
|
||||
pressCount = 0;
|
||||
releaseCount = 0;
|
||||
rightPressCount = 0;
|
||||
@ -280,8 +280,8 @@
|
||||
if ('enterCount' in expected) {
|
||||
assert.equal( enterCount, expected.enterCount, expected.description + 'enterHandler event count matches expected (' + expected.enterCount + ')' );
|
||||
}
|
||||
if ('exitCount' in expected) {
|
||||
assert.equal( exitCount, expected.exitCount, expected.description + 'exitHandler event count matches expected (' + expected.exitCount + ')' );
|
||||
if ('leaveCount' in expected) {
|
||||
assert.equal( leaveCount, expected.leaveCount, expected.description + 'leaveHandler event count matches expected (' + expected.leaveCount + ')' );
|
||||
}
|
||||
if ('pressCount' in expected) {
|
||||
assert.equal( pressCount, expected.pressCount, expected.description + 'pressHandler event count matches expected (' + expected.pressCount + ')' );
|
||||
@ -355,7 +355,7 @@
|
||||
assessGestureExpectations({
|
||||
description: 'enter-move-release (release in tracked element, press in unknown element): ',
|
||||
enterCount: 1,
|
||||
exitCount: 0,
|
||||
leaveCount: 0,
|
||||
pressCount: 0,
|
||||
releaseCount: 1,
|
||||
rightPressCount: 0,
|
||||
@ -375,16 +375,16 @@
|
||||
});
|
||||
simulateLeave(-1, -1); // flush tracked pointer
|
||||
|
||||
// enter-move-exit (fly-over)
|
||||
// enter-move-leave (fly-over)
|
||||
resetForAssessment();
|
||||
simulateEnter(0, 0);
|
||||
simulateMove(1, 1, 10);
|
||||
simulateMove(-1, -1, 10);
|
||||
simulateLeave(-1, -1);
|
||||
assessGestureExpectations({
|
||||
description: 'enter-move-exit (fly-over): ',
|
||||
description: 'enter-move-leave (fly-over): ',
|
||||
enterCount: 1,
|
||||
exitCount: 1,
|
||||
leaveCount: 1,
|
||||
pressCount: 0,
|
||||
releaseCount: 0,
|
||||
rightPressCount: 0,
|
||||
@ -403,34 +403,7 @@
|
||||
//quickClick: false
|
||||
});
|
||||
|
||||
// move-exit (fly-over, no enter event)
|
||||
resetForAssessment();
|
||||
simulateMove(1, 1, 10);
|
||||
simulateMove(-1, -1, 10);
|
||||
simulateLeave(-1, -1);
|
||||
assessGestureExpectations({
|
||||
description: 'move-exit (fly-over, no enter event): ',
|
||||
enterCount: 0,
|
||||
exitCount: 1,
|
||||
pressCount: 0,
|
||||
releaseCount: 0,
|
||||
rightPressCount: 0,
|
||||
rightReleaseCount: 0,
|
||||
middlePressCount: 0,
|
||||
middleReleaseCount: 0,
|
||||
moveCount: 20,
|
||||
clickCount: 0,
|
||||
dblClickCount: 0,
|
||||
dragCount: 0,
|
||||
dragEndCount: 0,
|
||||
//insideElementPressed: false,
|
||||
//insideElementReleased: false,
|
||||
contacts: 0,
|
||||
trackedPointers: 0
|
||||
//quickClick: false
|
||||
});
|
||||
|
||||
// enter-press-release-press-release-exit (primary/left double click)
|
||||
// enter-press-release-press-release-leave (primary/left double click)
|
||||
resetForAssessment();
|
||||
simulateEnter(0, 0);
|
||||
simulateDown(0, 0);
|
||||
@ -439,9 +412,9 @@
|
||||
simulateUp(0, 0);
|
||||
simulateLeave(-1, -1);
|
||||
assessGestureExpectations({
|
||||
description: 'enter-press-release-press-release-exit (primary/left double click): ',
|
||||
description: 'enter-press-release-press-release-leave (primary/left double click): ',
|
||||
enterCount: 1,
|
||||
exitCount: 1,
|
||||
leaveCount: 1,
|
||||
pressCount: 2,
|
||||
releaseCount: 2,
|
||||
rightPressCount: 0,
|
||||
@ -452,7 +425,7 @@
|
||||
clickCount: 2,
|
||||
dblClickCount: 1,
|
||||
dragCount: 0,
|
||||
dragEndCount: 0,
|
||||
dragEndCount: 2, // v2.5.0+ drag-end event now fired even if pointer didn't move (#1459)
|
||||
insideElementPressed: true,
|
||||
insideElementReleased: true,
|
||||
contacts: 0,
|
||||
@ -460,16 +433,16 @@
|
||||
//quickClick: true
|
||||
});
|
||||
|
||||
// enter-press-release-exit (primary/left click)
|
||||
// enter-press-release-leave (primary/left click)
|
||||
resetForAssessment();
|
||||
simulateEnter(0, 0);
|
||||
simulateDown(0, 0);
|
||||
simulateUp(0, 0);
|
||||
simulateLeave(-1, -1);
|
||||
assessGestureExpectations({
|
||||
description: 'enter-press-release-exit (primary/left click): ',
|
||||
description: 'enter-press-release-leave (primary/left click): ',
|
||||
enterCount: 1,
|
||||
exitCount: 1,
|
||||
leaveCount: 1,
|
||||
pressCount: 1,
|
||||
releaseCount: 1,
|
||||
rightPressCount: 0,
|
||||
@ -480,7 +453,7 @@
|
||||
clickCount: 1,
|
||||
dblClickCount: 0,
|
||||
dragCount: 0,
|
||||
dragEndCount: 0,
|
||||
dragEndCount: 1, // v2.5.0+ drag-end event now fired even if pointer didn't move (#1459)
|
||||
insideElementPressed: true,
|
||||
insideElementReleased: true,
|
||||
contacts: 0,
|
||||
@ -488,16 +461,16 @@
|
||||
quickClick: true
|
||||
});
|
||||
|
||||
// enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click)
|
||||
// enter-nonprimarypress-nonprimaryrelease-leave (secondary/right click)
|
||||
resetForAssessment();
|
||||
simulateEnter(0, 0);
|
||||
simulateNonPrimaryDown(0, 0, 2);
|
||||
simulateNonPrimaryUp(0, 0, 2);
|
||||
simulateLeave(-1, -1);
|
||||
assessGestureExpectations({
|
||||
description: 'enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click): ',
|
||||
description: 'enter-nonprimarypress-nonprimaryrelease-leave (secondary/right click): ',
|
||||
enterCount: 1,
|
||||
exitCount: 1,
|
||||
leaveCount: 1,
|
||||
pressCount: 0,
|
||||
releaseCount: 0,
|
||||
rightPressCount: 1,
|
||||
@ -516,16 +489,16 @@
|
||||
//quickClick: true
|
||||
});
|
||||
|
||||
// enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click)
|
||||
// enter-nonprimarypress-nonprimaryrelease-leave (aux/middle click)
|
||||
resetForAssessment();
|
||||
simulateEnter(0, 0);
|
||||
simulateNonPrimaryDown(0, 0, 1);
|
||||
simulateNonPrimaryUp(0, 0, 1);
|
||||
simulateLeave(-1, -1);
|
||||
assessGestureExpectations({
|
||||
description: 'enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click): ',
|
||||
description: 'enter-nonprimarypress-nonprimaryrelease-leave (aux/middle click): ',
|
||||
enterCount: 1,
|
||||
exitCount: 1,
|
||||
leaveCount: 1,
|
||||
pressCount: 0,
|
||||
releaseCount: 0,
|
||||
rightPressCount: 0,
|
||||
@ -544,7 +517,7 @@
|
||||
//quickClick: true
|
||||
});
|
||||
|
||||
// enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element)
|
||||
// enter-nonprimarypress-move-nonprimaryrelease-move-leave (secondary/right button drag, release in tracked element)
|
||||
resetForAssessment();
|
||||
simulateEnter(0, 0);
|
||||
simulateNonPrimaryDown(0, 0, 2);
|
||||
@ -553,9 +526,9 @@
|
||||
simulateMove(-1, -1, 100);
|
||||
simulateLeave(-1, -1);
|
||||
assessGestureExpectations({
|
||||
description: 'enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element): ',
|
||||
description: 'enter-nonprimarypress-move-nonprimaryrelease-move-leave (secondary/right button drag, release in tracked element): ',
|
||||
enterCount: 1,
|
||||
exitCount: 1,
|
||||
leaveCount: 1,
|
||||
pressCount: 0,
|
||||
releaseCount: 0,
|
||||
rightPressCount: 1,
|
||||
@ -574,7 +547,7 @@
|
||||
//quickClick: false
|
||||
});
|
||||
|
||||
// enter-press-move-release-move-exit (drag, release in tracked element)
|
||||
// enter-press-move-release-move-leave (drag, release in tracked element)
|
||||
resetForAssessment();
|
||||
simulateEnter(0, 0);
|
||||
simulateDown(0, 0);
|
||||
@ -583,9 +556,9 @@
|
||||
simulateMove(-1, -1, 100);
|
||||
simulateLeave(-1, -1);
|
||||
assessGestureExpectations({
|
||||
description: 'enter-press-move-release-move-exit (drag, release in tracked element): ',
|
||||
description: 'enter-press-move-release-move-leave (drag, release in tracked element): ',
|
||||
enterCount: 1,
|
||||
exitCount: 1,
|
||||
leaveCount: 1,
|
||||
pressCount: 1,
|
||||
releaseCount: 1,
|
||||
rightPressCount: 0,
|
||||
@ -604,7 +577,7 @@
|
||||
quickClick: false
|
||||
});
|
||||
|
||||
// enter-press-move-exit-move-release (drag, release outside tracked element)
|
||||
// enter-press-move-leave-move-release (drag, release outside tracked element)
|
||||
resetForAssessment();
|
||||
simulateEnter(0, 0);
|
||||
simulateDown(0, 0);
|
||||
@ -614,9 +587,9 @@
|
||||
simulateMove(-1, -1, 5);
|
||||
simulateUp(-5, -5);
|
||||
assessGestureExpectations({
|
||||
description: 'enter-press-move-exit-move-release (drag, release outside tracked element): ',
|
||||
description: 'enter-press-move-leave-move-release (drag, release outside tracked element): ',
|
||||
enterCount: 1,
|
||||
exitCount: 1,
|
||||
leaveCount: 1,
|
||||
pressCount: 1,
|
||||
releaseCount: 1,
|
||||
rightPressCount: 0,
|
||||
@ -635,7 +608,7 @@
|
||||
quickClick: false
|
||||
});
|
||||
|
||||
//// enter-press-move-exit-move-release-outside (drag, release outside iframe)
|
||||
//// enter-press-move-leave-move-release-outside (drag, release outside iframe)
|
||||
//resetForAssessment();
|
||||
//simulateEnter(0, 0);
|
||||
//simulateDown(0, 0);
|
||||
@ -644,9 +617,9 @@
|
||||
//simulateLeaveFrame(-1, -1);
|
||||
//// you don't actually receive the mouseup if you mouseup outside of the document
|
||||
//assessGestureExpectations({
|
||||
// description: 'enter-press-move-exit-move-release-outside (drag, release outside iframe): ',
|
||||
// description: 'enter-press-move-leave-move-release-outside (drag, release outside iframe): ',
|
||||
// enterCount: 1,
|
||||
// exitCount: 1,
|
||||
// leaveCount: 1,
|
||||
// pressCount: 1,
|
||||
// releaseCount: 1,
|
||||
// rightPressCount: 0,
|
||||
@ -679,8 +652,7 @@
|
||||
if ('TouchEvent' in window) {
|
||||
QUnit.test( 'MouseTracker: touch events', function (assert) {
|
||||
var done = assert.async();
|
||||
var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ),
|
||||
tracker = viewer.innerTracker,
|
||||
var tracker = viewer.innerTracker,
|
||||
touches;
|
||||
|
||||
var reset = function () {
|
||||
@ -757,7 +729,6 @@
|
||||
var done = assert.async();
|
||||
var $canvas = $(viewer.element).find('.openseadragon-canvas')
|
||||
.not('.navigator .openseadragon-canvas');
|
||||
var tracker = viewer.innerTracker;
|
||||
var epsilon = 0.0000001;
|
||||
|
||||
function simulateClickAndDrag() {
|
||||
@ -787,16 +758,14 @@
|
||||
viewer.removeHandler('open', onOpen);
|
||||
|
||||
// Hook viewer events to set preventDefaultAction
|
||||
var origClickHandler = tracker.clickHandler;
|
||||
tracker.clickHandler = function(event) {
|
||||
var onCanvasClick = function (event) {
|
||||
event.preventDefaultAction = true;
|
||||
return origClickHandler(event);
|
||||
};
|
||||
var origDragHandler = tracker.dragHandler;
|
||||
tracker.dragHandler = function(event) {
|
||||
var onCanvasDrag = function (event) {
|
||||
event.preventDefaultAction = true;
|
||||
return origDragHandler(event);
|
||||
};
|
||||
viewer.addHandler("canvas-click", onCanvasClick);
|
||||
viewer.addHandler("canvas-drag", onCanvasDrag);
|
||||
|
||||
var originalZoom = viewer.viewport.getZoom();
|
||||
var originalBounds = viewer.viewport.getBounds();
|
||||
@ -810,8 +779,8 @@
|
||||
Util.assertRectangleEquals(assert, bounds, originalBounds, epsilon,
|
||||
'Pan should be prevented');
|
||||
|
||||
tracker.clickHandler = origClickHandler;
|
||||
tracker.dragHandler = origDragHandler;
|
||||
viewer.removeHandler("canvas-click", onCanvasClick);
|
||||
viewer.removeHandler("canvas-drag", onCanvasDrag);
|
||||
|
||||
simulateClickAndDrag();
|
||||
|
||||
@ -837,31 +806,64 @@
|
||||
// ----------
|
||||
QUnit.test('Viewer: preventDefaultAction in dblClickHandler', function(assert) {
|
||||
var done = assert.async();
|
||||
var tracker = viewer.innerTracker;
|
||||
var epsilon = 0.0000001;
|
||||
var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ),
|
||||
simEvent = {},
|
||||
offset = $canvas.offset();
|
||||
|
||||
var simulateEnter = function (x, y) {
|
||||
simEvent.clientX = offset.left + x;
|
||||
simEvent.clientY = offset.top + y;
|
||||
$canvas.simulate( 'mouseenter', simEvent );
|
||||
};
|
||||
|
||||
var simulateLeave = function (x, y) {
|
||||
simEvent.clientX = offset.left + x;
|
||||
simEvent.clientY = offset.top + y;
|
||||
simEvent.relatedTarget = document.body;
|
||||
$canvas.simulate( 'mouseleave', simEvent );
|
||||
};
|
||||
|
||||
var simulateDown = function (x, y) {
|
||||
simEvent.button = 0;
|
||||
simEvent.clientX = offset.left + x;
|
||||
simEvent.clientY = offset.top + y;
|
||||
$canvas.simulate( 'mousedown', simEvent );
|
||||
};
|
||||
|
||||
var simulateUp = function (x, y) {
|
||||
simEvent.button = 0;
|
||||
simEvent.clientX = offset.left + x;
|
||||
simEvent.clientY = offset.top + y;
|
||||
$canvas.simulate( 'mouseup', simEvent );
|
||||
};
|
||||
|
||||
function simulateDblTap() {
|
||||
var touches = [];
|
||||
TouchUtil.reset();
|
||||
|
||||
touches.push(TouchUtil.start([0,0]));
|
||||
TouchUtil.end( touches[0] );
|
||||
touches.push(TouchUtil.start([0,0]));
|
||||
TouchUtil.end( touches[1] );
|
||||
simulateEnter(2, 2);
|
||||
simulateDown(2, 2);
|
||||
simulateUp(2, 2);
|
||||
simulateDown(2, 2);
|
||||
simulateUp(2, 2);
|
||||
simulateLeave(-1, -1);
|
||||
}
|
||||
|
||||
var onOpen = function() {
|
||||
viewer.removeHandler('open', onOpen);
|
||||
|
||||
var origClickSetting = viewer.gestureSettingsMouse.clickToZoom;
|
||||
var origDblClickSetting = viewer.gestureSettingsMouse.dblClickToZoom;
|
||||
|
||||
viewer.gestureSettingsMouse.clickToZoom = false;
|
||||
viewer.gestureSettingsMouse.dblClickToZoom = true;
|
||||
|
||||
var originalZoom = viewer.viewport.getZoom();
|
||||
|
||||
var origDblClickHandler = tracker.dblClickHandler;
|
||||
tracker.dblClickHandler = function(event) {
|
||||
var onCanvasDblClick = function (event) {
|
||||
event.preventDefaultAction = true;
|
||||
return origDblClickHandler(event);
|
||||
};
|
||||
|
||||
TouchUtil.initTracker(tracker);
|
||||
viewer.addHandler('canvas-double-click', onCanvasDblClick);
|
||||
|
||||
simulateDblTap();
|
||||
|
||||
var zoom = viewer.viewport.getZoom();
|
||||
@ -869,37 +871,19 @@
|
||||
"Zoom on double tap should be prevented");
|
||||
|
||||
// Reset event handler to original
|
||||
tracker.dblClickHandler = origDblClickHandler;
|
||||
viewer.removeHandler("canvas-double-click", onCanvasDblClick);
|
||||
|
||||
simulateDblTap();
|
||||
originalZoom = originalZoom * viewer.zoomPerClick;
|
||||
originalZoom *= viewer.zoomPerClick;
|
||||
|
||||
zoom = viewer.viewport.getZoom();
|
||||
Util.assessNumericValue(assert, originalZoom, zoom, epsilon,
|
||||
"Zoom on double tap should not be prevented");
|
||||
|
||||
|
||||
var dblClickHandler = function(event) {
|
||||
event.preventDefaultAction = true;
|
||||
};
|
||||
viewer.gestureSettingsMouse.clickToZoom = origClickSetting;
|
||||
viewer.gestureSettingsMouse.dblClickToZoom = origDblClickSetting;
|
||||
|
||||
viewer.addHandler('canvas-double-click', dblClickHandler);
|
||||
|
||||
zoom = viewer.viewport.getZoom();
|
||||
Util.assessNumericValue(assert, originalZoom, zoom, epsilon,
|
||||
"Zoom on double tap should be prevented");
|
||||
|
||||
// Remove custom event handler
|
||||
viewer.removeHandler('canvas-double-click', dblClickHandler);
|
||||
|
||||
simulateDblTap();
|
||||
originalZoom = originalZoom * viewer.zoomPerClick;
|
||||
|
||||
zoom = viewer.viewport.getZoom();
|
||||
Util.assessNumericValue(assert, originalZoom, zoom, epsilon,
|
||||
"Zoom on double tap should not be prevented");
|
||||
|
||||
TouchUtil.resetTracker(tracker);
|
||||
viewer.close();
|
||||
done();
|
||||
};
|
||||
@ -926,10 +910,9 @@
|
||||
eventsHandledViewer = 0,
|
||||
originalEventsPassedViewer = 0,
|
||||
dragEndsExpected = 1,
|
||||
releasesExpected = 1,
|
||||
clicksExpected = 1;
|
||||
releasesExpected = 1;
|
||||
|
||||
var onOpen = function ( event ) {
|
||||
var onOpen = function ( ) {
|
||||
viewer.removeHandler( 'open', onOpen );
|
||||
|
||||
viewer.addHandler( 'canvas-drag', onEventSourceDrag );
|
||||
@ -953,7 +936,7 @@
|
||||
dragEndHandler: onMouseTrackerDragEnd,
|
||||
releaseHandler: onMouseTrackerRelease,
|
||||
clickHandler: onMouseTrackerClick,
|
||||
exitHandler: onMouseTrackerExit
|
||||
leaveHandler: onMouseTrackerLeave
|
||||
} );
|
||||
|
||||
var event = {
|
||||
@ -1050,7 +1033,7 @@
|
||||
checkOriginalEventReceived( event );
|
||||
};
|
||||
|
||||
var onMouseTrackerExit = function ( event ) {
|
||||
var onMouseTrackerLeave = function ( event ) {
|
||||
checkOriginalEventReceived( event );
|
||||
|
||||
mouseTracker.destroy();
|
||||
|
249
test/modules/iiif.js
Normal file
249
test/modules/iiif.js
Normal file
@ -0,0 +1,249 @@
|
||||
(function() {
|
||||
|
||||
var id = "http://example.com/identifier";
|
||||
|
||||
var configure = function(data) {
|
||||
return OpenSeadragon.IIIFTileSource.prototype.configure.apply(
|
||||
new OpenSeadragon.TileSource(), [ data, 'http://example.com/identifier' ]
|
||||
);
|
||||
};
|
||||
|
||||
var getSource = function( data ) {
|
||||
var options = configure( data );
|
||||
return new OpenSeadragon.IIIFTileSource( options );
|
||||
};
|
||||
|
||||
var infoXml10level0 = new DOMParser().parseFromString('<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
'<info xmlns="http://library.stanford.edu/iiif/image-api/ns/">' +
|
||||
'<identifier>http://example.com/identifier</identifier>' +
|
||||
'<width>6000</width>' +
|
||||
'<height>4000</height>' +
|
||||
'<scale_factors>' +
|
||||
'<scale_factor>1</scale_factor>' +
|
||||
'<scale_factor>2</scale_factor>' +
|
||||
'<scale_factor>4</scale_factor>' +
|
||||
'</scale_factors>' +
|
||||
'<profile>http://library.stanford.edu/iiif/image-api/compliance.html#level0</profile>' +
|
||||
'</info>',
|
||||
'text/xml'
|
||||
),
|
||||
infoXml10level1 = new DOMParser().parseFromString('<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
'<info xmlns="http://library.stanford.edu/iiif/image-api/ns/">' +
|
||||
'<identifier>http://example.com/identifier</identifier>' +
|
||||
'<width>6000</width>' +
|
||||
'<height>4000</height>' +
|
||||
'<profile>http://library.stanford.edu/iiif/image-api/compliance.html#level1</profile>' +
|
||||
'</info>',
|
||||
'text/xml'
|
||||
),
|
||||
infoJson10level0 = {
|
||||
"identifier": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile" : "http://library.stanford.edu/iiif/image-api/compliance.html#level0"
|
||||
},
|
||||
infoJson10level1 = {
|
||||
"identifier": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile" : "http://library.stanford.edu/iiif/image-api/compliance.html#level1"
|
||||
},
|
||||
infoJson11level0 = {
|
||||
"@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
|
||||
"@id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0"
|
||||
},
|
||||
infoJson11level1 = {
|
||||
"@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
|
||||
"@id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1"
|
||||
},
|
||||
infoJson11level1WithTiles = {
|
||||
"@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
|
||||
"@id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"tile_width": 512,
|
||||
"tile_height": 256,
|
||||
"profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1"
|
||||
},
|
||||
infoJson2level0 = {
|
||||
"@context": "http://iiif.io/api/image/2/context.json",
|
||||
"@id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"sizes": [
|
||||
{ width: 2000, height: 1000 },
|
||||
{ width: 1000, height: 500 }
|
||||
],
|
||||
"profile": ["http://iiif.io/api/image/2/level0.json"]
|
||||
},
|
||||
infoJson2level0sizeByW = {
|
||||
"@context": "http://iiif.io/api/image/2/context.json",
|
||||
"@id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile": ["http://iiif.io/api/image/2/level0.json", {"supports": "sizeByW"} ]
|
||||
},
|
||||
infoJson2level1 = {
|
||||
"@context": "http://iiif.io/api/image/2/context.json",
|
||||
"@id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile": ["http://iiif.io/api/image/2/level1.json"]
|
||||
},
|
||||
infoJson3level0 = {
|
||||
"@context": "http://iiif.io/api/image/3/context.json",
|
||||
"id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"sizes": [
|
||||
{ width: 2000, height: 1000 },
|
||||
{ width: 1000, height: 500 }
|
||||
],
|
||||
"profile": "level0"
|
||||
},
|
||||
infoJson3level0ContextExtension = {
|
||||
"@context": [
|
||||
"http://iiif.io/api/image/3/context.json",
|
||||
{
|
||||
"example": "http://example.com/vocab"
|
||||
}
|
||||
],
|
||||
"id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile": "level0"
|
||||
},
|
||||
infoJson3level0sizeByW = {
|
||||
"@context": "http://iiif.io/api/image/3/context.json",
|
||||
"id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile": "level0",
|
||||
"extraFeatures": "sizeByW"
|
||||
},
|
||||
infoJson3level0sizeByWh = {
|
||||
"@context": "http://iiif.io/api/image/3/context.json",
|
||||
"id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile": "level0",
|
||||
"extraFeatures": "sizeByWh"
|
||||
},
|
||||
infoJson3level1 = {
|
||||
"@context": "http://iiif.io/api/image/3/context.json",
|
||||
"id": id,
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"profile": "level1"
|
||||
};
|
||||
|
||||
QUnit.test('IIIFTileSource.configure determins correct version', function(assert) {
|
||||
var options1_0xml = configure(infoXml10level0);
|
||||
assert.ok(options1_0xml.version);
|
||||
assert.equal(options1_0xml.version, 1, 'Version is 1 for version 1.0 info.xml');
|
||||
|
||||
var options1_0 = configure(infoJson10level0);
|
||||
assert.ok(options1_0.version);
|
||||
assert.equal(options1_0.version, 1, 'Version is 1 for version 1.0 info.json');
|
||||
|
||||
var options1_1 = configure(infoJson11level0);
|
||||
assert.ok(options1_1.version);
|
||||
assert.equal(options1_1.version, 1, 'Version is 1 for version 1.1 info.json');
|
||||
|
||||
var options2 = configure(infoJson2level0);
|
||||
assert.ok(options2.version);
|
||||
assert.equal(options2.version, 2, 'Version is 2 for version 2 info.json');
|
||||
|
||||
var options3 = configure(infoJson3level0);
|
||||
assert.ok(options3.version);
|
||||
assert.equal(options3.version, 3, 'Version is 3 for version 3 info.json');
|
||||
|
||||
var options3withContextExtension = configure(infoJson3level0ContextExtension);
|
||||
assert.ok(options3withContextExtension.version);
|
||||
assert.equal(options3withContextExtension.version, 3, 'Version is 3 for version 3 info.json');
|
||||
});
|
||||
|
||||
QUnit.test('IIIFTileSource private function canBeTiled works as expected', function(assert) {
|
||||
var canBeTiled = function( data ) {
|
||||
var source = getSource( data );
|
||||
return source.__testonly__.canBeTiled( source );
|
||||
};
|
||||
|
||||
assert.notOk(canBeTiled(infoXml10level0));
|
||||
assert.ok(canBeTiled(infoXml10level1));
|
||||
assert.notOk(canBeTiled(infoJson10level0));
|
||||
assert.ok(canBeTiled(infoJson10level1));
|
||||
assert.notOk(canBeTiled(infoJson11level0));
|
||||
assert.ok(canBeTiled(infoJson11level1));
|
||||
assert.notOk(canBeTiled(infoJson2level0));
|
||||
assert.ok(canBeTiled(infoJson2level0sizeByW));
|
||||
assert.ok(canBeTiled(infoJson2level1));
|
||||
assert.notOk(canBeTiled(infoJson3level0));
|
||||
assert.notOk(canBeTiled(infoJson3level0sizeByW));
|
||||
assert.ok(canBeTiled(infoJson3level0sizeByWh));
|
||||
assert.ok(canBeTiled(infoJson3level1));
|
||||
});
|
||||
|
||||
QUnit.test('IIIFTileSource private function constructLevels creates correct URLs for legacy pyramid', function( assert ) {
|
||||
var constructLevels = function( data ) {
|
||||
var source = getSource( data );
|
||||
return source.__testonly__.constructLevels( source );
|
||||
};
|
||||
var levelsVersion2 = constructLevels(infoJson2level0);
|
||||
assert.ok(Array.isArray(levelsVersion2));
|
||||
assert.equal(levelsVersion2.length, 2, 'Constructed levels contain 2 entries');
|
||||
assert.equal(levelsVersion2[0].url, 'http://example.com/identifier/full/1000,/0/default.jpg');
|
||||
assert.equal(levelsVersion2[1].url, 'http://example.com/identifier/full/2000,/0/default.jpg');
|
||||
// FIXME see below
|
||||
// assert.equal(levelsVersion2[1].url, 'http://example.com/identifier/full/full/0/default.jpg');
|
||||
|
||||
var levelsVersion3 = constructLevels(infoJson3level0);
|
||||
assert.ok(Array.isArray(levelsVersion3));
|
||||
assert.equal(levelsVersion3.length, 2, 'Constructed levels contain 2 entries');
|
||||
assert.equal(levelsVersion3[0].url, 'http://example.com/identifier/full/1000,500/0/default.jpg');
|
||||
assert.equal(levelsVersion3[1].url, 'http://example.com/identifier/full/2000,1000/0/default.jpg');
|
||||
/*
|
||||
* FIXME: following https://iiif.io/api/image/3.0/#47-canonical-uri-syntax and
|
||||
* https://iiif.io/api/image/2.1/#canonical-uri-syntax, I'd expect 'max' to be required to
|
||||
* be served by a level 0 compliant service instead of 'w,h', 'full' instead of 'w,' respectivley.
|
||||
*/
|
||||
//assert.equal(levelsVersion3[1].url, 'http://example.com/identifier/full/max/0/default.jpg');
|
||||
});
|
||||
|
||||
QUnit.test('IIIFTileSource.getTileUrl returns the correct URLs', function( assert ) {
|
||||
var source11Level1 = getSource(infoJson11level1);
|
||||
assert.equal(source11Level1.getTileUrl(0, 0, 0), "http://example.com/identifier/full/8,/0/native.jpg");
|
||||
assert.equal(source11Level1.getTileUrl(7, 0, 0), "http://example.com/identifier/0,0,1024,1000/512,/0/native.jpg");
|
||||
assert.equal(source11Level1.getTileUrl(7, 1, 0), "http://example.com/identifier/1024,0,976,1000/488,/0/native.jpg");
|
||||
assert.equal(source11Level1.getTileUrl(8, 0, 0), "http://example.com/identifier/0,0,512,512/512,/0/native.jpg");
|
||||
|
||||
var source2Level1 = getSource(infoJson2level1);
|
||||
assert.equal(source2Level1.getTileUrl(0, 0, 0), "http://example.com/identifier/full/8,/0/default.jpg");
|
||||
assert.equal(source2Level1.getTileUrl(7, 0, 0), "http://example.com/identifier/0,0,1024,1000/512,/0/default.jpg");
|
||||
assert.equal(source2Level1.getTileUrl(7, 1, 0), "http://example.com/identifier/1024,0,976,1000/488,/0/default.jpg");
|
||||
assert.equal(source2Level1.getTileUrl(8, 0, 0), "http://example.com/identifier/0,0,512,512/512,/0/default.jpg");
|
||||
assert.equal(source2Level1.getTileUrl(8, 3, 0), "http://example.com/identifier/1536,0,464,512/464,/0/default.jpg");
|
||||
assert.equal(source2Level1.getTileUrl(8, 0, 1), "http://example.com/identifier/0,512,512,488/512,/0/default.jpg");
|
||||
assert.equal(source2Level1.getTileUrl(8, 3, 1), "http://example.com/identifier/1536,512,464,488/464,/0/default.jpg");
|
||||
|
||||
var source2Level0 = getSource(infoJson2level0);
|
||||
assert.equal(source2Level0.getTileUrl(0, 0, 0), "http://example.com/identifier/full/1000,/0/default.jpg");
|
||||
assert.equal(source2Level0.getTileUrl(1, 0, 0), "http://example.com/identifier/full/2000,/0/default.jpg");
|
||||
|
||||
var source3Level1 = getSource(infoJson3level1);
|
||||
assert.equal(source3Level1.getTileUrl(0, 0, 0), "http://example.com/identifier/full/8,4/0/default.jpg");
|
||||
assert.equal(source3Level1.getTileUrl(7, 0, 0), "http://example.com/identifier/0,0,1024,1000/512,500/0/default.jpg");
|
||||
assert.equal(source3Level1.getTileUrl(7, 1, 0), "http://example.com/identifier/1024,0,976,1000/488,500/0/default.jpg");
|
||||
assert.equal(source3Level1.getTileUrl(8, 0, 0), "http://example.com/identifier/0,0,512,512/512,512/0/default.jpg");
|
||||
assert.equal(source3Level1.getTileUrl(8, 3, 0), "http://example.com/identifier/1536,0,464,512/464,512/0/default.jpg");
|
||||
assert.equal(source3Level1.getTileUrl(8, 0, 1), "http://example.com/identifier/0,512,512,488/512,488/0/default.jpg");
|
||||
assert.equal(source3Level1.getTileUrl(8, 3, 1), "http://example.com/identifier/1536,512,464,488/464,488/0/default.jpg");
|
||||
});
|
||||
|
||||
})();
|
@ -216,19 +216,34 @@
|
||||
clientY: offset.top + locationY
|
||||
};
|
||||
$canvas
|
||||
.simulate(OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseenter' : 'mouseover', event)
|
||||
.simulate('mouseenter', event)
|
||||
.simulate('mousedown', event)
|
||||
.simulate('mouseup', event);
|
||||
};
|
||||
|
||||
var simulateNavigatorDrag = function (viewer, distanceX, distanceY) {
|
||||
var $canvas = $(viewer.element).find('.displayregion'),
|
||||
event = {
|
||||
dx: Math.floor(distanceX),
|
||||
dy: Math.floor(distanceY)
|
||||
};
|
||||
$canvas
|
||||
.simulate('drag', event);
|
||||
var $canvas = $(viewer.element).find('.openseadragon-canvas'),
|
||||
offset = $canvas.offset(),
|
||||
event = {};
|
||||
|
||||
event.clientX = offset.left + 1;
|
||||
event.clientY = offset.top + 1;
|
||||
$canvas.simulate( 'mouseenter', event );
|
||||
|
||||
event.button = 0;
|
||||
$canvas.simulate( 'mousedown', event );
|
||||
|
||||
event.clientX += distanceX;
|
||||
event.clientY += distanceY;
|
||||
$canvas.simulate( 'mousemove', event );
|
||||
|
||||
event.button = 0;
|
||||
$canvas.simulate( 'mouseup', event );
|
||||
|
||||
event.clientX = offset.left - 1;
|
||||
event.clientY = offset.top - 1;
|
||||
event.relatedTarget = document.body;
|
||||
$canvas.simulate( 'mouseleave', event );
|
||||
};
|
||||
|
||||
var dragNavigatorBackToCenter = function () {
|
||||
|
@ -41,8 +41,11 @@
|
||||
viewer.addHandler('open', function(event) {
|
||||
var image = viewer.world.getItemAt(0);
|
||||
var contentSize = image.getContentSize();
|
||||
var sizeInWindowCoords = image.getSizeInWindowCoordinates();
|
||||
assert.equal(contentSize.x, 500, 'contentSize.x');
|
||||
assert.equal(contentSize.y, 2000, 'contentSize.y');
|
||||
assert.equal(sizeInWindowCoords.x, 125, 'sizeInWindowCoords.x');
|
||||
assert.equal(sizeInWindowCoords.y, 500, 'sizeInWindowCoords.y');
|
||||
|
||||
checkBounds(assert, image, new OpenSeadragon.Rect(5, 6, 10, 40), 'initial bounds');
|
||||
|
||||
@ -74,7 +77,18 @@
|
||||
image.setHeight(4);
|
||||
checkBounds(assert, image, new OpenSeadragon.Rect(7, 8, 1, 4), 'bounds after width');
|
||||
|
||||
assert.equal(handlerCount, 1, 'correct number of handlers called');
|
||||
viewer.addHandler('zoom', function zoomHandler(event) {
|
||||
var sizeInWindowCoords = image.getSizeInWindowCoordinates();
|
||||
viewer.removeHandler('zoom', zoomHandler);
|
||||
handlerCount++;
|
||||
assert.equal(sizeInWindowCoords.x, 4000, 'sizeInWindowCoords.x after zoom');
|
||||
assert.equal(sizeInWindowCoords.y, 16000, 'sizeInWindowCoords.y after zoom');
|
||||
});
|
||||
|
||||
viewer.viewport.zoomTo(8, null, true);
|
||||
|
||||
assert.equal(handlerCount, 2, 'correct number of handlers called');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
|
93
test/modules/viewerretrieval.js
Normal file
93
test/modules/viewerretrieval.js
Normal file
@ -0,0 +1,93 @@
|
||||
/* global QUnit, $, testLog */
|
||||
|
||||
(function() {
|
||||
var viewer1;
|
||||
var viewer2;
|
||||
|
||||
QUnit.module('ViewerRetrieval', {
|
||||
beforeEach: function () {
|
||||
$('<div id="example1"></div><div id="example2"></div>')
|
||||
.appendTo("#qunit-fixture");
|
||||
|
||||
testLog.reset();
|
||||
|
||||
viewer1 = OpenSeadragon({
|
||||
id: 'example1',
|
||||
prefixUrl: 'build/openseadragon/images/',
|
||||
springStiffness: 100 // Faster animation = faster tests
|
||||
});
|
||||
|
||||
viewer2 = OpenSeadragon({
|
||||
id: 'example2',
|
||||
prefixUrl: 'build/openseadragon/images/',
|
||||
springStiffness: 100
|
||||
});
|
||||
},
|
||||
|
||||
afterEach: function () {
|
||||
if (viewer1 && viewer1.destroy) {
|
||||
viewer1.destroy();
|
||||
}
|
||||
if (viewer2 && viewer2.destroy) {
|
||||
viewer2.destroy();
|
||||
}
|
||||
viewer1 = viewer2 = null;
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('Get Viewers by Id', function(assert) {
|
||||
var retrievedViewer1 = OpenSeadragon.getViewer('example1');
|
||||
assert.ok(retrievedViewer1, 'Attached viewer retrieved');
|
||||
assert.equal(retrievedViewer1, viewer1, 'Viewers are same instance');
|
||||
|
||||
var retrievedViewer2 = OpenSeadragon.getViewer('example2');
|
||||
assert.ok(retrievedViewer2, 'Attached viewer retrieved');
|
||||
assert.equal(retrievedViewer2, viewer2, 'Viewers are same instance');
|
||||
|
||||
// Internal state
|
||||
assert.equal(OpenSeadragon._viewers.size, 2, 'Correct amount of viewers');
|
||||
});
|
||||
|
||||
QUnit.test('Get Viewers by Element', function(assert) {
|
||||
var retrievedViewer1 = OpenSeadragon.getViewer(
|
||||
document.getElementById('example1'));
|
||||
assert.ok(retrievedViewer1, 'Attached viewer retrieved');
|
||||
assert.equal(retrievedViewer1, viewer1, 'Viewers are same instance');
|
||||
|
||||
var retrievedViewer2 = OpenSeadragon.getViewer(
|
||||
document.getElementById('example2'));
|
||||
assert.ok(retrievedViewer2, 'Attached viewer retrieved');
|
||||
assert.equal(retrievedViewer2, viewer2, 'Viewers are same instance');
|
||||
|
||||
// Internal state
|
||||
assert.equal(OpenSeadragon._viewers.size, 2, 'Correct amount of viewers');
|
||||
});
|
||||
|
||||
QUnit.test('Undefined on Get Non-Existent Viewer by Id', function(assert) {
|
||||
var notFoundViewer = OpenSeadragon.getViewer('no-viewer');
|
||||
assert.equal(notFoundViewer, undefined, "Not found viewer is undefined");
|
||||
});
|
||||
|
||||
QUnit.test('Undefined on Get Non-Existent Viewer by Element', function(assert) {
|
||||
var element = document.createElement('div');
|
||||
element.id = 'no-viewer';
|
||||
document.body.appendChild(element);
|
||||
|
||||
var notFoundViewer = OpenSeadragon.getViewer(element);
|
||||
assert.equal(notFoundViewer, undefined, "Not found viewer is undefined");
|
||||
});
|
||||
|
||||
QUnit.test('Cleanup Viewers Registration', function(assert) {
|
||||
viewer1.destroy();
|
||||
viewer2.destroy();
|
||||
viewer1 = viewer2 = null;
|
||||
|
||||
var retrievedViewer1 = OpenSeadragon.getViewer('example1');
|
||||
var retrievedViewer2 = OpenSeadragon.getViewer('example2');
|
||||
assert.equal(retrievedViewer1, undefined, 'Viewer was destroyed');
|
||||
assert.equal(retrievedViewer2, undefined, 'Viewer was destroyed');
|
||||
|
||||
// Internal state
|
||||
assert.equal(OpenSeadragon._viewers.size, 0, 'No viewers are registered');
|
||||
});
|
||||
})();
|
@ -22,6 +22,7 @@
|
||||
<!-- Polyfill must be inserted first because it is testing functions
|
||||
reassignments which could be done by other test. -->
|
||||
<script src="/test/modules/polyfills.js"></script>
|
||||
<script src="/test/modules/viewerretrieval.js"></script>
|
||||
<script src="/test/modules/basic.js"></script>
|
||||
<script src="/test/modules/strings.js"></script>
|
||||
<script src="/test/modules/formats.js"></script>
|
||||
@ -44,6 +45,7 @@
|
||||
<script src="/test/modules/rectangle.js"></script>
|
||||
<script src="/test/modules/ajax-tiles.js"></script>
|
||||
<script src="/test/modules/imageloader.js"></script>
|
||||
<script src="/test/modules/iiif.js"></script>
|
||||
<!--The navigator tests are the slowest (for now; hopefully they can be sped up)
|
||||
so we put them last. -->
|
||||
<script src="/test/modules/navigator.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user