Merge remote branch 'upstream/master'

This commit is contained in:
Heath Nielson 2014-04-10 14:03:21 -06:00
commit aa4b5f6e65
212 changed files with 11529 additions and 3476 deletions

2
.gitignore vendored
View File

@ -1,5 +1,3 @@
*.sublime-workspace
node_modules
build/
openseadragon.zip
openseadragon.tar

14
.jshintrc Normal file
View File

@ -0,0 +1,14 @@
{
"browser": true,
"curly": true,
"eqeqeq": false,
"loopfunc": false,
"noarg": true,
"trailing": true,
"undef": true,
"unused": false,
"globals": {
"OpenSeadragon": true
}
}

View File

@ -10,15 +10,19 @@ module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-clean");
grunt.loadNpmTasks("grunt-git-describe");
grunt.loadNpmTasks('grunt-text-replace');
// ----------
var distribution = "build/openseadragon/openseadragon.js",
var packageJson = grunt.file.readJSON("package.json"),
distribution = "build/openseadragon/openseadragon.js",
minified = "build/openseadragon/openseadragon.min.js",
packageDirName = "openseadragon-bin-" + packageJson.version,
packageDir = "build/" + packageDirName + "/",
releaseRoot = "../site-build/built-openseadragon/",
sources = [
"src/openseadragon.js",
"src/fullscreen.js",
"src/eventhandler.js",
"src/eventsource.js",
"src/mousetracker.js",
"src/control.js",
"src/controldock.js",
@ -30,6 +34,7 @@ module.exports = function(grunt) {
"src/tilesource.js",
"src/dzitilesource.js",
"src/iiiftilesource.js",
"src/iiif1_1tilesource.js",
"src/osmtilesource.js",
"src/tmstilesource.js",
"src/legacytilesource.js",
@ -49,9 +54,16 @@ module.exports = function(grunt) {
// ----------
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
pkg: packageJson,
osdVersion: {
versionStr: packageJson.version,
major: parseInt(packageJson.version.split('.')[0], 10),
minor: parseInt(packageJson.version.split('.')[1], 10),
revision: parseInt(packageJson.version.split('.')[2], 10)
},
clean: {
build: ["build"],
package: [packageDir],
release: {
src: [releaseRoot],
options: {
@ -64,7 +76,8 @@ module.exports = function(grunt) {
banner: "//! <%= pkg.name %> <%= pkg.version %>\n"
+ "//! Built on <%= grunt.template.today('yyyy-mm-dd') %>\n"
+ "//! Git commit: <%= gitInfo %>\n"
+ "//! http://openseadragon.github.io\n\n",
+ "//! http://openseadragon.github.io\n"
+ "//! License: http://openseadragon.github.io/license/\n\n",
process: true
},
dist: {
@ -72,9 +85,27 @@ module.exports = function(grunt) {
dest: distribution
}
},
replace: {
cleanPaths: {
src: ['build/openseadragon/*.map'],
overwrite: true,
replacements: [
{
from: /build\/openseadragon\//g,
to: ''
}
]
}
},
uglify: {
options: {
preserveComments: "some"
preserveComments: "some",
sourceMap: function (filename) {
return filename.replace(/\.js$/, '.js.map');
},
sourceMappingURL: function (filename) {
return filename.replace(/\.js$/, '.js.map').replace('build/openseadragon/', '');
},
},
openseadragon: {
src: [ distribution ],
@ -84,24 +115,27 @@ module.exports = function(grunt) {
compress: {
zip: {
options: {
archive: "build/openseadragon.zip"
archive: "build/releases/" + packageDirName + ".zip",
level: 9
},
files: [
{ expand: true, cwd: "build/", src: ["openseadragon/**"] }
{ expand: true, cwd: "build/", src: [ packageDirName + "/**" ] }
]
},
tar: {
options: {
archive: "build/openseadragon.tar"
archive: "build/releases/" + packageDirName + ".tar.gz",
level: 9
},
files: [
{ expand: true, cwd: "build/", src: [ "openseadragon/**" ] }
{ expand: true, cwd: "build/", src: [ packageDirName + "/**" ] }
]
}
},
qunit: {
all: {
options: {
timeout: 10000,
urls: [ "http://localhost:8000/test/test.html" ]
}
}
@ -120,12 +154,7 @@ module.exports = function(grunt) {
},
jshint: {
options: {
browser: true,
eqeqeq: false,
loopfunc: false,
globals: {
OpenSeadragon: true
}
jshintrc: '.jshintrc'
},
beforeconcat: sources,
afterconcat: [ distribution ]
@ -144,10 +173,22 @@ module.exports = function(grunt) {
// Copies the image files into the appropriate location in the build folder.
grunt.registerTask("copy:build", function() {
grunt.file.recurse("images", function(abspath, rootdir, subdir, filename) {
grunt.file.copy(abspath, "build/openseadragon/images/" + (subdir || "") + filename);
grunt.file.copy(abspath, "build/openseadragon/images/" + (subdir || "") + filename);
});
});
grunt.file.copy("changelog.txt", "build/changelog.txt");
// ----------
// Copy:package task.
// Creates a directory tree to be compressed into a package.
grunt.registerTask("copy:package", function() {
grunt.file.recurse("build/openseadragon", function(abspath, rootdir, subdir, filename) {
var dest = packageDir
+ (subdir ? subdir + "/" : '/')
+ filename;
grunt.file.copy(abspath, dest);
});
grunt.file.copy("changelog.txt", packageDir + "changelog.txt");
grunt.file.copy("LICENSE.txt", packageDir + "LICENSE.txt");
});
// ----------
@ -155,6 +196,10 @@ module.exports = function(grunt) {
// Copies the contents of the build folder into the release folder.
grunt.registerTask("copy:release", function() {
grunt.file.recurse("build", function(abspath, rootdir, subdir, filename) {
if (subdir === 'releases') {
return;
}
var dest = releaseRoot
+ (subdir ? subdir + "/" : '/')
+ filename;
@ -167,7 +212,8 @@ module.exports = function(grunt) {
// Build task.
// Cleans out the build folder and builds the code and images into it, checking lint.
grunt.registerTask("build", [
"clean:build", "jshint:beforeconcat", "git-describe", "concat", "jshint:afterconcat", "uglify", "copy:build"
"clean:build", "jshint:beforeconcat", "git-describe", "concat", "jshint:afterconcat",
"uglify", "replace:cleanPaths", "copy:build"
]);
// ----------
@ -177,8 +223,8 @@ module.exports = function(grunt) {
// ----------
// Package task.
// Builds and creates the .zip and .tar files.
grunt.registerTask("package", ["build", "compress"]);
// Builds and creates the .zip and .tar.gz files.
grunt.registerTask("package", ["build", "copy:package", "compress", "clean:package"]);
// ----------
// Publish task.

28
LICENSE.txt Normal file
View File

@ -0,0 +1,28 @@
Copyright (C) 2009 CodePlex Foundation
Copyright (C) 2010-2013 OpenSeadragon contributors
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of CodePlex Foundation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,14 +1,20 @@
# OpenSeadragon
# OpenSeadragon
This project is a fork of the OpenSeadragon project at http://openseadragon.codeplex.com/
An open-source, web-based viewer for zoomable images, implemented in pure JavaScript.
## On the Web
See it in action and get started using it at http://openseadragon.github.io/.
http://openseadragon.github.io/
## Stable Builds
## First Time Setup
See the [GitHub releases page](https://github.com/openseadragon/openseadragon/releases).
All command-line operations are scripted using [Grunt](http://gruntjs.com/) which is based on [Node.js](http://nodejs.org/). To get set up:
## Development
If you want to use OpenSeadragon in your own projects, you can find the latest stable build, API documentation, and example code at http://openseadragon.github.io/. If you want to modify OpenSeadragon and/or contribute to its development, read on.
### First Time Setup
All command-line operations for building and testing OpenSeadragon are scripted using [Grunt](http://gruntjs.com/) which is based on [Node.js](http://nodejs.org/). To get set up:
1. Install Node, if you haven't already (available at the link above)
1. Install the Grunt command line runner (if you haven't already); on the command line, run `npm install -g grunt-cli`
@ -18,7 +24,7 @@ All command-line operations are scripted using [Grunt](http://gruntjs.com/) whic
You're set... continue reading for build and test instructions.
## Building from Source
### Building from Source
To build, just run (on the command line, in the openseadragon folder):
@ -40,9 +46,9 @@ You can also publish the built version to the site-build repository. This assume
grunt publish
... which will delete the existing openseadragon folder, along with the .zip and .tar files, out of the site-build folder and replace them with newly built ones from the source in this repository; you'll then need to commit the changes to site-build.
... which will delete the existing openseadragon folder, along with the .zip and .tar.gz files, out of the site-build folder and replace them with newly built ones from the source in this repository; you'll then need to commit the changes to site-build.
## Testing
### Testing
Our tests are based on [QUnit](http://qunitjs.com/) and [PhantomJS](http://phantomjs.org/); they're both installed when you run `npm install`. At the moment we don't have much in the way of tests, but we're working to fix that. To run on the command line:
@ -52,58 +58,27 @@ If you wish to work interactively with the tests or test your changes:
grunt connect watch
and open `http://localhost:8000/` in your browser
and open `http://localhost:8000/test/test.html` in your browser.
## Contributing
Another good page, if you want to interactively test out your changes, is `http://localhost:8000/test/demo/basic.html`.
### Contributing
OpenSeadragon is truly a community project; we welcome your involvement!
When contributing, please attempt to match the code style already in the codebase. Note that we use four spaces per indentation stop. For more thoughts on code style, see https://github.com/rwldrn/idiomatic.js/.
## Licenses
When fixing bugs and adding features, when appropriate please also:
OpenSeadragon was initially released with a New BSD License ( preserved below ), while work done by Chris Thatcher is additionally licensed under the MIT License.
* Update related doc comments (we use [JSDoc 3](http://usejsdoc.org/))
* Add/update related unit tests
### Original license preserved below
If you're new to the project, check out our [good first bug](https://github.com/openseadragon/openseadragon/issues?labels=good+first+bug&page=1&state=open) issues for some places to dip your toe in the water.
-------------------------------------
License: New BSD License (BSD)
Copyright (c) 2010, OpenSeadragon
All rights reserved.
If you're new to open source in general, check out [GitHub's open source intro guide](https://guides.github.com/overviews/os-contributing/).
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
## License
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of OpenSeadragon nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
### MIT License
--------------------------------------
(c) Christopher Thatcher 2011, 2012. All rights reserved.
Licensed with the MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
OpenSeadragon is released under the New BSD license. For details, see the file LICENSE.txt.
[![Build Status](https://secure.travis-ci.org/openseadragon/openseadragon.png?branch=master)](http://travis-ci.org/openseadragon/openseadragon)

View File

@ -1,12 +1,171 @@
OPENSEADRAGON CHANGELOG
=======================
0.9.125: In Progress
1.1.0: (in progress)
* Fully deprecated OpenSeadragon.createFromDZI, safely deprecated Viewer.openTileSource and
* BREAKING CHANGE: the openseadragon-canvas element now has two child divs. This means: (#298)
* The drawer element is no longer accessible via viewer.canvas.firstChild but via viewer.drawersContainer.firstChild or viewer.drawer.canvas.
* The overlays elements are no longer accessible via viewer.canvas.childNodes but via viewer.overlaysContainer.childNodes or viewer.currentOverlays[i].element.
* BREAKING CHANGE: Pseudo full screen mode on IE<11 using activex has been dropped. OpenSeadragon will run in full page if full screen mode is requested.
* DEPRECATION: overlay functions have been moved from Drawer to Viewer (#331)
* DEPRECATION: OpenSeadragon.cancelFullScreen has been renamed OpenSeadragon.exitFullScreen (#358)
* Added layers support. Multiple images can now been displayed on top of each other with transparency via the Viewer.addLayer method (#298)
* Improved overlay functions (#331)
* Fixed: Nav button highlight states aren't quite aligned on Firefox (#303)
* Added ControlAnchor options for default controls (#304)
* Enabled basic cross-domain tile loading without tainting canvas (works in Chrome and Firefox) (#308)
* Added crossOriginPolicy drawer configuration to enable or disable CORS image requests (#364)
* Disabled CORS by default (#377)
* Added a ControlAnchor.ABSOLUTE enumeration. Enables absolute positioning of control elements in the viewer (#310)
* Added a 'navigator-scroll' event to Navigator. Fired when mousewheel/pinch events occur in the navigator (#310)
* Added a navigatorMaintainSizeRatio option. If set to true, the navigator minimap resizes when the viewer element is resized (#310)
* Added 'ABSOLUTE' as a navigatorPosition option, along with corresponding navigatorTop, navigatorLeft options. Allows the navigator minimap to be placed anywhere in the viewer (#310)
* Enhanced the navigatorTop, navigatorLeft, navigatorHeight, and navigatorWidth options to allow a number for pixel units or a string for other element units (%, em, etc.) (#310)
* Additional enhancements for IIIF support (#315)
* Fixed: Setting degrees in Viewer constructor has no effect (#336)
* Added pre-draw event for tiles to allow applications to alter the image (#348)
* Added optional Rotate Left/Right buttons to standard controls (#341)
* Added optimization for large numbers of overlays: `checkResize = false` option for OpenSeadragon.Overlay (#365)
* Updated full screen API, adding support for Opera and IE11 and allowing keyboard input in Chrome (#358)
* Various fixes to bring OpenSeadragon into W3C compliance (#375)
* Added separate flags for turning off each of the nav buttons (#376)
1.0.0:
NOTE: This version has a number of breaking changes to the API, mostly in event handling. See below.
* BREAKING CHANGE: All EventSource and MouseTracker event handler method signatures changed to 'handlerMethod(event)' where event == { eventSource, userData, ... } (#251) (Also fixes #23, #224, #239)
* The new eventSource property in the event object replaces the old eventSource parameter that was passed to handler methods.
* Where the event object duplicated the eventSource value, those properties have been removed. This affects the following events:
* All Button events - 'button' property removed
* All Viewer (Viewer, Drawer, Viewport) events - 'viewer' property removed
* BREAKING CHANGE: Renamed EventHandler to EventSource (#225)
* BREAKING CHANGE: Event names changed for consistency: changed to lower case, compound names hyphenated, and "on" prefixes removed (#226):
* Viewer "animationstart" changed to "animation-start"
* Viewer "animationfinish" changed to "animation-finish"
* Button "onPress" changed to "press"
* Button "onRelease" changed to "release"
* Button "onClick" changed to "click"
* Button "onEnter" changed to "enter"
* Button "onExit" changed to "exit"
* Button "onFocus" changed to "focus"
* Button "onBlur" changed to "blur"
* BREAKING CHANGE: Numerous improvements to fullPage/fullScreen (#256):
* Retains zoom/pan position better when switching into and out of fullPage.
* Retains scroll position when switching back out.
* More resilient to styling variations on the page.
* setFullPage no longer automatically engages fullScreen; there's now a separate setFullScreen.
* 'fullpage' event is now 'full-page'.
* The `fullpage` property of the 'full-page' event is now `fullPage`.
* There is now a 'full-screen' event with a `fullScreen` property (true if it has gone to full screen).
* There are now 'pre-full-page' and 'pre-full-screen' events that include a `preventDefaultAction` property you can set in your handler to cancel. They also have `fullPage` and `fullScreen` properties respectively, to indicate if they are going into or out of the mode.
* BREAKING CHANGE: Removed the 'onPageChange' callback from the viewer options. Viewer.goToPage() now raises the 'page' event only (#285)
* Major documentation improvements (#281)
* MouseTracker now passes the original event objects to its handler methods (#23)
* MouseTracker now supports an optional 'moveHandler' method for tracking mousemove events (#215)
* Added stopHandler to MouseTracker. (#262)
* Fixed: Element-relative mouse coordinates now correct if the element and/or page is scrolled (using new OpenSeadragon.getElementOffset() method) (#131)
* Fixed: Pinch zoom event issue, regressive issue from previous event system changes (#244)
* Added IIIF Image API 1.1 Tile Source (#230)
* IIIF 1.0 now uses pixel based syntax (#249)
* Fixed: Touch event issue where no canvas-click events were being raised (#240)
* Check that zoom reference point is valid before using it in zoomTo and zoomBy (#247)
* Added a number of easier coordinate conversion methods to viewport (#243)
* Added the ability to create a viewer and start at a specified page (#252)
* Fixed image resolve issue with collection mode (#255)
* DOM events are now passed through as 'event.originalEvent' in viewer and button events where appropriate. (#257) Affects the following events:
* Viewer: 'canvas-release', 'canvas-click', 'canvas-drag', 'canvas-scroll', 'container-enter', 'container-exit', 'container-release'
* Button: 'enter', 'exit', 'press', 'release', 'focus', 'blur', 'click'
* Fixed: IE 10 not reading DZI file correctly in certain circumstances (#218)
* Added support for the 'wheel' DOM mousewheel event (#261)
* Fix for non-canvas tile rendering at large size (#264)
* Drawer now uses an HTML5 canvas element whenever it's available. Can be overridden with the Viewer.useCanvas option (#191)
* Added a boolean preventDefaultAction property (default false) to the event object passed to MouseTracker handler methods. (#270) Implemented in the following MouseTracker subscribers:
* Viewer.keyboardCommandArea.innerTracker.focusHandler: preventDefaultAction == true prevents scrolling viewer into view
* Viewer.keyboardCommandArea.innerTracker.keyHandler: preventDefaultAction == true prevents viewer keyboard navigation
* Viewer.innerTracker.clickHandler: preventDefaultAction == true prevents viewer zoom on click
* Viewer.innerTracker.dragHandler: preventDefaultAction == true prevents viewer panning with mouse/touch
* Viewer.innerTracker.scrollHandler: preventDefaultAction == true prevents viewer zooming on mousewheel/pinch
* Fixed: IE8 error with custom buttons - "Object doesn't support this action" (#279)
* Support IIIF servers that don't report tile dimensions (#286)
* Added an autoResize option. Default is true. When set to false, the viewer takes no action when its container element is resized. (#291)
* Added a static 'version' property to OpenSeadragon. Useful for plugins that require specific OpenSeadragon versions. (#292)
0.9.131:
* Fixed: canvas-click event shouldn't fire as you drag (#198)
* Fixed: LegacyTileSource doesn't fail gracefully when no supported file formats are found (#202)
* Added an optional userData argument to EventHandler.addHandler() which is passed unchanged to the handler method (#203)
* Fixed AJAX error reporting on IE8 (#208)
* Added viewportToImageRectangle method, and updated imageToViewportRectangle, imageToViewportCoordinates, and viewportToImageCoordinates to be more flexible with params (#212)
* Fixed: Viewer is not responsive (css) after returning from full screen (#222)
0.9.130:
* Added partial support for rotation (just 90 degree increments for now). (#185)
* Hiding and restoring broke the viewer; fixed (#177)
* You can now provide an onDraw function for overlays to do custom overlay manipulation (#160)
* Added a destroy function on the viewer to clean up and remove elements (#179)
* Fixed: navigatorPosition option corrected. (#163)
* OpenSeadragon.now() returned undefined the first time; fixed
* onTouchEnd did not call the correct mouse up handler; fixed (#159)
* Touch events no longer capture mouse (was causing issues on devices that support both) (#168)
* Clicking on a button control no longer refreshes page (#184)
* Drawer now works when the page is rtl (#187)
* Fixed a situation that could throw errors in touch handling (#188)
0.9.129:
* Fixed: navigator image not updating when base zoom image is changed (#147)
* Fixed tile rendering issue at lower zoom levels with the IIIF TileSource (#55)
* On IE, ajax errors would cause an exception to be thrown; fixed (#144)
* Faster and more consistent millisecond getter (#138)
* Fixed an error when using navPrevNextWrap on single images (#135)
* Various fixes to our timer handling (#133)
* Now generating source map for openseadragon.min.js (#51)
* Fix for calculating overlay width / height (#142)
* JSHint tidying (#136)
* Improved Ajax method (#149)
* Overhauled AJAX error reporting (#151)
0.9.128:
* The navigator is now off by default (#102)
* Reverted minPixelRatio to 0.5 for better quality (#116)
* Sometimes tiles wouldn't resolve if you used the blendTime option; fixed. (#95)
* You can now choose to have previous and next buttons wrap using the config.navPrevNextWrap. (#114)
* You can now specify an ID for a div to hold the navigator (#46)
* You can now click in the navigator to go to a new location (#46)
* Keyboard handling is now done in the viewer rather than navigator (#46)
* Additional navigator fixes (#46)
* Drawer events now fire properly (#94)
* Fixed an error in EventHandler.removeHandler() (#48)
* Better requestAnimationFrame detection on older Firefox (#103)
* More efficient navigator loading (#115)
* Simplified element opacity setting implementation (#123)
0.9.127:
* Fixed a problem with getString when the string property is a sub-property. (#64)
* Fixed: Tooltips for Navigation Controls not displaying (#63)
* Cleaned up some diagnostic code that was broken.
* Added fullpage class to viewer element when in fullpage mode (#61)
* Reverted to original New BSD license; cleaned up license declarations (#89)
0.9.126:
* DZI JSONp was broken; fixed.
0.9.125:
* Fully deprecated OpenSeadragon.createFromDZI, safely deprecated Viewer.openTileSource and
Viewer.openDZI to use Viewer.open internally. (#53 & #54).
* Full page bug fix for when viewer is child of document body (#43).
* Overlays for DZI bug fix (#45).
* Overlays for DZI bug fix (#45).
* DziTileSource: avoid changing relative paths (#56).
* Fix typo in preserveViewport handling (#77).
* Fix updateMulti timer leak after multiple Viewer.open() calls (#76).
* Minor documentation fixes.
0.9.124:

0
images/fullpage_grouphover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

0
images/fullpage_hover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

0
images/fullpage_pressed.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

0
images/fullpage_rest.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

0
images/home_grouphover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

0
images/home_hover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

0
images/home_pressed.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

0
images/home_rest.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
images/rotateleft_hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/rotateleft_rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/rotateright_rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

0
images/zoomin_grouphover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

0
images/zoomin_hover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

0
images/zoomin_pressed.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

0
images/zoomin_rest.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

0
images/zoomout_grouphover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

0
images/zoomout_hover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

0
images/zoomout_pressed.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

0
images/zoomout_rest.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -1,21 +0,0 @@
(c) Christopher Thatcher 2011, 2012. All rights reserved.
Licensed with the MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,36 +0,0 @@
This license is preserved from the OpenSeadragon project at
http://openseadragon.codeplex.com/ as per the text below.
-------------------------------------
License: New BSD License (BSD)
Copyright (c) 2010, OpenSeadragon
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of OpenSeadragon nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-------------------------------------

View File

@ -3,12 +3,19 @@
[
{
"path": ".",
"file_exclude_patterns": ["*.sublime-project", "*.sublime-workspace"]
"file_exclude_patterns": [
"*.sublime-project",
"*.sublime-workspace"
],
"folder_exclude_patterns": [
"node_modules"
]
}
],
"settings":
{
"tab_size": 4,
"translate_tabs_to_spaces": true
"translate_tabs_to_spaces": true,
"trim_trailing_white_space_on_save": true
}
}

View File

@ -1,18 +1,19 @@
{
"name": "OpenSeadragon",
"version": "0.9.124",
"version": "1.0.0",
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
"devDependencies": {
"grunt": "~0.4.0",
"grunt-contrib-compress": "~0.4.0",
"grunt-contrib-concat": "~0.1.2",
"grunt-contrib-jshint": "~0.1.1",
"grunt-contrib-uglify": "~0.1.1",
"grunt-contrib-qunit": "~0.2.0",
"grunt-contrib-connect": "~0.1.2",
"grunt-contrib-watch": "~0.2.0",
"grunt-contrib-clean": "~0.4.0",
"grunt-git-describe": "~2.0.0"
"grunt": "~0.4.1",
"grunt-contrib-compress": "~0.5.2",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-uglify": "~0.2.7",
"grunt-contrib-qunit": "~0.3.0",
"grunt-contrib-connect": "~0.5.0",
"grunt-contrib-watch": "~0.5.3",
"grunt-contrib-clean": "~0.5.0",
"grunt-git-describe": "~2.0.0",
"grunt-text-replace": "~0.3.9"
},
"scripts": {
"test": "grunt test"

View File

@ -1,8 +1,49 @@
/*
* OpenSeadragon - Button
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* An enumeration of button states including, REST, GROUP, HOVER, and DOWN
* An enumeration of button states
* @member ButtonState
* @memberof OpenSeadragon
* @static
* @type {Object}
* @property {Number} REST
* @property {Number} GROUP
* @property {Number} HOVER
* @property {Number} DOWN
*/
$.ButtonState = {
REST: 0,
@ -12,47 +53,39 @@ $.ButtonState = {
};
/**
* Manages events, hover states for individual buttons, tool-tips, as well
* as fading the bottons out when the user has not interacted with them
* @class Button
* @classdesc Manages events, hover states for individual buttons, tool-tips, as well
* as fading the buttons out when the user has not interacted with them
* for a specified period.
* @class
* @extends OpenSeadragon.EventHandler
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.EventSource
* @param {Object} options
* @param {String} options.tooltip Provides context help for the button we the
* @param {Element} [options.element=null] Element to use as the button. If not specified, an HTML &lt;button&gt; element is created.
* @param {String} [options.tooltip=null] Provides context help for the button when the
* user hovers over it.
* @param {String} options.srcRest URL of image to use in 'rest' state
* @param {String} options.srcGroup URL of image to use in 'up' state
* @param {String} options.srcHover URL of image to use in 'hover' state
* @param {String} options.srcDown URL of image to use in 'domn' state
* @param {Element} [options.element] Element to use as a container for the
* button.
* @property {String} tooltip Provides context help for the button we the
* user hovers over it.
* @property {String} srcRest URL of image to use in 'rest' state
* @property {String} srcGroup URL of image to use in 'up' state
* @property {String} srcHover URL of image to use in 'hover' state
* @property {String} srcDown URL of image to use in 'domn' state
* @property {Object} config Configurable settings for this button. DEPRECATED.
* @property {Element} [element] Element to use as a container for the
* button.
* @property {Number} fadeDelay How long to wait before fading
* @property {Number} fadeLength How long should it take to fade the button.
* @property {Number} fadeBeginTime When the button last began to fade.
* @property {Boolean} shouldFade Whether this button should fade after user
* stops interacting with the viewport.
this.fadeDelay = 0; // begin fading immediately
this.fadeLength = 2000; // fade over a period of 2 seconds
this.fadeBeginTime = null;
this.shouldFade = false;
* @param {String} [options.srcRest=null] URL of image to use in 'rest' state.
* @param {String} [options.srcGroup=null] URL of image to use in 'up' state.
* @param {String} [options.srcHover=null] URL of image to use in 'hover' state.
* @param {String} [options.srcDown=null] URL of image to use in 'down' state.
* @param {Number} [options.fadeDelay=0] How long to wait before fading.
* @param {Number} [options.fadeLength=2000] How long should it take to fade the button.
* @param {OpenSeadragon.EventHandler} [options.onPress=null] Event handler callback for {@link OpenSeadragon.Button.event:press}.
* @param {OpenSeadragon.EventHandler} [options.onRelease=null] Event handler callback for {@link OpenSeadragon.Button.event:release}.
* @param {OpenSeadragon.EventHandler} [options.onClick=null] Event handler callback for {@link OpenSeadragon.Button.event:click}.
* @param {OpenSeadragon.EventHandler} [options.onEnter=null] Event handler callback for {@link OpenSeadragon.Button.event:enter}.
* @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}.
*/
$.Button = function( options ) {
var _this = this;
$.EventHandler.call( this );
$.EventSource.call( this );
$.extend( true, this, {
tooltip: null,
srcRest: null,
srcGroup: null,
@ -60,9 +93,17 @@ $.Button = function( options ) {
srcDown: null,
clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold,
clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold,
// begin fading immediately
fadeDelay: 0,
// fade over a period of 2 seconds
/**
* How long to wait before fading.
* @member {Number} fadeDelay
* @memberof OpenSeadragon.Button#
*/
fadeDelay: 0,
/**
* How long should it take to fade the button.
* @member {Number} fadeLength
* @memberof OpenSeadragon.Button#
*/
fadeLength: 2000,
onPress: null,
onRelease: null,
@ -74,126 +115,240 @@ $.Button = function( options ) {
}, options );
this.element = options.element || $.makeNeutralElement( "button" );
this.element.href = this.element.href || '#';
/**
* The button element.
* @member {Element} element
* @memberof OpenSeadragon.Button#
*/
this.element = options.element || $.makeNeutralElement( "div" );
//if the user has specified the element to bind the control to explicitly
//then do not add the default control images
if( !options.element ){
if ( !options.element ) {
this.imgRest = $.makeTransparentImage( this.srcRest );
this.imgGroup = $.makeTransparentImage( this.srcGroup );
this.imgHover = $.makeTransparentImage( this.srcHover );
this.imgDown = $.makeTransparentImage( this.srcDown );
this.imgRest.alt =
this.imgGroup.alt =
this.imgHover.alt =
this.imgDown.alt =
this.tooltip;
this.element.style.position = "relative";
this.imgGroup.style.position =
this.imgHover.style.position =
this.imgDown.style.position =
"absolute";
this.imgGroup.style.top =
this.imgHover.style.top =
this.imgDown.style.top =
"0px";
this.imgGroup.style.left =
this.imgHover.style.left =
this.imgDown.style.left =
"0px";
this.imgHover.style.visibility =
this.imgDown.style.visibility =
"hidden";
if ( $.Browser.vendor == $.BROWSERS.FIREFOX && $.Browser.version < 3 ){
this.imgGroup.style.top =
this.imgHover.style.top =
this.imgDown.style.top =
"";
}
this.element.appendChild( this.imgRest );
this.element.appendChild( this.imgGroup );
this.element.appendChild( this.imgHover );
this.element.appendChild( this.imgDown );
this.imgGroup.style.position =
this.imgHover.style.position =
this.imgDown.style.position =
"absolute";
this.imgGroup.style.top =
this.imgHover.style.top =
this.imgDown.style.top =
"0px";
this.imgGroup.style.left =
this.imgHover.style.left =
this.imgDown.style.left =
"0px";
this.imgHover.style.visibility =
this.imgDown.style.visibility =
"hidden";
if ( $.Browser.vendor == $.BROWSERS.FIREFOX && $.Browser.version < 3 ){
this.imgGroup.style.top =
this.imgHover.style.top =
this.imgDown.style.top =
"";
}
}
this.addHandler( "onPress", this.onPress );
this.addHandler( "onRelease", this.onRelease );
this.addHandler( "onClick", this.onClick );
this.addHandler( "onEnter", this.onEnter );
this.addHandler( "onExit", this.onExit );
this.addHandler( "onFocus", this.onFocus );
this.addHandler( "onBlur", this.onBlur );
this.addHandler( "press", this.onPress );
this.addHandler( "release", this.onRelease );
this.addHandler( "click", this.onClick );
this.addHandler( "enter", this.onEnter );
this.addHandler( "exit", this.onExit );
this.addHandler( "focus", this.onFocus );
this.addHandler( "blur", this.onBlur );
/**
* The button's current state.
* @member {OpenSeadragon.ButtonState} currentState
* @memberof OpenSeadragon.Button#
*/
this.currentState = $.ButtonState.GROUP;
// When the button last began to fade.
this.fadeBeginTime = null;
// Whether this button should fade after user stops interacting with the viewport.
this.shouldFade = false;
this.element.style.display = "inline-block";
this.element.style.position = "relative";
this.element.title = this.tooltip;
/**
* Tracks mouse/touch/key events on the button.
* @member {OpenSeadragon.MouseTracker} tracker
* @memberof OpenSeadragon.Button#
*/
this.tracker = new $.MouseTracker({
element: this.element,
clickTimeThreshold: this.clickTimeThreshold,
element: this.element,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
enterHandler: function( tracker, position, buttonDownElement, buttonDownAny ) {
if ( buttonDownElement ) {
enterHandler: function( event ) {
if ( event.insideElementPressed ) {
inTo( _this, $.ButtonState.DOWN );
_this.raiseEvent( "onEnter", _this );
} else if ( !buttonDownAny ) {
/**
* Raised when the cursor enters the Button element.
*
* @event enter
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( "enter", { originalEvent: event.originalEvent } );
} else if ( !event.buttonDownAny ) {
inTo( _this, $.ButtonState.HOVER );
}
},
focusHandler: function( tracker, position, buttonDownElement, buttonDownAny ) {
this.enterHandler( tracker, position, buttonDownElement, buttonDownAny );
_this.raiseEvent( "onFocus", _this );
focusHandler: function ( event ) {
this.enterHandler( event );
/**
* Raised when the Button element receives focus.
*
* @event focus
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( "focus", { originalEvent: event.originalEvent } );
},
exitHandler: function( tracker, position, buttonDownElement, buttonDownAny ) {
exitHandler: function( event ) {
outTo( _this, $.ButtonState.GROUP );
if ( buttonDownElement ) {
_this.raiseEvent( "onExit", _this );
if ( event.insideElementPressed ) {
/**
* Raised when the cursor leaves the Button element.
*
* @event exit
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( "exit", { originalEvent: event.originalEvent } );
}
},
blurHandler: function( tracker, position, buttonDownElement, buttonDownAny ) {
this.exitHandler( tracker, position, buttonDownElement, buttonDownAny );
_this.raiseEvent( "onBlur", _this );
blurHandler: function ( event ) {
this.exitHandler( event );
/**
* Raised when the Button element loses focus.
*
* @event blur
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( "blur", { originalEvent: event.originalEvent } );
},
pressHandler: function( tracker, position ) {
pressHandler: function ( event ) {
inTo( _this, $.ButtonState.DOWN );
_this.raiseEvent( "onPress", _this );
/**
* Raised when a mouse button is pressed or touch occurs in the Button element.
*
* @event press
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( "press", { originalEvent: event.originalEvent } );
},
releaseHandler: function( tracker, position, insideElementPress, insideElementRelease ) {
if ( insideElementPress && insideElementRelease ) {
releaseHandler: function( event ) {
if ( event.insideElementPressed && event.insideElementReleased ) {
outTo( _this, $.ButtonState.HOVER );
_this.raiseEvent( "onRelease", _this );
} else if ( insideElementPress ) {
/**
* Raised when the mouse button is released or touch ends in the Button element.
*
* @event release
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( "release", { originalEvent: event.originalEvent } );
} else if ( event.insideElementPressed ) {
outTo( _this, $.ButtonState.GROUP );
} else {
inTo( _this, $.ButtonState.HOVER );
}
},
clickHandler: function( tracker, position, quick, shift ) {
if ( quick ) {
_this.raiseEvent("onClick", _this);
clickHandler: function( event ) {
if ( event.quick ) {
/**
* Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold.
*
* @event click
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent("click", { originalEvent: event.originalEvent });
}
},
keyHandler: function( tracker, key ){
//console.log( "%s : handling key %s!", _this.tooltip, key);
if( 13 === key ){
_this.raiseEvent( "onClick", _this );
_this.raiseEvent( "onRelease", _this );
keyHandler: function( event ){
//console.log( "%s : handling key %s!", _this.tooltip, event.keyCode);
if( 13 === event.keyCode ){
/***
* Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold.
*
* @event click
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( "click", { originalEvent: event.originalEvent } );
/***
* Raised when the mouse button is released or touch ends in the Button element.
*
* @event release
* @memberof OpenSeadragon.Button
* @type {object}
* @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( "release", { originalEvent: event.originalEvent } );
return false;
}
return true;
@ -204,13 +359,12 @@ $.Button = function( options ) {
outTo( this, $.ButtonState.REST );
};
$.extend( $.Button.prototype, $.EventHandler.prototype, {
$.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.
* @function
* @name OpenSeadragon.Button.prototype.notifyGroupEnter
*/
notifyGroupEnter: function() {
inTo( this, $.ButtonState.GROUP );
@ -220,18 +374,23 @@ $.extend( $.Button.prototype, $.EventHandler.prototype, {
* TODO: Determine what this function is intended to do and if it's actually
* useful as an API point.
* @function
* @name OpenSeadragon.Button.prototype.notifyGroupExit
*/
notifyGroupExit: function() {
outTo( this, $.ButtonState.REST );
},
/**
* @function
*/
disable: function(){
this.notifyGroupExit();
this.element.disabled = true;
$.setElementOpacity( this.element, 0.2, true );
},
/**
* @function
*/
enable: function(){
this.element.disabled = false;
$.setElementOpacity( this.element, 1.0, true );
@ -253,7 +412,7 @@ function updateFade( button ) {
opacity;
if ( button.shouldFade ) {
currentTime = +new Date();
currentTime = $.now();
deltaTime = currentTime - button.fadeBeginTime;
opacity = 1.0 - deltaTime / button.fadeLength;
opacity = Math.min( 1.0, opacity );
@ -271,8 +430,8 @@ function updateFade( button ) {
function beginFading( button ) {
button.shouldFade = true;
button.fadeBeginTime = +new Date() + button.fadeDelay;
window.setTimeout( function(){
button.fadeBeginTime = $.now() + button.fadeDelay;
window.setTimeout( function(){
scheduleFade( button );
}, button.fadeDelay );
}
@ -290,13 +449,13 @@ function inTo( button, newState ) {
return;
}
if ( newState >= $.ButtonState.GROUP &&
if ( newState >= $.ButtonState.GROUP &&
button.currentState == $.ButtonState.REST ) {
stopFading( button );
button.currentState = $.ButtonState.GROUP;
}
if ( newState >= $.ButtonState.HOVER &&
if ( newState >= $.ButtonState.HOVER &&
button.currentState == $.ButtonState.GROUP ) {
if( button.imgHover ){
button.imgHover.style.visibility = "";
@ -304,7 +463,7 @@ function inTo( button, newState ) {
button.currentState = $.ButtonState.HOVER;
}
if ( newState >= $.ButtonState.DOWN &&
if ( newState >= $.ButtonState.DOWN &&
button.currentState == $.ButtonState.HOVER ) {
if( button.imgDown ){
button.imgDown.style.visibility = "";
@ -320,7 +479,7 @@ function outTo( button, newState ) {
return;
}
if ( newState <= $.ButtonState.HOVER &&
if ( newState <= $.ButtonState.HOVER &&
button.currentState == $.ButtonState.DOWN ) {
if( button.imgDown ){
button.imgDown.style.visibility = "hidden";
@ -328,7 +487,7 @@ function outTo( button, newState ) {
button.currentState = $.ButtonState.HOVER;
}
if ( newState <= $.ButtonState.GROUP &&
if ( newState <= $.ButtonState.GROUP &&
button.currentState == $.ButtonState.HOVER ) {
if( button.imgHover ){
button.imgHover.style.visibility = "hidden";
@ -336,7 +495,7 @@ function outTo( button, newState ) {
button.currentState = $.ButtonState.GROUP;
}
if ( newState <= $.ButtonState.REST &&
if ( newState <= $.ButtonState.REST &&
button.currentState == $.ButtonState.GROUP ) {
beginFading( button );
button.currentState = $.ButtonState.REST;

View File

@ -1,41 +1,74 @@
/*
* OpenSeadragon - ButtonGroup
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* Manages events on groups of buttons.
* @class
* @param {Object} options - a dictionary of settings applied against the entire
* group of buttons
* @param {Array} options.buttons Array of buttons
* @param {Element} [options.group] Element to use as the container,
* @param {Object} options.config Object with Viewer settings ( TODO: is
* this actually used anywhere? )
* @param {Function} [options.enter] Function callback for when the mouse
* enters group
* @param {Function} [options.exit] Function callback for when mouse leaves
* the group
* @param {Function} [options.release] Function callback for when mouse is
* released
* @property {Array} buttons - An array containing the buttons themselves.
* @property {Element} element - The shared container for the buttons.
* @property {Object} config - Configurable settings for the group of buttons.
* @property {OpenSeadragon.MouseTracker} tracker - Tracks mouse events accross
* the group of buttons.
* @class ButtonGroup
* @classdesc Manages events on groups of buttons.
*
* @memberof OpenSeadragon
* @param {Object} options - A dictionary of settings applied against the entire group of buttons.
* @param {Array} options.buttons Array of buttons
* @param {Element} [options.element] Element to use as the container
**/
$.ButtonGroup = function( options ) {
$.extend( true, this, {
/**
* An array containing the buttons themselves.
* @member {Array} buttons
* @memberof OpenSeadragon.ButtonGroup#
*/
buttons: [],
clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold,
clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold,
labelText: ""
}, options );
// copy the botton elements
var buttons = this.buttons.concat([]),
// copy the button elements TODO: Why?
var buttons = this.buttons.concat([]),
_this = this,
i;
this.element = options.element || $.makeNeutralElement( "fieldgroup" );
/**
* The shared container for the buttons.
* @member {Element} element
* @memberof OpenSeadragon.ButtonGroup#
*/
this.element = options.element || $.makeNeutralElement( "div" );
// TODO What if there IS an options.group specified?
if( !options.group ){
this.label = $.makeNeutralElement( "label" );
//TODO: support labels for ButtonGroups
@ -47,33 +80,32 @@ $.ButtonGroup = function( options ) {
}
}
/**
* Tracks mouse/touch/key events accross the group of buttons.
* @member {OpenSeadragon.MouseTracker} tracker
* @memberof OpenSeadragon.ButtonGroup#
*/
this.tracker = new $.MouseTracker({
element: this.element,
clickTimeThreshold: this.clickTimeThreshold,
element: this.element,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
enterHandler: function() {
enterHandler: function ( event ) {
var i;
for ( i = 0; i < _this.buttons.length; i++ ) {
_this.buttons[ i ].notifyGroupEnter();
}
},
exitHandler: function() {
var i,
buttonDownElement = arguments.length > 2 ?
arguments[ 2 ] :
null;
if ( !buttonDownElement ) {
exitHandler: function ( event ) {
var i;
if ( !event.insideElementPressed ) {
for ( i = 0; i < _this.buttons.length; i++ ) {
_this.buttons[ i ].notifyGroupExit();
}
}
},
releaseHandler: function() {
var i,
insideElementRelease = arguments.length > 3 ?
arguments[ 3 ] :
null;
if ( !insideElementRelease ) {
releaseHandler: function ( event ) {
var i;
if ( !event.insideElementReleased ) {
for ( i = 0; i < _this.buttons.length; i++ ) {
_this.buttons[ i ].notifyGroupExit();
}
@ -82,26 +114,26 @@ $.ButtonGroup = function( options ) {
}).setTracking( true );
};
$.ButtonGroup.prototype = {
$.ButtonGroup.prototype = /** @lends OpenSeadragon.ButtonGroup.prototype */{
/**
* TODO: Figure out why this is used on the public API and if a more useful
* api can be created.
* @function
* @name OpenSeadragon.ButtonGroup.prototype.emulateEnter
* @private
*/
emulateEnter: function() {
this.tracker.enterHandler();
this.tracker.enterHandler( { eventSource: this.tracker } );
},
/**
* TODO: Figure out why this is used on the public API and if a more useful
* api can be created.
* @function
* @name OpenSeadragon.ButtonGroup.prototype.emulateExit
* @private
*/
emulateExit: function() {
this.tracker.exitHandler();
this.tracker.exitHandler( { eventSource: this.tracker } );
}
};

View File

@ -1,62 +1,158 @@
/*
* OpenSeadragon - Control
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* An enumeration of supported locations where controls can be anchored,
* including NONE, TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, and BOTTOM_LEFT.
* The anchoring is always relative to the container
* An enumeration of supported locations where controls can be anchored.
* The anchoring is always relative to the container.
* @member ControlAnchor
* @memberof OpenSeadragon
* @static
* @type {Object}
* @property {Number} NONE
* @property {Number} TOP_LEFT
* @property {Number} TOP_RIGHT
* @property {Number} BOTTOM_LEFT
* @property {Number} BOTTOM_RIGHT
* @property {Number} ABSOLUTE
*/
$.ControlAnchor = {
NONE: 0,
TOP_LEFT: 1,
TOP_RIGHT: 2,
BOTTOM_RIGHT: 3,
BOTTOM_LEFT: 4
BOTTOM_LEFT: 4,
ABSOLUTE: 5
};
/**
* A Control represents any interface element which is meant to allow the user
* to interact with the zoomable interface. Any control can be anchored to any
* @class Control
* @classdesc A Control represents any interface element which is meant to allow the user
* to interact with the zoomable interface. Any control can be anchored to any
* element.
* @class
* @param {Element} element - the contol element to be anchored in the container.
* @param {OpenSeadragon.ControlAnchor} anchor - the location to anchor at.
* @param {Element} container - the element to control will be anchored too.
*
* @property {Element} element - the element providing the user interface with
* some type of control. Eg a zoom-in button
* @property {OpenSeadragon.ControlAnchor} anchor - the position of the control
*
* @memberof OpenSeadragon
* @param {Element} element - the control element to be anchored in the container.
* @param {Object } options - All required and optional settings for configuring a control element.
* @param {OpenSeadragon.ControlAnchor} [options.anchor=OpenSeadragon.ControlAnchor.NONE] - the position of the control
* relative to the container.
* @property {Element} container - the element within with the control is
* positioned.
* @property {Element} wrapper - a nuetral element surrounding the control
* element.
* @param {Boolean} [options.attachToViewer=true] - Whether the control should be added directly to the viewer, or
* directly to the container
* @param {Boolean} [options.autoFade=true] - Whether the control should have the autofade behavior
* @param {Element} container - the element to control will be anchored too.
*/
$.Control = function ( element, anchor, container ) {
$.Control = function ( element, options, container ) {
var parent = element.parentNode;
if (typeof options === 'number')
{
$.console.error("Passing an anchor directly into the OpenSeadragon.Control constructor is deprecated; " +
"please use an options object instead. " +
"Support for this deprecated variant is scheduled for removal in December 2013");
options = {anchor: options};
}
options.attachToViewer = (typeof options.attachToViewer === 'undefined') ? true : options.attachToViewer;
/**
* True if the control should have autofade behavior.
* @member {Boolean} autoFade
* @memberof OpenSeadragon.Control#
*/
this.autoFade = (typeof options.autoFade === 'undefined') ? true : options.autoFade;
/**
* The element providing the user interface with some type of control (e.g. a zoom-in button).
* @member {Element} element
* @memberof OpenSeadragon.Control#
*/
this.element = element;
this.anchor = anchor;
/**
* The position of the Control relative to its container.
* @member {OpenSeadragon.ControlAnchor} anchor
* @memberof OpenSeadragon.Control#
*/
this.anchor = options.anchor;
/**
* The Control's containing element.
* @member {Element} container
* @memberof OpenSeadragon.Control#
*/
this.container = container;
this.wrapper = $.makeNeutralElement( "span" );
this.wrapper.style.display = "inline-block";
/**
* A neutral element surrounding the control element.
* @member {Element} wrapper
* @memberof OpenSeadragon.Control#
*/
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.margin = "0px";
this.wrapper.style.padding = "0px";
this.element.style.position = "relative";
this.element.style.top = "0px";
this.element.style.left = "0px";
this.element.style.height = "100%";
this.element.style.width = "100%";
} else {
this.wrapper = $.makeNeutralElement( "div" );
this.wrapper.style.display = "inline-block";
if ( this.anchor == $.ControlAnchor.NONE ) {
// IE6 fix
this.wrapper.style.width = this.wrapper.style.height = "100%";
}
}
this.wrapper.appendChild( this.element );
if ( this.anchor == $.ControlAnchor.NONE ) {
// IE6 fix
this.wrapper.style.width = this.wrapper.style.height = "100%";
}
if ( this.anchor == $.ControlAnchor.TOP_RIGHT ||
this.anchor == $.ControlAnchor.BOTTOM_RIGHT ) {
this.container.insertBefore(
this.wrapper,
this.container.firstChild
);
if (options.attachToViewer ) {
if ( this.anchor == $.ControlAnchor.TOP_RIGHT ||
this.anchor == $.ControlAnchor.BOTTOM_RIGHT ) {
this.container.insertBefore(
this.wrapper,
this.container.firstChild
);
} else {
this.container.appendChild( this.wrapper );
}
} else {
this.container.appendChild( this.wrapper );
parent.appendChild( this.wrapper );
}
};
$.Control.prototype = {
$.Control.prototype = /** @lends OpenSeadragon.Control.prototype */{
/**
* Removes the control from the container.
@ -82,8 +178,8 @@ $.Control.prototype = {
* @param {Boolean} visible - true to make visible, false to hide.
*/
setVisible: function( visible ) {
this.wrapper.style.display = visible ?
"inline-block" :
this.wrapper.style.display = visible ?
( this.anchor == $.ControlAnchor.ABSOLUTE ? 'block' : 'inline-block' ) :
"none";
},

View File

@ -1,26 +1,65 @@
(function( $ ){
/*
* OpenSeadragon - ControlDock
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//id hash for private properties;
var THIS = {};
(function( $ ){
/**
* @class
* @class ControlDock
* @classdesc Provides a container element (a &lt;form&gt; element) with support for the layout of control elements.
*
* @memberof OpenSeadragon
*/
$.ControlDock = function( options ){
var layouts = [ 'topleft', 'topright', 'bottomright', 'bottomleft'],
layout,
i;
$.extend( true, this, {
id: 'controldock-'+(+new Date())+'-'+Math.floor(Math.random()*1000000),
container: $.makeNeutralElement('form'),
id: 'controldock-'+$.now()+'-'+Math.floor(Math.random()*1000000),
container: $.makeNeutralElement( 'div' ),
controls: []
}, options );
// Disable the form's submit; otherwise button clicks and return keys
// can trigger it.
this.container.onsubmit = function() {
return false;
};
if( this.element ){
this.element = $.getElement( this.element );
this.element.appendChild( this.container );
this.element.style.position = 'relative';
this.element.appendChild( this.container );
this.element.style.position = 'relative';
this.container.style.width = '100%';
this.container.style.height = '100%';
}
@ -49,12 +88,12 @@
this.container.appendChild( this.controls.bottomleft );
};
$.ControlDock.prototype = {
$.ControlDock.prototype = /** @lends OpenSeadragon.ControlDock.prototype */{
/**
* @function
*/
addControl: function ( element, anchor ) {
addControl: function ( element, controlOptions ) {
element = $.getElement( element );
var div = null;
@ -62,7 +101,7 @@
return; // they're trying to add a duplicate control
}
switch ( anchor ) {
switch ( controlOptions.anchor ) {
case $.ControlAnchor.TOP_RIGHT:
div = this.controls.topright;
element.style.position = "relative";
@ -87,6 +126,11 @@
element.style.paddingLeft = "0px";
element.style.paddingTop = "0px";
break;
case $.ControlAnchor.ABSOLUTE:
div = this.container;
element.style.margin = "0px";
element.style.padding = "0px";
break;
default:
case $.ControlAnchor.NONE:
div = this.container;
@ -96,7 +140,7 @@
}
this.controls.push(
new $.Control( element, anchor, div )
new $.Control( element, controlOptions, div )
);
element.style.display = "inline-block";
},
@ -109,7 +153,7 @@
removeControl: function ( element ) {
element = $.getElement( element );
var i = getControlIndex( this, element );
if ( i >= 0 ) {
this.controls[ i ].destroy();
this.controls.splice( i, 1 );
@ -126,7 +170,7 @@
while ( this.controls.length > 0 ) {
this.controls.pop().destroy();
}
return this;
},
@ -137,7 +181,7 @@
*/
areControlsEnabled: function () {
var i;
for ( i = this.controls.length - 1; i >= 0; i-- ) {
if ( this.controls[ i ].isVisible() ) {
return true;
@ -181,4 +225,4 @@
return -1;
}
}( OpenSeadragon ));
}( OpenSeadragon ));

View File

@ -1,10 +1,46 @@
/*
* OpenSeadragon - DisplayRect
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* A display rectanlge is very similar to the OpenSeadragon.Rect but adds two
* @class DisplayRect
* @classdesc A display rectangle is very similar to {@link OpenSeadragon.Rect} but adds two
* fields, 'minLevel' and 'maxLevel' which denote the supported zoom levels
* for this rectangle.
* @class
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.Rect
* @param {Number} x The vector component 'x'.
* @param {Number} y The vector component 'y'.
@ -12,13 +48,21 @@
* @param {Number} height The vector component 'width'.
* @param {Number} minLevel The lowest zoom level supported.
* @param {Number} maxLevel The highest zoom level supported.
* @property {Number} minLevel The lowest zoom level supported.
* @property {Number} maxLevel The highest zoom level supported.
*/
$.DisplayRect = function( x, y, width, height, minLevel, maxLevel ) {
$.Rect.apply( this, [ x, y, width, height ] );
/**
* The lowest zoom level supported.
* @member {Number} minLevel
* @memberof OpenSeadragon.DisplayRect#
*/
this.minLevel = minLevel;
/**
* The highest zoom level supported.
* @member {Number} maxLevel
* @memberof OpenSeadragon.DisplayRect#
*/
this.maxLevel = maxLevel;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,42 @@
/*
* OpenSeadragon - DziTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* @class
* @class DziTileSource
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
* @param {Number|Object} width - the pixel width of the image or the idiomatic
* options object which is used instead of positional arguments.
@ -15,13 +49,13 @@
* @property {String} tilesUrl
* @property {String} fileFormat
* @property {OpenSeadragon.DisplayRect[]} displayRects
*/
*/
$.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, fileFormat, displayRects, minLevel, maxLevel ) {
var i,
rect,
level,
options;
if( $.isPlainObject( width ) ){
options = width;
}else{
@ -33,7 +67,7 @@ $.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, file
tilesUrl: arguments[ 4 ],
fileFormat: arguments[ 5 ],
displayRects: arguments[ 6 ],
minLevel: arguments[ 7 ],
minLevel: arguments[ 7 ],
maxLevel: arguments[ 8 ]
};
}
@ -42,7 +76,7 @@ $.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, file
this.tilesUrl = options.tilesUrl;
this.fileFormat = options.fileFormat;
this.displayRects = options.displayRects;
if ( this.displayRects ) {
for ( i = this.displayRects.length - 1; i >= 0; i-- ) {
rect = this.displayRects[ i ];
@ -54,19 +88,18 @@ $.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, file
}
}
}
$.TileSource.apply( this, [ options ] );
};
$.extend( $.DziTileSource.prototype, $.TileSource.prototype, {
$.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.DziTileSource.prototype */{
/**
* Determine if the data and/or url imply the image service is supported by
* this tile source.
* @function
* @name OpenSeadragon.DziTileSource.prototype.supports
* @param {Object|Array} data
* @param {String} optional - url
*/
@ -83,21 +116,16 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, {
},
/**
*
*
* @function
* @name OpenSeadragon.DziTileSource.prototype.configure
* @param {Object|XMLDocument} data - the raw configuration
* @param {String} url - the url the data was retreived from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function( data, url ){
var dziPath,
dziName,
tilesUrl,
options,
host;
var options;
if( !$.isPlainObject(data) ){
@ -109,7 +137,7 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, {
}
if (url && !options.tilesUrl) {
options.tilesUrl = url.replace(/([^\/]+)\.dzi$/, '$1_files/');
options.tilesUrl = url.replace(/([^\/]+)\.(dzi|xml|js)$/, '$1_files/');
}
return options;
@ -118,7 +146,6 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, {
/**
* @function
* @name OpenSeadragon.DziTileSource.prototype.getTileUrl
* @param {Number} level
* @param {Number} x
* @param {Number} y
@ -130,7 +157,6 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, {
/**
* @function
* @name OpenSeadragon.DziTileSource.prototype.tileExists
* @param {Number} level
* @param {Number} x
* @param {Number} y
@ -183,7 +209,7 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, {
* @function
*/
function configureFromXML( tileSource, xmlDoc ){
if ( !xmlDoc || !xmlDoc.documentElement ) {
throw new Error( $.getString( "Errors.Xml" ) );
}
@ -199,7 +225,7 @@ function configureFromXML( tileSource, xmlDoc ){
i;
if ( rootName == "Image" ) {
try {
sizeNode = root.getElementsByTagName( "Size" )[ 0 ];
configuration = {
@ -208,7 +234,7 @@ function configureFromXML( tileSource, xmlDoc ){
Url: root.getAttribute( "Url" ),
Format: root.getAttribute( "Format" ),
DisplayRect: null,
Overlap: parseInt( root.getAttribute( "Overlap" ), 10 ),
Overlap: parseInt( root.getAttribute( "Overlap" ), 10 ),
TileSize: parseInt( root.getAttribute( "TileSize" ), 10 ),
Size: {
Height: parseInt( sizeNode.getAttribute( "Height" ), 10 ),
@ -222,7 +248,7 @@ function configureFromXML( tileSource, xmlDoc ){
$.getString( "Errors.ImageFormat", configuration.Image.Format.toUpperCase() )
);
}
dispRectNodes = root.getElementsByTagName( "DisplayRect" );
for ( i = 0; i < dispRectNodes.length; i++ ) {
dispRectNode = dispRectNodes[ i ];
@ -247,14 +273,14 @@ function configureFromXML( tileSource, xmlDoc ){
return configureFromObject( tileSource, configuration );
} catch ( e ) {
throw (e instanceof Error) ?
e :
throw (e instanceof Error) ?
e :
new Error( $.getString("Errors.Dzi") );
}
} else if ( rootName == "Collection" ) {
throw new Error( $.getString( "Errors.Dzc" ) );
} else if ( rootName == "Error" ) {
return processDZIError( root );
return $._processDZIError( root );
}
throw new Error( $.getString( "Errors.Dzi" ) );
@ -281,7 +307,7 @@ function configureFromObject( tileSource, configuration ){
//TODO: need to figure out out to better handle image format compatibility
// which actually includes additional file formats like xml and pdf
// and plain text for various tilesource implementations to avoid low
// and plain text for various tilesource implementations to avoid low
// level errors.
//
// For now, just don't perform the check.

View File

@ -1,114 +0,0 @@
(function($){
/**
* For use by classes which want to support custom, non-browser events.
* TODO: This is an aweful name! This thing represents an "event source",
* not an "event handler". PLEASE change the to EventSource. Also please
* change 'addHandler', 'removeHandler' and 'raiseEvent' to 'bind',
* 'unbind', and 'trigger' respectively. Finally add a method 'one' which
* automatically unbinds a listener after the first triggered event that
* matches.
* @class
*/
$.EventHandler = function() {
this.events = {};
};
$.EventHandler.prototype = {
/**
* Add an event handler for a given event.
* @function
* @param {String} eventName - Name of event to register.
* @param {Function} handler - Function to call when event is triggered.
*/
addHandler: function( eventName, handler ) {
var events = this.events[ eventName ];
if( !events ){
this.events[ eventName ] = events = [];
}
if( handler && $.isFunction( handler ) ){
events[ events.length ] = handler;
}
},
/**
* Remove a specific event handler for a given event.
* @function
* @param {String} eventName - Name of event for which the handler is to be removed.
* @param {Function} handler - Function to be removed.
*/
removeHandler: function( eventName, handler ) {
var events = this.events[ eventName ],
handlers = [],
i;
if ( !events ){
return;
}
if( $.isArray( events ) ){
for( i = 0; i < events.length; i++ ){
if( events[ i ] !== handler ){
handlers.push( handler );
}
}
this.events[ eventName ] = handlers;
}
},
/**
* Remove all event handler for a given event type.
* @function
* @param {String} eventName - Name of event for which all handlers are to be removed.
*/
removeAllHandlers: function( eventName ){
this.events[ eventName ] = [];
},
/**
* Retrive the list of all handlers registered for a given event.
* @function
* @param {String} eventName - Name of event to get handlers for.
*/
getHandler: function( eventName ) {
var events = this.events[ eventName ];
if ( !events || !events.length ){
return null;
}
events = events.length === 1 ?
[ events[ 0 ] ] :
Array.apply( null, events );
return function( source, args ) {
var i,
length = events.length;
for ( i = 0; i < length; i++ ) {
if( events[ i ] ){
events[ i ]( source, args );
}
}
};
},
/**
* Trigger an event, optionally passing additional information.
* @function
* @param {String} eventName - Name of event to register.
* @param {Function} handler - Function to call when event is triggered.
*/
raiseEvent: function( eventName, eventArgs ) {
//uncomment if you want to get a log og all events
//$.console.log( eventName );
var handler = this.getHandler( eventName );
if ( handler ) {
if ( !eventArgs ) {
eventArgs = {};
}
handler( this, eventArgs );
}
}
};
}( OpenSeadragon ));

164
src/eventsource.js Normal file
View File

@ -0,0 +1,164 @@
/*
* OpenSeadragon - EventSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function($){
/**
* Event handler method signature used by all OpenSeadragon events.
*
* @callback EventHandler
* @memberof OpenSeadragon
* @param {Object} event - See individual events for event-specific properties.
*/
/**
* @class EventSource
* @classdesc For use by classes which want to support custom, non-browser events.
*
* @memberof OpenSeadragon
*/
$.EventSource = function() {
this.events = {};
};
$.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{
// TODO: Add a method 'one' which automatically unbinds a listener after the first triggered event that matches.
/**
* Add an event handler for a given event.
* @function
* @param {String} eventName - Name of event to register.
* @param {OpenSeadragon.EventHandler} handler - Function to call when event is triggered.
* @param {Object} [userData=null] - Arbitrary object to be passed unchanged to the handler.
*/
addHandler: function ( eventName, handler, userData ) {
var events = this.events[ eventName ];
if ( !events ) {
this.events[ eventName ] = events = [];
}
if ( handler && $.isFunction( handler ) ) {
events[ events.length ] = { handler: handler, userData: userData || null };
}
},
/**
* Remove a specific event handler for a given event.
* @function
* @param {String} eventName - Name of event for which the handler is to be removed.
* @param {OpenSeadragon.EventHandler} handler - Function to be removed.
*/
removeHandler: function ( eventName, handler ) {
var events = this.events[ eventName ],
handlers = [],
i;
if ( !events ) {
return;
}
if ( $.isArray( events ) ) {
for ( i = 0; i < events.length; i++ ) {
if ( events[i].handler !== handler ) {
handlers.push( events[ i ] );
}
}
this.events[ eventName ] = handlers;
}
},
/**
* Remove all event handlers for a given event type. If no type is given all
* event handlers for every event type are removed.
* @function
* @param {String} eventName - Name of event for which all handlers are to be removed.
*/
removeAllHandlers: function( eventName ) {
if ( eventName ){
this.events[ eventName ] = [];
} else{
for ( var eventType in this.events ) {
this.events[ eventType ] = [];
}
}
},
/**
* Get a function which iterates the list of all handlers registered for a given event, calling the handler for each.
* @function
* @param {String} eventName - Name of event to get handlers for.
*/
getHandler: function ( eventName ) {
var events = this.events[ eventName ];
if ( !events || !events.length ) {
return null;
}
events = events.length === 1 ?
[ events[ 0 ] ] :
Array.apply( null, events );
return function ( source, args ) {
var i,
length = events.length;
for ( i = 0; i < length; i++ ) {
if ( events[ i ] ) {
args.eventSource = source;
args.userData = events[ i ].userData;
events[ i ].handler( args );
}
}
};
},
/**
* Trigger an event, optionally passing additional information.
* @function
* @param {String} eventName - Name of event to register.
* @param {Object} eventArgs - Event-specific data.
*/
raiseEvent: function( eventName, eventArgs ) {
//uncomment if you want to get a log of all events
//$.console.log( eventName );
var handler = this.getHandler( eventName );
if ( handler ) {
if ( !eventArgs ) {
eventArgs = {};
}
handler( this, eventArgs );
}
}
};
}( OpenSeadragon ));

View File

@ -1,78 +1,145 @@
/**
* Determines the appropriate level of native full screen support we can get
* from the browser.
* Thanks to John Dyer for the implementation and research
* http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/
* Also includes older IE support based on
* http://stackoverflow.com/questions/1125084/how-to-make-in-javascript-full-screen-windows-stretching-all-over-the-screen/7525760
* @name $.supportsFullScreen
/*
* OpenSeadragon - full-screen support functions
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ) {
/**
* Determine native full screen support we can get from the browser.
* @member fullScreenApi
* @memberof OpenSeadragon
* @type {object}
* @property {Boolean} supportsFullScreen Return true if full screen API is supported.
* @property {Function} isFullScreen Return true if currently in full screen mode.
* @property {Function} getFullScreenElement Return the element currently in full screen mode.
* @property {Function} requestFullScreen Make a request to go in full screen mode.
* @property {Function} exitFullScreen Make a request to exit full screen mode.
* @property {Function} cancelFullScreen Deprecated, use exitFullScreen instead.
* @property {String} fullScreenEventName Event fired when the full screen mode change.
* @property {String} fullScreenErrorEventName Event fired when a request to go
* in full screen mode failed.
*/
var fullScreenApi = {
supportsFullScreen: false,
isFullScreen: function() { return false; },
requestFullScreen: function() {},
cancelFullScreen: function() {},
fullScreenEventName: '',
prefix: ''
},
browserPrefixes = 'webkit moz o ms khtml'.split(' ');
supportsFullScreen: false,
isFullScreen: function() { return false; },
getFullScreenElement: function() { return null; },
requestFullScreen: function() {},
exitFullScreen: function() {},
cancelFullScreen: function() {},
fullScreenEventName: '',
fullScreenErrorEventName: ''
};
// check for native support
if (typeof document.cancelFullScreen != 'undefined') {
if ( document.exitFullscreen ) {
// W3C standard
fullScreenApi.supportsFullScreen = true;
} else {
// check for fullscreen support by vendor prefix
for (var i = 0, il = browserPrefixes.length; i < il; i++ ) {
fullScreenApi.prefix = browserPrefixes[i];
if (typeof document[fullScreenApi.prefix + 'CancelFullScreen' ] != 'undefined' ) {
fullScreenApi.supportsFullScreen = true;
break;
}
}
}
// update methods to do something useful
if (fullScreenApi.supportsFullScreen) {
fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
fullScreenApi.isFullScreen = function() {
switch (this.prefix) {
case '':
return document.fullScreen;
case 'webkit':
return document.webkitIsFullScreen;
default:
return document[this.prefix + 'FullScreen'];
}
fullScreenApi.getFullScreenElement = function() {
return document.fullscreenElement;
};
fullScreenApi.requestFullScreen = function( element ) {
return (this.prefix === '') ?
element.requestFullScreen() :
element[this.prefix + 'RequestFullScreen']();
return element.requestFullscreen();
};
fullScreenApi.cancelFullScreen = function( element ) {
return (this.prefix === '') ?
document.cancelFullScreen() :
document[this.prefix + 'CancelFullScreen']();
fullScreenApi.exitFullScreen = function() {
document.exitFullscreen();
};
} else if ( typeof window.ActiveXObject !== "undefined" ){
// Older IE.
fullScreenApi.requestFullScreen = function(){
var wscript = new ActiveXObject("WScript.Shell");
if ( wscript !== null ) {
wscript.SendKeys("{F11}");
}
return false;
fullScreenApi.fullScreenEventName = "fullscreenchange";
fullScreenApi.fullScreenErrorEventName = "fullscreenerror";
} else if ( document.msExitFullscreen ) {
// IE 11
fullScreenApi.supportsFullScreen = true;
fullScreenApi.getFullScreenElement = function() {
return document.msFullscreenElement;
};
fullScreenApi.cancelFullScreen = fullScreenApi.requestFullScreen;
fullScreenApi.requestFullScreen = function( element ) {
return element.msRequestFullscreen();
};
fullScreenApi.exitFullScreen = function() {
document.msExitFullscreen();
};
fullScreenApi.fullScreenEventName = "MSFullscreenChange";
fullScreenApi.fullScreenErrorEventName = "MSFullscreenError";
} else if ( document.webkitExitFullscreen ) {
// Recent webkit
fullScreenApi.supportsFullScreen = true;
fullScreenApi.getFullScreenElement = function() {
return document.webkitFullscreenElement;
};
fullScreenApi.requestFullScreen = function( element ) {
return element.webkitRequestFullscreen();
};
fullScreenApi.exitFullScreen = function() {
document.webkitExitFullscreen();
};
fullScreenApi.fullScreenEventName = "webkitfullscreenchange";
fullScreenApi.fullScreenErrorEventName = "webkitfullscreenerror";
} else if ( document.webkitCancelFullScreen ) {
// Old webkit
fullScreenApi.supportsFullScreen = true;
fullScreenApi.getFullScreenElement = function() {
return document.webkitCurrentFullScreenElement;
};
fullScreenApi.requestFullScreen = function( element ) {
return element.webkitRequestFullScreen();
};
fullScreenApi.exitFullScreen = function() {
document.webkitCancelFullScreen();
};
fullScreenApi.fullScreenEventName = "webkitfullscreenchange";
fullScreenApi.fullScreenErrorEventName = "webkitfullscreenerror";
} else if ( document.mozCancelFullScreen ) {
// Firefox
fullScreenApi.supportsFullScreen = true;
fullScreenApi.getFullScreenElement = function() {
return document.mozFullScreenElement;
};
fullScreenApi.requestFullScreen = function( element ) {
return element.mozRequestFullScreen();
};
fullScreenApi.exitFullScreen = function() {
document.mozCancelFullScreen();
};
fullScreenApi.fullScreenEventName = "mozfullscreenchange";
fullScreenApi.fullScreenErrorEventName = "mozfullscreenerror";
}
fullScreenApi.isFullScreen = function() {
return fullScreenApi.getFullScreenElement() !== null;
};
fullScreenApi.cancelFullScreen = function() {
$.console.error("cancelFullScreen is deprecated. Use exitFullScreen instead.");
fullScreenApi.exitFullScreen();
};
// export api
$.extend( $, fullScreenApi );
})( OpenSeadragon );
})( OpenSeadragon );

192
src/iiif1_1tilesource.js Normal file
View File

@ -0,0 +1,192 @@
/*
* OpenSeadragon - IIIF1_1TileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* @class IIIF1_1TileSource
* @classdesc A client implementation of the International Image Interoperability
* Format: Image API 1.1
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
* @see http://library.stanford.edu/iiif/image-api/
*/
$.IIIF1_1TileSource = function( options ){
$.extend( true, this, options );
if ( !( this.height && this.width && this['@id'] ) ){
throw new Error( 'IIIF required parameters not provided.' );
}
if ( ( this.profile &&
this.profile == "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0" ) ){
// what if not reporting a profile?
throw new Error( 'IIIF Image API 1.1 compliance level 1 or greater is required.' );
}
if ( this.tile_width ) {
options.tileSize = this.tile_width;
} else if ( this.tile_height ) {
options.tileSize = this.tile_height;
} else {
// use the largest of tileOptions that is smaller than the short
// dimension
var shortDim = Math.min( this.height, this.width ),
tileOptions = [256,512,1024],
smallerTiles = [];
for ( var c = 0; c < tileOptions.length; c++ ) {
if ( tileOptions[c] <= shortDim ) {
smallerTiles.push( tileOptions[c] );
}
}
if ( smallerTiles.length > 0 ) {
options.tileSize = Math.max.apply( null, smallerTiles );
} else {
// If we're smaller than 256, just use the short side.
options.tileSize = shortDim;
}
this.tile_width = options.tileSize; // So that 'full' gets used for
this.tile_height = options.tileSize; // the region below
}
if ( !options.maxLevel ) {
var mf = -1;
var scfs = this.scale_factors || this.scale_factor;
if ( scfs instanceof Array ) {
for ( var i = 0; i < scfs.length; i++ ) {
var cf = Number( scfs[i] );
if ( !isNaN( cf ) && cf > mf ) { mf = cf; }
}
}
if ( mf < 0 ) { options.maxLevel = Number( Math.ceil( Math.log( Math.max( this.width, this.height ), 2 ) ) ); }
else { options.maxLevel = mf; }
}
$.TileSource.apply( this, [ options ] );
};
$.extend( $.IIIF1_1TileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.IIIF1_1TileSource.prototype */{
/**
* Determine if the data and/or url imply the image service is supported by
* this tile source.
* @function
* @param {Object|Array} data
* @param {String} optional - url
*/
supports: function( data, url ) {
return ( data['@context'] &&
data['@context'] == "http://library.stanford.edu/iiif/image-api/1.1/context.json" );
},
/**
*
* @function
* @param {Object} data - the raw configuration
* @example <caption>IIIF 1.1 Info Looks like this (XML syntax is no more)</caption>
* {
* "@context" : "http://library.stanford.edu/iiif/image-api/1.1/context.json",
* "@id" : "http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C",
* "width" : 6000,
* "height" : 4000,
* "scale_factors" : [ 1, 2, 4 ],
* "tile_width" : 1024,
* "tile_height" : 1024,
* "formats" : [ "jpg", "png" ],
* "qualities" : [ "native", "grey" ],
* "profile" : "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0"
* }
*/
configure: function( data ){
return data;
},
/**
* Responsible for retreiving the url which will return an image for the
* region specified by the given x, y, and level components.
* @function
* @param {Number} level - z index
* @param {Number} x
* @param {Number} y
* @throws {Error}
*/
getTileUrl: function( level, x, y ){
//# constants
var IIIF_ROTATION = '0',
IIIF_QUALITY = 'native.jpg',
//## get the scale (level as a decimal)
scale = Math.pow( 0.5, this.maxLevel - level ),
//# image dimensions at this level
levelWidth = Math.ceil( this.width * scale ),
levelHeight = Math.ceil( this.height * scale ),
//## iiif region
iiifTileSizeWidth = Math.ceil( this.tileSize / scale ),
iiifTileSizeHeight = Math.ceil( this.tileSize / scale ),
iiifRegion,
iiifTileX,
iiifTileY,
iiifTileW,
iiifTileH,
iiifSize,
uri;
if ( levelWidth < this.tile_width && levelHeight < this.tile_height ){
iiifSize = levelWidth + ",";
iiifRegion = 'full';
} else {
iiifTileX = x * iiifTileSizeWidth;
iiifTileY = y * iiifTileSizeHeight;
iiifTileW = Math.min( iiifTileSizeWidth, this.width - iiifTileX );
iiifTileH = Math.min( iiifTileSizeHeight, this.height - iiifTileY );
iiifSize = Math.ceil( iiifTileW * scale ) + ",";
iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' );
}
uri = [ this['@id'], iiifRegion, iiifSize, IIIF_ROTATION, IIIF_QUALITY ].join( '/' );
return uri;
}
});
}( OpenSeadragon ));

View File

@ -1,14 +1,52 @@
(function( $ ){
/**
* A client implementation of the International Image Interoperability
* Format: Image API Draft 0.2 - Please read more about the specification
* at
/*
* OpenSeadragon - IIIFTileSource
*
* The getTileUrl implementation is based on the gist from:
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* The getTileUrl implementation is based on Jon Stroop's Python version,
* which is released under the New BSD license:
* https://gist.github.com/jpstroop/4624253
*/
(function( $ ){
/**
* @class IIIFTileSource
* @classdesc A client implementation of the International Image Interoperability
* Format: Image API Draft 0.2
*
* @class
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
* @see http://library.stanford.edu/iiif/image-api/
*/
@ -27,32 +65,40 @@ $.IIIFTileSource = function( options ){
// to preserve backward compatibility.
options.tileSize = this.tile_width;
options.maxLevel = options.maxLevel ? options.maxLevel : Number(
Math.ceil( Math.log( Math.max( this.width, this.height ), 2 ) )
);
if (! options.maxLevel ) {
var mf = -1;
var scfs = this.scale_factors || this.scale_factor;
if ( scfs instanceof Array ) {
for ( var i = 0; i < scfs.length; i++ ) {
var cf = Number( scfs[i] );
if ( !isNaN( cf ) && cf > mf ) { mf = cf; }
}
}
if ( mf < 0 ) { options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2))); }
else { options.maxLevel = mf; }
}
$.TileSource.apply( this, [ options ] );
};
$.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, {
$.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.IIIFTileSource.prototype */{
/**
* Determine if the data and/or url imply the image service is supported by
* this tile source.
* @function
* @name OpenSeadragon.IIIFTileSource.prototype.supports
* @method
* @param {Object|Array} data
* @param {String} optional - url
*/
supports: function( data, url ){
return (
data.ns &&
return (
data.ns &&
"http://library.stanford.edu/iiif/image-api/ns/" == data.ns
) || (
data.profile && (
"http://library.stanford.edu/iiif/image-api/compliance.html#level1" == data.profile ||
"http://library.stanford.edu/iiif/image-api/compliance.html#level2" == data.profile ||
"http://library.stanford.edu/iiif/image-api/compliance.html#level3" == data.profile ||
"http://library.stanford.edu/iiif/image-api/compliance.html" == data.profile
"http://library.stanford.edu/iiif/image-api/compliance.html" == data.profile
)
) || (
data.documentElement &&
@ -62,18 +108,16 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, {
);
},
/**
*
* @function
* @name OpenSeadragon.IIIFTileSource.prototype.configure
/**
*
* @method
* @param {Object|XMLDocument} data - the raw configuration
* @param {String} url - the url the data was retreived from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile source via it's constructor.
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile source via its constructor.
*/
configure: function( data, url ){
var service,
identifier,
options,
host;
@ -104,31 +148,30 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, {
},
/**
* Responsible for retreiving the url which will return an image for the
* Responsible for retreiving the url which will return an image for the
* region speified by the given x, y, and level components.
* @function
* @name OpenSeadragon.IIIFTileSource.prototype.getTileUrl
* @method
* @param {Number} level - z index
* @param {Number} x
* @param {Number} y
* @throws {Error}
*/
getTileUrl: function( level, x, y ){
//# constants
var IIIF_ROTATION = '0',
IIIF_QUALITY = 'native.jpg',
//## get the scale (level as a decimal)
scale = Math.pow( 0.5, this.maxLevel - level ),
//## get iiif size
iiif_size = 'pct:' + ( scale * 100 ),
// iiif_size = 'pct:' + ( scale * 100 ),
//# image dimensions at this level
level_width = Math.ceil( this.width * scale ),
level_height = Math.ceil( this.height * scale ),
//## iiif region
iiif_tile_size_width = Math.ceil( this.tileSize / scale ),
iiif_tile_size_height = Math.ceil( this.tileSize / scale ),
@ -136,26 +179,29 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, {
iiif_tile_x,
iiif_tile_y,
iiif_tile_w,
iiif_tile_h;
if ( level_width < this.tile_width || level_height < this.tile_height ){
iiif_tile_h,
iiif_size;
if ( level_width < this.tile_width && level_height < this.tile_height ){
iiif_size = level_width + ","; // + level_height; only one dim. for IIIF level 1 compliance
iiif_region = 'full';
} else {
iiif_tile_x = x * iiif_tile_size_width;
iiif_tile_y = y * iiif_tile_size_height;
iiif_tile_w = Math.min( iiif_tile_size_width, this.width - iiif_tile_x );
iiif_tile_h = Math.min( iiif_tile_size_height, this.height - iiif_tile_y );
iiif_size = Math.ceil(iiif_tile_w * scale) + ",";
iiif_region = [ iiif_tile_x, iiif_tile_y, iiif_tile_w, iiif_tile_h ].join(',');
}
return [
this.tilesUrl,
this.identifier,
iiif_region,
iiif_size,
IIIF_ROTATION,
IIIF_QUALITY
return [
this.tilesUrl,
this.identifier,
iiif_region,
iiif_size,
IIIF_ROTATION,
IIIF_QUALITY
].join('/');
}
@ -166,28 +212,28 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, {
* @private
* @inner
* @function
*
<?xml version="1.0" encoding="UTF-8"?>
<info xmlns="http://library.stanford.edu/iiif/image-api/ns/">
<identifier>1E34750D-38DB-4825-A38A-B60A345E591C</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>
<tile_width>1024</tile_width>
<tile_height>1024</tile_height>
<formats>
<format>jpg</format>
<format>png</format>
</formats>
<qualities>
<quality>native</quality>
<quality>grey</quality>
</qualities>
</info>
* @example
* <?xml version="1.0" encoding="UTF-8"?>
* <info xmlns="http://library.stanford.edu/iiif/image-api/ns/">
* <identifier>1E34750D-38DB-4825-A38A-B60A345E591C</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>
* <tile_width>1024</tile_width>
* <tile_height>1024</tile_height>
* <formats>
* <format>jpg</format>
* <format>png</format>
* </formats>
* <qualities>
* <quality>native</quality>
* <quality>grey</quality>
* </qualities>
* </info>
*/
function configureFromXml( tileSource, xmlDoc ){
@ -198,14 +244,10 @@ function configureFromXml( tileSource, xmlDoc ){
var root = xmlDoc.documentElement,
rootName = root.tagName,
configuration = null,
scale_factors,
formats,
qualities,
i;
configuration = null;
if ( rootName == "info" ) {
try {
configuration = {
@ -217,8 +259,8 @@ function configureFromXml( tileSource, xmlDoc ){
return configureFromObject( tileSource, configuration );
} catch ( e ) {
throw (e instanceof Error) ?
e :
throw (e instanceof Error) ?
e :
new Error( $.getString("Errors.IIIF") );
}
}
@ -261,18 +303,18 @@ function parseXML( node, configuration, property ){
* @private
* @inner
* @function
*
{
"profile" : "http://library.stanford.edu/iiif/image-api/compliance.html#level1",
"identifier" : "1E34750D-38DB-4825-A38A-B60A345E591C",
"width" : 6000,
"height" : 4000,
"scale_factors" : [ 1, 2, 4 ],
"tile_width" : 1024,
"tile_height" : 1024,
"formats" : [ "jpg", "png" ],
"quality" : [ "native", "grey" ]
}
* @example
* {
* "profile" : "http://library.stanford.edu/iiif/image-api/compliance.html#level1",
* "identifier" : "1E34750D-38DB-4825-A38A-B60A345E591C",
* "width" : 6000,
* "height" : 4000,
* "scale_factors" : [ 1, 2, 4 ],
* "tile_width" : 1024,
* "tile_height" : 1024,
* "formats" : [ "jpg", "png" ],
* "quality" : [ "native", "grey" ]
* }
*/
function configureFromObject( tileSource, configuration ){
//the image_host property is not part of the iiif standard but is included here to
@ -284,4 +326,4 @@ function configureFromObject( tileSource, configuration ){
return configuration;
}
}( OpenSeadragon ));
}( OpenSeadragon ));

View File

@ -1,13 +1,49 @@
/*
* OpenSeadragon - LegacyTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* The LegacyTileSource allows simple, traditional image pyramids to be loaded
* @class LegacyTileSource
* @classdesc The LegacyTileSource allows simple, traditional image pyramids to be loaded
* into an OpenSeadragon Viewer. Basically, this translates to the historically
* common practice of starting with a 'master' image, maybe a tiff for example,
* and generating a set of 'service' images like one or more thumbnails, a medium
* and generating a set of 'service' images like one or more thumbnails, a medium
* resolution image and a high resolution image in standard web formats like
* png or jpg.
* @class
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
* @param {Array} levels An array of file descriptions, each is an object with
* a 'url', a 'width', and a 'height'. Overriding classes can expect more
@ -21,7 +57,7 @@
* @property {Number} minLevel
* @property {Number} maxLevel
* @property {Array} levels
*/
*/
$.LegacyTileSource = function( levels ) {
var options,
@ -37,35 +73,42 @@ $.LegacyTileSource = function( levels ) {
//clean up the levels to make sure we support all formats
options.levels = filterFiles( options.levels );
width = options.levels[ options.levels.length - 1 ].width;
height = options.levels[ options.levels.length - 1 ].height;
$.extend( true, options, {
width: width,
height: height,
tileSize: Math.max( height, width ),
if ( options.levels.length > 0 ) {
width = options.levels[ options.levels.length - 1 ].width;
height = options.levels[ options.levels.length - 1 ].height;
}
else {
width = 0;
height = 0;
$.console.error( "No supported image formats found" );
}
$.extend( true, options, {
width: width,
height: height,
tileSize: Math.max( height, width ),
tileOverlap: 0,
minLevel: 0,
maxLevel: options.levels.length - 1
});
minLevel: 0,
maxLevel: options.levels.length > 0 ? options.levels.length - 1 : 0
} );
$.TileSource.apply( this, [ options ] );
this.levels = options.levels;
};
$.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, {
$.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.LegacyTileSource.prototype */{
/**
* Determine if the data and/or url imply the image service is supported by
* this tile source.
* @function
* @name OpenSeadragon.LegacyTileSource.prototype.supports
* @param {Object|Array} data
* @param {String} optional - url
*/
supports: function( data, url ){
return (
data.type &&
return (
data.type &&
"legacy-image-pyramid" == data.type
) || (
data.documentElement &&
@ -75,12 +118,11 @@ $.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, {
/**
*
*
* @function
* @name OpenSeadragon.LegacyTileSource.prototype.configure
* @param {Object|XMLDocument} configuration - the raw configuration
* @param {String} dataUrl - the url the data was retreived from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function( configuration, dataUrl ){
@ -99,25 +141,23 @@ $.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, {
return options;
},
/**
* @function
* @name OpenSeadragon.LegacyTileSource.prototype.getLevelScale
* @param {Number} level
*/
getLevelScale: function( level ) {
getLevelScale: function ( level ) {
var levelScale = NaN;
if ( level >= this.minLevel && level <= this.maxLevel ){
levelScale =
this.levels[ level ].width /
if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {
levelScale =
this.levels[ level ].width /
this.levels[ this.maxLevel ].width;
}
}
return levelScale;
},
/**
* @function
* @name OpenSeadragon.LegacyTileSource.prototype.getNumTiles
* @param {Number} level
*/
getNumTiles: function( level ) {
@ -131,7 +171,6 @@ $.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, {
/**
* @function
* @name OpenSeadragon.LegacyTileSource.prototype.getTileAtPoint
* @param {Number} level
* @param {OpenSeadragon.Point} point
*/
@ -142,24 +181,23 @@ $.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, {
/**
* This method is not implemented by this class other than to throw an Error
* announcing you have to implement it. Because of the variety of tile
* announcing you have to implement it. Because of the variety of tile
* server technologies, and various specifications for building image
* pyramids, this method is here to allow easy integration.
* @function
* @name OpenSeadragon.LegacyTileSource.prototype.getTileUrl
* @param {Number} level
* @param {Number} x
* @param {Number} y
* @throws {Error}
*/
getTileUrl: function( level, x, y ) {
getTileUrl: function ( level, x, y ) {
var url = null;
if( level >= this.minLevel && level <= this.maxLevel ){
if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {
url = this.levels[ level ].url;
}
return url;
}
});
} );
/**
* This method removes any files from the Array which dont conform to our
@ -174,12 +212,12 @@ function filterFiles( files ){
i;
for( i = 0; i < files.length; i++ ){
file = files[ i ];
if( file.height &&
file.width &&
if( file.height &&
file.width &&
file.url && (
file.url.toLowerCase().match(/^.*\.(png|jpg|jpeg|gif)$/) || (
file.mimetype &&
file.mimetype.toLowerCase().match(/^.*\/(png|jpg|jpeg|gif)$/)
file.mimetype &&
file.mimetype.toLowerCase().match(/^.*\/(png|jpg|jpeg|gif)$/)
)
) ){
//This is sufficient to serve as a level
@ -189,6 +227,9 @@ function filterFiles( files ){
height: Number( file.height )
});
}
else {
$.console.error( 'Unsupported image format: %s', file.url ? file.url : '<no URL>' );
}
}
return filtered.sort(function(a,b){
@ -203,7 +244,7 @@ function filterFiles( files ){
* @function
*/
function configureFromXML( tileSource, xmlDoc ){
if ( !xmlDoc || !xmlDoc.documentElement ) {
throw new Error( $.getString( "Errors.Xml" ) );
}
@ -216,13 +257,13 @@ function configureFromXML( tileSource, xmlDoc ){
i;
if ( rootName == "image" ) {
try {
conf = {
type: root.getAttribute( "type" ),
levels: []
};
levels = root.getElementsByTagName( "level" );
for ( i = 0; i < levels.length; i++ ) {
level = levels[ i ];
@ -237,8 +278,8 @@ function configureFromXML( tileSource, xmlDoc ){
return configureFromObject( tileSource, conf );
} catch ( e ) {
throw (e instanceof Error) ?
e :
throw (e instanceof Error) ?
e :
new Error( 'Unknown error parsing Legacy Image Pyramid XML.' );
}
} else if ( rootName == "collection" ) {
@ -256,7 +297,7 @@ function configureFromXML( tileSource, xmlDoc ){
* @function
*/
function configureFromObject( tileSource, configuration ){
return configuration.levels;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,98 @@
/*
* OpenSeadragon - Navigator
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* The Navigator provides a small view of the current image as fixed
* @class Navigator
* @classdesc The Navigator provides a small view of the current image as fixed
* while representing the viewport as a moving box serving as a frame
* of reference in the larger viewport as to which portion of the image
* is currently being examined. The navigator's viewport can be interacted
* with using the keyboard or the mouse.
* @class
* @name OpenSeadragon.Navigator
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.Viewer
* @extends OpenSeadragon.EventHandler
* @extends OpenSeadragon.EventSource
* @param {Object} options
* @param {String} options.viewerId
*/
$.Navigator = function( options ){
var _this = this,
viewer = options.viewer,
viewerSize = $.getElementSize( viewer.element );
var viewer = options.viewer,
viewerSize,
navigatorSize,
unneededElement;
//We may need to create a new element and id if they did not
//provide the id for the existing element
if( !options.id ){
options.id = 'navigator-' + (+new Date());
options.id = 'navigator-' + $.now();
this.element = $.makeNeutralElement( "div" );
this.element.id = options.id;
this.element.className = 'navigator';
options.controlOptions = {
anchor: $.ControlAnchor.TOP_RIGHT,
attachToViewer: true,
autoFade: true
};
if( options.position ){
if( 'BOTTOM_RIGHT' == options.position ){
options.controlOptions.anchor = $.ControlAnchor.BOTTOM_RIGHT;
} else if( 'BOTTOM_LEFT' == options.position ){
options.controlOptions.anchor = $.ControlAnchor.BOTTOM_LEFT;
} else if( 'TOP_RIGHT' == options.position ){
options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT;
} else if( 'TOP_LEFT' == options.position ){
options.controlOptions.anchor = $.ControlAnchor.TOP_LEFT;
} else if( 'ABSOLUTE' == options.position ){
options.controlOptions.anchor = $.ControlAnchor.ABSOLUTE;
options.controlOptions.top = options.top;
options.controlOptions.left = options.left;
options.controlOptions.height = options.height;
options.controlOptions.width = options.width;
}
}
} else {
this.element = document.getElementById( options.id );
options.controlOptions = {
anchor: $.ControlAnchor.NONE,
attachToViewer: false,
autoFade: false
};
}
this.element.id = options.id;
this.element.className += ' navigator';
options = $.extend( true, {
sizeRatio: $.DEFAULT_SETTINGS.navigatorSizeRatio
@ -40,139 +106,71 @@ $.Navigator = function( options ){
showSequenceControl: false,
immediateRender: true,
blendTime: 0,
animationTime: 0
animationTime: 0,
autoResize: options.autoResize
});
options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;
(function( style ){
style.marginTop = '0px';
style.marginRight = '0px';
style.marginBottom = '0px';
style.marginLeft = '0px';
style.border = '2px solid #555';
style.background = '#000';
style.opacity = 0.8;
style.overflow = 'hidden';
}( this.element.style ));
this.borderWidth = 2;
//At some browser magnification levels the display regions lines up correctly, but at some there appears to
//be a one pixel gap.
this.fudge = new $.Point(1, 1);
this.totalBorderWidths = new $.Point(this.borderWidth*2, this.borderWidth*2).minus(this.fudge);
this.displayRegion = $.makeNeutralElement( "textarea" );
if ( options.controlOptions.anchor != $.ControlAnchor.NONE ) {
(function( style, borderWidth ){
style.margin = '0px';
style.border = borderWidth + 'px solid #555';
style.padding = '0px';
style.background = '#000';
style.opacity = 0.8;
style.overflow = 'hidden';
}( this.element.style, this.borderWidth));
}
this.displayRegion = $.makeNeutralElement( "div" );
this.displayRegion.id = this.element.id + '-displayregion';
this.displayRegion.className = 'displayregion';
(function( style ){
(function( style, borderWidth ){
style.position = 'relative';
style.top = '0px';
style.left = '0px';
style.fontSize = '0px';
style.overflow = 'hidden';
style.border = '2px solid #900';
style.border = borderWidth + 'px solid #900';
style.margin = '0px';
style.padding = '0px';
//TODO: IE doesnt like this property being set
//try{ style.outline = '2px auto #909'; }catch(e){/*ignore*/}
style.background = 'transparent';
// We use square bracket notation on the statement below, because float is a keyword.
// This is important for the Google Closure compiler, if nothing else.
/*jshint sub:true */
/*jshint sub:true */
style['float'] = 'left'; //Webkit
style.cssFloat = 'left'; //Firefox
style.styleFloat = 'left'; //IE
style.zIndex = 999999999;
style.cursor = 'default';
}( this.displayRegion.style ));
}( this.displayRegion.style, this.borderWidth ));
this.element.innerTracker = new $.MouseTracker({
element: this.element,
scrollHandler: function(){
//dont scroll the page up and down if the user is scrolling
//in the navigator
return false;
}
element: this.element,
dragHandler: $.delegate( this, onCanvasDrag ),
clickHandler: $.delegate( this, onCanvasClick ),
releaseHandler: $.delegate( this, onCanvasRelease ),
scrollHandler: $.delegate( this, onCanvasScroll )
}).setTracking( true );
this.displayRegion.innerTracker = new $.MouseTracker({
element: this.displayRegion,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
clickHandler: $.delegate( this, onCanvasClick ),
dragHandler: $.delegate( this, onCanvasDrag ),
releaseHandler: $.delegate( this, onCanvasRelease ),
scrollHandler: $.delegate( this, onCanvasScroll ),
focusHandler: function(){
var point = $.getElementPosition( _this.viewer.element );
window.scrollTo( 0, point.y );
_this.viewer.setControlsEnabled( true );
(function( style ){
style.border = '2px solid #437AB2';
//style.outline = '2px auto #437AB2';
}( this.element.style ));
},
blurHandler: function(){
_this.viewer.setControlsEnabled( false );
(function( style ){
style.border = '2px solid #900';
//style.outline = '2px auto #900';
}( this.element.style ));
},
keyHandler: function(tracker, keyCode, shiftKey){
//console.log( keyCode );
switch( keyCode ){
case 61://=|+
_this.viewer.viewport.zoomBy(1.1);
_this.viewer.viewport.applyConstraints();
return false;
case 45://-|_
_this.viewer.viewport.zoomBy(0.9);
_this.viewer.viewport.applyConstraints();
return false;
case 48://0|)
_this.viewer.viewport.goHome();
_this.viewer.viewport.applyConstraints();
return false;
case 119://w
case 87://W
case 38://up arrow
if (shiftKey)
_this.viewer.viewport.zoomBy(1.1);
else
_this.viewer.viewport.panBy(new $.Point(0, -0.05));
_this.viewer.viewport.applyConstraints();
return false;
case 115://s
case 83://S
case 40://down arrow
if (shiftKey)
_this.viewer.viewport.zoomBy(0.9);
else
_this.viewer.viewport.panBy(new $.Point(0, 0.05));
_this.viewer.viewport.applyConstraints();
return false;
case 97://a
case 37://left arrow
_this.viewer.viewport.panBy(new $.Point(-0.05, 0));
_this.viewer.viewport.applyConstraints();
return false;
case 100://d
case 39://right arrow
_this.viewer.viewport.panBy(new $.Point(0.05, 0));
_this.viewer.viewport.applyConstraints();
return false;
default:
//console.log( 'navigator keycode %s', keyCode );
return true;
}
}
}).setTracking( true ); // default state
/*this.displayRegion.outerTracker = new $.MouseTracker({
element: this.container,
clickTimeThreshold: this.clickTimeThreshold,
element: this.container,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
enterHandler: $.delegate( this, onContainerEnter ),
exitHandler: $.delegate( this, onContainerExit ),
@ -180,66 +178,131 @@ $.Navigator = function( options ){
}).setTracking( this.mouseNavEnabled ? true : false ); // always tracking*/
viewer.addControl(
this.element,
$.ControlAnchor.TOP_RIGHT
viewer.addControl(
this.element,
options.controlOptions
);
if( options.width && options.height ){
this.element.style.width = options.width + 'px';
this.element.style.height = options.height + 'px';
} else {
this.element.style.width = ( viewerSize.x * options.sizeRatio ) + 'px';
this.element.style.height = ( viewerSize.y * options.sizeRatio ) + 'px';
if ( options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE && options.controlOptions.anchor != $.ControlAnchor.NONE ) {
if ( options.width && options.height ) {
this.element.style.height = typeof ( options.height ) == "number" ? ( options.height + 'px' ) : options.height;
this.element.style.width = typeof ( options.width ) == "number" ? ( options.width + 'px' ) : options.width;
} else {
viewerSize = $.getElementSize( viewer.element );
this.element.style.height = ( viewerSize.y * options.sizeRatio ) + 'px';
this.element.style.width = ( viewerSize.x * options.sizeRatio ) + 'px';
this.oldViewerSize = viewerSize;
}
navigatorSize = $.getElementSize( this.element );
this.elementArea = navigatorSize.x * navigatorSize.y;
}
$.Viewer.apply( this, [ options ] );
this.oldContainerSize = new $.Point( 0, 0 );
this.element.getElementsByTagName('form')[0].appendChild( this.displayRegion );
$.Viewer.apply( this, [ options ] );
this.element.getElementsByTagName( 'div' )[0].appendChild( this.displayRegion );
unneededElement = this.element.getElementsByTagName('textarea')[0];
if (unneededElement) {
unneededElement.parentNode.removeChild(unneededElement);
}
};
$.extend( $.Navigator.prototype, $.EventHandler.prototype, $.Viewer.prototype, {
$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{
/**
* Used to notify the navigator when its size has changed.
* Especially useful when {@link OpenSeadragon.Options}.navigatorAutoResize is set to false and the navigator is resizable.
* @function
* @name OpenSeadragon.Navigator.prototype.update
*/
update: function( viewport ){
updateSize: function () {
if ( this.viewport ) {
var containerSize = new $.Point(
(this.container.clientWidth === 0 ? 1 : this.container.clientWidth),
(this.container.clientHeight === 0 ? 1 : this.container.clientHeight)
);
if ( !containerSize.equals( this.oldContainerSize ) ) {
var oldBounds = this.viewport.getBounds();
var oldCenter = this.viewport.getCenter();
this.viewport.resize( containerSize, true );
var imageHeight = 1 / this.source.aspectRatio;
var newWidth = oldBounds.width <= 1 ? oldBounds.width : 1;
var newHeight = oldBounds.height <= imageHeight ?
oldBounds.height : imageHeight;
var newBounds = new $.Rect(
oldCenter.x - ( newWidth / 2.0 ),
oldCenter.y - ( newHeight / 2.0 ),
newWidth,
newHeight
);
this.viewport.fitBounds( newBounds, true );
this.oldContainerSize = containerSize;
this.drawer.update();
}
}
},
var bounds,
/**
* Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs.
* @function
* @param {OpenSeadragon.Viewport} The viewport this navigator is tracking.
*/
update: function( viewport ) {
var viewerSize,
newWidth,
newHeight,
bounds,
topleft,
bottomright;
if( viewport && this.viewport ){
bounds = viewport.getBounds( true );
topleft = this.viewport.pixelFromPoint( bounds.getTopLeft() );
bottomright = this.viewport.pixelFromPoint( bounds.getBottomRight() );
viewerSize = $.getElementSize( this.viewer.element );
if ( !viewerSize.equals( this.oldViewerSize ) ) {
this.oldViewerSize = viewerSize;
if ( this.maintainSizeRatio ) {
newWidth = viewerSize.x * this.sizeRatio;
newHeight = viewerSize.y * this.sizeRatio;
}
else {
newWidth = Math.sqrt(this.elementArea * (viewerSize.x / viewerSize.y));
newHeight = this.elementArea / newWidth;
}
this.element.style.width = newWidth + 'px';
this.element.style.height = newHeight + 'px';
this.updateSize();
}
//update style for navigator-box
(function(style){
if( viewport && this.viewport ) {
bounds = viewport.getBounds( true );
topleft = this.viewport.pixelFromPoint( bounds.getTopLeft(), false );
bottomright = this.viewport.pixelFromPoint( bounds.getBottomRight(), false ).minus( this.totalBorderWidths );
//update style for navigator-box
(function(style) {
style.top = topleft.y + 'px';
style.left = topleft.x + 'px';
var width = Math.abs( topleft.x - bottomright.x ) - 3; // TODO: What does this magic number mean?
var height = Math.abs( topleft.y - bottomright.y ) - 3;
var width = Math.abs( topleft.x - bottomright.x );
var height = Math.abs( topleft.y - bottomright.y );
// make sure width and height are non-negative so IE doesn't throw
style.width = Math.max( width, 0 ) + 'px';
style.height = Math.max( height, 0 ) + 'px';
}( this.displayRegion.style ));
}
}( this.displayRegion.style ));
}
},
open: function( source ){
open: function( source ) {
this.updateSize();
var containerSize = this.viewer.viewport.containerSize.times( this.sizeRatio );
if( source.tileSize > containerSize.x ||
if( source.tileSize > containerSize.x ||
source.tileSize > containerSize.y ){
this.minPixelRatio = Math.min(
containerSize.x,
containerSize.y
this.minPixelRatio = Math.min(
containerSize.x,
containerSize.y
) / source.tileSize;
} else {
this.minPixelRatio = this.viewer.minPixelRatio;
@ -249,34 +312,44 @@ $.extend( $.Navigator.prototype, $.EventHandler.prototype, $.Viewer.prototype, {
});
/**
* @private
* @inner
* @function
*/
function onCanvasClick( tracker, position, quick, shift ) {
this.displayRegion.focus();
function onCanvasClick( event ) {
var newBounds,
viewerPosition,
dimensions;
if (! this.drag) {
if ( this.viewer.viewport ) {
this.viewer.viewport.panTo( this.viewport.pointFromPixel( event.position ) );
this.viewer.viewport.applyConstraints();
}
}
else {
this.drag = false;
}
}
/**
* @private
* @inner
* @function
*/
function onCanvasDrag( tracker, position, delta, shift ) {
function onCanvasDrag( event ) {
if ( this.viewer.viewport ) {
this.drag = true;
if( !this.panHorizontal ){
delta.x = 0;
event.delta.x = 0;
}
if( !this.panVertical ){
delta.y = 0;
event.delta.y = 0;
}
this.viewer.viewport.panBy(
this.viewport.deltaPointsFromPixels(
delta
)
this.viewer.viewport.panBy(
this.viewport.deltaPointsFromPixels(
event.delta
)
);
}
}
@ -287,8 +360,8 @@ function onCanvasDrag( tracker, position, delta, shift ) {
* @inner
* @function
*/
function onCanvasRelease( tracker, position, insideElementPress, insideElementRelease ) {
if ( insideElementPress && this.viewer.viewport ) {
function onCanvasRelease( event ) {
if ( event.insideElementPressed && this.viewer.viewport ) {
this.viewer.viewport.applyConstraints();
}
}
@ -299,18 +372,31 @@ function onCanvasRelease( tracker, position, insideElementPress, insideElementRe
* @inner
* @function
*/
function onCanvasScroll( tracker, position, scroll, shift ) {
var factor;
if ( this.viewer.viewport ) {
factor = Math.pow( this.zoomPerScroll, scroll );
this.viewer.viewport.zoomBy(
factor,
//this.viewport.pointFromPixel( position, true )
this.viewport.getCenter()
);
this.viewer.viewport.applyConstraints();
}
//cancels event
function onCanvasScroll( event ) {
/**
* Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#navigator} element (mouse wheel, touch pinch, etc.).
*
* @event navigator-scroll
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
* @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 {?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
});
//dont scroll the page up and down if the user is scrolling
//in the navigator
return false;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,63 @@
/*
* OpenSeadragon - OsmTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Derived from the OSM tile source in Rainer Simon's seajax-utils project
* <http://github.com/rsimon/seajax-utils>. Rainer Simon has contributed
* the included code to the OpenSeadragon project under the New BSD license;
* see <https://github.com/openseadragon/openseadragon/issues/58>.
*/
(function( $ ){
/**
* A tilesource implementation for OpenStreetMap. Adopted from Rainer Simon
* project http://github.com/rsimon/seajax-utils.
* @class OsmTileSource
* @classdesc A tilesource implementation for OpenStreetMap.<br><br>
*
* Note 1. Zoomlevels. Deep Zoom and OSM define zoom levels differently. In Deep
* Note 1. Zoomlevels. Deep Zoom and OSM define zoom levels differently. In Deep
* Zoom, level 0 equals an image of 1x1 pixels. In OSM, level 0 equals an image of
* 256x256 levels (see http://gasi.ch/blog/inside-deep-zoom-2). I.e. there is a
* difference of log2(256)=8 levels.
* 256x256 levels (see http://gasi.ch/blog/inside-deep-zoom-2). I.e. there is a
* difference of log2(256)=8 levels.<br><br>
*
* Note 2. Image dimension. According to the OSM Wiki
* Note 2. Image dimension. According to the OSM Wiki
* (http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels)
* the highest Mapnik zoom level has 256.144x256.144 tiles, with a 256x256
* pixel size. I.e. the Deep Zoom image dimension is 65.572.864x65.572.864
* pixels.
*
* @class
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
* @param {Number|Object} width - the pixel width of the image or the idiomatic
* options object which is used instead of positional arguments.
@ -23,7 +65,7 @@
* @param {Number} tileSize
* @param {Number} tileOverlap
* @param {String} tilesUrl
*/
*/
$.OsmTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) {
var options;
@ -53,36 +95,34 @@ $.OsmTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) {
options.tilesUrl = "http://tile.openstreetmap.org/";
}
options.minLevel = 8;
$.TileSource.apply( this, [ options ] );
};
$.extend( $.OsmTileSource.prototype, $.TileSource.prototype, {
$.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.OsmTileSource.prototype */{
/**
* Determine if the data and/or url imply the image service is supported by
* this tile source.
* @function
* @name OpenSeadragon.OsmTileSource.prototype.supports
* @param {Object|Array} data
* @param {String} optional - url
*/
supports: function( data, url ){
return (
data.type &&
return (
data.type &&
"openstreetmaps" == data.type
);
},
/**
*
*
* @function
* @name OpenSeadragon.OsmTileSource.prototype.configure
* @param {Object} data - the raw configuration
* @param {String} url - the url the data was retreived from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function( data, url ){
@ -92,7 +132,6 @@ $.extend( $.OsmTileSource.prototype, $.TileSource.prototype, {
/**
* @function
* @name OpenSeadragon.OsmTileSource.prototype.getTileUrl
* @param {Number} level
* @param {Number} x
* @param {Number} y

View File

@ -1,10 +1,55 @@
/*
* OpenSeadragon - Overlay
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* An enumeration of positions that an overlay may be assigned relative
* to the viewport including CENTER, TOP_LEFT (default), TOP, TOP_RIGHT,
* RIGHT, BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT, and LEFT.
* An enumeration of positions that an overlay may be assigned relative to
* the viewport.
* @member OverlayPlacement
* @memberof OpenSeadragon
* @static
* @type {Object}
* @property {Number} CENTER
* @property {Number} TOP_LEFT
* @property {Number} TOP
* @property {Number} TOP_RIGHT
* @property {Number} RIGHT
* @property {Number} BOTTOM_RIGHT
* @property {Number} BOTTOM
* @property {Number} BOTTOM_LEFT
* @property {Number} LEFT
*/
$.OverlayPlacement = {
CENTER: 0,
@ -19,34 +64,76 @@
};
/**
* An Overlay provides a
* @class
* @class Overlay
* @classdesc Provides a way to float an HTML element on top of the viewer element.
*
* @memberof OpenSeadragon
* @param {Object} options
* @param {Element} options.element
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The
* location of the overlay on the image. If a {@link OpenSeadragon.Point}
* is specified, the overlay will keep a constant size independently of the
* zoom. If a {@link OpenSeadragon.Rect} is specified, the overlay size will
* be adjusted when the zoom changes.
* @param {OpenSeadragon.OverlayPlacement} [options.placement=OpenSeadragon.OverlayPlacement.TOP_LEFT]
* Relative position to the viewport.
* Only used if location is a {@link OpenSeadragon.Point}.
* @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw]
* @param {Boolean} [options.checkResize=true] Set to false to avoid to
* check the size of the overlay everytime it is drawn when using a
* {@link OpenSeadragon.Point} as options.location. It will improve
* performances but will cause a misalignment if the overlay size changes.
*/
$.Overlay = function( element, location, placement ) {
this.element = element;
this.scales = location instanceof $.Rect;
/**
* onDraw callback signature used by {@link OpenSeadragon.Overlay}.
*
* @callback OnDrawCallback
* @memberof OpenSeadragon.Overlay
* @param {OpenSeadragon.Point} position
* @param {OpenSeadragon.Point} size
* @param {Element} element
*/
var options;
if ( $.isPlainObject( element ) ) {
options = element;
} else {
options = {
element: element,
location: location,
placement: placement
};
}
this.element = options.element;
this.scales = options.location instanceof $.Rect;
this.bounds = new $.Rect(
location.x,
location.y,
location.width,
location.height
options.location.x,
options.location.y,
options.location.width,
options.location.height
);
this.position = new $.Point(
location.x,
location.y
options.location.x,
options.location.y
);
this.size = new $.Point(
location.width,
location.height
options.location.width,
options.location.height
);
this.style = element.style;
this.style = options.element.style;
// rects are always top-left
this.placement = location instanceof $.Point ?
placement :
$.OverlayPlacement.TOP_LEFT;
this.placement = options.location instanceof $.Point ?
options.placement :
$.OverlayPlacement.TOP_LEFT;
this.onDraw = options.onDraw;
this.checkResize = options.checkResize === undefined ?
true : options.checkResize;
};
$.Overlay.prototype = {
$.Overlay.prototype = /** @lends OpenSeadragon.Overlay.prototype */{
/**
* @function
@ -100,9 +187,9 @@
element.parentNode.removeChild( element );
//this should allow us to preserve overlays when required between
//pages
if( element.prevElementParent ){
if ( element.prevElementParent ) {
style.display = 'none';
//element.prevElementParent.insertBefore(
//element.prevElementParent.insertBefore(
// element,
// element.prevNextSibling
//);
@ -110,6 +197,9 @@
}
}
// clear the onDraw callback
this.onDraw = null;
style.top = "";
style.left = "";
style.position = "";
@ -124,40 +214,80 @@
* @function
* @param {Element} container
*/
drawHTML: function( container ) {
drawHTML: function( container, viewport ) {
var element = this.element,
style = this.style,
scales = this.scales,
position,
size;
degrees = viewport.degrees,
position = viewport.pixelFromPoint(
this.bounds.getTopLeft(),
true
),
size,
overlayCenter;
if ( element.parentNode != container ) {
//save the source parent for later if we need it
element.prevElementParent = element.parentNode;
element.prevNextSibling = element.nextSibling;
container.appendChild( element );
}
if ( !scales ) {
this.size = $.getElementSize( element );
}
position = this.position;
size = this.size;
if ( scales ) {
size = viewport.deltaPixelsFromPoints(
this.bounds.getSize(),
true
);
} else if ( this.checkResize ) {
size = $.getElementSize( element );
} else {
size = this.size;
}
this.position = position;
this.size = size;
this.adjust( position, size );
position = position.apply( Math.floor );
size = size.apply( Math.ceil );
style.left = position.x + "px";
style.top = position.y + "px";
style.position = "absolute";
style.display = 'block';
// rotate the position of the overlay
// TODO only rotate overlays if in canvas mode
// TODO replace the size rotation with CSS3 transforms
// TODO add an option to overlays to not rotate with the image
// Currently only rotates position and size
if( degrees !== 0 && this.scales ) {
overlayCenter = new $.Point( size.x / 2, size.y / 2 );
if ( scales ) {
style.width = size.x + "px";
style.height = size.y + "px";
var drawerCenter = new $.Point(
viewport.viewer.drawer.canvas.width / 2,
viewport.viewer.drawer.canvas.height / 2
);
position = position.plus( overlayCenter ).rotate(
degrees,
drawerCenter
).minus( overlayCenter );
size = size.rotate( degrees, new $.Point( 0, 0 ) );
size = new $.Point( Math.abs( size.x ), Math.abs( size.y ) );
}
// call the onDraw callback if it exists to allow one to overwrite
// the drawing/positioning/sizing of the overlay
if ( this.onDraw ) {
this.onDraw( position, size, element );
} else {
style.left = position.x + "px";
style.top = position.y + "px";
style.position = "absolute";
style.display = 'block';
if ( scales ) {
style.width = size.x + "px";
style.height = size.y + "px";
}
}
},
@ -168,16 +298,16 @@
*/
update: function( location, placement ) {
this.scales = location instanceof $.Rect;
this.bounds = new $.Rect(
location.x,
location.y,
location.width,
this.bounds = new $.Rect(
location.x,
location.y,
location.width,
location.height
);
// rects are always top-left
this.placement = location instanceof $.Point ?
placement :
$.OverlayPlacement.TOP_LEFT;
placement :
$.OverlayPlacement.TOP_LEFT;
}
};

View File

@ -1,21 +1,65 @@
/*
* OpenSeadragon - Point
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* A Point is really used as a 2-dimensional vector, equally useful for
* @class Point
* @classdesc A Point is really used as a 2-dimensional vector, equally useful for
* representing a point on a plane, or the height and width of a plane
* not requiring any other frame of reference.
* @class
*
* @memberof OpenSeadragon
* @param {Number} [x] The vector component 'x'. Defaults to the origin at 0.
* @param {Number} [y] The vector component 'y'. Defaults to the origin at 0.
* @property {Number} [x] The vector component 'x'.
* @property {Number} [y] The vector component 'y'.
*/
$.Point = function( x, y ) {
/**
* The vector component 'x'.
* @member {Number} x
* @memberof OpenSeadragon.Point#
*/
this.x = typeof ( x ) == "number" ? x : 0;
/**
* The vector component 'y'.
* @member {Number} y
* @memberof OpenSeadragon.Point#
*/
this.y = typeof ( y ) == "number" ? y : 0;
};
$.Point.prototype = {
$.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
/**
* Add another Point to this point and return a new Point.
@ -26,58 +70,57 @@ $.Point.prototype = {
*/
plus: function( point ) {
return new $.Point(
this.x + point.x,
this.x + point.x,
this.y + point.y
);
},
/**
* Add another Point to this point and return a new Point.
* Substract another Point to this point and return a new Point.
* @function
* @param {OpenSeadragon.Point} point The point to add vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* @param {OpenSeadragon.Point} point The point to substract vector components.
* @returns {OpenSeadragon.Point} A new point representing the substraction of the
* vector components
*/
minus: function( point ) {
return new $.Point(
this.x - point.x,
this.x - point.x,
this.y - point.y
);
},
/**
* Add another Point to this point and return a new Point.
* Multiply this point by a factor and return a new Point.
* @function
* @param {OpenSeadragon.Point} point The point to add vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* vector components
* @param {Number} factor The factor to multiply vector components.
* @returns {OpenSeadragon.Point} A new point representing the multiplication
* of the vector components by the factor
*/
times: function( factor ) {
return new $.Point(
this.x * factor,
this.x * factor,
this.y * factor
);
},
/**
* Add another Point to this point and return a new Point.
* Divide this point by a factor and return a new Point.
* @function
* @param {OpenSeadragon.Point} point The point to add vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* vector components
* @param {Number} factor The factor to divide vector components.
* @returns {OpenSeadragon.Point} A new point representing the division of the
* vector components by the factor
*/
divide: function( factor ) {
return new $.Point(
this.x / factor,
this.x / factor,
this.y / factor
);
},
/**
* Add another Point to this point and return a new Point.
* Compute the opposite of this point and return a new Point.
* @function
* @param {OpenSeadragon.Point} point The point to add vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* @returns {OpenSeadragon.Point} A new point representing the opposite of the
* vector components
*/
negate: function() {
@ -85,11 +128,10 @@ $.Point.prototype = {
},
/**
* Add another Point to this point and return a new Point.
* Compute the distance between this point and another point.
* @function
* @param {OpenSeadragon.Point} point The point to add vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* vector components
* @param {OpenSeadragon.Point} point The point to compute the distance with.
* @returns {Number} The distance between the 2 points
*/
distanceTo: function( point ) {
return Math.sqrt(
@ -99,39 +141,52 @@ $.Point.prototype = {
},
/**
* Add another Point to this point and return a new Point.
* Apply a function to each coordinate of this point and return a new point.
* @function
* @param {OpenSeadragon.Point} point The point to add vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* vector components
* @param {function} func The function to apply to each coordinate.
* @returns {OpenSeadragon.Point} A new point with the coordinates computed
* by the specified function
*/
apply: function( func ) {
return new $.Point( func( this.x ), func( this.y ) );
},
/**
* Add another Point to this point and return a new Point.
* Check if this point is equal to another one.
* @function
* @param {OpenSeadragon.Point} point The point to add vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* vector components
* @param {OpenSeadragon.Point} point The point to compare this point with.
* @returns {Boolean} true if they are equal, false otherwise.
*/
equals: function( point ) {
return (
point instanceof $.Point
) && (
this.x === point.x
) && (
this.y === point.y
return (
point instanceof $.Point
) && (
this.x === point.x
) && (
this.y === point.y
);
},
/**
* Add another Point to this point and return a new Point.
* Rotates the point around the specified pivot
* From http://stackoverflow.com/questions/4465931/rotate-rectangle-around-a-point
* @function
* @param {OpenSeadragon.Point} point The point to add vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* vector components
* @param {Number} degress to rotate around the pivot.
* @param {OpenSeadragon.Point} pivot Point about which to rotate.
* @returns {OpenSeadragon.Point}. A new point representing the point rotated around the specified pivot
*/
rotate: function ( degrees, pivot ) {
var angle = degrees * Math.PI / 180.0,
x = Math.cos( angle ) * ( this.x - pivot.x ) - Math.sin( angle ) * ( this.y - pivot.y ) + pivot.x,
y = Math.sin( angle ) * ( this.x - pivot.x ) + Math.cos( angle ) * ( this.y - pivot.y ) + pivot.y;
return new $.Point( x, y );
},
/**
* Convert this point to a string in the format (x,y) where x and y are
* rounded to the nearest integer.
* @function
* @returns {String} A string representation of this point.
*/
toString: function() {
return "(" + Math.round(this.x) + "," + Math.round(this.y) + ")";

View File

@ -1,9 +1,45 @@
/*
* OpenSeadragon - Profiler
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* A utility class useful for developers to establish baseline performance
* @class Profiler
* @classdesc A utility class useful for developers to establish baseline performance
* metrics of rendering routines.
* @class
*
* @memberof OpenSeadragon
* @property {Boolean} midUpdate
* @property {Number} numUpdates
* @property {Number} lastBeginTime
@ -32,7 +68,7 @@ $.Profiler = function() {
this.maxIdleTime = 0;
};
$.Profiler.prototype = {
$.Profiler.prototype = /** @lends OpenSeadragon.Profiler.prototype */{
/**
* @function
@ -43,7 +79,7 @@ $.Profiler.prototype = {
}
this.midUpdate = true;
this.lastBeginTime = new Date().getTime();
this.lastBeginTime = $.now();
if (this.numUpdates < 1) {
return; // this is the first update
@ -69,7 +105,7 @@ $.Profiler.prototype = {
return;
}
this.lastEndTime = new Date().getTime();
this.lastEndTime = $.now();
this.midUpdate = false;
var time = this.lastEndTime - this.lastBeginTime;

View File

@ -1,29 +1,80 @@
/*
* OpenSeadragon - Rect
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* A Rectangle really represents a 2x2 matrix where each row represents a
* 2 dimensional vector component, the first is (x,y) and the second is
* (width, height). The latter component implies the equation of a simple
* @class Rect
* @classdesc A Rectangle really represents a 2x2 matrix where each row represents a
* 2 dimensional vector component, the first is (x,y) and the second is
* (width, height). The latter component implies the equation of a simple
* plane.
*
* @class
* @memberof OpenSeadragon
* @param {Number} x The vector component 'x'.
* @param {Number} y The vector component 'y'.
* @param {Number} width The vector component 'height'.
* @param {Number} height The vector component 'width'.
* @property {Number} x The vector component 'x'.
* @property {Number} y The vector component 'y'.
* @property {Number} width The vector component 'width'.
* @property {Number} height The vector component 'height'.
*/
$.Rect = function( x, y, width, height ) {
/**
* The vector component 'x'.
* @member {Number} x
* @memberof OpenSeadragon.Rect#
*/
this.x = typeof ( x ) == "number" ? x : 0;
/**
* The vector component 'y'.
* @member {Number} y
* @memberof OpenSeadragon.Rect#
*/
this.y = typeof ( y ) == "number" ? y : 0;
/**
* The vector component 'width'.
* @member {Number} width
* @memberof OpenSeadragon.Rect#
*/
this.width = typeof ( width ) == "number" ? width : 0;
/**
* The vector component 'height'.
* @member {Number} height
* @memberof OpenSeadragon.Rect#
*/
this.height = typeof ( height ) == "number" ? height : 0;
};
$.Rect.prototype = {
$.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{
/**
* The aspect ratio is simply the ratio of width to height.
@ -35,14 +86,17 @@ $.Rect.prototype = {
},
/**
* Provides the coordinates of the upper-left corner of the rectanglea s a
* Provides the coordinates of the upper-left corner of the rectangle as a
* point.
* @function
* @returns {OpenSeadragon.Point} The coordinate of the upper-left corner of
* the rectangle.
*/
getTopLeft: function() {
return new $.Point( this.x, this.y );
return new $.Point(
this.x,
this.y
);
},
/**
@ -54,7 +108,35 @@ $.Rect.prototype = {
*/
getBottomRight: function() {
return new $.Point(
this.x + this.width,
this.x + this.width,
this.y + this.height
);
},
/**
* Provides the coordinates of the top-right corner of the rectangle as a
* point.
* @function
* @returns {OpenSeadragon.Point} The coordinate of the top-right corner of
* the rectangle.
*/
getTopRight: function() {
return new $.Point(
this.x + this.width,
this.y
);
},
/**
* Provides the coordinates of the bottom-left corner of the rectangle as a
* point.
* @function
* @returns {OpenSeadragon.Point} The coordinate of the bottom-left corner of
* the rectangle.
*/
getBottomLeft: function() {
return new $.Point(
this.x,
this.y + this.height
);
},
@ -62,7 +144,7 @@ $.Rect.prototype = {
/**
* Computes the center of the rectangle.
* @function
* @returns {OpenSeadragon.Point} The center of the rectangle as represnted
* @returns {OpenSeadragon.Point} The center of the rectangle as represented
* as represented by a 2-dimensional vector (x,y)
*/
getCenter: function() {
@ -75,7 +157,7 @@ $.Rect.prototype = {
/**
* Returns the width and height component as a vector OpenSeadragon.Point
* @function
* @returns {OpenSeadragon.Point} The 2 dimensional vector represnting the
* @returns {OpenSeadragon.Point} The 2 dimensional vector representing the
* the width and height of the rectangle.
*/
getSize: function() {
@ -83,31 +165,86 @@ $.Rect.prototype = {
},
/**
* Determines if two Rectanlges have equivalent components.
* Determines if two Rectangles have equivalent components.
* @function
* @param {OpenSeadragon.Rect} rectangle The Rectangle to compare to.
* @return {Boolean} 'true' if all components are equal, otherwise 'false'.
*/
equals: function( other ) {
return ( other instanceof $.Rect ) &&
( this.x === other.x ) &&
( this.x === other.x ) &&
( this.y === other.y ) &&
( this.width === other.width ) &&
( this.width === other.width ) &&
( this.height === other.height );
},
/**
* Provides a string representation of the retangle which is useful for
* Rotates a rectangle around a point. Currently only 90, 180, and 270
* degrees are supported.
* @function
* @param {Number} degrees The angle in degrees to rotate.
* @param {OpenSeadragon.Point} pivot The point about which to rotate.
* Defaults to the center of the rectangle.
* @return {OpenSeadragon.Rect}
*/
rotate: function( degrees, pivot ) {
// TODO support arbitrary rotation
var width = this.width,
height = this.height,
newTopLeft;
degrees = ( degrees + 360 ) % 360;
if( degrees % 90 !== 0 ) {
throw new Error('Currently only 0, 90, 180, and 270 degrees are supported.');
}
if( degrees === 0 ){
return new $.Rect(
this.x,
this.y,
this.width,
this.height
);
}
pivot = pivot || this.getCenter();
switch ( degrees ) {
case 90:
newTopLeft = this.getBottomLeft();
width = this.height;
height = this.width;
break;
case 180:
newTopLeft = this.getBottomRight();
break;
case 270:
newTopLeft = this.getTopRight();
width = this.height;
height = this.width;
break;
default:
newTopLeft = this.getTopLeft();
break;
}
newTopLeft = newTopLeft.rotate(degrees, pivot);
return new $.Rect(newTopLeft.x, newTopLeft.y, width, height);
},
/**
* Provides a string representation of the rectangle which is useful for
* debugging.
* @function
* @returns {String} A string representation of the rectangle.
*/
toString: function() {
return "[" +
Math.round(this.x*100) + "," +
Math.round(this.y*100) + "," +
return "[" +
Math.round(this.x*100) + "," +
Math.round(this.y*100) + "," +
Math.round(this.width*100) + "x" +
Math.round(this.height*100) +
Math.round(this.height*100) +
"]";
}
};

View File

@ -1,15 +1,48 @@
/*
* OpenSeadragon - ReferenceStrip
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function ( $ ) {
(function( $ ){
// dictionary from id to private properties
var THIS = {};
/**
* The CollectionDrawer is a reimplementation if the Drawer API that
* focuses on allowing a viewport to be redefined as a collection
* focuses on allowing a viewport to be redefined as a collection
* of smaller viewports, defined by a clear number of rows and / or
* columns of which each item in the matrix of viewports has its own
* source.
* source.
*
* This idea is a reexpression of the idea of dzi collections
* which allows a clearer algorithm to reuse the tile sources already
@ -18,26 +51,29 @@ var THIS = {};
* for the purpose of image sequnces.
*
* TODO: The difficult part of this feature is figuring out how to express
* this functionality as a combination of the functionality already
* provided by Drawer, Viewport, TileSource, and Navigator. It may
* this functionality as a combination of the functionality already
* provided by Drawer, Viewport, TileSource, and Navigator. It may
* require better abstraction at those points in order to effeciently
* reuse those paradigms.
*/
$.ReferenceStrip = function( options ){
/**
* @class ReferenceStrip
* @memberof OpenSeadragon
* @param {Object} options
*/
$.ReferenceStrip = function ( options ) {
var _this = this,
viewer = options.viewer,
viewerSize = $.getElementSize( viewer.element ),
miniViewer,
minPixelRatio,
element,
style,
i;
//We may need to create a new element and id if they did not
//provide the id for the existing element
if( !options.id ){
options.id = 'referencestrip-' + (+new Date());
if ( !options.id ) {
options.id = 'referencestrip-' + $.now();
this.element = $.makeNeutralElement( "div" );
this.element.id = options.id;
this.element.className = 'referencestrip';
@ -57,17 +93,17 @@ $.ReferenceStrip = function( options ){
mouseNavEnabled: false,
showNavigationControl: false,
showSequenceControl: false
});
} );
$.extend( this, options );
//Private state properties
THIS[ this.id ] = {
"animating": false
THIS[this.id] = {
"animating": false
};
this.minPixelRatio = this.viewer.minPixelRatio;
style = this.element.style;
style = this.element.style;
style.marginTop = '0px';
style.marginRight = '0px';
style.marginBottom = '0px';
@ -81,56 +117,56 @@ $.ReferenceStrip = function( options ){
$.setElementOpacity( this.element, 0.8 );
this.viewer = viewer;
this.innerTracker = new $.MouseTracker({
this.innerTracker = new $.MouseTracker( {
element: this.element,
dragHandler: $.delegate( this, onStripDrag ),
scrollHandler: $.delegate( this, onStripScroll ),
enterHandler: $.delegate( this, onStripEnter ),
exitHandler: $.delegate( this, onStripExit ),
keyHandler: $.delegate( this, onKeyPress )
}).setTracking( true );
} ).setTracking( true );
//Controls the position and orientation of the reference strip and sets the
//Controls the position and orientation of the reference strip and sets the
//appropriate width and height
if( options.width && options.height ){
if ( options.width && options.height ) {
this.element.style.width = options.width + 'px';
this.element.style.height = options.height + 'px';
viewer.addControl(
this.element,
$.ControlAnchor.BOTTOM_LEFT
viewer.addControl(
this.element,
{ anchor: $.ControlAnchor.BOTTOM_LEFT }
);
} else {
if( "horizontal" == options.scroll ){
this.element.style.width = (
viewerSize.x *
options.sizeRatio *
if ( "horizontal" == options.scroll ) {
this.element.style.width = (
viewerSize.x *
options.sizeRatio *
viewer.tileSources.length
) + ( 12 * viewer.tileSources.length ) + 'px';
this.element.style.height = (
viewerSize.y *
options.sizeRatio
this.element.style.height = (
viewerSize.y *
options.sizeRatio
) + 'px';
viewer.addControl(
this.element,
$.ControlAnchor.BOTTOM_LEFT
viewer.addControl(
this.element,
{ anchor: $.ControlAnchor.BOTTOM_LEFT }
);
}else {
this.element.style.height = (
viewerSize.y *
options.sizeRatio *
} else {
this.element.style.height = (
viewerSize.y *
options.sizeRatio *
viewer.tileSources.length
) + ( 12 * viewer.tileSources.length ) + 'px';
this.element.style.width = (
viewerSize.x *
options.sizeRatio
this.element.style.width = (
viewerSize.x *
options.sizeRatio
) + 'px';
viewer.addControl(
this.element,
$.ControlAnchor.TOP_LEFT
viewer.addControl(
this.element,
{ anchor: $.ControlAnchor.TOP_LEFT }
);
}
@ -141,9 +177,9 @@ $.ReferenceStrip = function( options ){
this.panels = [];
/*jshint loopfunc:true*/
for( i = 0; i < viewer.tileSources.length; i++ ){
element = $.makeNeutralElement('div');
for ( i = 0; i < viewer.tileSources.length; i++ ) {
element = $.makeNeutralElement( 'div' );
element.id = this.element.id + "-" + i;
element.style.width = _this.panelWidth + 'px';
@ -154,27 +190,28 @@ $.ReferenceStrip = function( options ){
element.style.styleFloat = 'left'; //IE
element.style.padding = '2px';
element.innerTracker = new $.MouseTracker({
element.innerTracker = new $.MouseTracker( {
element: element,
clickTimeThreshold: this.clickTimeThreshold,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
pressHandler: function( tracker ){
tracker.dragging = +new Date();
pressHandler: function ( event ) {
event.eventSource.dragging = $.now();
},
releaseHandler: function( tracker, position, insideElementPress, insideElementRelease ){
var id = tracker.element.id,
page = Number( id.split( '-' )[ 2 ] ),
now = +new Date();
if ( insideElementPress &&
insideElementRelease &&
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 ){
( now - tracker.dragging ) < tracker.clickTimeThreshold ) {
tracker.dragging = null;
viewer.goToPage( page );
}
}
}).setTracking( true );
} ).setTracking( true );
this.element.appendChild( element );
@ -183,49 +220,52 @@ $.ReferenceStrip = function( options ){
this.panels.push( element );
}
loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.y, 0);
loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.y, 0 );
this.setFocus( 0 );
};
$.extend( $.ReferenceStrip.prototype, $.EventHandler.prototype, $.Viewer.prototype, {
$.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.ReferenceStrip.prototype */{
setFocus: function( page ){
var element = $.getElement( this.element.id + '-' + page ),
viewerSize = $.getElementSize( this.viewer.canvas ),
scrollWidth = Number(this.element.style.width.replace('px','')),
scrollHeight = Number(this.element.style.height.replace('px','')),
offsetLeft = -Number(this.element.style.marginLeft.replace('px','')),
offsetTop = -Number(this.element.style.marginTop.replace('px','')),
/**
* @function
*/
setFocus: function ( page ) {
var element = $.getElement( this.element.id + '-' + page ),
viewerSize = $.getElementSize( this.viewer.canvas ),
scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),
scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),
offsetLeft = -Number( this.element.style.marginLeft.replace( 'px', '' ) ),
offsetTop = -Number( this.element.style.marginTop.replace( 'px', '' ) ),
offset;
if ( this.currentSelected !== element ){
if( this.currentSelected ){
if ( this.currentSelected !== element ) {
if ( this.currentSelected ) {
this.currentSelected.style.background = '#000';
}
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){
offset = Math.min(offset, (scrollWidth - viewerSize.x));
offset = ( Number( page ) ) * ( this.panelWidth + 3 );
if ( offset > offsetLeft + viewerSize.x - this.panelWidth ) {
offset = Math.min( offset, ( scrollWidth - viewerSize.x ) );
this.element.style.marginLeft = -offset + 'px';
loadPanels( this, viewerSize.x, -offset );
}else if( offset < offsetLeft ){
offset = Math.max(0, offset - viewerSize.x / 2);
} else if ( offset < offsetLeft ) {
offset = Math.max( 0, offset - viewerSize.x / 2 );
this.element.style.marginLeft = -offset + 'px';
loadPanels( this, viewerSize.x, -offset );
}
}else{
offset = (Number(page) ) * ( this.panelHeight + 3 );
if( offset > offsetTop + viewerSize.y - this.panelHeight){
offset = Math.min(offset, (scrollHeight - viewerSize.y));
} else {
offset = ( Number( page ) ) * ( this.panelHeight + 3 );
if ( offset > offsetTop + viewerSize.y - this.panelHeight ) {
offset = Math.min( offset, ( scrollHeight - viewerSize.y ) );
this.element.style.marginTop = -offset + 'px';
loadPanels( this, viewerSize.y, -offset );
}else if( offset < offsetTop ){
offset = Math.max(0, offset - viewerSize.y / 2);
} else if ( offset < offsetTop ) {
offset = Math.max( 0, offset - viewerSize.y / 2 );
this.element.style.marginTop = -offset + 'px';
loadPanels( this, viewerSize.y, -offset );
}
@ -233,24 +273,22 @@ $.extend( $.ReferenceStrip.prototype, $.EventHandler.prototype, $.Viewer.prototy
this.currentPage = page;
$.getElement( element.id + '-displayregion' ).focus();
onStripEnter.call( this, this.innerTracker );
onStripEnter.call( this, { eventSource: this.innerTracker } );
}
},
/**
* @function
* @name OpenSeadragon.ReferenceStrip.prototype.update
*/
update: function( viewport ){
if( THIS[ this.id ].animating ){
$.console.log('image reference strip update');
update: function () {
if ( THIS[this.id].animating ) {
$.console.log( 'image reference strip update' );
return true;
}
return false;
}
});
} );
@ -260,41 +298,41 @@ $.extend( $.ReferenceStrip.prototype, $.EventHandler.prototype, $.Viewer.prototy
* @inner
* @function
*/
function onStripDrag( tracker, position, delta, shift ) {
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 );
function onStripDrag( event ) {
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 ( -delta.x > 0 ) {
if ( 'horizontal' == this.scroll ) {
if ( -event.delta.x > 0 ) {
//forward
if( offsetLeft > -(scrollWidth - viewerSize.x)){
this.element.style.marginLeft = ( offsetLeft + (delta.x * 2) ) + 'px';
loadPanels( this, viewerSize.x, offsetLeft + (delta.x * 2) );
if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) {
this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px';
loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) );
}
} else if ( -delta.x < 0 ) {
} else if ( -event.delta.x < 0 ) {
//reverse
if( offsetLeft < 0 ){
this.element.style.marginLeft = ( offsetLeft + (delta.x * 2) ) + 'px';
loadPanels( this, viewerSize.x, offsetLeft + (delta.x * 2) );
if ( offsetLeft < 0 ) {
this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px';
loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) );
}
}
}else{
if ( -delta.y > 0 ) {
} else {
if ( -event.delta.y > 0 ) {
//forward
if( offsetTop > -(scrollHeight - viewerSize.y)){
this.element.style.marginTop = ( offsetTop + (delta.y * 2) ) + 'px';
loadPanels( this, viewerSize.y, offsetTop + (delta.y * 2) );
if ( offsetTop > -( scrollHeight - viewerSize.y ) ) {
this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px';
loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) );
}
} else if ( -delta.y < 0 ) {
} else if ( -event.delta.y < 0 ) {
//reverse
if( offsetTop < 0 ){
this.element.style.marginTop = ( offsetTop + (delta.y * 2) ) + 'px';
loadPanels( this, viewerSize.y, offsetTop + (delta.y * 2) );
if ( offsetTop < 0 ) {
this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px';
loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) );
}
}
}
@ -310,39 +348,39 @@ function onStripDrag( tracker, position, delta, shift ) {
* @inner
* @function
*/
function onStripScroll( tracker, position, scroll, shift ) {
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 );
function onStripScroll( event ) {
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 ( scroll > 0 ) {
if ( 'horizontal' == this.scroll ) {
if ( event.scroll > 0 ) {
//forward
if( offsetLeft > -(scrollWidth - viewerSize.x)){
this.element.style.marginLeft = ( offsetLeft - (scroll * 60) ) + 'px';
loadPanels( this, viewerSize.x, offsetLeft - (scroll * 60) );
if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) {
this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px';
loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) );
}
} else if ( scroll < 0 ) {
} else if ( event.scroll < 0 ) {
//reverse
if( offsetLeft < 0 ){
this.element.style.marginLeft = ( offsetLeft - (scroll * 60) ) + 'px';
loadPanels( this, viewerSize.x, offsetLeft - (scroll * 60) );
if ( offsetLeft < 0 ) {
this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px';
loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) );
}
}
}else{
if ( scroll < 0 ) {
} else {
if ( event.scroll < 0 ) {
//scroll up
if( offsetTop > viewerSize.y - scrollHeight ){
this.element.style.marginTop = ( offsetTop + (scroll * 60) ) + 'px';
loadPanels( this, viewerSize.y, offsetTop + (scroll * 60) );
if ( offsetTop > viewerSize.y - scrollHeight ) {
this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px';
loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) );
}
} else if ( scroll > 0 ) {
} else if ( event.scroll > 0 ) {
//scroll dowm
if( offsetTop < 0 ){
this.element.style.marginTop = ( offsetTop + (scroll * 60) ) + 'px';
loadPanels( this, viewerSize.y, offsetTop + (scroll * 60) );
if ( offsetTop < 0 ) {
this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px';
loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) );
}
}
}
@ -352,29 +390,30 @@ function onStripScroll( tracker, position, scroll, shift ) {
}
function loadPanels(strip, viewerSize, scroll){
function loadPanels( strip, viewerSize, scroll ) {
var panelSize,
activePanelsStart,
activePanelsEnd,
miniViewer,
style,
i;
if( 'horizontal' == strip.scroll ){
i,
element;
if ( 'horizontal' == strip.scroll ) {
panelSize = strip.panelWidth;
}else{
} else {
panelSize = strip.panelHeight;
}
activePanelsStart = Math.ceil( viewerSize / panelSize ) + 5;
activePanelsEnd = Math.ceil( (Math.abs(scroll) + viewerSize ) / panelSize ) + 1;
activePanelsEnd = Math.ceil( ( Math.abs( scroll ) + viewerSize ) / panelSize ) + 1;
activePanelsStart = activePanelsEnd - activePanelsStart;
activePanelsStart = activePanelsStart < 0 ? 0 : activePanelsStart;
for( i = activePanelsStart; i < activePanelsEnd && i < strip.panels.length; i++ ){
element = strip.panels[ i ];
if ( !element.activePanel ){
for ( i = activePanelsStart; i < activePanelsEnd && i < strip.panels.length; i++ ) {
element = strip.panels[i];
if ( !element.activePanel ) {
miniViewer = new $.Viewer( {
id: element.id,
tileSources: [ strip.viewer.tileSources[ i ] ],
tileSources: [strip.viewer.tileSources[i]],
element: element,
navigatorSizeRatio: strip.sizeRatio,
showNavigator: false,
@ -384,13 +423,13 @@ function loadPanels(strip, viewerSize, scroll){
immediateRender: true,
blendTime: 0,
animationTime: 0
} );
} );
miniViewer.displayRegion = $.makeNeutralElement( "textarea" );
miniViewer.displayRegion.id = element.id + '-displayregion';
miniViewer.displayRegion.className = 'displayregion';
style = miniViewer.displayRegion.style;
style = miniViewer.displayRegion.style;
style.position = 'relative';
style.top = '0px';
style.left = '0px';
@ -404,12 +443,12 @@ function loadPanels(strip, viewerSize, scroll){
style.width = ( strip.panelWidth - 4 ) + 'px';
style.height = ( strip.panelHeight - 4 ) + 'px';
miniViewer.displayRegion.innerTracker = new $.MouseTracker({
element: miniViewer.displayRegion
});
miniViewer.displayRegion.innerTracker = new $.MouseTracker( {
element: miniViewer.displayRegion
} );
element.getElementsByTagName('form')[ 0 ].appendChild(
miniViewer.displayRegion
element.getElementsByTagName( 'div' )[0].appendChild(
miniViewer.displayRegion
);
element.activePanel = true;
@ -423,22 +462,23 @@ function loadPanels(strip, viewerSize, scroll){
* @inner
* @function
*/
function onStripEnter( tracker ) {
function onStripEnter( event ) {
var element = event.eventSource.element;
//$.setElementOpacity(element, 0.8);
//$.setElementOpacity(tracker.element, 0.8);
//element.style.border = '1px solid #555';
//element.style.background = '#000';
//tracker.element.style.border = '1px solid #555';
//tracker.element.style.background = '#000';
if ( 'horizontal' == this.scroll ) {
if( 'horizontal' == this.scroll ){
//tracker.element.style.paddingTop = "0px";
tracker.element.style.marginBottom = "0px";
//element.style.paddingTop = "0px";
element.style.marginBottom = "0px";
} else {
//tracker.element.style.paddingRight = "0px";
tracker.element.style.marginLeft = "0px";
//element.style.paddingRight = "0px";
element.style.marginLeft = "0px";
}
return false;
@ -450,25 +490,19 @@ function onStripEnter( tracker ) {
* @inner
* @function
*/
function onStripExit( tracker ) {
var viewerSize = $.getElementSize( this.viewer.element );
//$.setElementOpacity(tracker.element, 0.4);
//tracker.element.style.border = 'none';
//tracker.element.style.background = '#fff';
function onStripExit( event ) {
var element = event.eventSource.element;
if ( 'horizontal' == this.scroll ) {
//element.style.paddingTop = "10px";
element.style.marginBottom = "-" + ( $.getElementSize( element ).y / 2 ) + "px";
if( 'horizontal' == this.scroll ){
//tracker.element.style.paddingTop = "10px";
tracker.element.style.marginBottom = "-" + ( $.getElementSize( tracker.element ).y / 2 ) + "px";
} else {
//tracker.element.style.paddingRight = "10px";
tracker.element.style.marginLeft = "-" + ( $.getElementSize( tracker.element ).x / 2 )+ "px";
//element.style.paddingRight = "10px";
element.style.marginLeft = "-" + ( $.getElementSize( element ).x / 2 ) + "px";
}
return false;
}
@ -480,41 +514,41 @@ function onStripExit( tracker ) {
* @inner
* @function
*/
function onKeyPress( tracker, keyCode, shiftKey ){
//console.log( keyCode );
function onKeyPress( event ) {
//console.log( event.keyCode );
switch( keyCode ){
case 61://=|+
onStripScroll.call(this, this.tracker, null, 1, null);
switch ( event.keyCode ) {
case 61: //=|+
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );
return false;
case 45://-|_
onStripScroll.call(this, this.tracker, null, -1, null);
case 45: //-|_
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );
return false;
case 48://0|)
case 119://w
case 87://W
case 38://up arrow
onStripScroll.call(this, this.tracker, null, 1, null);
case 48: //0|)
case 119: //w
case 87: //W
case 38: //up arrow
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );
return false;
case 115://s
case 83://S
case 40://down arrow
onStripScroll.call(this, this.tracker, null, -1, null);
case 115: //s
case 83: //S
case 40: //down arrow
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );
return false;
case 97://a
case 37://left arrow
onStripScroll.call(this, this.tracker, null, -1, null);
case 97: //a
case 37: //left arrow
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );
return false;
case 100://d
case 39://right arrow
onStripScroll.call(this, this.tracker, null, 1, null);
case 100: //d
case 39: //right arrow
onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );
return false;
default:
//console.log( 'navigator keycode %s', keyCode );
//console.log( 'navigator keycode %s', event.keyCode );
return true;
}
}
}( OpenSeadragon ));
} ( OpenSeadragon ) );

View File

@ -1,62 +1,116 @@
/*
* OpenSeadragon - Spring
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* @class
* @class Spring
* @memberof OpenSeadragon
* @param {Object} options - Spring configuration settings.
* @param {Number} options.initial - Initial value of spring, default to 0 so
* @param {Number} options.initial - Initial value of spring, default to 0 so
* spring is not in motion initally by default.
* @param {Number} options.springStiffness - Spring stiffness.
* @param {Number} options.animationTime - Animation duration per spring.
*
* @property {Number} initial - Initial value of spring, default to 0 so
* spring is not in motion initally by default.
* @property {Number} springStiffness - Spring stiffness.
* @property {Number} animationTime - Animation duration per spring.
* @property {Object} current
* @property {Number} start
* @property {Number} target
*/
$.Spring = function( options ) {
var args = arguments;
if( typeof( options ) != 'object' ){
//allows backward compatible use of ( initialValue, config ) as
//allows backward compatible use of ( initialValue, config ) as
//constructor parameters
options = {
initial: args.length && typeof ( args[ 0 ] ) == "number" ?
args[ 0 ] :
initial: args.length && typeof ( args[ 0 ] ) == "number" ?
args[ 0 ] :
0,
springStiffness: args.length > 1 ?
args[ 1 ].springStiffness :
/**
* Spring stiffness.
* @member {Number} springStiffness
* @memberof OpenSeadragon.Spring#
*/
springStiffness: args.length > 1 ?
args[ 1 ].springStiffness :
5.0,
animationTime: args.length > 1 ?
args[ 1 ].animationTime :
/**
* Animation duration per spring.
* @member {Number} animationTime
* @memberof OpenSeadragon.Spring#
*/
animationTime: args.length > 1 ?
args[ 1 ].animationTime :
1.5
};
}
$.extend( true, this, options);
/**
* @member {Object} current
* @memberof OpenSeadragon.Spring#
* @property {Number} value
* @property {Number} time
*/
this.current = {
value: typeof ( this.initial ) == "number" ?
this.initial :
value: typeof ( this.initial ) == "number" ?
this.initial :
0,
time: new Date().getTime() // always work in milliseconds
time: $.now() // always work in milliseconds
};
/**
* @member {Object} start
* @memberof OpenSeadragon.Spring#
* @property {Number} value
* @property {Number} time
*/
this.start = {
value: this.current.value,
time: this.current.time
};
/**
* @member {Object} target
* @memberof OpenSeadragon.Spring#
* @property {Number} value
* @property {Number} time
*/
this.target = {
value: this.current.value,
time: this.current.time
};
};
$.Spring.prototype = {
$.Spring.prototype = /** @lends OpenSeadragon.Spring.prototype */{
/**
* @function
@ -93,14 +147,14 @@ $.Spring.prototype = {
* @function
*/
update: function() {
this.current.time = new Date().getTime();
this.current.value = (this.current.time >= this.target.time) ?
this.current.time = $.now();
this.current.value = (this.current.time >= this.target.time) ?
this.target.value :
this.start.value +
this.start.value +
( this.target.value - this.start.value ) *
transform(
this.springStiffness,
( this.current.time - this.start.time ) /
transform(
this.springStiffness,
( this.current.time - this.start.time ) /
( this.target.time - this.start.time )
);
}
@ -110,7 +164,7 @@ $.Spring.prototype = {
* @private
*/
function transform( stiffness, x ) {
return ( 1.0 - Math.exp( stiffness * -x ) ) /
return ( 1.0 - Math.exp( stiffness * -x ) ) /
( 1.0 - Math.exp( -stiffness ) );
}

View File

@ -1,26 +1,52 @@
/*
* OpenSeadragon - getString/setString
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
//TODO: I guess this is where the i18n needs to be reimplemented. I'll look
//TODO: I guess this is where the i18n needs to be reimplemented. I'll look
// into existing patterns for i18n in javascript but i think that mimicking
// pythons gettext might be a reasonable approach.
var I18N = {
Errors: {
Failure: "Sorry, but Seadragon Ajax can't run on your browser!\n" +
"Please try using IE 7 or Firefox 3.\n",
Dzc: "Sorry, we don't support Deep Zoom Collections!",
Dzi: "Hmm, this doesn't appear to be a valid Deep Zoom Image.",
Xml: "Hmm, this doesn't appear to be a valid Deep Zoom Image.",
Empty: "You asked us to open nothing, so we did just that.",
ImageFormat: "Sorry, we don't support {0}-based Deep Zoom Images.",
Security: "It looks like a security restriction stopped us from " +
"loading this Deep Zoom Image.",
Status: "This space unintentionally left blank ({0} {1}).",
Unknown: "Whoops, something inexplicably went wrong. Sorry!"
},
Messages: {
Loading: "Loading..."
OpenFailed: "Unable to open {0}: {1}"
},
Tooltips: {
@ -29,19 +55,20 @@ var I18N = {
ZoomIn: "Zoom in",
ZoomOut: "Zoom out",
NextPage: "Next page",
PreviousPage: "Previous page"
PreviousPage: "Previous page",
RotateLeft: "Rotate left",
RotateRight: "Rotate right"
}
};
$.extend( $, {
$.extend( $, /** @lends OpenSeadragon */{
/**
* @function
* @name OpenSeadragon.getString
* @param {String} property
*/
getString: function( prop ) {
var props = prop.split('.'),
string = null,
args = arguments,
@ -55,27 +82,27 @@ $.extend( $, {
string = container[ props[ i ] ];
if ( typeof( string ) != "string" ) {
string = "";
$.console.debug( "Untranslated source string:", prop );
string = ""; // FIXME: this breaks gettext()-style convention, which would return source
}
return string.replace(/\{\d+\}/g, function(capture) {
var i = parseInt( capture.match( /\d+/ ), 10 ) + 1;
return i < args.length ?
args[ i ] :
return i < args.length ?
args[ i ] :
"";
});
},
/**
* @function
* @name OpenSeadragon.setString
* @param {String} property
* @param {*} value
*/
setString: function( prop, value ) {
var props = prop.split('.'),
container = $.Strings,
container = I18N,
i;
for ( i = 0; i < props.length - 1; i++ ) {

View File

@ -1,67 +1,181 @@
/*
* OpenSeadragon - Tile
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
var TILE_CACHE = {};
/**
* @class
* @class Tile
* @memberof OpenSeadragon
* @param {Number} level The zoom level this tile belongs to.
* @param {Number} x The vector component 'x'.
* @param {Number} y The vector component 'y'.
* @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized
* @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized
* coordinates.
* @param {Boolean} exists Is this tile a part of a sparse image? ( Also has
* @param {Boolean} exists Is this tile a part of a sparse image? ( Also has
* this tile failed to load? )
* @param {String} url The URL of this tile's image.
*
* @property {Number} level The zoom level this tile belongs to.
* @property {Number} x The vector component 'x'.
* @property {Number} y The vector component 'y'.
* @property {OpenSeadragon.Point} bounds Where this tile fits, in normalized
* coordinates
* @property {Boolean} exists Is this tile a part of a sparse image? ( Also has
* this tile failed to load?
* @property {String} url The URL of this tile's image.
* @property {Boolean} loaded Is this tile loaded?
* @property {Boolean} loading Is this tile loading
* @property {Element} element The HTML element for this tile
* @property {Image} image The Image object for this tile
* @property {String} style The alias of this.element.style.
* @property {String} position This tile's position on screen, in pixels.
* @property {String} size This tile's size on screen, in pixels
* @property {String} blendStart The start time of this tile's blending
* @property {String} opacity The current opacity this tile should be.
* @property {String} distance The distance of this tile to the viewport center
* @property {String} visibility The visibility score of this tile.
* @property {Boolean} beingDrawn Whether this tile is currently being drawn
* @property {Number} lastTouchTime Timestamp the tile was last touched.
*/
$.Tile = function(level, x, y, bounds, exists, url) {
/**
* The zoom level this tile belongs to.
* @member {Number} level
* @memberof OpenSeadragon.Tile#
*/
this.level = level;
/**
* The vector component 'x'.
* @member {Number} x
* @memberof OpenSeadragon.Tile#
*/
this.x = x;
/**
* The vector component 'y'.
* @member {Number} y
* @memberof OpenSeadragon.Tile#
*/
this.y = y;
/**
* Where this tile fits, in normalized coordinates
* @member {OpenSeadragon.Point} bounds
* @memberof OpenSeadragon.Tile#
*/
this.bounds = bounds;
/**
* Is this tile a part of a sparse image? Also has this tile failed to load?
* @member {Boolean} exists
* @memberof OpenSeadragon.Tile#
*/
this.exists = exists;
/**
* The URL of this tile's image.
* @member {String} url
* @memberof OpenSeadragon.Tile#
*/
this.url = url;
/**
* Is this tile loaded?
* @member {Boolean} loaded
* @memberof OpenSeadragon.Tile#
*/
this.loaded = false;
/**
* Is this tile loading?
* @member {Boolean} loading
* @memberof OpenSeadragon.Tile#
*/
this.loading = false;
/**
* The HTML div element for this tile
* @member {Element} element
* @memberof OpenSeadragon.Tile#
*/
this.element = null;
/**
* The HTML img element for this tile.
* @member {Element} imgElement
* @memberof OpenSeadragon.Tile#
*/
this.imgElement = null;
/**
* The Image object for this tile.
* @member {Object} image
* @memberof OpenSeadragon.Tile#
*/
this.image = null;
/**
* The alias of this.element.style.
* @member {String} style
* @memberof OpenSeadragon.Tile#
*/
this.style = null;
/**
* This tile's position on screen, in pixels.
* @member {OpenSeadragon.Point} position
* @memberof OpenSeadragon.Tile#
*/
this.position = null;
/**
* This tile's size on screen, in pixels.
* @member {OpenSeadragon.Point} size
* @memberof OpenSeadragon.Tile#
*/
this.size = null;
/**
* The start time of this tile's blending.
* @member {Number} blendStart
* @memberof OpenSeadragon.Tile#
*/
this.blendStart = null;
/**
* The current opacity this tile should be.
* @member {Number} opacity
* @memberof OpenSeadragon.Tile#
*/
this.opacity = null;
/**
* The distance of this tile to the viewport center.
* @member {Number} distance
* @memberof OpenSeadragon.Tile#
*/
this.distance = null;
/**
* The visibility score of this tile.
* @member {Number} visibility
* @memberof OpenSeadragon.Tile#
*/
this.visibility = null;
/**
* Whether this tile is currently being drawn.
* @member {Boolean} beingDrawn
* @memberof OpenSeadragon.Tile#
*/
this.beingDrawn = false;
/**
* Timestamp the tile was last touched.
* @member {Number} lastTouchTime
* @memberof OpenSeadragon.Tile#
*/
this.lastTouchTime = 0;
};
$.Tile.prototype = {
$.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
/**
* Provides a string representation of this tiles level and (x,y)
* Provides a string representation of this tiles level and (x,y)
* components.
* @function
* @returns {String}
@ -76,9 +190,6 @@ $.Tile.prototype = {
* @param {Element} container
*/
drawHTML: function( container ) {
var containerSize = $.getElementSize( container );
if ( !this.loaded || !this.image ) {
$.console.warn(
"Attempting to draw tile %s when it's not yet loaded.",
@ -87,33 +198,16 @@ $.Tile.prototype = {
return;
}
/* EXISTING IMPLEMENTATION
if ( !this.element ) {
this.element = $.makeNeutralElement("img");
this.element.src = this.url;
this.style = this.element.style;
this.style.position = "absolute";
this.style.msInterpolationMode = "nearest-neighbor";
}
if ( this.element.parentNode != container ) {
container.appendChild( this.element );
}
this.style.top = position.y + "px";
this.style.left = position.x + "px";
this.style.height = size.y + "px";
this.style.width = size.x + "px";
*/
//EXPERIMENTAL - trying to figure out how to scale the container
// content during animation of the container size.
if ( !this.element ) {
this.element = $.makeNeutralElement("img");
this.element.src = this.url;
this.element.style.msInterpolationMode = "nearest-neighbor";
this.element = $.makeNeutralElement( "div" );
this.imgElement = $.makeNeutralElement( "img" );
this.imgElement.src = this.url;
this.imgElement.style.msInterpolationMode = "nearest-neighbor";
this.imgElement.style.width = "100%";
this.imgElement.style.height = "100%";
this.style = this.element.style;
this.style.position = "absolute";
@ -121,23 +215,26 @@ $.Tile.prototype = {
if ( this.element.parentNode != container ) {
container.appendChild( this.element );
}
if ( this.imgElement.parentNode != this.element ) {
this.element.appendChild( this.imgElement );
}
this.style.top = this.position.y + "px";
this.style.left = this.position.x + "px";
this.style.height = this.size.y + "px";
this.style.width = this.size.x + "px";
this.style.top = 100 * ( this.position.y / containerSize.y ) + "%";
this.style.left = 100 * ( this.position.x / containerSize.x ) + "%";
this.style.height = 100 * ( this.size.y / containerSize.y ) + "%";
this.style.width = 100 * ( this.size.x / containerSize.x ) + "%";
$.setElementOpacity( this.element, this.opacity );
},
/**
* Renders the tile in a canvas-based context.
* @function
* @param {Canvas} context
* @param {Function} method for firing the drawing event. drawingHandler({context, tile, rendered})
* where <code>rendered</code> is the context with the pre-drawn image.
*/
drawCanvas: function( context ) {
drawCanvas: function( context, drawingHandler ) {
var position = this.position,
size = this.size,
@ -162,11 +259,11 @@ $.Tile.prototype = {
if( context.globalAlpha == 1 && this.url.match('.png') ){
//clearing only the inside of the rectangle occupied
//by the png prevents edge flikering
context.clearRect(
position.x+1,
position.y+1,
size.x-2,
size.y-2
context.clearRect(
position.x+1,
position.y+1,
size.x-2,
size.y-2
);
}
@ -184,18 +281,21 @@ $.Tile.prototype = {
}
rendered = TILE_CACHE[ this.url ];
// This gives the application a chance to make image manipulation changes as we are rendering the image
drawingHandler({context: context, tile: this, rendered: rendered});
//rendered.save();
context.drawImage(
rendered.canvas,
context.drawImage(
rendered.canvas,
0,
0,
rendered.canvas.width,
rendered.canvas.height,
position.x,
position.y,
size.x,
size.y
0,
rendered.canvas.width,
rendered.canvas.height,
position.x,
position.y,
size.x,
size.y
);
//rendered.restore();
@ -203,21 +303,25 @@ $.Tile.prototype = {
},
/**
* Removes tile from it's contianer.
* Removes tile from its container.
* @function
*/
unload: function() {
if ( this.imgElement && this.imgElement.parentNode ) {
this.imgElement.parentNode.removeChild( this.imgElement );
}
if ( this.element && this.element.parentNode ) {
this.element.parentNode.removeChild( this.element );
}
}
if ( TILE_CACHE[ this.url ]){
delete TILE_CACHE[ this.url ];
}
this.element = null;
this.image = null;
this.loaded = false;
this.loading = false;
this.element = null;
this.imgElement = null;
this.image = null;
this.loaded = false;
this.loading = false;
}
};

View File

@ -1,25 +1,61 @@
/*
* OpenSeadragon - TileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* The TileSource contains the most basic implementation required to create a
* smooth transition between layer in an image pyramid. It has only a single key
* interface that must be implemented to complete it key functionality:
* 'getTileUrl'. It also has several optional interfaces that can be
* @class TileSource
* @classdesc The TileSource contains the most basic implementation required to create a
* smooth transition between layer in an image pyramid. It has only a single key
* interface that must be implemented to complete it key functionality:
* 'getTileUrl'. It also has several optional interfaces that can be
* implemented if a new TileSource wishes to support configuration via a simple
* object or array ('configure') and if the tile source supports or requires
* configuration via retreival of a document on the network ala AJAX or JSONP,
* object or array ('configure') and if the tile source supports or requires
* configuration via retreival of a document on the network ala AJAX or JSONP,
* ('getImageInfo').
* <br/>
* By default the image pyramid is split into N layers where the images longest
* side in M (in pixels), where N is the smallest integer which satisfies
* side in M (in pixels), where N is the smallest integer which satisfies
* <strong>2^(N+1) >= M</strong>.
* @class
* @extends OpenSeadragon.EventHandler
* @param {Number|Object|Array|String} width
* If more than a single argument is supplied, the traditional use of
* positional parameters is supplied and width is expected to be the width
* source image at it's max resolution in pixels. If a single argument is supplied and
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.EventSource
* @param {Number|Object|Array|String} width
* If more than a single argument is supplied, the traditional use of
* positional parameters is supplied and width is expected to be the width
* source image at its max resolution in pixels. If a single argument is supplied and
* it is an Object or Array, the construction is assumed to occur through
* the extending classes implementation of 'configure'. Finally if only a
* single argument is supplied and it is a String, the extending class is
@ -28,7 +64,7 @@
* Width of the source image at max resolution in pixels.
* @param {Number} tileSize
* The size of the tiles to assumed to make up each pyramid layer in pixels.
* Tile size determines the point at which the image pyramid must be
* Tile size determines the point at which the image pyramid must be
* divided into a matrix of smaller images.
* @param {Number} tileOverlap
* The number of pixels each tile is expected to overlap touching tiles.
@ -36,23 +72,9 @@
* The minimum level to attempt to load.
* @param {Number} maxLevel
* The maximum level to attempt to load.
* @property {Number} aspectRatio
* Ratio of width to height
* @property {OpenSeadragon.Point} dimensions
* Vector storing x and y dimensions ( width and height respectively ).
* @property {Number} tileSize
* The size of the image tiles used to compose the image.
* @property {Number} tileOverlap
* The overlap in pixels each tile shares with it's adjacent neighbors.
* @property {Number} minLevel
* The minimum pyramid level this tile source supports or should attempt to load.
* @property {Number} maxLevel
* The maximum pyramid level this tile source supports or should attempt to load.
*/
*/
$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) {
var _this = this,
callback = null,
readyHandler = null,
var callback = null,
args = arguments,
options,
i;
@ -71,8 +93,8 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
}
//Tile sources supply some events, namely 'ready' when they must be configured
//by asyncronously fetching their configuration data.
$.EventHandler.call( this );
//by asynchronously fetching their configuration data.
$.EventSource.call( this );
//we allow options to override anything we dont treat as
//required via idiomatic options or which is functionally
@ -82,17 +104,53 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
//Any functions that are passed as arguments are bound to the ready callback
/*jshint loopfunc:true*/
for( i = 0; i < arguments.length; i++ ){
if( $.isFunction( arguments[i] ) ){
for ( i = 0; i < arguments.length; i++ ) {
if ( $.isFunction( arguments[ i ] ) ) {
callback = arguments[ i ];
this.addHandler( 'ready', function( placeHolderSource, readySource ){
callback( readySource );
});
this.addHandler( 'ready', function ( event ) {
callback( event );
} );
//only one callback per constructor
break;
}
}
/**
* Ratio of width to height
* @member {Number} aspectRatio
* @memberof OpenSeadragon.TileSource#
*/
/**
* Vector storing x and y dimensions ( width and height respectively ).
* @member {OpenSeadragon.Point} dimensions
* @memberof OpenSeadragon.TileSource#
*/
/**
* The size of the image tiles used to compose the image.
* @member {Number} tileSize
* @memberof OpenSeadragon.TileSource#
*/
/**
* The overlap in pixels each tile shares with its adjacent neighbors.
* @member {Number} tileOverlap
* @memberof OpenSeadragon.TileSource#
*/
/**
* The minimum pyramid level this tile source supports or should attempt to load.
* @member {Number} minLevel
* @memberof OpenSeadragon.TileSource#
*/
/**
* The maximum pyramid level this tile source supports or should attempt to load.
* @member {Number} maxLevel
* @memberof OpenSeadragon.TileSource#
*/
/**
*
* @member {Boolean} ready
* @memberof OpenSeadragon.TileSource#
*/
if( 'string' == $.type( arguments[ 0 ] ) ){
//in case the getImageInfo method is overriden and/or implies an
//async mechanism set some safe defaults first
@ -103,26 +161,26 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
this.minLevel = 0;
this.maxLevel = 0;
this.ready = false;
//configuration via url implies the extending class
//configuration via url implies the extending class
//implements and 'configure'
this.getImageInfo( arguments[ 0 ] );
} else {
//explicit configuration via positional args in constructor
//or the more idiomatic 'options' object
this.ready = true;
this.aspectRatio = ( options.width && options.height ) ?
this.aspectRatio = ( options.width && options.height ) ?
( options.width / options.height ) : 1;
this.dimensions = new $.Point( options.width, options.height );
this.tileSize = options.tileSize ? options.tileSize : 0;
this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0;
this.minLevel = options.minLevel ? options.minLevel : 0;
this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ?
this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ?
options.maxLevel : (
( options.width && options.height ) ? Math.ceil(
Math.log( Math.max( options.width, options.height ) ) /
Math.log( 2 )
( options.width && options.height ) ? Math.ceil(
Math.log( Math.max( options.width, options.height ) ) /
Math.log( 2 )
) : 0
);
if( callback && $.isFunction( callback ) ){
@ -134,8 +192,8 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
};
$.TileSource.prototype = {
$.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
/**
* @function
* @param {Number} level
@ -230,7 +288,7 @@ $.TileSource.prototype = {
return new $.Rect( px * scale, py * scale, sx * scale, sy * scale );
},
/**
* Responsible for retrieving, and caching the
@ -240,16 +298,14 @@ $.TileSource.prototype = {
* @throws {Error}
*/
getImageInfo: function( url ) {
var _this = this,
error,
var _this = this,
callbackName,
callback,
readySource,
options,
urlParts,
filename,
lastDot,
tilesUrl;
lastDot;
if( url ) {
@ -260,13 +316,42 @@ $.TileSource.prototype = {
urlParts[ urlParts.length - 1 ] = filename.slice( 0, lastDot );
}
}
callback = function( data ){
if( typeof(data) === "string" ) {
data = $.parseXml( data );
}
var $TileSource = $.TileSource.determineType( _this, data, url );
if ( !$TileSource ) {
/**
* Raised when an error occurs loading a TileSource.
*
* @event open-failed
* @memberof OpenSeadragon.TileSource
* @type {object}
* @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.
* @property {String} message
* @property {String} source
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( 'open-failed', { message: "Unable to load TileSource", source: url } );
return;
}
options = $TileSource.prototype.configure.apply( _this, [ data, url ]);
readySource = new $TileSource( options );
_this.ready = true;
_this.raiseEvent( 'ready', readySource );
/**
* Raised when a TileSource is opened and initialized.
*
* @event ready
* @memberof OpenSeadragon.TileSource
* @type {object}
* @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.
* @property {Object} tileSource
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( 'ready', { tileSource: readySource } );
};
if( url.match(/\.js$/) ){
@ -281,10 +366,46 @@ $.TileSource.prototype = {
callback: callback
});
} else {
// request info via xhr asyncronously.
// request info via xhr asynchronously.
$.makeAjaxRequest( url, function( xhr ) {
var data = processResponse( xhr );
callback( data );
}, function ( xhr, exc ) {
var msg;
/*
IE < 10 will block XHR requests to different origins. Any property access on the request
object will raise an exception which we'll attempt to handle by formatting the original
exception rather than the second one raised when we try to access xhr.status
*/
try {
msg = "HTTP " + xhr.status + " attempting to load TileSource";
} catch ( e ) {
var formattedExc;
if ( typeof( exc ) == "undefined" || !exc.toString ) {
formattedExc = "Unknown error";
} else {
formattedExc = exc.toString();
}
msg = formattedExc + " attempting to load TileSource";
}
/***
* Raised when an error occurs loading a TileSource.
*
* @event open-failed
* @memberof OpenSeadragon.TileSource
* @type {object}
* @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.
* @property {String} message
* @property {String} source
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( 'open-failed', {
message: msg,
source: url
});
});
}
@ -300,7 +421,7 @@ $.TileSource.prototype = {
* and sufficient mechanisim for clear determination.
* @function
* @param {String|Object|Array|Document} data
* @param {String} url - the url the data was loaded
* @param {String} url - the url the data was loaded
* from if any.
* @return {Boolean}
*/
@ -312,14 +433,14 @@ $.TileSource.prototype = {
* Responsible for parsing and configuring the
* image metadata pertinent to this TileSources implementation.
* This method is not implemented by this class other than to throw an Error
* announcing you have to implement it. Because of the variety of tile
* announcing you have to implement it. Because of the variety of tile
* server technologies, and various specifications for building image
* pyramids, this method is here to allow easy integration.
* @function
* @param {String|Object|Array|Document} data
* @param {String} url - the url the data was loaded
* @param {String} url - the url the data was loaded
* from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
* @throws {Error}
*/
@ -328,10 +449,10 @@ $.TileSource.prototype = {
},
/**
* Responsible for retriving the url which will return an image for the
* Responsible for retriving the url which will return an image for the
* region speified by the given x, y, and level components.
* This method is not implemented by this class other than to throw an Error
* announcing you have to implement it. Because of the variety of tile
* announcing you have to implement it. Because of the variety of tile
* server technologies, and various specifications for building image
* pyramids, this method is here to allow easy integration.
* @function
@ -352,23 +473,23 @@ $.TileSource.prototype = {
*/
tileExists: function( level, x, y ) {
var numTiles = this.getNumTiles( level );
return level >= this.minLevel &&
return level >= this.minLevel &&
level <= this.maxLevel &&
x >= 0 &&
y >= 0 &&
x < numTiles.x &&
x >= 0 &&
y >= 0 &&
x < numTiles.x &&
y < numTiles.y;
}
};
$.extend( true, $.TileSource.prototype, $.EventHandler.prototype );
$.extend( true, $.TileSource.prototype, $.EventSource.prototype );
/**
* Decides whether to try to process the response as xml, json, or hand back
* the text
* @eprivate
* @private
* @inner
* @function
* @param {XMLHttpRequest} xhr - the completed network request
@ -383,16 +504,16 @@ function processResponse( xhr ){
throw new Error( $.getString( "Errors.Security" ) );
} else if ( xhr.status !== 200 && xhr.status !== 0 ) {
status = xhr.status;
statusText = ( status == 404 ) ?
"Not Found" :
statusText = ( status == 404 ) ?
"Not Found" :
xhr.statusText;
throw new Error( $.getString( "Errors.Status", status, statusText ) );
}
if( responseText.match(/\s*<.*/) ){
try{
data = ( xhr.responseXML && xhr.responseXML.documentElement ) ?
xhr.responseXML :
data = ( xhr.responseXML && xhr.responseXML.documentElement ) ?
xhr.responseXML :
$.parseXml( responseText );
} catch (e){
data = xhr.responseText;
@ -410,7 +531,7 @@ function processResponse( xhr ){
/**
* Determines the TileSource Implementation by introspection of OpenSeadragon
* namespace, calling each TileSource implementation of 'isType'
* @eprivate
* @private
* @inner
* @function
* @param {Object|Array|Document} data - the tile source configuration object
@ -428,6 +549,8 @@ $.TileSource.determineType = function( tileSource, data, url ){
return OpenSeadragon[ property ];
}
}
$.console.error( "No TileSource was able to open %s %s", url, data );
};

View File

@ -1,12 +1,47 @@
/*
* OpenSeadragon - TileSourceCollection
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* @class
* @class TileSourceCollection
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
*/
*/
$.TileSourceCollection = function( tileSize, tileSources, rows, layout ) {
var options;
if( $.isPlainObject( tileSize ) ){
options = tileSize;
}else{
@ -51,18 +86,17 @@ $.TileSourceCollection = function( tileSize, tileSources, rows, layout ) {
options.minLevel = minLevel;
//for( var name in options ){
// $.console.log( 'Collection %s %s', name, options[ name ] );
// $.console.log( 'Collection %s %s', name, options[ name ] );
//}
$.TileSource.apply( this, [ options ] );
};
$.extend( $.TileSourceCollection.prototype, $.TileSource.prototype, {
$.extend( $.TileSourceCollection.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.TileSourceCollection.prototype */{
/**
* @function
* @name OpenSeadragon.TileSourceCollection.prototype.getTileBounds
* @param {Number} level
* @param {Number} x
* @param {Number} y
@ -82,9 +116,8 @@ $.extend( $.TileSourceCollection.prototype, $.TileSource.prototype, {
},
/**
*
*
* @function
* @name OpenSeadragon.TileSourceCollection.prototype.configure
*/
configure: function( data, url ){
return;
@ -93,7 +126,6 @@ $.extend( $.TileSourceCollection.prototype, $.TileSource.prototype, {
/**
* @function
* @name OpenSeadragon.TileSourceCollection.prototype.getTileUrl
* @param {Number} level
* @param {Number} x
* @param {Number} y
@ -104,7 +136,7 @@ $.extend( $.TileSourceCollection.prototype, $.TileSource.prototype, {
}
});

View File

@ -1,12 +1,54 @@
(function( $ ){
/**
* A tilesource implementation for Tiled Map Services (TMS). Adopted from Rainer Simon
* project http://github.com/rsimon/seajax-utils. TMS tile
* scheme ( [ as supported by OpenLayers ] is described here
* ( http://openlayers.org/dev/examples/tms.html ) )
/*
* OpenSeadragon - TmsTileSource
*
* @class
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Derived from the TMS tile source in Rainer Simon's seajax-utils project
* <http://github.com/rsimon/seajax-utils>. Rainer Simon has contributed
* the included code to the OpenSeadragon project under the New BSD license;
* see <https://github.com/openseadragon/openseadragon/issues/58>.
*/
(function( $ ){
/**
* @class TmsTileSource
* @classdesc A tilesource implementation for Tiled Map Services (TMS).
* TMS tile scheme ( [ as supported by OpenLayers ] is described here
* ( http://openlayers.org/dev/examples/tms.html ).
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
* @param {Number|Object} width - the pixel width of the image or the idiomatic
* options object which is used instead of positional arguments.
@ -14,7 +56,7 @@
* @param {Number} tileSize
* @param {Number} tileOverlap
* @param {String} tilesUrl
*/
*/
$.TmsTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) {
var options;
@ -45,19 +87,18 @@ $.TmsTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) {
options.tileSize = 256;
options.width = bufferedWidth;
options.height = bufferedHeight;
$.TileSource.apply( this, [ options ] );
};
$.extend( $.TmsTileSource.prototype, $.TileSource.prototype, {
$.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.TmsTileSource.prototype */{
/**
* Determine if the data and/or url imply the image service is supported by
* this tile source.
* @function
* @name OpenSeadragon.TmsTileSource.prototype.supports
* @param {Object|Array} data
* @param {String} optional - url
*/
@ -66,12 +107,11 @@ $.extend( $.TmsTileSource.prototype, $.TileSource.prototype, {
},
/**
*
*
* @function
* @name OpenSeadragon.TmsTileSource.prototype.configure
* @param {Object} data - the raw configuration
* @param {String} url - the url the data was retreived from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function( data, url ){
@ -81,7 +121,6 @@ $.extend( $.TmsTileSource.prototype, $.TileSource.prototype, {
/**
* @function
* @name OpenSeadragon.TmsTileSource.prototype.getTileUrl
* @param {Number} level
* @param {Number} x
* @param {Number} y
@ -95,4 +134,4 @@ $.extend( $.TmsTileSource.prototype, $.TileSource.prototype, {
});
}( OpenSeadragon ));
}( OpenSeadragon ));

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,50 @@
/*
* OpenSeadragon - Viewport
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of CodePlex Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function( $ ){
/**
* @class
* @class Viewport
* @classdesc Handles coordinate-related functionality (zoom, pan, rotation, etc.) for an {@link OpenSeadragon.Viewer}.
* A new instance is created for each TileSource opened (see {@link OpenSeadragon.Viewer#viewport}).
*
* @memberof OpenSeadragon
*/
$.Viewport = function( options ) {
//backward compatibility for positional args while prefering more
//backward compatibility for positional args while prefering more
//idiomatic javascript options object as the only argument
var args = arguments;
if( args.length && args[ 0 ] instanceof $.Point ){
@ -19,14 +57,14 @@ $.Viewport = function( options ) {
//options.config and the general config argument are deprecated
//in favor of the more direct specification of optional settings
//being pass directly on the options object
//being passed directly on the options object
if ( options.config ){
$.extend( true, options, options.config );
delete options.config;
}
$.extend( true, this, {
//required settings
containerSize: null,
contentSize: null,
@ -45,22 +83,23 @@ $.Viewport = function( options ) {
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel,
minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel,
degrees: $.DEFAULT_SETTINGS.degrees
}, options );
this.centerSpringX = new $.Spring({
initial: 0,
initial: 0,
springStiffness: this.springStiffness,
animationTime: this.animationTime
});
this.centerSpringY = new $.Spring({
initial: 0,
initial: 0,
springStiffness: this.springStiffness,
animationTime: this.animationTime
});
this.zoomSpring = new $.Spring({
initial: 1,
initial: 1,
springStiffness: this.springStiffness,
animationTime: this.animationTime
});
@ -70,11 +109,12 @@ $.Viewport = function( options ) {
this.update();
};
$.Viewport.prototype = {
$.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/**
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:reset-size
*/
resetContentSize: function( contentSize ){
this.contentSize = contentSize;
@ -86,12 +126,21 @@ $.Viewport.prototype = {
this.homeBounds = new $.Rect( 0, 0, 1, this.contentAspectY );
if( this.viewer ){
this.viewer.raiseEvent( 'reset-size', {
contentSize: contentSize,
viewer: this.viewer
/**
* Raised when the viewer's content size is reset (see {@link OpenSeadragon.Viewport#resetContentSize}).
*
* @event reset-size
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.Point} contentSize
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'reset-size', {
contentSize: contentSize
});
}
return this;
},
@ -99,14 +148,14 @@ $.Viewport.prototype = {
* @function
*/
getHomeZoom: function() {
var aspectFactor =
var aspectFactor =
this.contentAspectX / this.getAspectRatio();
if( this.defaultZoomLevel ){
return this.defaultZoomLevel;
} else {
return ( aspectFactor >= 1 ) ?
1 :
return ( aspectFactor >= 1 ) ?
1 :
aspectFactor;
}
},
@ -120,9 +169,9 @@ $.Viewport.prototype = {
height = width / this.getAspectRatio();
return new $.Rect(
center.x - ( width / 2.0 ),
center.x - ( width / 2.0 ),
center.y - ( height / 2.0 ),
width,
width,
height
);
},
@ -130,12 +179,22 @@ $.Viewport.prototype = {
/**
* @function
* @param {Boolean} immediately
* @fires OpenSeadragon.Viewer.event:home
*/
goHome: function( immediately ) {
if( this.viewer ){
this.viewer.raiseEvent( 'home', {
immediately: immediately,
viewer: this.viewer
/**
* Raised when the "home" operation occurs (see {@link OpenSeadragon.Viewport#goHome}).
*
* @event home
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {Boolean} immediately
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'home', {
immediately: immediately
});
}
return this.fitBounds( this.getHomeBounds(), immediately );
@ -146,8 +205,8 @@ $.Viewport.prototype = {
*/
getMinZoom: function() {
var homeZoom = this.getHomeZoom(),
zoom = this.minZoomLevel ?
this.minZoomLevel :
zoom = this.minZoomLevel ?
this.minZoomLevel :
this.minZoomImageRatio * homeZoom;
return Math.min( zoom, homeZoom );
@ -176,13 +235,14 @@ $.Viewport.prototype = {
*/
getContainerSize: function() {
return new $.Point(
this.containerSize.x,
this.containerSize.x,
this.containerSize.y
);
},
/**
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
*/
getBounds: function( current ) {
var center = this.getCenter( current ),
@ -190,15 +250,16 @@ $.Viewport.prototype = {
height = width / this.getAspectRatio();
return new $.Rect(
center.x - ( width / 2.0 ),
center.x - ( width / 2.0 ),
center.y - ( height / 2.0 ),
width,
width,
height
);
},
/**
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
*/
getCenter: function( current ) {
var centerCurrent = new $.Point(
@ -231,8 +292,8 @@ $.Viewport.prototype = {
height = width / this.getAspectRatio();
bounds = new $.Rect(
centerCurrent.x - width / 2.0,
centerCurrent.y - height / 2.0,
width,
centerCurrent.y - height / 2.0,
width,
height
);
@ -249,6 +310,7 @@ $.Viewport.prototype = {
/**
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
*/
getZoom: function( current ) {
if ( current ) {
@ -261,11 +323,12 @@ $.Viewport.prototype = {
/**
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:constrain
*/
applyConstraints: function( immediately ) {
var actualZoom = this.getZoom(),
constrainedZoom = Math.max(
Math.min( actualZoom, this.getMaxZoom() ),
Math.min( actualZoom, this.getMaxZoom() ),
this.getMinZoom()
),
bounds,
@ -275,10 +338,8 @@ $.Viewport.prototype = {
right,
top,
bottom,
center,
dx = 0,
dy = 0,
dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0;
dy = 0;
if ( actualZoom != constrainedZoom ) {
this.zoomTo( constrainedZoom, this.zoomPoint, immediately );
@ -299,9 +360,9 @@ $.Viewport.prototype = {
} else {
if ( left < horizontalThreshold ) {
dx = horizontalThreshold - left;
}
}
if ( right < horizontalThreshold ) {
dx = dx ?
dx = dx ?
( dx + right - horizontalThreshold ) / 2 :
( right - horizontalThreshold );
}
@ -312,9 +373,9 @@ $.Viewport.prototype = {
} else {
if ( top < verticalThreshold ) {
dy = ( verticalThreshold - top );
}
}
if ( bottom < verticalThreshold ) {
dy = dy ?
dy = dy ?
( dy + bottom - verticalThreshold ) / 2 :
( bottom - verticalThreshold );
}
@ -333,9 +394,18 @@ $.Viewport.prototype = {
}
if( this.viewer ){
this.viewer.raiseEvent( 'constrain', {
immediately: immediately,
viewer: this.viewer
/**
* Raised when the viewport constraints are applied (see {@link OpenSeadragon.Viewport#applyConstraints}).
*
* @event constrain
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {Boolean} immediately
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'constrain', {
immediately: immediately
});
}
@ -360,9 +430,9 @@ $.Viewport.prototype = {
var aspect = this.getAspectRatio(),
center = bounds.getCenter(),
newBounds = new $.Rect(
bounds.x,
bounds.y,
bounds.width,
bounds.x,
bounds.y,
bounds.width,
bounds.height
),
oldBounds,
@ -388,20 +458,20 @@ $.Viewport.prototype = {
return this.panTo( center, immediately );
}
referencePoint = oldBounds.getTopLeft().times(
this.containerSize.x / oldBounds.width
referencePoint = oldBounds.getTopLeft().times(
this.containerSize.x / oldBounds.width
).minus(
newBounds.getTopLeft().times(
this.containerSize.x / newBounds.width
newBounds.getTopLeft().times(
this.containerSize.x / newBounds.width
)
).divide(
this.containerSize.x / oldBounds.width -
this.containerSize.x / oldBounds.width -
this.containerSize.x / newBounds.width
);
return this.zoomTo( newZoom, referencePoint, immediately );
},
/**
* @function
@ -437,8 +507,8 @@ $.Viewport.prototype = {
var center = this.getCenter();
if ( this.wrapHorizontal ) {
center.x = (
this.contentAspectX + ( center.x % this.contentAspectX )
center.x = (
this.contentAspectX + ( center.x % this.contentAspectX )
) % this.contentAspectX;
this.centerSpringX.resetTo( center.x );
this.centerSpringX.update();
@ -459,12 +529,14 @@ $.Viewport.prototype = {
* @param {OpenSeadragon.Point} delta
* @param {Boolean} immediately
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:pan
*/
panBy: function( delta, immediately ) {
var center = new $.Point(
this.centerSpringX.target.value,
this.centerSpringY.target.value
);
delta = delta.rotate( -this.degrees, new $.Point( 0, 0 ) );
return this.panTo( center.plus( delta ), immediately );
},
@ -473,6 +545,7 @@ $.Viewport.prototype = {
* @param {OpenSeadragon.Point} center
* @param {Boolean} immediately
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:pan
*/
panTo: function( center, immediately ) {
if ( immediately ) {
@ -484,10 +557,20 @@ $.Viewport.prototype = {
}
if( this.viewer ){
this.viewer.raiseEvent( 'pan', {
/**
* Raised when the viewport is panned (see {@link OpenSeadragon.Viewport#panBy} and {@link OpenSeadragon.Viewport#panTo}).
*
* @event pan
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.Point} center
* @property {Boolean} immediately
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'pan', {
center: center,
immediately: immediately,
viewer: this.viewer
immediately: immediately
});
}
@ -497,33 +580,54 @@ $.Viewport.prototype = {
/**
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:zoom
*/
zoomBy: function( factor, refPoint, immediately ) {
if( refPoint instanceof $.Point && !isNaN( refPoint.x ) && !isNaN( refPoint.y ) ) {
refPoint = refPoint.rotate(
-this.degrees,
new $.Point( this.centerSpringX.target.value, this.centerSpringY.target.value )
);
}
return this.zoomTo( this.zoomSpring.target.value * factor, refPoint, immediately );
},
/**
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:zoom
*/
zoomTo: function( zoom, refPoint, immediately ) {
this.zoomPoint = refPoint instanceof $.Point ?
refPoint :
this.zoomPoint = refPoint instanceof $.Point &&
!isNaN(refPoint.x) &&
!isNaN(refPoint.y) ?
refPoint :
null;
if ( immediately ) {
this.zoomSpring.resetTo( zoom );
} else {
} else {
this.zoomSpring.springTo( zoom );
}
if( this.viewer ){
this.viewer.raiseEvent( 'zoom', {
/**
* Raised when the viewport zoom level changes (see {@link OpenSeadragon.Viewport#zoomBy} and {@link OpenSeadragon.Viewport#zoomTo}).
*
* @event zoom
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {Number} zoom
* @property {OpenSeadragon.Point} refPoint
* @property {Boolean} immediately
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'zoom', {
zoom: zoom,
refPoint: refPoint,
immediately: immediately,
viewer: this.viewer
immediately: immediately
});
}
@ -531,29 +635,73 @@ $.Viewport.prototype = {
},
/**
* Currently only 90 degree rotation is supported and it only works
* with the canvas. Additionally, the navigator does not rotate yet,
* debug mode doesn't rotate yet, and overlay rotation is only
* partially supported.
* @function
* @return {OpenSeadragon.Viewport} Chainable.
*/
setRotation: function( degrees ) {
if( !( this.viewer && this.viewer.drawer.canRotate() ) ) {
return this;
}
degrees = ( degrees + 360 ) % 360;
if( degrees % 90 !== 0 ) {
throw new Error('Currently only 0, 90, 180, and 270 degrees are supported.');
}
this.degrees = degrees;
this.viewer.forceRedraw();
return this;
},
/**
* Gets the current rotation in degrees.
* @function
* @return {Number} The current rotation in degrees.
*/
getRotation: function() {
return this.degrees;
},
/**
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:resize
*/
resize: function( newContainerSize, maintain ) {
var oldBounds = this.getBounds(),
newBounds = oldBounds,
widthDeltaFactor = newContainerSize.x / this.containerSize.x;
widthDeltaFactor;
this.containerSize = new $.Point(
newContainerSize.x,
newContainerSize.x,
newContainerSize.y
);
if (maintain) {
if ( maintain ) {
widthDeltaFactor = newContainerSize.x / this.containerSize.x;
newBounds.width = oldBounds.width * widthDeltaFactor;
newBounds.height = newBounds.width / this.getAspectRatio();
}
if( this.viewer ){
this.viewer.raiseEvent( 'resize', {
/**
* Raised when the viewer is resized (see {@link OpenSeadragon.Viewport#resize}).
*
* @event resize
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.Point} newContainerSize
* @property {Boolean} maintain
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'resize', {
newContainerSize: newContainerSize,
maintain: maintain,
viewer: this.viewer
maintain: maintain
});
}
@ -599,7 +747,9 @@ $.Viewport.prototype = {
/**
* Convert a delta (translation vector) from pixels coordinates to viewport coordinates
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
*/
deltaPixelsFromPoints: function( deltaPoints, current ) {
return deltaPoints.times(
@ -608,7 +758,9 @@ $.Viewport.prototype = {
},
/**
* Convert a delta (translation vector) from viewport coordinates to pixels coordinates.
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
*/
deltaPointsFromPixels: function( deltaPixels, current ) {
return deltaPixels.divide(
@ -617,7 +769,9 @@ $.Viewport.prototype = {
},
/**
* Convert image pixel coordinates to viewport coordinates.
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
*/
pixelFromPoint: function( point, current ) {
var bounds = this.getBounds( current );
@ -629,7 +783,9 @@ $.Viewport.prototype = {
},
/**
* Convert viewport coordinates to image pixel coordinates.
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
*/
pointFromPixel: function( pixel, current ) {
var bounds = this.getBounds( current );
@ -641,34 +797,65 @@ $.Viewport.prototype = {
},
/**
* Translates from Seajax viewer coordinate
* system to image coordinate system
* Translates from OpenSeadragon viewer coordinate system to image coordinate system.
* This method can be called either by passing X,Y coordinates or an
* OpenSeadragon.Point
* @function
* @param {OpenSeadragon.Point} viewerX the point in viewport coordinate system.
* @param {Number} viewerX X coordinate in viewport coordinate system.
* @param {Number} viewerY Y coordinate in viewport coordinate system.
* @return {OpenSeadragon.Point} a point representing the coordinates in the image.
*/
viewportToImageCoordinates: function(viewerX, viewerY) {
return new $.Point(viewerX * this.contentSize.x, viewerY * this.contentSize.y * this.contentAspectX);
viewportToImageCoordinates: function( viewerX, viewerY ) {
if ( arguments.length == 1 ) {
//they passed a point instead of individual components
return this.viewportToImageCoordinates( viewerX.x, viewerX.y );
}
return new $.Point( viewerX * this.contentSize.x, viewerY * this.contentSize.y * this.contentAspectX );
},
/**
* Translates from image coordinate system to
* Seajax viewer coordinate system
* Translates from image coordinate system to OpenSeadragon viewer coordinate system
* This method can be called either by passing X,Y coordinates or an
* OpenSeadragon.Point
* @function
* @param {OpenSeadragon.Point} imageX the point in image coordinate system.
* @param {Number} imageX X coordinate in image coordinate system.
* @param {Number} imageY Y coordinate in image coordinate system.
* @return {OpenSeadragon.Point} a point representing the coordinates in the viewport.
*/
imageToViewportCoordinates: function( imageX, imageY ) {
return new $.Point( imageX / this.contentSize.x, imageY / this.contentSize.y / this.contentAspectX);
if ( arguments.length == 1 ) {
//they passed a point instead of individual components
return this.imageToViewportCoordinates( imageX.x, imageX.y );
}
return new $.Point( imageX / this.contentSize.x, imageY / this.contentSize.y / this.contentAspectX );
},
/**
* Translates from a rectanlge which describes a portion of
* the image in pixel coordinates to OpenSeadragon viewport
* rectangle coordinates.
* Translates from a rectangle which describes a portion of the image in
* pixel coordinates to OpenSeadragon viewport rectangle coordinates.
* This method can be called either by passing X,Y,width,height or an
* OpenSeadragon.Rect
* @function
* @param {OpenSeadragon.Rect} imageX the rectangle in image coordinate system.
* @param {Number} imageX the X coordinate of the top left corner of the rectangle
* in image coordinate system.
* @param {Number} imageY the Y coordinate of the top left corner of the rectangle
* in image coordinate system.
* @param {Number} pixelWidth the width in pixel of the rectangle.
* @param {Number} pixelHeight the height in pixel of the rectangle.
*/
imageToViewportRectangle: function( imageX, imageY, pixelWidth, pixelHeight ) {
var coordA,
coordB,
rect;
if( arguments.length == 1 ){
if( arguments.length == 1 ) {
//they passed a rectangle instead of individual components
rect = imageX;
return this.imageToViewportRectangle(rect.x, rect.y, rect.width, rect.height);
return this.imageToViewportRectangle(
rect.x, rect.y, rect.width, rect.height
);
}
coordA = this.imageToViewportCoordinates(
imageX, imageY
@ -676,12 +863,169 @@ $.Viewport.prototype = {
coordB = this.imageToViewportCoordinates(
pixelWidth, pixelHeight
);
return new $.Rect(
return new $.Rect(
coordA.x,
coordA.y,
coordA.x + coordB.x,
coordA.y + coordB.y
coordB.x,
coordB.y
);
},
/**
* Translates from a rectangle which describes a portion of
* the viewport in point coordinates to image rectangle coordinates.
* This method can be called either by passing X,Y,width,height or an
* OpenSeadragon.Rect
* @function
* @param {OpenSeadragon.Rect} viewerX the rectangle in viewport coordinate system.
* @param {Number} viewerX the X coordinate of the top left corner of the rectangle
* in viewport coordinate system.
* @param {Number} imageY the Y coordinate of the top left corner of the rectangle
* in viewport coordinate system.
* @param {Number} pointWidth the width of the rectangle in viewport coordinate system.
* @param {Number} pointHeight the height of the rectangle in viewport coordinate system.
*/
viewportToImageRectangle: function( viewerX, viewerY, pointWidth, pointHeight ) {
var coordA,
coordB,
rect;
if ( arguments.length == 1 ) {
//they passed a rectangle instead of individual components
rect = viewerX;
return this.viewportToImageRectangle(
rect.x, rect.y, rect.width, rect.height
);
}
coordA = this.viewportToImageCoordinates( viewerX, viewerY );
coordB = this.viewportToImageCoordinates( pointWidth, pointHeight );
return new $.Rect(
coordA.x,
coordA.y,
coordB.x,
coordB.y
);
},
/**
* Convert pixel coordinates relative to the viewer element to image
* coordinates.
* @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point}
*/
viewerElementToImageCoordinates: function( pixel ) {
var point = this.pointFromPixel( pixel, true );
return this.viewportToImageCoordinates( point );
},
/**
* Convert pixel coordinates relative to the image to
* viewer element coordinates.
* @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point}
*/
imageToViewerElementCoordinates: function( pixel ) {
var point = this.imageToViewportCoordinates( pixel );
return this.pixelFromPoint( point, true );
},
/**
* Convert pixel coordinates relative to the window to image coordinates.
* @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point}
*/
windowToImageCoordinates: function( pixel ) {
var viewerCoordinates = pixel.minus(
OpenSeadragon.getElementPosition( this.viewer.element ));
return this.viewerElementToImageCoordinates( viewerCoordinates );
},
/**
* Convert image coordinates to pixel coordinates relative to the window.
* @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point}
*/
imageToWindowCoordinates: function( pixel ) {
var viewerCoordinates = this.imageToViewerElementCoordinates( pixel );
return viewerCoordinates.plus(
OpenSeadragon.getElementPosition( this.viewer.element ));
},
/**
* Convert pixel coordinates relative to the viewer element to viewport
* coordinates.
* @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point}
*/
viewerElementToViewportCoordinates: function( pixel ) {
return this.pointFromPixel( pixel, true );
},
/**
* Convert viewport coordinates to pixel coordinates relative to the
* viewer element.
* @param {OpenSeadragon.Point} point
* @returns {OpenSeadragon.Point}
*/
viewportToViewerElementCoordinates: function( point ) {
return this.pixelFromPoint( point, true );
},
/**
* Convert pixel coordinates relative to the window to viewport coordinates.
* @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point}
*/
windowToViewportCoordinates: function( pixel ) {
var viewerCoordinates = pixel.minus(
OpenSeadragon.getElementPosition( this.viewer.element ));
return this.viewerElementToViewportCoordinates( viewerCoordinates );
},
/**
* Convert viewport coordinates to pixel coordinates relative to the window.
* @param {OpenSeadragon.Point} point
* @returns {OpenSeadragon.Point}
*/
viewportToWindowCoordinates: function( point ) {
var viewerCoordinates = this.viewportToViewerElementCoordinates( point );
return viewerCoordinates.plus(
OpenSeadragon.getElementPosition( this.viewer.element ));
},
/**
* Convert a viewport zoom to an image zoom.
* Image zoom: ratio of the original image size to displayed image size.
* 1 means original image size, 0.5 half size...
* Viewport zoom: ratio of the displayed image's width to viewport's width.
* 1 means identical width, 2 means image's width is twice the viewport's width...
* @function
* @param {Number} viewportZoom The viewport zoom
* target zoom.
* @returns {Number} imageZoom The image zoom
*/
viewportToImageZoom: function( viewportZoom ) {
var imageWidth = this.viewer.source.dimensions.x;
var containerWidth = this.getContainerSize().x;
var viewportToImageZoomRatio = containerWidth / imageWidth;
return viewportZoom * viewportToImageZoomRatio;
},
/**
* Convert an image zoom to a viewport zoom.
* Image zoom: ratio of the original image size to displayed image size.
* 1 means original image size, 0.5 half size...
* Viewport zoom: ratio of the displayed image's width to viewport's width.
* 1 means identical width, 2 means image's width is twice the viewport's width...
* @function
* @param {Number} imageZoom The image zoom
* target zoom.
* @returns {Number} viewportZoom The viewport zoom
*/
imageToViewportZoom: function( imageZoom ) {
var imageWidth = this.viewer.source.dimensions.x;
var containerWidth = this.getContainerSize().x;
var viewportToImageZoomRatio = imageWidth / containerWidth;
return imageZoom * viewportToImageZoomRatio;
}
};

View File

@ -1,115 +1,303 @@
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
(function() {
var viewer;
// TODO: Tighten up springs and use "immediate" where possible, so tests run faster
// TODO: Test drag
module('Basic', {
setup: function () {
var example = $('<div id="example"></div>').appendTo("#qunit-fixture");
var viewer = null;
testLog.reset();
// ----------
asyncTest('Open', function() {
$(document).ready(function() {
viewer = OpenSeadragon({
id: 'example',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
showNavigator: true
springStiffness: 100 // Faster animation = faster tests
});
},
teardown: function () {
if (viewer && viewer.close) {
viewer.close();
}
ok(viewer, 'Viewer exists');
viewer = null;
}
});
var openHandler = function(eventSender, eventData) {
viewer.removeHandler('open', openHandler);
ok(true, 'Open event was sent');
equal(eventSender, viewer, 'Sender of open event was viewer');
ok(eventData, 'Handler also received event data');
ok(viewer.viewport, 'Viewport exists');
start();
};
// ----------
asyncTest('Open', function() {
ok(viewer, 'Viewer exists');
viewer.addHandler('open', openHandler);
var openHandler = function(event) {
viewer.removeHandler('open', openHandler);
ok(true, 'Open event was sent');
ok(event, 'Handler received event data');
equal(event.eventSource, viewer, 'Sender of open event was viewer');
ok(viewer.viewport, 'Viewport exists');
ok(viewer.source, 'source exists');
ok(viewer._updateRequestId, 'timer is on');
start();
};
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('Open Error Handling', function() {
ok(viewer, 'Viewer exists');
viewer.addHandler('open', function(event) {
ok(false, "The open event should not fire for failed opens");
start();
});
viewer.addHandler('open-failed', function(event) {
ok(true, "The open-failed event should be fired when the source 404s");
equal($(".openseadragon-message").length, 1, "Open failures should display a message");
ok(testLog.log.contains('["AJAX request returned %s: %s",404,"/test/data/not-a-real-file"]'),
"AJAX failures should be logged to the console");
start();
});
viewer.open('/test/data/not-a-real-file');
});
// ----------
asyncTest('Zoom', function() {
var viewport = viewer.viewport;
equal(viewport.getZoom(), 1, 'We start out unzoomed');
viewer.addHandler("open", function () {
var viewport = viewer.viewport;
var zoomHandler = function() {
viewer.removeHandler('animationfinish', zoomHandler);
equal(viewport.getZoom(), 2, 'Zoomed correctly');
start();
};
equal(viewport.getZoom(), 1, 'We start out unzoomed');
viewer.addHandler('animationfinish', zoomHandler);
viewport.zoomTo(2);
var zoomHandler = function() {
viewer.removeHandler('animation-finish', zoomHandler);
equal(viewport.getZoom(), 2, 'Zoomed correctly');
start();
};
viewer.addHandler('animation-finish', zoomHandler);
viewport.zoomTo(2);
});
viewer.open('/test/data/testpattern.dzi');
});
// ----------
asyncTest('Pan', function() {
var viewport = viewer.viewport;
var center = viewport.getCenter();
ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned');
viewer.addHandler("open", function () {
var viewport = viewer.viewport,
center = viewport.getCenter();
var panHandler = function() {
viewer.removeHandler('animationfinish', panHandler);
center = viewport.getCenter();
ok(center.x === 0.1 && center.y === 0.1, 'Panned correctly');
start();
};
ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned');
viewer.addHandler('animationfinish', panHandler);
viewport.panTo(new OpenSeadragon.Point(0.1, 0.1));
var panHandler = function() {
viewer.removeHandler('animation-finish', panHandler);
center = viewport.getCenter();
ok(center.x === 0.1 && center.y === 0.1, 'Panned correctly');
start();
};
viewer.addHandler('animation-finish', panHandler);
viewport.panTo(new OpenSeadragon.Point(0.1, 0.1));
});
viewer.open('/test/data/testpattern.dzi');
});
// ----------
asyncTest('Home', function() {
var viewport = viewer.viewport;
var center = viewport.getCenter();
ok(center.x !== 0.5 && center.y !== 0.5, 'We start out panned');
notEqual(viewport.getZoom(), 1, 'We start out zoomed');
// Test setup:
function opener() {
var viewport = viewer.viewport;
viewport.panTo(new OpenSeadragon.Point(0.1, 0.1));
viewport.zoomTo(2);
}
var homeHandler = function() {
viewer.removeHandler('animationfinish', homeHandler);
center = viewport.getCenter();
ok(center.x === 0.5 && center.y === 0.5, 'We end up unpanned');
equal(viewport.getZoom(), 1, 'We end up unzoomed');
start();
};
function stage1() {
var viewport = viewer.viewport,
center = viewport.getCenter();
viewer.addHandler('animationfinish', homeHandler);
viewport.goHome(true);
viewer.removeHandler('animation-finish', stage1);
ok(center.x !== 0.5 && center.y !== 0.5, 'We start out panned');
notEqual(viewport.getZoom(), 1, 'We start out zoomed');
var homeHandler = function() {
viewer.removeHandler('animation-finish', homeHandler);
center = viewport.getCenter();
ok(center.x === 0.5 && center.y === 0.5, 'We end up unpanned');
equal(viewport.getZoom(), 1, 'We end up unzoomed');
start();
};
viewer.addHandler('animation-finish', homeHandler);
viewport.goHome(true);
}
viewer.addHandler("open", opener);
viewer.addHandler("animation-finish", stage1);
viewer.open('/test/data/testpattern.dzi');
});
// ----------
asyncTest('Click', function() {
var viewport = viewer.viewport;
center = viewport.getCenter();
ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned');
equal(viewport.getZoom(), 1, 'We start out unzoomed');
var clickHandler = function() {
viewer.removeHandler('animationfinish', clickHandler);
viewer.addHandler("open", function () {
var viewport = viewer.viewport,
center = viewport.getCenter();
ok(center.x > 0.37 && center.x < 0.38 && center.y > 0.37 && center.y < 0.38, 'Panned correctly');
equal(viewport.getZoom(), 2, 'Zoomed correctly');
start();
};
viewer.addHandler('animationfinish', clickHandler);
Util.simulateViewerClick(viewer, 0.25, 0.25);
ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned');
equal(viewport.getZoom(), 1, 'We start out unzoomed');
var clickHandler = function() {
viewer.removeHandler('animation-finish', clickHandler);
center = viewport.getCenter();
ok(center.x > 0.37 && center.x < 0.38 && center.y > 0.37 && center.y < 0.38, 'Panned correctly');
equal(viewport.getZoom(), 2, 'Zoomed correctly');
start();
};
viewer.addHandler('animation-finish', clickHandler);
Util.simulateViewerClickWithDrag( {
viewer: viewer,
widthFactor: 0.25,
heightFactor: 0.25,
dragCount: 0,
dragDx: 0,
dragDy: 0
} );
} );
viewer.open('/test/data/testpattern.dzi');
});
// ----------
asyncTest('FullPage', function() {
viewer.addHandler("open", function () {
ok(!viewer.isFullPage(), 'Started out not fullpage');
ok(!$(viewer.element).hasClass('fullpage'),
'No fullpage class on div');
var checkEnteringPreFullPage = function(event) {
viewer.removeHandler('pre-full-page', checkEnteringPreFullPage);
ok(event.fullPage, 'Switching to fullpage');
ok(!viewer.isFullPage(), 'Not yet fullpage');
};
var checkEnteringFullPage = function(event) {
viewer.removeHandler('full-page', checkEnteringFullPage);
ok(event.fullPage, 'Switched to fullpage');
ok(viewer.isFullPage(), 'Enabled fullpage');
ok($(viewer.element).hasClass('fullpage'),
'Fullpage class added to div');
var checkExitingPreFullPage = function(event) {
viewer.removeHandler('pre-full-page', checkExitingPreFullPage);
ok(!event.fullPage, 'Exiting fullpage');
ok(viewer.isFullPage(), 'Still fullpage');
};
var checkExitingFullPage = function(event) {
viewer.removeHandler('full-page', checkExitingFullPage);
ok(!event.fullPage, 'Exiting fullpage');
ok(!viewer.isFullPage(), 'Disabled fullpage');
ok(!$(viewer.element).hasClass('fullpage'),
'Fullpage class removed from div');
start();
};
viewer.addHandler("pre-full-page", checkExitingPreFullPage);
viewer.addHandler("full-page", checkExitingFullPage);
viewer.setFullPage(false);
};
viewer.addHandler("pre-full-page", checkEnteringPreFullPage);
viewer.addHandler("full-page", checkEnteringFullPage);
viewer.setFullPage(true);
});
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('FullScreen', function() {
if (!OpenSeadragon.supportsFullScreen) {
expect(0);
start();
return;
}
viewer.addHandler("open", function () {
ok(!OpenSeadragon.isFullScreen(), 'Started out not fullscreen');
var checkEnteringPreFullScreen = function(event) {
viewer.removeHandler('pre-full-screen', checkEnteringPreFullScreen);
ok(event.fullScreen, 'Switching to fullscreen');
ok(!OpenSeadragon.isFullScreen(), 'Not yet fullscreen');
};
// The fullscreen mode is always denied during tests so we are
// exiting directly.
var checkExitingFullScreen = function(event) {
viewer.removeHandler('full-screen', checkExitingFullScreen);
ok(!event.fullScreen, 'Exiting fullscreen');
ok(!OpenSeadragon.isFullScreen(), 'Disabled fullscreen');
start();
};
viewer.addHandler("pre-full-screen", checkEnteringPreFullScreen);
viewer.addHandler("full-screen", checkExitingFullScreen);
viewer.setFullScreen(true);
});
viewer.open('/test/data/testpattern.dzi');
});
// ----------
asyncTest('Close', function() {
var closeHandler = function() {
viewer.removeHandler('close', closeHandler);
ok(true, 'Close event was sent');
start();
};
viewer.addHandler("open", function () {
var closeHandler = function() {
viewer.removeHandler('close', closeHandler);
ok(!viewer.source, 'no source');
ok(true, 'Close event was sent');
ok(!viewer._updateRequestId, 'timer is off');
setTimeout(function() {
ok(!viewer._updateRequestId, 'timer is still off');
start();
}, 100);
};
viewer.addHandler('close', closeHandler);
viewer.close();
viewer.addHandler('close', closeHandler);
viewer.close();
});
viewer.open('/test/data/testpattern.dzi');
});
// ----------
asyncTest('Destroy', function() {
viewer.addHandler("open", function () {
// Check that the DOM has been modified
notEqual(0, $('#example').children().length);
var closeCalled = false;
var closeHandler = function() {
viewer.removeHandler('close', closeHandler);
closeCalled = true;
};
viewer.addHandler('close', closeHandler);
viewer.destroy();
// Check that the DOM has been cleaned up
equal(0, $('#example').children().length);
equal(null, viewer.canvas);
equal(null, viewer.keyboardCommandArea);
equal(null, viewer.container);
equal(null, viewer.element);
equal(true, closeCalled);
start();
});
viewer.open('/test/data/testpattern.dzi');
});
})();

383
test/controls.js vendored Normal file
View File

@ -0,0 +1,383 @@
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
(function () {
var viewer;
module('Controls', {
setup: function () {
var example = $('<div id="controlsTests"></div>').appendTo("#qunit-fixture");
testLog.reset();
},
teardown: function () {
if (viewer && viewer.close) {
viewer.close();
}
viewer = null;
}
});
asyncTest('ZoomControlOff', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(!viewer.showZoomControl, 'showZoomControl should be off');
ok(!viewer.zoomInButton, "zoomIn button should be null");
ok(!viewer.zoomOutButton, "zoomOut button should be null");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100, // Faster animation = faster tests
showZoomControl: false
});
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('ZoomControlOn', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(viewer.showZoomControl, 'showZoomControl should be on');
ok(!!viewer.zoomInButton, "zoomIn button should not be null");
ok(!!viewer.zoomOutButton, "zoomOut button should not be null");
notEqual(viewer.buttons.buttons.indexOf(viewer.zoomInButton), -1,
"The zoomIn button should be present");
notEqual(viewer.buttons.buttons.indexOf(viewer.zoomOutButton), -1,
"The zoomOut button should be present");
var oldZoom = viewer.viewport.getZoom();
viewer.zoomInButton.onClick();
var newZoom = viewer.viewport.getZoom();
ok(oldZoom < newZoom, "OSD should have zoomed in.");
oldZoom = newZoom;
viewer.zoomOutButton.onClick();
newZoom = viewer.viewport.getZoom();
ok(oldZoom > newZoom, "OSD should have zoomed out.");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100, // Faster animation = faster tests
showZoomControl: true
});
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('HomeControlOff', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(!viewer.showHomeControl, 'showHomeControl should be off');
ok(!viewer.homeButton, "Home button should be null");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100, // Faster animation = faster tests
showHomeControl: false
});
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('HomeControlOn', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(viewer.showHomeControl, 'showHomeControl should be on');
ok(!!viewer.homeButton, "Home button should not be null");
notEqual(viewer.buttons.buttons.indexOf(viewer.homeButton), -1,
"The home button should be present");
viewer.viewport.zoomBy(1.1);
var bounds = viewer.viewport.getBounds();
var homeBounds = viewer.viewport.getHomeBounds();
ok(bounds.x !== homeBounds.x ||
bounds.y !== homeBounds.y ||
bounds.width !== homeBounds.width ||
bounds.height !== homeBounds.height,
"OSD should not be at home.");
viewer.homeButton.onRelease();
bounds = viewer.viewport.getBounds();
ok(bounds.x === homeBounds.x &&
bounds.y === homeBounds.y &&
bounds.width === homeBounds.width &&
bounds.height === homeBounds.height, "OSD should have get home.");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100, // Faster animation = faster tests
showHomeControl: true
});
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('FullPageControlOff', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(!viewer.showFullPageControl, 'showFullPageControl should be off');
ok(!viewer.fullPageButton, "FullPage button should be null");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100, // Faster animation = faster tests
showFullPageControl: false
});
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('FullPageControlOn', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(viewer.showHomeControl, 'showFullPageControl should be on');
ok(!!viewer.fullPageButton, "FullPage button should not be null");
notEqual(viewer.buttons.buttons.indexOf(viewer.fullPageButton), -1,
"The full page button should be present");
ok(!viewer.isFullPage(), "OSD should not be in full page.");
viewer.fullPageButton.onRelease();
ok(viewer.isFullPage(), "OSD should be in full page.");
viewer.fullPageButton.onRelease();
ok(!viewer.isFullPage(), "OSD should not be in full page.");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100, // Faster animation = faster tests
showHomeControl: true
});
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('RotateControlOff', function () {
var openHandler = function (event) {
viewer.removeHandler('open', openHandler);
ok(true, 'Open event was sent');
ok(viewer.drawer, 'Drawer exists');
ok(viewer.drawer.canRotate(), 'drawer.canRotate needs to be true');
ok(!viewer.showRotationControl, 'showRotationControl should be off');
ok(!viewer.rotateLeftButton, "rotateLeft button should be null");
ok(!viewer.rotateRightButton, "rotateRight button should be null");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100, // Faster animation = faster tests
showRotationControl: false
});
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('RotateControlOn', function () {
var openHandler = function (event) {
viewer.removeHandler('open', openHandler);
ok(true, 'Open event was sent');
ok(viewer.drawer, 'Drawer exists');
ok(viewer.drawer.canRotate(), 'drawer.canRotate needs to be true');
ok(viewer.showRotationControl, 'showRotationControl should be true');
notEqual(viewer.buttons.buttons.indexOf(viewer.rotateLeftButton), -1,
"rotateLeft should be found");
notEqual(viewer.buttons.buttons.indexOf(viewer.rotateRightButton), -1,
"rotateRight should be found");
// Now simulate the left/right button clicks.
// TODO: re-factor simulateViewerClickWithDrag so it'll accept any element, and use that.
equal(viewer.viewport.degrees, 0, "Image should start at 0 degrees rotation");
viewer.rotateLeftButton.onRelease();
equal(viewer.viewport.degrees, 270, "Image should be 270 degrees rotation (left)");
viewer.rotateRightButton.onRelease();
equal(viewer.viewport.degrees, 0, "Image should be 270 degrees rotation (right)");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100, // Faster animation = faster tests
showRotationControl: true
});
viewer.addHandler('open', openHandler);
viewer.open('/test/data/testpattern.dzi');
});
asyncTest('SequenceControlOff', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(!viewer.showSequenceControl, 'showSequenceControl should be off');
ok(!viewer.previousButton, "Previous button should be null");
ok(!viewer.nextButton, "Next button should be null");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
tileSources: [
'/test/data/testpattern.dzi',
'/test/data/testpattern.dzi',
'/test/data/testpattern.dzi'
],
springStiffness: 100, // Faster animation = faster tests
showSequenceControl: false
});
viewer.addHandler('open', openHandler);
});
asyncTest('SequenceControlOnPrevNextWrapOff', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(viewer.showSequenceControl, 'showSequenceControl should be on');
ok(!!viewer.previousButton, "Previous button should not be null");
ok(!!viewer.nextButton, "Next button should not be null");
notEqual(viewer.paging.buttons.indexOf(viewer.previousButton), -1,
"The previous button should be present");
notEqual(viewer.paging.buttons.indexOf(viewer.nextButton), -1,
"The next button should be present");
equal(viewer.currentPage(), 0, "OSD should open on first page.");
ok(viewer.previousButton.element.disabled,
"Previous should be disabled on first page.");
ok(!viewer.nextButton.element.disabled,
"Next should be enabled on first page.");
viewer.nextButton.onRelease();
equal(viewer.currentPage(), 1, "OSD should be on second page.");
ok(!viewer.previousButton.element.disabled,
"Previous should be enabled on second page.");
ok(!viewer.nextButton.element.disabled,
"Next should be enabled on second page.");
viewer.nextButton.onRelease();
equal(viewer.currentPage(), 2, "OSD should be on third page.");
ok(!viewer.previousButton.element.disabled,
"Previous should be enabled on third page.");
ok(viewer.nextButton.element.disabled,
"Next should be disabled on third page.");
viewer.previousButton.onRelease();
equal(viewer.currentPage(), 1, "OSD should be on second page.");
ok(!viewer.previousButton.element.disabled,
"Previous should be enabled on second page.");
ok(!viewer.nextButton.element.disabled,
"Next should be enabled on second page.");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
tileSources: [
'/test/data/testpattern.dzi',
'/test/data/testpattern.dzi',
'/test/data/testpattern.dzi'
],
springStiffness: 100, // Faster animation = faster tests
showSequenceControl: true,
navPrevNextWrap: false
});
viewer.addHandler('open', openHandler);
});
asyncTest('SequenceControlOnPrevNextWrapOn', function () {
var openHandler = function () {
viewer.removeHandler('open', openHandler);
ok(viewer.showSequenceControl, 'showSequenceControl should be on');
ok(!!viewer.previousButton, "Previous button should not be null");
ok(!!viewer.nextButton, "Next button should not be null");
notEqual(viewer.paging.buttons.indexOf(viewer.previousButton), -1,
"The previous button should be present");
notEqual(viewer.paging.buttons.indexOf(viewer.nextButton), -1,
"The next button should be present");
equal(viewer.currentPage(), 0, "OSD should open on first page.");
ok(!viewer.previousButton.element.disabled,
"Previous should be enabled on first page.");
ok(!viewer.nextButton.element.disabled,
"Next should be enabled on first page.");
viewer.previousButton.onRelease();
equal(viewer.currentPage(), 2, "OSD should be on third page.");
ok(!viewer.previousButton.element.disabled,
"Previous should be enabled on third page.");
ok(!viewer.nextButton.element.disabled,
"Next should be enabled on third page.");
viewer.nextButton.onRelease();
equal(viewer.currentPage(), 0, "OSD should be on first page.");
ok(!viewer.previousButton.element.disabled,
"Previous should be enabled on first page.");
ok(!viewer.nextButton.element.disabled,
"Next should be enabled on first page.");
viewer.close();
start();
};
viewer = OpenSeadragon({
id: 'controlsTests',
prefixUrl: '/build/openseadragon/images/',
tileSources: [
'/test/data/testpattern.dzi',
'/test/data/testpattern.dzi',
'/test/data/testpattern.dzi'
],
springStiffness: 100, // Faster animation = faster tests
showSequenceControl: true,
navPrevNextWrap: true
});
viewer.addHandler('open', openHandler);
});
})();

BIN
test/data/A.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
test/data/BBlue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
test/data/CCyan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
test/data/DDandelion.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

26
test/data/iiif1_0.json Normal file
View File

@ -0,0 +1,26 @@
{
"identifier": "iiif_1_0_files",
"width": 775,
"height": 1024,
"scale_factors": [
1,
2,
3,
4,
5,
6
],
"tile_width": 256,
"tile_height": 256,
"formats": [
"jpg",
"png"
],
"qualities": [
"native",
"bitonal",
"grey",
"color"
],
"profile": "http://library.stanford.edu/iiif/image-api/compliance.html#level1"
}

26
test/data/iiif1_0.xml Normal file
View File

@ -0,0 +1,26 @@
<info xmlns="http://library.stanford.edu/iiif/image-api/ns/">
<identifier>iiif_1_0_files</identifier>
<width>775</width>
<height>1024</height>
<scale_factors>
<scale_factor>1</scale_factor>
<scale_factor>2</scale_factor>
<scale_factor>3</scale_factor>
<scale_factor>4</scale_factor>
<scale_factor>5</scale_factor>
<scale_factor>6</scale_factor>
</scale_factors>
<tile_width>256</tile_width>
<tile_height>256</tile_height>
<formats>
<format>jpg</format>
<format>png</format>
</formats>
<qualities>
<quality>native</quality>
<quality>bitonal</quality>
<quality>grey</quality>
<quality>color</quality>
</qualities>
<profile>http://library.stanford.edu/iiif/image-api/compliance.html#level1</profile>
</info>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Some files were not shown because too many files have changed in this diff Show More