Compare commits

...

937 commits

Author SHA1 Message Date
Ian Gilman
99fcb408fe Changelog for #2702 2025-04-02 09:36:33 -07:00
Ian Gilman
479ef0ec82
Merge pull request #2702 from achu1998/expose-nav-button
Exposed Zoom In and Out methods for end users
2025-04-02 09:33:44 -07:00
achu1998
9e01a1e18b Made changes according to review. 2025-04-01 11:04:04 +10:30
achu1998
2e3f0923f5 Explicitly bind 'this' to the Viewer instance 2025-03-29 14:17:54 +10:30
achu1998
3550dfafd3 Refactored code to minimise the changes required 2025-03-29 13:47:02 +10:30
achu1998
12de02938a Exposed Zoom In and Out methods for end users 2025-03-29 13:33:25 +10:30
Ian Gilman
8f093f54df Changelog and minor fixes for #2698 2025-03-26 09:44:50 -07:00
Ian Gilman
6bdd186219
Merge pull request #2698 from lokaesshwar/duplicate_ids_overlay_html_2682
Duplicate ids overlay html 2682
2025-03-26 09:36:17 -07:00
lokaesshwar
c54c292873 Fix #2682: Ensure unique ID for overlay wrapper to prevent duplicate IDs 2025-03-26 19:38:02 +05:30
lokaesshwar
4c7d9a2ffa Resolved Duplicate IDs in overlay HTML 2025-03-14 00:35:22 +05:30
Ian Gilman
595066abd1 Changelog for #2690 2025-03-12 09:32:08 -07:00
Ian Gilman
b4e14d4804
Merge pull request #2690 from MichaelWGibson/load-area-fixes
Make load code more robust to out of image panning
2025-03-12 09:31:08 -07:00
Michael Gibson
be87b47469 Make load code more robust to out of image panning 2025-03-10 11:19:44 -06:00
Ian Gilman
62fa378f51 Changelog for #2686 2025-03-10 10:04:26 -07:00
Ian Gilman
c386eca94d
Merge pull request #2686 from MichaelWGibson/animation-dest-tile-loading
During animations, load tiles in the destination region
2025-03-10 09:59:12 -07:00
Michael Gibson
8c6d1f4f88 Update documentation to match new flag behavior 2025-03-07 21:21:40 -07:00
Michael Gibson
3cb5152905 Change flag name 2025-03-07 21:18:42 -07:00
Michael Gibson
5cc76737b4 Fix flag type 2025-02-28 15:37:13 -07:00
Michael Gibson
f312bae614 Document flag 2025-02-28 15:35:25 -07:00
Michael Gibson
97d388be7d Add loadTilesOnAnimationPath flag 2025-02-28 11:30:30 -07:00
Michael Gibson
fd27327737 Factor out common traversal code 2025-02-28 11:10:29 -07:00
Michael Gibson
5c60f669ec Clean up 2025-02-28 09:33:49 -07:00
Michael Gibson
6ceac75b7a During animations, load tiles in the destination region 2025-02-28 09:17:41 -07:00
Ian Gilman
2387c3afd5 Stopped sponsor images from wrapping 2025-01-31 09:51:18 -08:00
Ian Gilman
5184ed6c9f Changelog for #2676 2025-01-31 09:40:00 -08:00
Ian Gilman
b22b689dae
Merge pull request #2676 from bennlich/patch-1
Update viewer.addOverlay doc
2025-01-31 09:38:38 -08:00
Benny Lichtner
138215e22f
delete trailing whitepsace 2025-01-30 20:12:05 +01:00
Ian Gilman
22e766bd1a Trimming sponsor logos 2025-01-30 09:37:34 -08:00
Benny Lichtner
337af91373
Update viewer.addOverlay doc
Mention the preserveOverlays option
2025-01-30 14:45:30 +01:00
Ian Gilman
ced1bde338 Changelog for #2643 2025-01-23 09:45:25 -08:00
Ian Gilman
dbc72d4d98
Merge pull request #2643 from RationAI/fix/fallback-canvas-drawer
Flexible support for drawers to modify cache
2025-01-23 09:37:52 -08:00
Aiosa
994f0e25a4 Fix renaming also in tests. 2025-01-14 12:26:28 +01:00
Aiosa
71c3c8437a Rename new drawer base api to reflect that it deals with internal cache. 2025-01-14 12:20:39 +01:00
Aiosa
6e81bedc39 Improve docs, change order of calls in prepareForRendering for better code stability. 2025-01-14 12:14:28 +01:00
Ian Gilman
a9562fbb64
Improved sponsor logo styling 2025-01-13 09:57:54 -08:00
Ian Gilman
b4c7e75109 Merge branch 'master' of github.com:openseadragon/openseadragon 2025-01-13 09:47:20 -08:00
Ian Gilman
301191a0b8 Actually adding the logos 2025-01-13 09:46:57 -08:00
Ian Gilman
edb422007c
Merge pull request #2661 from openseadragon/ian
Additional sponsor logos
2025-01-13 09:45:09 -08:00
Ian Gilman
f8aad5f237 Additional sponsor logos 2025-01-13 09:44:18 -08:00
Aiosa
1286fa4549 Test drawers collide with drawer render testing - remove after cache tests. 2025-01-10 22:13:16 +01:00
Aiosa
03b7c5b9a6 Update tests, fix async cache bug - first convert to supported format, then process. Record drawer ID in the internal cache type. 2025-01-10 22:05:16 +01:00
Ian Gilman
7dfde9da3a Changelog for #2644 2025-01-10 09:53:09 -08:00
Ian Gilman
ffe12888cf
Merge pull request #2644 from RationAI/feat/import
Import Openseadragon Dynamically
2025-01-10 09:51:54 -08:00
Ian Gilman
8b30e7a307 Changelog for #2657 2025-01-10 09:34:25 -08:00
Ian Gilman
306adb9b6a
Merge pull request #2657 from cff29546/master
use unique hash for MouseTracker
2025-01-10 09:32:12 -08:00
Aiosa
226a44c498 Fix docs. 2025-01-10 14:57:41 +01:00
Aiosa
b1feb367b8 Fix typo. 2025-01-10 14:49:59 +01:00
Aiosa
cb06a5c0fb Debug fallback to canvas drawer, small bugfixes, add support for drawer cleanup in cache. 2025-01-10 14:46:52 +01:00
Ian Gilman
9b8b4c2728 Changelog for #2652 2025-01-09 10:06:05 -08:00
Ian Gilman
d6740dab25 Merge branch 'master' of github.com:openseadragon/openseadragon 2025-01-09 10:04:58 -08:00
Ian Gilman
003dd3a9da
Merge pull request #2652 from pearcetm/fix-2651
Mark tiled image as needing update when opacity changes
2025-01-09 10:02:35 -08:00
Ian Gilman
a1fa790e19 Changelog for #2649 2025-01-09 09:45:33 -08:00
Ian Gilman
3aaa8fa721
Merge pull request #2649 from Seafret/master
Fixed issue with MouseTracker where hasGestureHandlers and hasScrollHandler values were not getting updated upon dynamically adding/removing handlers.
2025-01-09 09:42:51 -08:00
Min Xiang
39671f4d78 use unique hash for MouseTracker 2025-01-09 07:53:05 +08:00
Aiosa
426700b1c6 Temporarily disable tests - discussing design. 2025-01-07 19:57:37 +01:00
Aiosa
6315662078 DrawerBase API for internal cache. 2025-01-07 19:56:21 +01:00
Ian Gilman
e193557e56 Changelog for #2636 2025-01-06 09:45:36 -08:00
Ian Gilman
b8b6a9656a
Merge pull request #2636 from pcram-techcyte/v5.0.1-hasTransparency-fix
Typo in hasTransparency check in webgldrawer
2025-01-06 09:42:55 -08:00
Tom
f5f9eab200 mark tiled image as needing an update when opacity changes 2025-01-06 09:40:23 -05:00
Tom
3f22b6aa3a mark tiled image as needing an update when opacity changes 2025-01-06 09:39:28 -05:00
Jessica R.
641e085259
Updated MouseTracker's hasGestureHandlers and hasScrollHandler to be getters 2025-01-02 23:07:13 -07:00
Jessica R.
9527f15f52
Changed hasScrollHandler to be a function to better work with dynamically added handlers
Previously, we were setting hasScrollHandler once in the constructor and never re-assigning it after the initial creation. Changing hasScrollHandler to a function better accommodates dynamically added/removed handlers. See previous commit for change to hasGestureHandlers for further details and reasoning.
2025-01-01 22:45:12 -07:00
Jessica R.
865c3884b2
Changed hasGestureHandlers to be a function to better work with dynamically added handlers
Previously, we were setting hasGestureHandlers once in the constructor and never re-assigning it after the initial creation. This resulted in MouseTrackers created without gesture handlers never updating its hasGestureHandlers values, even when gesture handlers were dynamically added after creation. By changing this to a function, our MouseTrackers' hasGestureHandlers value should always be in the proper state, even if handlers are dynamically created or removed.
2025-01-01 22:38:48 -07:00
Ian Gilman
56d0d982da Changelog for #2640 2024-12-20 09:32:24 -08:00
Ian Gilman
58f4e6a36e
Merge pull request #2640 from harshkg23/master
Refactor assessNumericValue for improved clarity and debugging
2024-12-20 09:28:11 -08:00
Paul Cram
ef0f14a03d Revert "Add useTwoPassRendering as an option to the webgl drawer"
This reverts commit 55f53e8369.
2024-12-19 15:32:00 -05:00
Harsh Kumar Gupta
d31562e34f Fix the function arguments for the required file 2024-12-20 00:31:40 +05:30
Aiosa
ad943e5472 feat: ability to attach OSD to window reference if available 2024-12-19 16:22:50 +01:00
Aiosa
4c2b0715af fix: typo 2024-12-19 16:20:50 +01:00
Aiosa
a5c569ab5d fix: reference to the cpuData on webgldrawer 2024-12-19 16:11:53 +01:00
Harsh Kumar Gupta
8fdd639bf0 Rename parameters in helper functions for clarity and consistency 2024-12-19 16:30:04 +05:30
Harsh Kumar Gupta
a0fcfc20ad Correct function names in test helpers for consistency 2024-12-19 16:12:27 +05:30
Harsh Kumar Gupta
15627ee18e Bump version to 5.0.1 and update argument names for clarity in helper functions 2024-12-19 15:52:14 +05:30
Harsh Kumar Gupta
33c3d4b380 Corrected arguments name and fixed the identation issue 2024-12-19 15:24:34 +05:30
Harsh Kumar Gupta
74ffb66f40 Refactor test helper functions for improved readability and consistency 2024-12-18 00:53:44 +05:30
Paul Cram
55f53e8369 Add useTwoPassRendering as an option to the webgl drawer 2024-12-17 10:36:31 -05:00
pcram-techcyte
acb7563257
Merge branch 'openseadragon:master' into v5.0.1-hasTransparency-fix 2024-12-17 09:01:36 -05:00
Ian Gilman
c06e719198 Changelog for #2407 2024-12-16 09:30:47 -08:00
Ian Gilman
64bb7e25c7
Merge pull request #2407 from RationAI/cache-overhaul-reviewed
Cache Overhaul for OpenSeadragon (reviewed).
2024-12-16 09:26:13 -08:00
Aiosa
c392f2d205 Change location of logos, add link 2024-12-12 19:28:58 +01:00
pcram-techcyte
45bd3f48f9
Typo in hasTransparency check 2024-12-10 09:12:39 -05:00
Aiosa
bee3c243fb Delete demos with old plugins. 2024-12-10 14:38:34 +01:00
Aiosa
563c7674c7 Add sponsors section to README. 2024-12-10 14:37:30 +01:00
Aiosa
fec033f9d2 Clear up few todos, introduce tile processing promise to await single tiles. 2024-12-10 14:16:19 +01:00
Aiosa
e12a349f52 Merge branch 'temporary-merge' into cache-overhaul-reviewed 2024-12-10 13:51:56 +01:00
Aiosa
bee5cb2471 Merge conflicts from master. 2024-12-10 13:50:41 +01:00
Ian Gilman
c8c7b481b8 Started on version 6 2024-12-09 09:37:19 -08:00
Ian Gilman
480de92d0a Version 5.0.1 2024-12-09 09:31:27 -08:00
Ian Gilman
e9dd9e9dfc Changelog for #2627 2024-12-06 09:32:44 -08:00
Ian Gilman
07502e6d58
Merge pull request #2627 from pearcetm/pixel-density-change
Fix #2623
2024-12-06 09:30:41 -08:00
Tom
1843bbd89c update docs 2024-12-04 16:42:25 -05:00
Tom
a5987db8d5 fix #2623 2024-12-04 16:41:24 -05:00
Aiosa
039ffbd37a Fix typo 2024-12-04 09:16:04 +01:00
Aiosa
1a7a5ee1d6 Respect tainted() when uploading a texture. 2024-12-04 09:08:00 +01:00
Ian Gilman
9b96707dec Changelog for #2620 2024-12-02 09:51:24 -08:00
Ian Gilman
3ce307f309
Merge pull request #2620 from sbarex/master
Update webgldrawer.js
2024-12-02 09:48:24 -08:00
Aiosa
d6bb8d3bd1 Fix typo. Remove tileSource prototype extension - adds implementation for methods that throw exceptions. 2024-11-30 10:03:39 +01:00
Aiosa
271f437568 Force prototype extension on inlined tile source. Ensure zombies are processed with invalidation before restored in the system. WebGL drawer can use canvas drawer. Add changelog updates. 2024-11-30 09:52:27 +01:00
sbarex
5438fd65e1
Update webgldrawer.js
Fixed a bug that caused a completely white image to be rendered when two-pass rendering mode was requested (required when multiple images, using transparency, or in debug mode).
2024-11-26 23:38:13 +01:00
Aiosa
85e8b381b8 Add cache clear on viewer.clear(). Add tile and viewer state checks to invalidation. Fix IIF test (timer is now built-in). 2024-11-26 15:24:51 +01:00
Aiosa
ef7628f098 Fix bug: webgl 'manual instanced rendering' return -> continue, do not count as drawn index. 2024-11-26 14:08:32 +01:00
Aiosa
17f13885c7 Add back overlapFraction logic for webgl drawer. 2024-11-26 00:48:43 +01:00
Aiosa
6b4c0f873a Add maxTilesPerFrame degradation, fix tests. 2024-11-22 13:03:16 +01:00
Aiosa
8b16628950 Write documentation fo cache/data overhaul. Rename url type to be more explicit. 2024-11-22 12:43:14 +01:00
Ian Gilman
04211fbb27 Changelog for #2619 2024-11-21 09:58:12 -08:00
Ian Gilman
3885fa7bfc
Merge pull request #2619 from jbakarich/fix/2612/incorrect-display-region-rotation
Remove displayRegion transform
2024-11-21 09:53:08 -08:00
Aiosa
f03f2a5d31 Add fixes for working smoothing in the webgl renderer. 2024-11-21 16:51:38 +01:00
Aiosa
ce4b16616d Merge branch 'openseadragon-master' into cache-overhaul-reviewed 2024-11-21 16:13:36 +01:00
Aiosa
af9bf9e07f Resolve conflicts, implement setImageSmoothingEnabled on webgl drawer by invalidation routine. 2024-11-21 16:12:52 +01:00
Aiosa
1851405fcf Remove warning from cache attaching if the tile has already reference. 2024-11-21 15:48:11 +01:00
Aiosa
0bc7deccd7 Fixed tests & bugs for the new design of invalidation inside events. 2024-11-21 15:35:27 +01:00
Jacob Bakarich
2dc0e29647 Remove displayRegion transform
ref #2612

- Remove display region transform in `setFlip()` as it is not needed for flipping and was overriding existing rotation transforms.
2024-11-20 14:07:26 -07:00
Ian Gilman
0e3abe16f4 Changelog for #2615 2024-11-15 09:32:07 -08:00
Ian Gilman
cd9e4e8c4e
Merge pull request #2615 from pearcetm/webgl-glnearest
Add support for imageSmoothingEnabled to WebGLDrawer
2024-11-15 09:27:18 -08:00
Tom
02805226d4 only redraw after setImageSmoothingEnabled() when changed 2024-11-14 13:13:13 -05:00
Tom
4163a46a24 Update docs 2024-11-13 16:49:54 -05:00
Tom
16dbfc62be Add support for imageSmoothingEnabled to WebGLDrawer 2024-11-13 16:43:46 -05:00
Aiosa
e24f7d1358 Update demo plugins to the new api design 2024-11-13 15:04:09 +01:00
Aiosa
541fe2e4df Redesign working cache: it is now owned by the event, not a tile. Tests are not yet updated. 2024-11-13 14:35:50 +01:00
Aiosa
e059b8982e Add try-catch for a plugin 2024-11-07 12:22:18 +01:00
Aiosa
3b1b2d6d23 Fix: reference the correct drawer in invalidation routine. 2024-11-07 12:01:02 +01:00
Aiosa
535507568f Fix docs syntax. 2024-11-05 12:06:59 +01:00
Aiosa
cc7474ec9b
Merge branch 'openseadragon:master' into cache-overhaul-reviewed 2024-11-05 18:59:34 +09:00
Aiosa
9bfdd55b2e Make tile-invalidated event before tile-loaded. Try to fix behavior of maxTilesperFrame 2024-11-05 10:58:41 +01:00
Aiosa
5fdeb382ea Increase the test timeout: it seems that 5 seconds is not enough, maybe reason for tests failing. 2024-11-01 22:20:15 +01:00
Aiosa
cf65f1a4f4 Add ability to run only a specific module from CLI. 2024-11-01 22:06:18 +01:00
Aiosa
f127014f0f Design of separated events: drop update data support for tile-loaded, use only invalidated event. 2024-11-01 21:43:12 +01:00
Ian Gilman
e1e0ec6b24 Changelog for #2606 2024-10-28 09:17:59 -07:00
Ian Gilman
faf6d19db5
Merge pull request #2606 from pearcetm/viewerMargins
Fix problem with asymmetric viewport margins in webgl drawer
2024-10-28 09:14:09 -07:00
Tom
fab607584c fix problem with asymmetric viewport margins 2024-10-25 11:15:52 -06:00
Aiosa
cd60aff5dc Fix demo further: clear tile processing logics, perform locking on tile level, delete tile if drawn process encountered _destroyed state. 2024-10-23 15:54:31 +02:00
Aiosa
207bc88aab Fix demo further: _queuedInvalidateTiles was not being used, simplify how tile cache updates are being called (but without priorities). 2024-10-23 14:37:43 +02:00
Aiosa
6cbe359398 Fix demo filtering plugin: certain guards made rendering not being properly updated. 2024-10-23 10:07:16 +02:00
Ian Gilman
82314dd4bf Changelog for #2600 2024-10-22 09:43:43 -07:00
Ian Gilman
12e4607a30
Merge pull request #2600 from pearcetm/viewerMargins
Make webgl drawer account for viewport margins
2024-10-22 09:41:40 -07:00
Aiosa
20177116e7 Integration tests: bugfixing of manipulation of tiles that share data: when tiles are loaded, when tiles are processed, also await async data preparation befre finishing the invalidation event. 2024-10-22 17:25:02 +02:00
Aiosa
e403e29312 Fix tests: bug in type equality checking 2024-10-21 12:59:21 +02:00
Aiosa
82e1160508 Clean up outdated TODO comments. 2024-10-21 11:00:23 +02:00
Aiosa
d5cdf59993 Fix styling on the plugin demo. 2024-10-21 10:00:53 +02:00
Aiosa
3c6c7e0ab7 Add plugin interaction demo. 2024-10-21 09:55:23 +02:00
Aiosa
68f0ed8901 Do not spit out warns on invalid tile unload (preemtive working cache deletion), do not ignore working cache even if __restore=true. 2024-10-21 09:00:24 +02:00
Aiosa
b3cdeabf02 Flexible timeout for tests. 2024-10-18 14:56:05 +02:00
Aiosa
0cd17abafd Clean up old comments in a test. 2024-10-18 14:40:54 +02:00
Aiosa
1e47bd6add Add cache tests, add more robust CacheRecord creation/deletion logics. Zombies now do not replace data, prevents also potential memory leak. 2024-10-18 14:38:04 +02:00
Tom
6c20101c8b make webgl drawer account for viewport margins 2024-10-17 15:06:04 -04:00
Aiosa
bf25e2f069 Minor documentation and test cleanup. 2024-10-17 13:24:11 +02:00
Aiosa
06ac68d00e Html drawer add canvas to supported formats 2024-10-17 12:17:49 +02:00
Aiosa
1b6fea72d8 Add assets for fallback compatibility filtering plugin demo. 2024-10-17 12:17:24 +02:00
Aiosa
0b63a943b6 Tests & Bugfixes: new cache tests, working cache preemptively deleted when restore() called, zombie cache had bug (restored cache had no attached tile reference and restoration failed since we relied on any existing tile on the cache to inherit state), deprecated old HTMLDrawer props on tile, rewritten HTMLDrawer to work also with cache API. 2024-10-17 12:10:04 +02:00
Aiosa
f8e5cff117 Feature/Optimization: cache can be created by a callback (async or sync), to avoid premature data creation 2024-10-16 16:31:08 +02:00
Aiosa
b6693ee50d Fixed outdated demo pages. 2024-10-16 11:12:20 +02:00
Ian Gilman
8bdc0a4146 Changelog for #2590 2024-10-08 09:26:56 -07:00
Ian Gilman
3e0e39900e
Merge pull request #2590 from pearcetm/fix-setClip
Bug fix in TiledImage.setClip
2024-10-08 09:24:41 -07:00
Tom
263a664e58 add _needsUpdate during tiledImage.setClip() 2024-10-07 18:19:38 -04:00
Aiosa
3d21ec897b Set fully loaded for reset() call on tiled image to false. Add old plugins demo to see how they behave. Remove basic2 demo as it was added by accident. 2024-10-07 11:18:36 +02:00
Aiosa
2033814227 Update documentation and minor cleanup. 2024-10-05 11:50:21 +02:00
Ian Gilman
17c34a7985 Changelog for #2582 2024-09-24 09:50:10 -07:00
Ian Gilman
53e56932bd
Merge pull request #2582 from BeebBenjamin/2576-overlay-wrapping
Fixed: removeChild on Node
2024-09-24 09:43:56 -07:00
Richard Benjamin Allen
2b010a9a59 Fixed: JQuery cannot be used to get position with wrapper 2024-09-19 21:13:28 +01:00
Richard Benjamin Allen
4d4ccb99ba Fixed: Removed unused style attributes 2024-09-18 00:16:41 +01:00
Richard Benjamin Allen
c0eae951c6 Fixed: Removed unnecessary complexity 2024-09-17 23:38:48 +01:00
Richard Benjamin Allen
b28b77fdbd FIxed: Removed unnecessary references in selectors
We can test the overlay dimensions still
2024-09-17 23:30:06 +01:00
Richard Benjamin Allen
3b99665b32 Fixed: removeChild on Node
The overlay.js code has been changed to apply a div wrapper to the overlay element as opposed to its innerHTML.
2024-09-17 12:16:00 +01:00
Ian Gilman
50d7db595b
Merge pull request #2581 from openseadragon/dependabot/npm_and_yarn/serve-static-1.16.2
Bump serve-static from 1.14.2 to 1.16.2
2024-09-16 09:47:18 -07:00
dependabot[bot]
fe7e9a3315
Bump serve-static from 1.14.2 to 1.16.2
Bumps [serve-static](https://github.com/expressjs/serve-static) from 1.14.2 to 1.16.2.
- [Release notes](https://github.com/expressjs/serve-static/releases)
- [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md)
- [Commits](https://github.com/expressjs/serve-static/compare/v1.14.2...v1.16.2)

---
updated-dependencies:
- dependency-name: serve-static
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-16 13:29:14 +00:00
Aiosa
e3af370832 Merge branch 'cache-overhaul-reviewed' of github.com:RationAI/openseadragon into cache-overhaul-reviewed 2024-08-24 10:00:09 +02:00
Aiosa
63180a1589 Simplify filtering plugin demo. 2024-08-24 09:59:18 +02:00
Aiosa
c04b6af937
Merge branch 'master' into cache-overhaul-reviewed 2024-08-24 09:53:23 +02:00
Aiosa
29b01cf1bd First visually correct design: tile invalidation event manages three caches that are shared among equal tiles (based on cache key). Works with both latest drawers and shared caches. 2024-08-24 09:49:16 +02:00
Ian Gilman
a10b9086ab Changelog for #2570 2024-08-16 09:39:04 -07:00
Ian Gilman
a9f81190dd
Merge pull request #2570 from pearcetm/resize-after-drawer-swap
Remove resize handler from viewer when webgl drawer is destroyed
2024-08-16 09:36:49 -07:00
Tom
f3b92e0562 remove resize handler when webgl drawer is destroyed 2024-08-15 17:51:06 -04:00
Aiosa
cba40f4db8 Merge branch 'cache-overhaul-reviewed' of github.com:RationAI/openseadragon into cache-overhaul-reviewed 2024-08-15 12:58:07 +02:00
Aiosa
1b6f79661b Commit before merging master v5.0 2024-08-15 12:58:01 +02:00
Aiosa
999ff30e74
Merge branch 'master' into cache-overhaul-reviewed 2024-08-15 11:53:50 +01:00
Ian Gilman
d97ba581b0 Started 5.0.1 2024-08-14 09:37:49 -07:00
Ian Gilman
f28b7fc116 Version 5.0.0 2024-08-14 09:31:15 -07:00
Ian Gilman
a803e826a3 Changelog for #2563 2024-08-05 09:28:19 -07:00
Ian Gilman
8d2fd759cc Merge branch 'master' of github.com:openseadragon/openseadragon 2024-08-05 09:26:42 -07:00
Ian Gilman
d4c9b601c8
Merge pull request #2563 from openseadragon/ms-pixelDensityRatio-docs
JSDoc comments for OpenSeadragon.getCurrentPixelDensityRatio
2024-08-05 09:26:18 -07:00
Mark Salsbery
7740accfaf Update openseadragon.js
Fix jsdoc comments for OpenSeadragon.getCurrentPixelDensityRatio
2024-08-04 15:29:12 -07:00
Ian Gilman
8f6771ba91 Changelog for #2557 and #2558 2024-07-17 09:19:32 -07:00
Ian Gilman
980deca107
Merge pull request #2558 from pearcetm/webgl-update
Mark image-unloaded and tile-ready events as private
2024-07-17 09:17:54 -07:00
Ian Gilman
2db1c2f1da
Merge pull request #2557 from pearcetm/acceleration-test
add check for missing webgl context in WebGLDrawer.isSupported()
2024-07-17 09:16:58 -07:00
Tom
b87eaf3040 mark image-unloaded and tile-ready events as private 2024-07-16 14:17:29 -04:00
Tom
37ce7cc256 add check for missing webgl context in WebGLDrawer.isSupported() 2024-07-16 14:07:27 -04:00
Ian Gilman
74b69d99de Changelog for #2546 2024-07-16 09:36:24 -07:00
Ian Gilman
819d4cb20c
Merge pull request #2546 from BeebBenjamin/flip-overlay
Fixed: Invert overlay scale and rotate on flip
2024-07-16 09:30:02 -07:00
Richard Benjamin Allen
c1c1d480dd Fixed: Try renaming to something more descriptive 2024-07-16 08:38:39 +01:00
Richard Benjamin Allen
2c5d2eb7c6 Fixed: More meaning full variable and help text, innerStyle not outer 2024-07-12 20:36:11 +01:00
Richard Benjamin Allen
396fcb33a5 Fixed: Outer div added to element to allow independent flipping
An outer div has been added to the internal HTML of the overlay element to allow for independent flipping of the content.  Flipping will invert the `scaleX` value of the transform property for the style of the element.  By setting the value `overlayContentFlipped: true` in the OSD config we can flip the content in the opposite direction to the overlay, but by setting this to false we can flip the content along with the overlay.  This allows for some people who are using images in their overlay to flip the images along with the overlay.
2024-07-11 22:08:37 +01:00
Richard Benjamin Allen
176fae11e5 Fixed: Add inner div if text and invert x 2024-07-09 14:08:58 +01:00
Richard Benjamin Allen
fd9b701272 Fixed: Position.x not working on Scaled overlay 2024-07-09 10:37:51 +01:00
Ian Gilman
c0655ba370
Merge pull request #2553 from openseadragon/ms-IE11
More dropped support for IE11
2024-06-24 09:51:15 -07:00
Mark Salsbery
c08ef0ee36 Merge branch 'master' into ms-IE11 2024-06-23 16:36:59 -07:00
Mark Salsbery
fc7b942bc2 Update changelog.txt 2024-06-23 16:35:22 -07:00
Mark Salsbery
2290e5d08d More dropped support for IE11 2024-06-23 16:32:00 -07:00
Ian Gilman
ee6751e02f
Merge pull request #2548 from openseadragon/dependabot/npm_and_yarn/braces-3.0.3
Bump braces from 3.0.2 to 3.0.3
2024-06-20 09:24:13 -07:00
dependabot[bot]
3ed100d218
Bump braces from 3.0.2 to 3.0.3
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-18 23:24:55 +00:00
Richard Benjamin Allen
2c6b970f29 Fixed: Remove trailing space 2024-06-18 11:28:29 +01:00
Richard Benjamin Allen
263dc85fbd Fixed: Remove trailing spaces 2024-06-18 11:22:23 +01:00
Richard Benjamin Allen
79eecdcc76 Fixed: Remove duplicate line 2024-06-18 11:10:11 +01:00
Richard Benjamin Allen
44347fb2d0 Fixed: Invert overlay scale and rotate on flip 2024-06-18 10:57:55 +01:00
Ian Gilman
72d7c5353e
Merge pull request #2544 from openseadragon/ms-avif
Added avif to supported image formats
2024-06-17 09:35:06 -07:00
Mark Salsbery
88d7eb8c60 Update changelog.txt 2024-06-14 14:51:31 -07:00
Mark Salsbery
db0ab10428 Added avif to supported image formats (#2439) 2024-06-14 14:49:42 -07:00
Ian Gilman
fd74ea3dca Changelog for #2539 2024-06-10 09:27:44 -07:00
Ian Gilman
a96d186650
Merge pull request #2539 from eug-L/master
Fix Ajax headers not propagated to navigator
2024-06-10 09:24:05 -07:00
eug-L
35d468c4db propagate ajaxWithCredentials to navigator 2024-06-09 20:52:37 +08:00
Eugene Lu
65c727079c
Merge branch 'openseadragon:master' into master 2024-06-09 20:32:23 +08:00
Ian Gilman
feb5e13c32 Changelog for #2537 2024-06-04 09:29:40 -07:00
Ian Gilman
94954a699c Merge branch 'master' of github.com:openseadragon/openseadragon 2024-06-04 09:27:39 -07:00
Ian Gilman
3f5735be67
Merge pull request #2537 from pearcetm/fix-tile-loading
Fix sorting logic for best tiles to load
2024-06-04 09:25:12 -07:00
eug-L
834ed6ede5 fix ajax headers not propagated to navigator 2024-06-04 15:24:56 +08:00
Aiosa
0a035afc2d Merge master 2024-06-01 16:37:12 +02:00
Aiosa
cdb89ff5ad Add job queue full event. 2024-06-01 15:02:31 +02:00
Tom
65d30e7ce1 add minPixelRatio guard back in; fix tabs and spaces in comments' 2024-05-31 16:24:04 -04:00
Tom
f7c12a716b undo extra tabs before ach line introduced automatically by copy-and-pasting code 2024-05-22 18:59:19 -04:00
Tom
be30b429f8 remove unused code paths 2024-05-22 18:54:29 -04:00
Tom
3f03bd6e20 swap logic of haveDrawn and drawLevel within _updateTile 2024-05-22 17:36:16 -04:00
Tom
9ef1c5952e revert swapping order of arguments in _updateTile call to fix behavior of canvas drawer 2024-05-21 16:33:48 -04:00
Tom
5be44521b5 Fix sorting logic for best tiles to load 2024-05-21 04:30:17 -04:00
Ian Gilman
8d66acde53 Changelog for #2521 2024-04-29 10:50:35 -07:00
Ian Gilman
f3a942c522
Merge pull request #2521 from pearcetm/fix-2519
Fix #2519
2024-04-29 10:47:42 -07:00
Ian Gilman
3d54f8f686 Changelog for #2518 2024-04-29 10:41:38 -07:00
Ian Gilman
441ea71f40 Merge branch 'master' of github.com:openseadragon/openseadragon 2024-04-29 10:40:40 -07:00
Ian Gilman
d68a4024f8
Merge pull request #2518 from pearcetm/fix-canvas
Fix #2517
2024-04-29 10:38:44 -07:00
Tom
8b401e65e3 fix #2519 by checking minimumOverlapRequired on a per-tiled image basis 2024-04-28 08:38:03 -04:00
Tom
9d6a785aac add comment; clean up console.log messages from testing 2024-04-27 16:41:18 -04:00
Tom
f2c8db5db0 fix #2517 2024-04-27 16:38:30 -04:00
Ian Gilman
f8ef6818de Changelog for #2511 2024-04-12 09:24:16 -07:00
Ian Gilman
4f2bcbb1e3
Merge pull request #2511 from pearcetm/fix-canvas
Fix CanvasDrawer when viewport is flipped and a TiledImage is rotated
2024-04-12 09:19:39 -07:00
Tom
7ce5499868 fix comments 2024-04-11 12:45:11 -04:00
Ian Gilman
e809c9f198
Merge pull request #2512 from gaiborjosue/master
fix(citation): Fixed style issues for citation.cff
2024-04-11 09:32:43 -07:00
Tom
f7c8e4cf33 fix canvas drawer when viewport is flipped and tiled image is rotated. fix webgl drawer debug info when viewport is flipped. 2024-04-10 16:42:15 -04:00
Edward Gaibor
41c3abb12a
Update CITATION.cff 2024-04-10 12:35:30 -04:00
Edward Gaibor
3d97ac8ae7
Update CITATION.cff 2024-04-10 12:33:29 -04:00
Edward Gaibor
86395dfc78
Update CITATION.cff 2024-04-10 12:33:01 -04:00
Ian Gilman
49e2d7a987
Merge pull request #2509 from openseadragon/citation
Added citation file
2024-04-10 09:27:12 -07:00
Ian Gilman
5fefb8f976 Added Aseem and changed authors to chronological 2024-04-09 09:33:03 -07:00
Ian Gilman
6a4c3838c8 Added citation file 2024-04-08 09:43:16 -07:00
Ian Gilman
9f7b18adb6 Changelog for #2507 2024-04-08 09:36:39 -07:00
Ian Gilman
6ea7779318
Merge pull request #2507 from frameflare/master
chore: fix some comments
2024-04-08 09:35:11 -07:00
frameflare
0ba2f75213 Signed-off-by: frameflare <yangzenghua@outlook.com>
chore: fix some comments

Signed-off-by: frameflare <yangzenghua@outlook.com>
2024-04-07 10:50:24 +08:00
Ian Gilman
31c2c85c4f Changelog for #2506 2024-04-05 09:20:02 -07:00
Ian Gilman
0621958ca2
Merge pull request #2506 from eug-L/master
Getter & setter for Viewport.maxZoomPixelRatio
2024-04-05 09:18:22 -07:00
eug-L
4451131999 update flags for setMaxZoomPixelRatio 2024-04-05 12:47:15 +08:00
eug-L
b0926b3e69 Getter & setter for Viewport.maxZoomPixelRatio 2024-04-04 16:02:09 +08:00
Ian Gilman
63d8d63c1f Changelog for #2505 2024-04-03 09:28:56 -07:00
Ian Gilman
a2f6da52c0
Merge pull request #2505 from eug-L/imageToViewportZoom
update error message for Viewport.imageToViewportZoom
2024-04-03 09:26:24 -07:00
eug-L
5990e5649b update error message for Viewport.imageToViewportZoom 2024-04-03 23:06:42 +08:00
Ian Gilman
6a47104b4f Updated for version 4.1.1 2024-04-01 10:12:04 -07:00
Ian Gilman
9b7fc464ca Changelog for #2492 2024-03-07 09:30:00 -08:00
Ian Gilman
262d04c6c6
Merge pull request #2492 from pearcetm/fix-webgl-tilepadding
Make WebGLDrawer deal with tiles with padding
2024-03-07 09:29:19 -08:00
Ian Gilman
9a92d9e9ad Changelog for #2491 2024-03-07 09:24:47 -08:00
Ian Gilman
553795e8fa Merge branch 'master' of github.com:openseadragon/openseadragon 2024-03-07 09:23:24 -08:00
Ian Gilman
afeea19403
Merge pull request #2491 from pearcetm/fix-2490
Fix #2490
2024-03-07 09:21:59 -08:00
Tom
029a40aa21 deal with tiles that have padding 2024-03-05 15:39:54 -05:00
Tom
3e04c8854e make navigator.update's parameter optional, default to navigator.viewer.viewport 2024-03-05 13:01:42 -05:00
Aiosa
e0f442209b Fix black viewport with testing filtering demo on webgl renderer. Introduce managed mock getters for tests. 2024-03-05 10:48:07 +01:00
Tom
2cb1835533 fix docs 2024-03-04 21:32:14 -05:00
Tom
c177246675 fix #2490 2024-03-04 21:28:12 -05:00
Aiosa
e2c633a23b Small bugfixes, rename some properties. Add more redraw calls. 2024-03-04 19:23:47 +01:00
Aiosa
47419a090a Fix circular references in JSON test log serialization. 2024-03-04 10:49:05 +01:00
Aiosa
52ef8156c0 Fixed: internal cache not allways calling destructor, refresh handler was not called on internal cache. Polish code. Improve filtering demo. 2024-03-03 17:59:39 +01:00
Aiosa
a9b50a8fdb Test fixes (except gl null reference error - test fails sometimes). 2024-03-03 16:39:15 +01:00
Aiosa
135fa76fde Merge webgl PR - problems with tained canvas and texture upload. 2024-03-03 15:17:54 +01:00
Aiosa
360f0d6796 Fix docs, commit before upstream merge. 2024-03-03 14:50:01 +01:00
Ian Gilman
4d26c800ba Changelog for #2488 2024-03-01 09:25:16 -08:00
Ian Gilman
a42a0d1822
Merge pull request #2488 from pearcetm/setPosition-fix
Mark TiledImage as needing an update when position, scale, or rotation are set immediately
2024-03-01 09:18:33 -08:00
Tom
e4fd005fb0 Mark TiledImage as needing an update when position, scale, or rotation are set with immediately=true 2024-02-29 16:44:09 -05:00
Ian Gilman
1c0797e800 Changelog for #2472 2024-02-27 09:35:01 -08:00
Ian Gilman
01e70ab7d8
Merge pull request #2472 from pearcetm/canvas-fallback
In webgl drawer, fall back to canvas drawer for tiled images with tainted data
2024-02-27 09:33:06 -08:00
Tom
b6501a3786 fix typo in docs. change to options object for requestDrawer API 2024-02-22 13:30:05 -05:00
Ian Gilman
7dfc60a97f Changelog for #2478 2024-02-22 09:31:32 -08:00
Ian Gilman
da5abc1b39
Merge pull request #2478 from pearcetm/webgl-clipping
fix clip behavior with webgl drawer
2024-02-22 09:30:01 -08:00
Tom
5df791fc82 support viewport flipping for clip and cropping polygons in webglviewer 2024-02-21 18:12:22 -05:00
Tom
ae5f08b9bd call _setClip for test spyOnce 2024-02-21 17:53:23 -05:00
Tom
a0bcbc4d21 fix clip behavior with webgl drawer 2024-02-21 17:49:46 -05:00
Tom
c6e3e06194 Merge branch 'master' into canvas-fallback 2024-02-21 16:13:36 -05:00
Tom
1442e5d4e4 revert change in drawercomparison.js used for testing 2024-02-21 16:02:29 -05:00
Tom
99c35aa3cb consolidate drawer creation into viewer api. add drawer-error event 2024-02-21 16:01:18 -05:00
Tom
02898cfc17 clean up bound event handlers in webgldrawer.destroy 2024-02-12 18:05:33 -05:00
Ian Gilman
59645e3a0d Changelog for #2468 2024-02-12 09:53:00 -08:00
Ian Gilman
4c331a2000
Merge pull request #2468 from thec0keman/fix-this-scoping
Fix `this` scoping
2024-02-12 09:52:01 -08:00
Ian Gilman
b62fba80d6 Changelog for #2469 2024-02-12 09:32:37 -08:00
Ian Gilman
1c60e45a7f
Merge pull request #2469 from pearcetm/placeholder-for-webgl
Support placeholderFillStyle in WebGLDrawer, and other fixes
2024-02-12 09:29:20 -08:00
Tom
6e4914ada3 better cleanup for html drawer in destroy 2024-02-12 09:32:17 -05:00
Tom
8967e2bb03 support hot-swapping drawers with viewer.setDrawer() 2024-02-12 09:30:26 -05:00
Tom
0a154a3b21 In webgl drawer, fall back to canvas drawer for tiled images with tainted data 2024-02-11 11:51:38 -05:00
Aiosa
63f0adbc15 Fix issues with tile reference in cache: keep the 'most fresh' ref. 2024-02-11 17:18:03 +01:00
Aiosa
d91df0126b Add base drawer options and fix docs. Implement 'simple internal cache' for drawer data, optional to use. 2024-02-11 11:27:02 +01:00
Tom
3f21f84df4 clean up code added for testing 2024-02-09 18:16:30 -05:00
Tom
c734de531f fix placeholder positioning for canvas drawer 2024-02-09 17:18:54 -05:00
Tom
d4e82d374e account for viewport rotation in addition to tiledImage rotation 2024-02-09 15:19:40 -05:00
Tom
5b2c6d7ed9 add support for placeholderFillStyle to webgl drawer. fix spring logic to avoid getting stuck updating due to floating point math. update tilesource-swap demo. 2024-02-09 15:06:52 -05:00
John Ratcliff
8f483a3ba0 Fix this scoping 2024-02-09 11:23:38 -08:00
Aiosa
cae6ec6bee Revert weird tiledImage check - tests worked now also without. Add generic drawerswitcher utility for demos. 2024-02-08 13:11:10 +01:00
Aiosa
a97fe34d74 Remove merge marks. 2024-02-05 09:47:10 +01:00
Aiosa
9ef2d46e75 Fix tests: always fetch up-to-date pixel values, prevent adding loaded tile to the 'bestTiles' array. Enforce _needsDraw check to be based on lastDrawn - we are async now. 2024-02-05 09:42:26 +01:00
Aiosa
fcf20be8ea Drawers now use new cache API to draw onto a canvas. The type conversion now requires also the tile argument so that conversion can rely on the tile metadata. 2024-02-04 18:48:25 +01:00
Aiosa
3fa13570ef Resolve Merge with First WebGL PR: code is merged, but not operable [drawer refactoring needs interaction implemented with cache system]. 2024-02-04 15:41:05 +01:00
Ian Gilman
f7d86ac244 Changelog for #2466 2024-02-02 09:29:54 -08:00
Ian Gilman
e3c3634266
Merge pull request #2466 from pearcetm/fix-docs
fix jsdoc formatting for drawer classes
2024-02-02 09:26:43 -08:00
Tom
3ced918fb4 fix jsdoc formatting for drawer classes 2024-02-01 14:29:10 -05:00
Tom
23e50b6038 fix jsdoc formatting for drawer classes 2024-02-01 14:24:25 -05:00
Ian Gilman
fdaa3e2f16 Changelog for #2464, #2462 2024-02-01 09:43:51 -08:00
Ian Gilman
2e0868023a
Merge pull request #2464 from jonasengelmann/fix/touch-gesture-dragToPan
Fix dragToPan when flickEnabled is activated
2024-02-01 09:38:28 -08:00
Ian Gilman
98769af678
Merge pull request #2462 from pearcetm/fix-zero-opacity-case
Fix zero opacity case
2024-02-01 09:33:04 -08:00
jonasengelmann
e08274e2b0 fix dragToPan when flickEnabled is activated #2463 2024-02-01 18:01:21 +01:00
Tom
68623ace26 skip drawing zero-opacity images for webgl drawer. remove checks for preload in html and canvas drawers since that is done in tiledimage. 2024-02-01 10:46:45 -05:00
Tom
921171ed2b move logic about zero opacity case into getDrawArea 2024-02-01 08:47:03 -05:00
Tom
84a55968ee Allow preloading of tiles for zero opacity tiled images 2024-01-31 15:40:47 -05:00
Tom
1b44de3b68 Stop tiles from loading if opacity of tiled image is 0 2024-01-31 15:37:09 -05:00
Ian Gilman
f9a8b97cf9 Changelog for #2310 2024-01-31 09:47:49 -08:00
Ian Gilman
52fc10ffa2
Merge pull request #2310 from pearcetm/rotation-seams
Refactor drawing code, add WebGL drawer, and enable plugin renderers
2024-01-31 09:38:56 -08:00
Tom
59519e0e96 fix docs 2024-01-30 13:14:54 -05:00
Tom
d490592b99 expand event validation logic 2024-01-29 13:12:01 -05:00
Tom
024cee42f5 make event handler validation private 2024-01-29 13:01:44 -05:00
Tom
a55071f67b fix documentation for rejectEventHandler 2024-01-29 11:25:36 -05:00
Tom
2add108539 reject adding handlers for certain event names 2024-01-29 10:39:55 -05:00
Tom
c0104c7480 add validation at time of binding event handlers 2024-01-26 12:23:02 -05:00
Ian Gilman
5be1ab6f7d Changelog for #2455 2024-01-25 11:26:33 -08:00
Ian Gilman
4811dd0320
Merge pull request #2455 from BeebBenjamin/webp-support
Fix #2454, add webp to supported image formats
2024-01-25 11:23:25 -08:00
Richard Benjamin Allen
362a060512 Fix, change set supported format example 2024-01-25 16:47:51 +00:00
Tom
d2376b571f clean up comments and error logging 2024-01-24 13:02:50 -05:00
Richard Benjamin Allen
4e9134f66a Fix #2454, add webp to supported image formats 2024-01-22 09:43:02 +00:00
Tom
dc03989bbe throw error if MAX_TEXTURE_IMAGE_UNITS is a bad value 2024-01-19 14:42:34 -05:00
Tom
3cdd5fd711 throw error if MAX_TEXTURE_IMAGE_UNITS is a bad value 2024-01-19 13:19:43 -05:00
Tom
f6c35b44ed move qunit.starTest log message to test.js 2024-01-19 12:54:24 -05:00
Tom
43de595c24 clean up code from testing the MAX_TEXTURE_IMAGE_UNITS error issue 2024-01-18 16:20:28 -05:00
Tom
a2d31e9610 cleaned up additional viewers in tests 2024-01-18 16:06:49 -05:00
Tom
8271b6d8b2 more test details logged 2024-01-18 15:44:29 -05:00
Tom
aae82ab16a more test details logged 2024-01-18 15:34:14 -05:00
Tom
525d9b52fe more test details logged 2024-01-18 13:47:14 -05:00
Tom
bb676a8699 add test info to console.log 2024-01-18 13:32:30 -05:00
Tom
fd648c26e9 add logging directly to webgl drawer 2024-01-18 13:17:35 -05:00
Tom
f6c67b2159 remove additional test logging for testing travis ci 2024-01-18 12:56:03 -05:00
Tom
0a2657cb5b additional test logging for testing travis ci 2024-01-18 12:45:27 -05:00
Tom
44b66be0a9 update tests 2024-01-17 17:07:25 -05:00
Tom
db11611d7d add logging of gl max_texture_image_units errors to multi-image test 2024-01-17 16:13:34 -05:00
Tom
b902256a59 clean up comments. modify tests. add check for max textures in webgldrawer 2024-01-15 14:39:15 -05:00
Tom
f563600635 test canvas and webgl drawers in multi-image 2024-01-11 14:42:11 -05:00
Tom
e0fd78344b add description of WebGLDrawer drawing pipeline 2024-01-11 13:54:01 -05:00
Tom
3bab3c2190 small cleanups 2024-01-11 13:29:59 -05:00
Tom
500c22feb1 consolidate tiled-image-drawn event description and firing code 2024-01-10 18:00:01 -05:00
Tom
8be2ca2dfb test drawers separately 2024-01-10 17:46:17 -05:00
Tom
834795b4b8 fix basic demo 2024-01-10 14:48:48 -05:00
Tom
9725ac0398 update tiled-image-drawn event description 2024-01-10 12:21:05 -05:00
Tom
58f918aaa1 clean up tests 2024-01-10 12:13:00 -05:00
Tom
f3a90159c1 cleaning up webgldrawer 2024-01-08 19:18:58 -05:00
Tom
1239b22c30 updates to viewer 2023-12-22 13:46:36 -05:00
Tom
1a1e2c20c0 fix viewport.update so tests don't stall 2023-12-21 16:31:23 -05:00
Tom
22ecdfd75d fix documentation for viewport.update 2023-12-21 16:12:19 -05:00
Tom
bbee6e9605 update animating logic 2023-12-21 16:09:45 -05:00
Tom
40a4e42835 make reference strip always use the canvas drawer 2023-12-21 15:29:25 -05:00
Tom
1588f6b715 add documentation; rename parameters for clarity 2023-12-21 15:10:23 -05:00
Tom
55882b9215 fix docs. rename matrix.js to matrix3.js 2023-12-19 15:57:15 -05:00
Tom
d5a3cabf13 fixing jsdocs 2023-12-18 17:01:17 -05:00
Tom
9616e26dd2 updates in drawers and tiled image 2023-12-15 13:13:40 -05:00
Tom
074b65bfcd clean up comments and small fixes 2023-12-14 20:59:55 -05:00
Tom
3f7e7141b9 fixes from review of drawerbase.js 2023-12-14 19:14:05 -05:00
Tom
2d8c6fe4c3 cleaning up docs 2023-12-13 18:11:09 -05:00
Tom
a364c3f168 responding to review 2023-12-12 21:45:24 -05:00
Aiosa
3d6eb1b91c Fix broken tests (bad logics in event handling). 2023-12-10 17:58:50 +01:00
Aiosa
cf2413e0c9 Fix test for the preload hack (and fix the parentheses to always call updateMulti). 2023-12-10 16:49:56 +01:00
Aiosa
a690b50eee Add external execution pipeline (proof of concept implementation, needs polishing). Add filtering plugin live demo for testing. Fix issues with tile cache access outside its lifespan. Add custom css for the static page renderer and differentiate folder icons. Remove some old deprecations. 2023-12-10 16:34:42 +01:00
Tom
e50d3639ce bugfix in canvasdrawer tiled-image-drawn event 2023-12-02 15:47:01 -05:00
Tom
1200f0b081 clean up outdated code; add tiled-image-drawn event to canvasdrawer so tests work with this viewer 2023-12-02 15:40:47 -05:00
Tom
32f12b3ba5 check for valid ASSERT in tilesource-dynamic-url test 2023-11-29 19:34:41 -05:00
Tom
9dc96390fc update tests to skip fullscreen and certain drawer-related events 2023-11-29 19:04:27 -05:00
Tom
6b995c018b re-enable html drawer in drawer comparison demo; deal with merge conflict resolution issues 2023-11-29 17:35:49 -05:00
pearcetm
36d8b3d9ad
Merge branch 'master' into rotation-seams 2023-11-29 17:28:42 -05:00
Tom
c86158f0ca cleaning up changes 2023-11-29 16:46:14 -05:00
Aiosa
90ce0669c5 Add auto recognition of the need for tiledImage draw call. Fix ajax-headers test: did not finish because we don't call tile-loaded on cached tiles by default. 2023-11-27 12:12:54 +01:00
Aiosa
2c67860c61 Implement cache manipulation strategy: default copy on access if tile in the rendering process, remove 'canvas' type support, many bugfixes and new tests. 2023-11-26 21:32:26 +01:00
pearcetm
a578b97d96
Merge pull request #5 from Aiosa/rotation-seams
Small rendering bugfixes, URL params in demo pages.
2023-11-24 09:41:30 -05:00
Aiosa
191ba39cbb Remove demo references to the modular renderer. 2023-11-21 20:53:06 +01:00
Aiosa
23496cb049 Remove also file references. 2023-11-21 12:56:19 +01:00
Aiosa
f4efe2970a Remove modular implementation -> will be introduced in subsequent PR. 2023-11-21 12:54:09 +01:00
Aiosa
2a1090ffa8 Fix wrong test comparison. Add equality comparator to TileSource API. Return
deprecated support for getCompletionCallback. Turn on zombie cache if sources replaced & equal.
2023-11-19 16:14:28 +01:00
Aiosa
219049976c Add tests for zombie and data type conversion, ensure destructors are called.
Fix bugs (zombie was disabled on item replace, fix zombie cache system by separating to its own cache array). Fix CacheRecord destructor & dijkstra. Deduce cache only from originalCacheKey. Force explicit type declaration with types on users.
2023-11-18 20:16:35 +01:00
Aiosa
c3ab9a08e7 Merge branch 'cache-overhaul-reviewed' of github.com:RationAI/openseadragon into cache-overhaul-reviewed 2023-11-17 20:22:13 +01:00
Aiosa
023a864a36
Merge branch 'openseadragon:master' into cache-overhaul-reviewed 2023-11-17 20:21:24 +01:00
Ian Gilman
6abcc76a93 Changelog for #2431 2023-11-13 09:57:19 -08:00
Ian Gilman
c92f8ad65d
Merge pull request #2431 from cavenel/master
Fix zoom out when wheel event.deltaY is zero
2023-11-13 09:53:42 -08:00
Christophe Avenel
c1038af37d
Revert "Add debounce of pan events"
This reverts commit e836ffcc61.
2023-11-08 18:52:05 +01:00
Ian Gilman
89ae9c1376 Changelog for #2416 2023-11-06 09:32:00 -08:00
Ian Gilman
a8d37d892e
Merge pull request #2416 from lutzhelm/2415-iiif-tiling-error-for-descending-sizes
Fix #2415, order IIIF sizes on tile source init
2023-11-06 09:27:08 -08:00
Christophe Avenel
e836ffcc61 Add debounce of pan events
Group pan events together if needed, in order to avoid lag if drawing of layers takes more time than it should.
2023-10-31 15:38:38 +01:00
Christophe Avenel
810987210c
Fix zoom out when wheel event.deltaY is zero
Don't apply zoom in or zoom out when deltaY is zero on wheel events.
Should fix https://github.com/openseadragon/openseadragon/issues/947 and not make OpenSeadragon zoom out when scrolling horizontally on a touchpad
2023-10-25 09:26:48 +02:00
Aiosa
6447009c18 Remove blend time from comparison demo (not functional). 2023-10-23 16:05:18 +02:00
Aiosa
cd9d340038 Removed date loader (will be handled by future OSD cache system). Attempt to use instanced rendering. Refactoring of the module. 2023-10-23 16:03:47 +02:00
Lutz Helm
5272cf092c Ensure descending size order also works for level 0 2023-10-10 14:04:31 +02:00
Lutz Helm
b92a428e88 Sort levelSizes instead of sizes 2023-10-10 14:02:44 +02:00
Aiosa
31f9a71109 Working tiledimage-level transparency in a single pass. 2023-09-27 15:16:23 +02:00
Aiosa
174c4c709a Remove logs from debugging. 2023-09-26 15:47:50 +02:00
Aiosa
e3024deb46 Modular webgl2 drawer: fix small bugs. Add drawer IDs to demo page urls to allow refreshing/direct running 2023-09-26 15:31:43 +02:00
Aiosa
f796925ae5 Remove irrelevant code and comments. 2023-09-25 08:52:45 +02:00
Aiosa
750d45be81 Implement asynchronous tile processing logic wrt. tile cache conversion. 2023-09-24 22:30:28 +02:00
Lutz Helm
5542ead48b Fix #2415, order IIIF sizes on tile source init 2023-09-19 09:55:53 +02:00
Aiosa
f01a7a4b3c Cache Overhaul for OpenSeadragon (areas to discuss marked with FIXME). 2023-09-08 08:47:43 +02:00
Ian Gilman
640526b444 Changelog for #2393 2023-08-22 10:21:35 -07:00
Ian Gilman
8d2f8449ba
Merge pull request #2393 from VIRAT9358/fix496
fixed position issue
2023-08-22 10:16:17 -07:00
ViratSr
ed49d46237 syntax fixed and if statement amended 2023-08-17 10:39:45 +05:30
ViratSr
9b051f55de #fix496 2023-08-16 00:10:55 +05:30
ViratSr
b15ba75551 fixed position issue 2023-08-15 16:46:10 +05:30
Ian Gilman
17cd6b51ce Changelog for #2387 and tweaks to its demo page 2023-08-08 09:39:45 -07:00
Ian Gilman
cca81a37d5
Merge pull request #2387 from schuefflerlab/BestTiles
Introduced option maxTilesPerFrame
2023-08-08 09:25:17 -07:00
Peter
0bdd807d9d Cleaned code according to comments in PR 2023-08-08 11:05:33 +02:00
Peter
f8ad0acfa4 Sort the N tiles only once instead of when adding new indiviual tiles 2023-08-02 21:04:43 +02:00
Peter
55a05963a2 Sort N tiles always for a better look and feel. 2023-08-02 20:30:30 +02:00
pearcetm
e07745d790
Merge pull request #4 from Aiosa/rotation-seams
First modular webgl drawer implementation by @Aiosa

Thanks for putting this together @Aiosa! I'm going to merge it into the large refactor PR. It'd be great to have a demo page that includes all these features, for testing/debugging and to show off the capabilities.
2023-08-01 17:18:32 -04:00
Ian Gilman
4a3fc5b325
Merge pull request #2389 from openseadragon/ms-mousetracker-docs
MouseTracker options docs fixes
2023-08-01 09:33:12 -07:00
Tom
2fcdcc3f6a add attribution for rStats code 2023-08-01 12:20:13 -04:00
Mark Salsbery
fa8196ef4f changelog update 2023-07-31 13:16:36 -07:00
Mark Salsbery
1f47f5def1 MouseTracker options docs fixes 2023-07-31 13:08:07 -07:00
Tom
77b5766fa2 update drawerperformance demo 2023-07-31 15:48:29 -04:00
Peter
13955b0bf6 added demo with maxTilesPerFrame = 3 2023-07-31 10:14:27 +02:00
Tom
c77a7e7386 enhance performance demo. rename variables for clarity. 2023-07-28 17:49:24 -04:00
Peter
17873001b8 outsourced tile sorting from tile comparing. 2023-07-28 13:15:47 +02:00
Aiosa
054ad0d53b
Merge branch 'pearcetm:rotation-seams' into rotation-seams 2023-07-28 12:25:58 +02:00
Aiosa
a907aaa160 Merge remote-tracking branch 'origin/rotation-seams' into rotation-seams 2023-07-28 12:24:15 +02:00
Aiosa
b6273b95b8 First modular webgl drawer implementation. 2023-07-28 12:23:59 +02:00
pearcetm
d912ff3196
Merge pull request #3 from Aiosa/rotation-seams
Exposing matrix implementation, automatic drawer recognition

Thanks, @Aiosa!
2023-07-26 19:28:29 -04:00
Aiosa
ca45e96142
Merge branch 'rotation-seams' into rotation-seams 2023-07-26 23:58:07 +02:00
Aiosa
046612f8da Better drawer resolution, also supporting inline class spec. Fix minor review stuff. 2023-07-26 23:55:46 +02:00
Tom
1e37745764 sync webgldemodrawer with webgldrawer 2023-07-26 15:44:38 -04:00
Tom
f4ded1630f code cleanup 2023-07-26 15:42:18 -04:00
Aiosa
3c3842bdce Change comments TO DO -> TODO. Add automatic recognition of drawers. Matrix as an exposed class. 2023-07-26 20:01:26 +02:00
Peter
ccb4ae9f86 Fixed _updateViewport to come to a fullyLoaded state with n tiles.
Improved _compareTiles
2023-07-20 17:27:49 +02:00
Peter
9684a83b8c Updated Comment 2023-07-20 15:17:02 +02:00
P. Schueffler
7ad748799e
Pr for upstream (#3)
Added maxTilesPerFrame
2023-07-20 14:45:15 +02:00
Tom
f510301922 add performance test demo page. reduce number of drawing calls drawing pipeline of webgl drawer. 2023-07-19 18:18:56 -04:00
Ian Gilman
f50df84287
Merge pull request #2386 from openseadragon/dependabot/npm_and_yarn/word-wrap-1.2.4
Bump word-wrap from 1.2.3 to 1.2.4
2023-07-18 14:00:49 -07:00
dependabot[bot]
9f31919dc1
Bump word-wrap from 1.2.3 to 1.2.4
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-18 20:28:16 +00:00
Ian Gilman
e51053a6a3 Changelog for #2382 2023-07-17 14:03:59 -07:00
Ian Gilman
eec052f054
Merge pull request #2382 from AndrewADev/update-grunt-contrib-qunit
Update grunt-contrib-qunit and extend FullScreen test
2023-07-17 14:02:02 -07:00
Andrew Armbruster
be4d5ad7f7 Update grunt-contrib-qunit and extend FullScreen test
Update the package responsible for running tests, grunt-contrib-qunit.

The package change includes a significant bump to the puppeteer version used to run the tests (from v9 -> v19: https://github.com/gruntjs/grunt-contrib-qunit#release-history).

Running the tests with the newer puppeteer version leads to issues running the FullScreen test when run in the 'old'/current default headless mode (the test fails with a timeout).

Updating to the 'new' headless mode (eventually to be the default anyway), seems to allow the fullscreen request to succeed.

Thus, go ahead and extend the FullScreen test to verify the correct values for a successful request, as well as an additional step to exit fullscreen mode.
2023-07-16 13:10:56 +02:00
Tom
01a4ea6f2c Update documentation and remove commented code. Change from get type to getType(). 2023-07-09 14:10:20 -04:00
Tom
6feed0a68e Add clipping to demo. Update documentation and remove commented code. Change from get type to getType(). 2023-07-09 12:05:17 -04:00
Tom
0a3aa6172d add type property to drawers. only add extra padding to tiles for drawers that need it. 2023-06-30 16:38:07 -04:00
Tom
048b43e196 remove forced transparency from images in drawercomparison demo. change from context2d naming to canvas. 2023-06-30 16:06:17 -04:00
Tom
cc412f0a20 add documentation; remove unnecessary deprecated code 2023-06-29 21:55:59 -04:00
Tom
3a5a738508 remove viewer.destroy() from some tests 2023-06-29 17:06:45 -04:00
Tom
83ec2bb1f0 tiled image opacity works now with no overlapping regions at tile borders 2023-06-29 16:41:45 -04:00
Tom
24c4d2d2bc Remove tile-drawn event and replace with tiled-image-drawn for webgl drawer, and update related tests. 2023-06-27 13:57:02 -04:00
Tom
2ec2c0f2c7 remove three.js and associated plugin renderer; fix demo 2023-06-26 21:44:03 -04:00
Tom
386ca85db8 implement native webgl renderer, and many associated changes related to drawing pipeline and testing 2023-06-26 21:29:08 -04:00
Ian Gilman
ffbd8f985a Changelog for #2367 2023-06-21 14:19:06 -07:00
Ian Gilman
88f419330e Merge branch 'master' of github.com:openseadragon/openseadragon 2023-06-21 14:17:06 -07:00
Ian Gilman
3386a73e44
Merge pull request #2367 from akansjain/master
Removed createCallback function
2023-06-21 14:10:28 -07:00
akansjain
eaa41f7f05 Replaced the comment with Deprecated 2023-06-21 13:34:58 +05:30
Tom
128975ea0f only calculate tile positions when necessary 2023-06-18 19:28:48 -04:00
Tom
0584ca7be9 add to-do comments 2023-06-18 19:09:22 -04:00
Tom
37b8ef9519 deprecate useCanvas option; add option for drawer and drawerOptions 2023-06-18 19:08:33 -04:00
Tom
7bb02d51d0 reverted change to argument order in _updateTile call 2023-06-14 07:51:50 -07:00
akansjain
7dec7b9aba Added console.error() in createCallback() function 2023-06-09 17:58:22 +05:30
Tom
2e248baf91 additional fixes to get tests to pass 2023-06-08 12:10:55 -07:00
Tom
354590a17a convert DrawerBase and drawer implementations to classes; add html drawer to the demo page 2023-06-07 12:42:16 -07:00
Tom
8fda8ceae7 re-enable sequence mode demo viewer 2023-06-07 10:16:21 -04:00
Tom
8fe6a5f6e6 merging remote 2023-06-07 10:14:58 -04:00
Tom
1bc93be3f2 update tile drawing logic 2023-06-06 19:37:24 -04:00
Tom
36084703f0 conditional usage of draw() vs event handlers depending on initialization context 2023-06-06 18:08:53 -04:00
Tom
1089f79a5b remove drawer class 2023-06-06 18:08:50 -04:00
Tom
2a0af48bc1 updates to threejsdrawer, bugxfixes/improvements 2023-06-06 18:08:30 -04:00
Tom
dab8a9a3cd move tile update logic back to TiledImage to keep drawing logic cleaner 2023-06-06 18:08:30 -04:00
Tom
2f3bef0865 split canvas from html rendering 2023-06-06 18:08:30 -04:00
Tom
467597e2c2 cleaning up drawer APIs 2023-06-06 18:08:30 -04:00
Tom
5eece7d73a fix cropping when viewer is rotated 2023-06-06 18:08:30 -04:00
Tom
69c4ccf33e revert debugging changes in overlay demo 2023-06-06 18:08:30 -04:00
Tom
5328761877 finished many implementation details and demo 2023-06-06 18:08:01 -04:00
Tom
f9ab63944b ThreeJSRenderer nearly complete, starting refactor of core to support plugin drawers. 2023-06-06 18:05:17 -04:00
akansjain
3fc156d513 Removed createCallback function 2023-06-06 23:04:04 +05:30
Ian Gilman
c9cd7352c4 Changelog for #2364 2023-06-02 14:23:11 -07:00
Ian Gilman
ebab356c20
Merge pull request #2364 from SebDelile/master
workaround tile edge smoothing maxZoom + flip
2023-06-02 14:18:54 -07:00
Delile Sebastien
f96db3cf0f complete comment 2023-06-02 18:59:22 +02:00
Delile Sebastien
f004ecf323 fix comment 2023-06-01 10:20:14 +02:00
Delile Sebastien
2c03c1bbe9 workaround tile edge smoothing maxZoom + flip 2023-05-31 16:11:42 +02:00
Ian Gilman
b405a904a6
Merge pull request #2362 from AndrewADev/update-qunit
Update to most recent QUnit
2023-05-30 14:31:02 -07:00
Ian Gilman
c2a1df9ae0 Changelog for #2361 2023-05-30 14:25:44 -07:00
Ian Gilman
c69950c6e4
Merge pull request #2361 from AndrewADev/allow-es6-syntax
Allow Using ES6 Syntax
2023-05-30 14:24:34 -07:00
Andrew Armbruster
c7df7be7f1 Catch rejected Promise on failed fullscreen request
Add a `catch()` rejection of request for fullscreen (standard Fullscreen API implementation), as well as fullscreen exit. For now there is no actual handling, but we send a message to the internal error channel.

Motivation: The fullscreen request was causing certain tests to fail when run with newer versions of QUnit (starting in 2.5.0), which now fails tests that have unhandled Promise rejections (as we did here).

The exit case is not currently covered by tests, but works the same way (also returns a promise).

See: https://fullscreen.spec.whatwg.org/#ref-for-dom-element-requestfullscreen%E2%91%A0
2023-05-28 14:15:55 +02:00
Andrew Armbruster
ff67cf1cae Support ES6 Syntax
Bump ESLint's parser options to support ES6 syntax, which allows developers to start using a number of features associated with modern JavaScript.

Doing this now that #2286 has been marked as resolved, since IE 11 support was the last known blocker for such changes.
2023-05-28 12:41:30 +02:00
Andrew A
ad1179b9db Update to most recent QUnit
Update to most recent version of QUnit, which has been published under a new name for a while now.

Accordingly, replace the old package with the new one in both dependencies, as well as update references in test HTML files.
2023-05-27 13:16:28 +02:00
Ian Gilman
ea54427f42
Merge pull request #2359 from openseadragon/ian
Updated copyright to 2023
2023-05-25 14:53:05 -07:00
Ian Gilman
b9cb52a184 Updated copyright to 2023 2023-05-25 14:52:20 -07:00
Ian Gilman
3d57722b9f Changelog for #2300 2023-05-25 14:37:50 -07:00
Ian Gilman
ae9ad111c4
Merge pull request #2300 from AndrewADev/add-es-api-linting
Add ESLint plugin for linting browser compatibility
2023-05-25 14:35:47 -07:00
Ian Gilman
160cae7a4a Starting version 5.0.0 2023-05-25 13:58:21 -07:00
Ian Gilman
884968139d Version 4.1.0 2023-05-25 13:53:17 -07:00
Ian Gilman
324dc4ed30 Changelog for #2356 2023-05-24 14:03:14 -07:00
Ian Gilman
dedd85e184
Merge pull request #2356 from lcl45/rotating-navigator-region
Added navigator's region rotation
2023-05-24 13:59:23 -07:00
lcl45
7fb5744495 Resolved suggestions
- Avoid useless parameters _navigatorRotate since it already exists within the navigator;
- Automatically rotate the image in the demo page.
2023-05-24 08:45:15 +02:00
oro.niccolo
d897e5454f Added navigator's region rotation
When the "navigatorRotate" option is set to false, rotate the navigator's region accordigly to the image rotation.
2023-05-23 09:27:32 +02:00
Ian Gilman
01d940b938 Changelog for #2346 2023-05-19 15:04:46 -07:00
Ian Gilman
e6f2d3e07b
Merge pull request #2346 from uschmidt83/ajax-headers
Add `setAjaxHeaders` method to Viewer and TiledImage
2023-05-19 15:01:54 -07:00
Uwe Schmidt
4060dee4f9 Make updateAjaxHeaders private 2023-05-19 22:22:10 +02:00
Uwe Schmidt
e983bd8108 Add docs for updating ajax headers 2023-05-12 23:48:31 +02:00
Uwe Schmidt
857a825ed8 Fix some jsdoc typos 2023-05-12 23:37:34 +02:00
Uwe Schmidt
6fd828974d Update navigator ajax headers 2023-05-12 21:46:16 +02:00
Uwe Schmidt
e51aa4a9c5 Refine setAjaxHeaders
- Allow null to clear headers (same as empty object)
- Add TiledImage._updateAjaxHeaders
- Add error message in case of invalid headers
2023-05-05 01:13:44 +02:00
Uwe Schmidt
182c11481e Add tests for setAjaxHeaders 2023-05-05 00:03:22 +02:00
Ian Gilman
6981cfed01 Changelog for #2347 2023-05-04 13:45:06 -07:00
Ian Gilman
d4057aca12
Merge pull request #2347 from pearcetm/navigator-fix
update navigator size when calling setHeight or setWidth
2023-05-04 13:42:17 -07:00
Tom
528df37335 update navigator size when calling setHeight or setWidth 2023-05-03 22:38:49 -04:00
Uwe Schmidt
b23e8295d3 Propagate updated ajax headers by default 2023-05-03 23:51:07 +02:00
Uwe Schmidt
13603dd5f4 Update reference strip ajax headers 2023-05-03 19:33:50 +02:00
Uwe Schmidt
fe7a5eb01b Make ES5-compatible 2023-05-03 18:46:18 +02:00
Uwe Schmidt
3c2628f182 Add setAjaxHeaders method to Viewer and TiledImage
- First draft, not tested at all
- See openseadragon/openseadragon#1748
2023-05-03 16:05:58 +02:00
Ian Gilman
b1274515aa Tiny basic.html tweak 2023-04-27 14:27:40 -07:00
Ian Gilman
b088fc0da3 Changelog for #2337 2023-04-27 14:27:09 -07:00
Ian Gilman
d36c76127c
Merge pull request #2337 from ruven/master
Use resolution level dimensions provided in the info.json "sizes" field
2023-04-27 14:24:23 -07:00
Ruven
c5404006b2
Further optimization: code moved into constructor thereby eliminating need for getLevelSize() function. 2023-04-25 12:06:27 +02:00
Ruven
5fd125dc92
Added implementation of getTileAtPoint() function. This eliminates flickering at level transitions caused by mis-match in resolution size calculation between the getTileAtPoint() and getNumTiles() functions. 2023-04-24 22:44:46 +02:00
Ruven
877c3b68ed
Refactored code to take into account optimization suggestions (https://github.com/openseadragon/openseadragon/pull/2337#discussion_r1170931340) 2023-04-24 17:24:18 +02:00
Ruven
0c358c140d
Use resolution level dimensions provided in the info.json "sizes" field to determine tile sizes as well as the number of tiles that exist at a particular resolution. Fall back to calculation using ceil() if no resolution sizes provided. Avoids rounding errors for edge tiles and fixes https://github.com/openseadragon/openseadragon/issues/2321 2023-04-17 21:08:18 +02:00
Ian Gilman
60a6a610e0 Changelog for #2334 2023-04-10 14:23:31 -07:00
Ian Gilman
f91dbdd2c7
Merge pull request #2334 from Ughuuu/Fix-TileLoader-re-trying-even-if-successful
Fix TileLoader re-trying even if successful #2
2023-04-10 14:18:58 -07:00
Dragos Daian
d18a4c3fd7 mark tile.exists so that the retired tiles appear. 2023-04-08 16:48:04 +02:00
Ian Gilman
ebda5a909b Changelog for #2333 2023-04-07 13:49:12 -07:00
Ian Gilman
4f737f1714
Merge pull request #2333 from robertjcolley/master
Fixes navigator rotation not honoring immediately parameter
2023-04-07 13:47:35 -07:00
Robert Colley
e6b9c79bc1
Fixes #2332
Mirror the main viewer's rotation and account for immediately. Without 
this, viewer.setRotation(90, true) would rotate the main viewer without 
animation and the navigator with animation.
2023-04-06 18:10:38 -04:00
Ian Gilman
8b305546ed Changelog for #2324 2023-04-06 14:26:15 -07:00
Ian Gilman
5b56d6fa16
Merge pull request #2324 from rsimon/master
Applied touch rotate fix suggested in #2319
2023-04-06 14:22:54 -07:00
Ian Gilman
2e99e48603 Fixed changelog for #2136 2023-04-06 14:12:30 -07:00
Ian Gilman
b45d500f1e Changelog for #2328 2023-04-04 14:51:05 -07:00
Ian Gilman
cec0acafe1
Merge pull request #2328 from craigberry/master
Handle XML embedded in tilesource JSON
2023-04-04 14:48:52 -07:00
Ian Gilman
073b2e0b1f Changelog for #2318 2023-03-31 15:30:19 -07:00
Ian Gilman
3488d18e4c
Merge pull request #2318 from donotloveshampo/patch-1
Fixed #2314
2023-03-31 15:27:43 -07:00
Craig A. Berry
bff93af17e Handle XML embedded in tilesource JSON
The existing check for whether the tilesource data is XML or JSON
looks for a tag anywhere in the response content, which incorrectly
flags the content as XML in the case where it is really JSON with
XML embedded in it.

This commit corrects that problem by requiring the tag to occur as
the first non-whitespace part of the content. This is basically a
poor person's well-formedness check since well-formed XML cannot
have non-whitespace content outside of the root node.

N.B. While malformed XML content with non-whitespace characters
before the first element has been getting identified as XML, it
has not been getting parsed correctly.  With current parsing
infrastructure, the content has been getting replaced by a parsing
error message.  With more up-to-date parsing infrastructure, it
will throw an error.  Either way we're not losing anything by failing
to identify malformed XML as XML.

Addresses issue #2325.
2023-03-30 16:38:35 -05:00
Rainer Simon
84d2dcf11d Applied touch rotate fix suggested in #2319 2023-03-25 18:38:58 +01:00
donotloveshampo
244e54da69
Fixed #2314 2023-03-17 16:27:12 +08:00
Ian Gilman
292b62ba21 Change log for #2317 2023-03-16 13:26:59 -07:00
Ian Gilman
dec2afabb2 Merge branch 'master' of github.com:openseadragon/openseadragon 2023-03-16 13:23:40 -07:00
Ian Gilman
2ae9fb0e13
Merge pull request #2317 from pearcetm/after-resize-event
Add after-resize event
2023-03-16 13:22:50 -07:00
Ian Gilman
56ae09fc8a Changelog for #2316 2023-03-14 14:02:07 -07:00
Ian Gilman
5f816246e4
Merge pull request #2316 from pearcetm/scaled-crop-bugfix
partial bugfix for #2312
2023-03-14 13:57:35 -07:00
Tom
fb32cc7198 add after-resize event 2023-03-13 22:19:06 -04:00
Tom
a01c230b6e partial bugfix for #2312 2023-03-13 21:56:06 -04:00
Tom
8a4c95ef4b conditional usage of draw() vs event handlers depending on initialization context 2023-03-13 21:39:54 -04:00
Tom
9821b4589d remove drawer class 2023-03-13 17:56:53 -04:00
Tom
6d1895364f updates to threejsdrawer, bugxfixes/improvements 2023-03-13 17:43:35 -04:00
Tom
ade59513df move tile update logic back to TiledImage to keep drawing logic cleaner 2023-03-13 15:56:04 -04:00
Tom
641951aaed split canvas from html rendering 2023-03-12 11:42:03 -04:00
Tom
6159ca7c7c cleaning up drawer APIs 2023-03-11 11:38:21 -05:00
Ian Gilman
bf06f271c6 Changelog for #2293 2023-03-10 13:52:32 -08:00
Ian Gilman
cbb0a009e7
Merge pull request #2293 from pearcetm/zoom-constraints-fix
Take zoom constraint into account within _fitBounds
2023-03-10 13:49:41 -08:00
Ian Gilman
25b4d7a3ca
Merge pull request #2308 from AndrewADev/set-node-lts-in-ci
Update Travis to use latest Node LTS
2023-03-07 14:27:02 -08:00
Ian Gilman
624609d800 Changelog for #2306 2023-03-06 14:25:38 -08:00
Ian Gilman
afae0ec5ec
Merge pull request #2306 from MohitBansal321/addButton
add custom button for this viewer
2023-03-06 14:22:34 -08:00
Tom
a6e621b562 fix cropping when viewer is rotated 2023-03-06 14:29:39 -05:00
Tom
7c81d068e6 revert debugging changes in overlay demo 2023-03-05 16:12:30 -05:00
Tom
d1b8001adc finished many implementation details and demo 2023-03-05 16:08:32 -05:00
Andrew Armbruster
2764e3ad9a Try an even newer build env
This would buy even more time to find an alternative to pinning the runner version.
2023-02-28 21:16:41 +01:00
Andrew Armbruster
5c12e1ce1c Use newer runner version
Request a newer runner version from Travis CI due to a glibc version bump in newer versions of Node.
2023-02-28 21:04:22 +01:00
Andrew Armbruster
7d2ceac61a Travis uses latest Node LTS
Update CI config to use the most recent LTS.

For some other possible values, see: https://docs.travis-ci.com/user/languages/javascript-with-nodejs/#specifying-nodejs-versions
2023-02-28 20:21:10 +01:00
Mohit Bansal
8a201c12b4 add given button function to buttongroup 2023-02-28 01:05:22 +05:30
Mohit Bansal
f393547d9e add custom button 2023-02-27 23:52:29 +05:30
Andrew A
b0233f6a24 Drop non-standard lint command
Stick to existing approach leveraging grunt for dev tasks.
2023-02-24 19:51:42 +01:00
Andrew A
2932b0a800 Exclude IE 11 from query
We are ready to drop IE 11, so no need for it to be included in the browserslist

See: https://github.com/openseadragon/openseadragon/pull/2300#pullrequestreview-1308240522
2023-02-24 19:50:38 +01:00
Ian Gilman
59083b7669 Changelog for #2301 2023-02-23 15:07:09 -08:00
Ian Gilman
f0d15e3e79
Merge pull request #2301 from MohitBansal321/focusEvent
add canvas-focus and canvas-blur events to Viewer
2023-02-23 15:04:11 -08:00
Mohit Bansal
795e85bebb update doc comments 2023-02-22 10:21:51 +05:30
Tom
376ee38d3c ThreeJSRenderer nearly complete, starting refactor of core to support plugin drawers. 2023-02-21 18:59:40 -05:00
Mohit Bansal
c05af1d38b add focus and blur event 2023-02-19 15:49:43 +05:30
Andrew A
ab0ddcae3d Add a lint script
Make it easy to lint in stand-alone fashion.

Note that I'm going with a direct call to ESLint, as using `grunt eslint` leads to warnings about a circular dependency (per trace it seems to originate in istanbul?)
2023-02-18 15:55:03 +01:00
Andrew A
09a119afe3 Add ESLint plugin for ES API linting
Adding [eslint-plugin-compat](https://github.com/amilajack/eslint-plugin-compat) to check for usage of incompatible APIs.

For a list of browsers, we start out using both the 'defaults' query along with IE 11, which is still expressly supported in OSD v4 (current).
2023-02-18 15:50:21 +01:00
Ian Gilman
25aabbe766
Merge pull request #2298 from MohitBansal321/npmOutdated
some npm packages outdated
2023-02-17 14:16:07 -08:00
Ian Gilman
f2fa9dbb41 Changelog for #2297 2023-02-17 14:01:56 -08:00
Ian Gilman
9026c3a71d
Merge pull request #2297 from KevinBritten/docs/button-type-fix
2087 add type Element to documentation for custom ui buttons
2023-02-17 13:57:33 -08:00
Mohit Bansal
e765860aeb Merge branch 'master' of https://github.com/openseadragon/openseadragon into npmOutdated 2023-02-17 15:26:10 +05:30
Kevin Britten
8ec6e55304
Merge branch 'openseadragon:master' into docs/button-type-fix 2023-02-16 17:21:44 -05:00
Ian Gilman
5a5420972c Changelog for #2291 2023-02-16 14:16:56 -08:00
Ian Gilman
c7992411a5
Merge pull request #2291 from MohitBansal321/keyboardHandling
Consolidate viewer keyboard handling into keydown handler
2023-02-16 14:13:45 -08:00
Kevin Britten
cf3bf91b8d add type Element to documentation for custom ui buttons 2023-02-16 14:51:30 -05:00
Mohit Bansal
8442cc2b2b update npm packages 2023-02-15 19:15:22 +05:30
Mohit Bansal
0ab81df9b8 remove unwanted property 2023-02-15 09:37:03 +05:30
Mohit Bansal
6be459e451 formatting 2023-02-13 23:13:08 +05:30
Mohit Bansal
78928e3510 add comment 2023-02-13 23:01:19 +05:30
Mohit Bansal
4909320089 correction of keyCode 2023-02-12 13:30:41 +05:30
Mohit Bansal
3a8738fd43 spacing && documentation 2023-02-12 12:43:41 +05:30
Mohit Bansal
dac697c74e formatting 2023-02-10 16:44:55 +05:30
Mohit Bansal
4bc9ea4573 add keypress handler's event 2023-02-09 12:55:44 +05:30
Mohit Bansal
cfa88b701f replace canvasKeyPressEventArgs to canvasKeyDownEventArgs 2023-02-08 19:22:27 +05:30
Tom
16fc72d8fb Take zoom constraint into account within _fitBounds when constraints = true and immediately = false 2023-02-07 18:12:26 -05:00
Mohit Bansal
f36d44dc67 Consolidate viewer keyboard handling into keydown handler 2023-02-07 03:31:57 +05:30
Ian Gilman
ead728dc35 Changelog for #2282 2023-02-03 14:07:08 -08:00
Ian Gilman
3cf3fb50b2
Merge pull request #2282 from RationAI/master
Ensure tile-loaded event completionCallback is called only once.
2023-02-03 14:03:39 -08:00
Aiosa
37d4f62ce9 Remove discouraging note on getCompletionCallback use docs. 2023-02-02 17:18:12 +01:00
Aiosa
57486732b1 Prevent early tile completion with call order instead of guard flag. Improve getCompletionCallback docs. 2023-02-01 10:25:10 +01:00
Aiosa
55e7d2439a Change completionCallback with 'tile-loaded' event to support original scenario of async completion notification with additional guarding flags. 2023-01-31 08:05:02 +01:00
Aiosa
81d86570da Typo in the stopping comparison condition. 2023-01-28 14:08:00 +01:00
Aiosa
947109718c Ensure tile-loaded event completionCallback is called only once. Check when context2D used after cache creation. 2023-01-28 08:42:07 +01:00
Ian Gilman
ca5cc84988 Changelog for #2280 and #2238 2023-01-26 14:13:52 -08:00
Ian Gilman
dbb60cf026
Merge pull request #2280 from damonsson/patch-1
fix problem with click precision on ReferenceStrip
2023-01-26 14:11:16 -08:00
Damian Murawski
2484de5010
remove trailing space 2023-01-26 11:44:39 +01:00
Damian Murawski
8550b4fea5
fix problem with click precision on ReferenceStrip
temporary fix for #1992 . Just adding 4px which works in all use cases.
2023-01-25 23:15:12 +01:00
Ian Gilman
6f7e8c7a49
Merge pull request #2238 from Ughuuu/pr-1386-3
add loop for re-trying failed tiles [Take 3]
2023-01-24 15:15:58 -08:00
Ian Gilman
e6f7c78626 Changelog for #2273 2023-01-24 14:58:13 -08:00
Ian Gilman
d22eceed66
Merge pull request #2273 from RationAI/master
EventSource: promises, priorities and execution breaks
2023-01-24 14:53:07 -08:00
Dragos Daian
b4700d28bd Also add documentation for tileRetryDelay 2023-01-23 22:16:05 +01:00
Dragos Daian
f0f12c459e try fix with check for null and undefined 2023-01-23 22:10:23 +01:00
Dragos Daian
5d70a807da fix build error 2023-01-23 19:54:51 +01:00
Dragos Daian
77bc130636 Add tileRetryMax documentation. 2023-01-23 19:49:43 +01:00
Aiosa
377f2bd04f Merge branch 'master' of github.com:RationAI/openseadragon 2023-01-21 09:00:58 +01:00
Aiosa
7a7acdbe57
Merge branch 'openseadragon:master' into master 2023-01-21 08:00:29 +00:00
Aiosa
de00939d8d Revert async support and event breaking support in EventSource. 2023-01-21 09:00:24 +01:00
Ian Gilman
a1004bac86 Changelog for #2276 2023-01-20 13:53:46 -08:00
Ian Gilman
5a8e7ddcf8
Merge pull request #2276 from ambujsahu81/patch-1
Fix #2264: Navigator display rectangle is off when the page has box-sizing: border-box
2023-01-20 13:51:52 -08:00
ambujsahu81
f3a76a267c add box-sizing property to the navigator display region 2023-01-20 18:26:54 +05:30
Aiosa
c8dbb2c757 Implement support for async function and promise type recognition with $.type. Add $.Promise proxy. Implement support for promises in EventSource. Implement ability to abort events as well as prioritize events. 2023-01-17 11:13:48 +01:00
Ian Gilman
d80b6ad4ce Changelog for #2270 2023-01-12 13:57:44 -08:00
Ian Gilman
3d9ae49948
Merge pull request #2270 from hrghauri/issue-2192
issues/2192 fix - Introduced canvas-key-press for keypress.
2023-01-12 13:54:50 -08:00
Haris Ghauri
a9f0523b62 issues/2192 fix. 2023-01-11 23:15:24 -05:00
Ian Gilman
a111d0f616 Starting 4.0.1 2022-12-16 14:22:50 -08:00
Ian Gilman
8e6196a3f3 Version 4.0.0 2022-12-16 14:17:28 -08:00
Ian Gilman
c93df98363 JSDoc fixes 2022-12-16 14:14:40 -08:00
Ian Gilman
574f375467 Changelog for #2256 2022-12-16 13:57:02 -08:00
Ian Gilman
1351ac018a
Merge pull request #2256 from pearcetm/resize-listener
work in progress about viewer resize behavior
2022-12-16 13:48:45 -08:00
Ian Gilman
c5588a2313 Changelog for #2249 2022-12-15 14:03:46 -08:00
Ian Gilman
3342b7880d
Merge pull request #2249 from pearcetm/rotated-constraints-fix
fixed viewport constraint behavior when viewer is rotated
2022-12-15 13:57:44 -08:00
Tom
564121428c removed polling vs resizeviewer option from demo 2022-12-14 11:31:12 -05:00
Tom
67fc9eafe8 disabled autoResize for navigator 2022-12-14 10:53:40 -05:00
Tom
9ccf93d767 cleaning up changes 2022-12-14 09:25:23 -05:00
Tom
9daa8feec1 cleaning up changes; modified demo 2022-12-14 09:21:52 -05:00
Tom
9048abb05e Merge branch 'master' into resize-listener 2022-12-13 18:31:42 -05:00
Tom
69297c0181 Updated resize behavior 2022-12-13 16:49:23 -05:00
Ian Gilman
ae70c88e52
Merge pull request #2259 from openseadragon/ig-test
Fixed fullyLoaded test when run in browser
2022-12-12 15:26:44 -08:00
Ian Gilman
e6341ac1e0 Fixed fullyLoaded test when run in browser 2022-12-12 15:21:56 -08:00
Ian Gilman
2d713783ba
Merge pull request #2257 from pearcetm/fix-navigator-tests
Fix navigator tests
2022-12-12 14:44:03 -08:00
Tom
e122f372ba enable all tests 2022-12-11 15:07:43 -05:00
Tom
48bcd75f1a fixed logic of dragNavigatorBackToCenter method 2022-12-11 14:47:52 -05:00
Tom
37a024f023 bugfix in getCenter during zoom animation 2022-12-10 07:02:16 -05:00
Tom
86c105beaa bugfix in getCenter during zoom animation 2022-12-10 06:57:53 -05:00
Tom
2afd61b05d updates to work in progress 2022-12-08 23:12:28 -05:00
Tom
7e1b5c5665 fixed typo in documentation 2022-12-07 18:03:59 -05:00
Tom
54af53cf4e work in progress about viewer resize behavior 2022-12-07 17:46:25 -05:00
Ian Gilman
dd2f132577 Changelog for #2206 2022-12-07 14:27:43 -08:00
Ian Gilman
de4eac5a06
Merge pull request #2206 from filak/master
Update iiiftilesource.js
2022-12-07 14:21:47 -08:00
Ian Gilman
15b3e10727
Merge pull request #2254 from openseadragon/dependabot/npm_and_yarn/qs-6.11.0
Bump qs from 6.9.4 to 6.11.0
2022-12-07 13:59:18 -08:00
Tom
524b42c778 demo update 2022-12-06 17:21:03 -05:00
dependabot[bot]
44431beb13
Bump qs from 6.9.4 to 6.11.0
Bumps [qs](https://github.com/ljharb/qs) from 6.9.4 to 6.11.0.
- [Release notes](https://github.com/ljharb/qs/releases)
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.9.4...v6.11.0)

---
updated-dependencies:
- dependency-name: qs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-06 21:57:23 +00:00
Ian Gilman
c5c1fd156f Changelog for #2253 2022-12-06 13:54:38 -08:00
Tom
66b4b29424 small cleanup 2022-12-06 16:53:19 -05:00
Tom
256514bca6 small cleanup 2022-12-06 16:52:48 -05:00
Ian Gilman
4f990c74b7
Merge pull request #2253 from pearcetm/rotation-api-reconciliation
Rotation api reconciliation
2022-12-06 13:52:40 -08:00
Tom
757bf8690e fix Viewport._fixBounds to work with boundary constraints, and updated the demo page to show the behavior. 2022-12-06 16:42:13 -05:00
Tom
845cbced69 reverted Viewport.setRotation, created Viewport.setRotationWithPivot 2022-12-05 19:40:30 -05:00
Tom
05997d359c reverted Viewport.setRotation, created Viewport.setRotationWithPivot 2022-12-05 19:38:46 -05:00
Ian Gilman
f85c8ca4e9
Merge pull request #2251 from openseadragon/dependabot/npm_and_yarn/decode-uri-component-0.2.2
Bump decode-uri-component from 0.2.0 to 0.2.2
2022-12-05 13:51:19 -08:00
dependabot[bot]
5a11784173
Bump decode-uri-component from 0.2.0 to 0.2.2
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-04 03:42:28 +00:00
Tom
78c6295acf update unit tests 2022-12-02 22:08:15 -05:00
Tom
5aca85fe21 Merge branch 'master' of https://github.com/openseadragon/openseadragon into rotated-constraints-fix 2022-12-02 19:36:39 -05:00
Ian Gilman
1fe1630ab9
Merge pull request #2250 from openseadragon/ig-test
Fix unit tests
2022-12-02 16:33:24 -08:00
Ian Gilman
dfcfa4c02b Temporarily disabling navigator tests 2022-12-02 16:27:43 -08:00
Ian Gilman
77030096e4 Fixing test failures 2022-12-02 15:52:53 -08:00
Tom
8744a429f1 added documentation to _raiseConstraintsEvent 2022-12-02 18:48:28 -05:00
Tom
aede32c335 added documentation to getConstrainedBounds 2022-12-02 18:46:57 -05:00
Ian Gilman
9c42062efb Changelog for #2247 2022-12-02 14:18:22 -08:00
Ian Gilman
eb85b4498f
Merge pull request #2247 from JohnReagan/1970/support-tile-source-url-getter
Add support for dynamic urls from tile source. Fixes #1970
2022-12-02 14:16:40 -08:00
Tom
ac18d5629d fixed viewport constraint behavior when viewer is rotated 2022-12-02 16:43:39 -05:00
John Reagan
8ef5270d7f #1970: Update unit test to check for changed url behavior 2022-12-02 10:32:11 -05:00
Ian Gilman
09544f795f Changelog for #2246 2022-11-30 14:14:21 -08:00
Ian Gilman
c92fe116c5
Merge pull request #2246 from pearcetm/boundary-constraints-fix
boundary constraint logic fix
2022-11-30 14:12:16 -08:00
Tom
bd8e8a9e7f add line spacing 2022-11-30 16:48:04 -05:00
John Reagan
601160e9fb Add support for dynamic urls from tile source. Fixes #1970 2022-11-30 15:38:57 -05:00
Tom
5aa5d7ad56 removed extra space 2022-11-29 17:43:14 -05:00
Ian Gilman
11f70d54e8 Changelog for #2239 2022-11-29 13:53:35 -08:00
Ian Gilman
b8cc7e171e
Merge pull request #2239 from pearcetm/viewer-destroy-event
Viewer destroy event
2022-11-29 13:51:48 -08:00
Tom
554149cf4f merged .gitignore changes 2022-11-28 17:56:05 -05:00
Tom
968cb96bc4 added before-destroy event; reverted viewport boundary constraint changes 2022-11-28 17:54:23 -05:00
Tom
6d35f6df2c boundary constraint logic fix 2022-11-28 17:45:21 -05:00
Ian Gilman
c5639e32b5
Merge pull request #2244 from openseadragon/ig-test
Temporary fix to Travis builds: Pin the node version to one that works
2022-11-28 14:37:56 -08:00
Ian Gilman
da314c067c Travis debugging 2022-11-28 14:32:24 -08:00
Ian Gilman
11b7205ea4
Merge pull request #2243 from openseadragon/ig-test
Updating qunit test library
2022-11-28 14:28:10 -08:00
Ian Gilman
87f90c05b4 Merge branch 'master' into ig-test 2022-11-28 14:26:56 -08:00
Ian Gilman
9150af8592 Changelog for #2233 2022-11-28 13:50:22 -08:00
Ian Gilman
c25d15419c
Merge pull request #2233 from pearcetm/define-setRotation-axis
implemented rotation about a pivot point in viewport coordinates
2022-11-28 13:47:10 -08:00
Ian Gilman
7670892ae7 Just a tiny change to trigger Travis... 2022-11-26 18:01:44 -08:00
Tom
6fa8e6695d viewport _applyBoundaryConstraints fix 2022-11-26 12:04:05 -05:00
Tom
27399beffe banish .DS_Store 2022-11-23 15:33:09 -05:00
Tom
29384cd5ff Added event for viewer destroy 2022-11-23 15:28:40 -05:00
Tom
d55ccdf557 resolved package-lock.json conflict 2022-11-22 13:01:00 -05:00
Ian Gilman
22d4e62198 Updated package lock 2022-11-21 17:19:23 -08:00
Ian Gilman
cdfd5a454b Merge branch 'master' into ig-test 2022-11-21 17:16:45 -08:00
Dragos Daian
c3dec09d9c add loop for re-trying failed tiles [Take 3] 2022-11-20 12:27:51 +01:00
Ian Gilman
d7cd12679c
Merge pull request #2235 from openseadragon/dependabot/npm_and_yarn/minimatch-3.0.8
Bump minimatch from 3.0.4 to 3.0.8
2022-11-18 13:48:17 -08:00
Tom
7454d4323d updated setRotation param order to match rotateBy/rotateTo, deprecation warning for setting degrees, and private API 2022-11-16 18:07:56 -05:00
Ian Gilman
69c4b31853 Changelog tweak 2022-11-16 14:26:18 -08:00
Ian Gilman
89a69ee1e0 Changelog for #2225 2022-11-16 14:21:51 -08:00
dependabot[bot]
733f501a94
Bump minimatch from 3.0.4 to 3.0.8
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.0.8.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.0.8)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-16 22:20:58 +00:00
Ian Gilman
5bba14a763
Merge pull request #2225 from HamzaTatheer/master
One touch zoom in & out function #2077
2022-11-16 14:16:13 -08:00
Hamza Tatheer
7c44dc64bc Update viewer.js 2022-11-16 15:48:45 +05:00
Tom
2f174ad552 updated rotateBy 2022-11-15 23:51:44 -05:00
Tom
7f2725ba49 Slight API tweaks; added checks to rotationPivot 2022-11-15 19:01:19 -05:00
Tom
aea62de752 .DS_Store banished! 2022-11-15 17:50:56 -05:00
Tom
84bbc27a17 Add rotateBy and rotateTo to the API 2022-11-12 18:20:26 -05:00
Tom
bfddf7355b Add rotateBy and rotateTo to the API 2022-11-12 18:18:25 -05:00
Hamza Tatheer
6540a57aa9 pr changes 2022-11-12 16:32:45 +05:00
Tom
51807a77f0 implemented rotation about a pivot point in viewport coordinates 2022-11-11 22:15:52 -05:00
Hamza Tatheer
cb2fbe9b50 pr changes latest 2022-11-06 18:23:12 +05:00
Hamza Tatheer
fccab2da56 pr fixes 2022-11-03 23:55:35 +05:00
Hamza Tatheer
e4d9dcdd03 Triple Click Bug Fix 2022-10-30 01:27:56 +05:00
Hamza Tatheer
3ebc03ab3a demo page fix 2022-10-29 21:59:29 +05:00
Hamza Tatheer
05b596ce32 space removed 2022-10-29 21:47:37 +05:00
Hamza Tatheer
ca88de8e7f double click drag same position constraint removed 2022-10-29 21:46:12 +05:00
Hamza Tatheer
d44fc85582 pr changes 2022-10-29 21:22:25 +05:00
Hamza Tatheer
a0ac8666e0 Merge branch 'master' of https://github.com/HamzaTatheer/openseadragon 2022-10-29 20:18:23 +05:00
Hamza Tatheer
af3801367a
Merge branch 'openseadragon:master' into master 2022-10-26 11:03:28 +05:00
Ian Gilman
ed66c2d151 Changelog for #2212 2022-10-24 14:17:51 -07:00
Ian Gilman
af564547f0
Merge pull request #2212 from joedf/regression-fix-2201
Undefined check for object descriptor
2022-10-24 14:16:21 -07:00
Hamza Tatheer
89ab847ef6 bug fix 2022-10-24 23:17:03 +05:00
Hamza Tatheer
2f28970e32 zoom infinite 2022-10-24 11:08:37 +05:00
Hamza Tatheer
e12a626efb hide toolbar 2022-10-23 23:51:27 +05:00
Hamza Tatheer
2f2285711d Update viewer.js 2022-10-23 01:30:16 +05:00
Hamza Tatheer
9a4b802286 Update index.html 2022-10-22 21:10:01 +05:00
Hamza Tatheer
8336e8336b test 2022-10-22 21:04:58 +05:00
Hamza Tatheer
3a0bb0cd58 orignal Config 2022-10-22 15:50:18 +05:00
Hamza Tatheer
41a07b2250 zoom equation updated 2022-10-22 15:47:12 +05:00
Hamza Tatheer
cd9c5032f8 functionality test 2022-10-22 12:15:28 +05:00
Ian Gilman
c470e7effd Changelog for #2219 2022-10-20 14:29:06 -07:00
Ian Gilman
d5bcbcec3a
Merge pull request #2220 from jssullivan/master
Fixes #2219 TypeError: Cannot set property buttons of [object Object] which has only a getter when initializing OpenSeaDragon
2022-10-20 14:27:29 -07:00
Ian Gilman
38027e7588 Changelog for #2211 2022-10-20 14:23:27 -07:00
Ian Gilman
bbac0f0355
Merge pull request #2211 from openseaforce/docss
docs: change `@return` -> `@returns`
2022-10-20 14:21:42 -07:00
Joe DF
aec24d6dd7 add continue, update warning msg 2022-10-19 16:07:35 -04:00
Jimmy Sullivan
13330c4ede
Update viewer.js
Remove erroneous whitespace
2022-10-19 11:35:49 -04:00
Jimmy Sullivan
8bb600f6ae
Update viewer.js
Change removing buttons, to renaming it buttonGroup
2022-10-19 11:35:08 -04:00
Shyamkumar Yadav
98972d22d1
docs: fix a jsdoc 2022-10-19 10:25:37 +05:30
james.sullivan
333be9d6ca Remove version bump 2022-10-14 10:51:56 -04:00
james.sullivan
f87310c082 Fix initilization crash caused by Extend and buttons getter 2022-10-14 10:47:48 -04:00
james.sullivan
1a1b8e4510 v3.2.0-pre 2022-10-13 17:36:50 -04:00
Joe DF
476657ecad undefined check for obj. descriptor 2022-10-10 15:12:30 -04:00
Shyamkumar Yadav
5baa8d3252
docs: change @return -> @returns 2022-10-10 01:12:18 +05:30
Ian Gilman
39625aacaa
Merge pull request #2208 from openseaforce/readme
fix: links in README
2022-10-05 13:44:26 -07:00
Shyamkumar Yadav
f787d941e8
Remove Gitter and Build tags 2022-10-05 11:45:52 +05:30
Shyamkumar Yadav
2a90a2cdf4
Merge branch 'openseadragon:master' into readme 2022-10-05 11:42:38 +05:30
Ian Gilman
e212edae54
Merge pull request #2207 from openseaforce/contributing-links
fix: links in CONTRIBUTING
2022-10-04 13:53:46 -07:00
Shyamkumar Yadav
6b92904178
fix: links
- update `http` to `https`
- move all links at bottom
2022-10-01 14:16:27 +05:30
Shyamkumar Yadav
c48d143fe8
fix: links
- update JSDoc link
- update all links to https
- update `good first bug` to `good first issue`
2022-10-01 13:04:28 +05:30
Ian Gilman
0474d64ba1 Changelog for #2201 2022-09-28 14:00:46 -07:00
Ian Gilman
38bc89f455 Merge branch 'master' of github.com:openseadragon/openseadragon 2022-09-28 13:57:06 -07:00
Ian Gilman
d504a7ac83 Updating qunit to latest 2022-09-28 13:56:14 -07:00
Ian Gilman
9ec91891e6
Merge pull request #2201 from joedf/fix-2193
Fix "Viewer.buttons is deprecated" warning issue
2022-09-28 13:54:41 -07:00
filak
ce45e34265 Update iiiftilesource.js 2022-09-26 17:26:43 +02:00
Joe DF
6d74b684ec implement @iangilman 's fix 2022-09-17 17:10:03 +02:00
Joe DF
7497b83525 based on @pearcetm 's fix 2022-09-10 21:31:15 -04:00
Ian Gilman
f88a1f0603 Changelog for #2136 2022-08-23 14:17:39 -07:00
Ian Gilman
d3ef767487
Merge pull request #2136 from jonasengelmann/master
Viewport rotation animation
2022-08-23 14:13:22 -07:00
Ian Gilman
8e55dc7217 Changelog for #2190 2022-08-23 14:03:59 -07:00
Ian Gilman
5e7ce1afa5
Merge pull request #2190 from Aiosa/master
Provide deafult getTileHashKey implementation for "TileSource" object if missing
2022-08-23 14:01:45 -07:00
jonasengelmann
5f50d9e59e reworked setRotation to allow all degree values 2022-08-22 15:34:29 +02:00
jonasengelmann
9bce0e696c removed redundant EuclideanModulo function 2022-08-22 15:31:35 +02:00
Aiosa
61c77a3440 Fix hash tile generation by checking the validity of URL input parameter and fallback to level, x, y variables. 2022-08-21 10:09:36 +02:00
Aiosa
298f069c7e Change missing cacheKey in Tilesource constructor to warning. Provide default implementation of getTileHashKey for tileSource if the tileSource does not inherit from OpenSeadragon.TileSource 2022-08-09 10:40:57 +01:00
Ian Gilman
12402f2f0f Changelog for #2187 2022-08-01 14:19:22 -07:00
Ian Gilman
dafcf7bc14
Merge pull request #2187 from pearcetm/button-bugfix
Button bugfix
2022-08-01 14:15:55 -07:00
pearcetm
45643b94e3
Update button.js 2022-07-28 17:55:21 -04:00
pearcetm
6d5a75bcf7
Bugfix for enable/disable methods for Buttons
Fixes https://github.com/openseadragon/openseadragon/issues/2185
2022-07-28 17:53:49 -04:00
Ian Gilman
bdb44d84fb Changelog for #2183 2022-07-26 14:58:07 -07:00
Ian Gilman
c449a8353d
Merge pull request #2183 from altert/master
Fix closure for croppingPolygons in _drawTiles function
2022-07-26 14:55:09 -07:00
altert
5829a9e892 fix closure for croppingPolygons in drawTile 2022-07-26 13:12:48 +05:30
jonasengelmann
ddd4a05e5e Revert "always return Euclidean modulo of current rotation"
This reverts commit 32af983910.
2022-07-07 16:31:35 +02:00
jonasengelmann
32af983910 always return Euclidean modulo of current rotation 2022-06-29 20:32:47 +02:00
jonasengelmann
3cdd94e465 constrained rotation to shortest path 2022-06-29 19:47:26 +02:00
jonasengelmann
1b27e59be8 added Euclidean modulo helper function 2022-06-29 19:47:03 +02:00
Ian Gilman
0335f3f4ab Changelog for #2148 2022-06-28 14:15:35 -07:00
Ian Gilman
d1f46148a7 Merge branch 'master' of github.com:openseadragon/openseadragon 2022-06-28 14:13:21 -07:00
Ian Gilman
1d327d673e
Merge pull request #2148 from Aiosa/master
Delegate tile fetching and caching to the TileSource
2022-06-28 14:12:44 -07:00
Aiosa
2fbaf71448
Merge branch 'master' into master 2022-06-28 14:14:05 +02:00
Aiosa
0aadc23fcb Merge branch 'openseadragon-master' 2022-06-28 14:11:30 +02:00
Aiosa
bb1755613e Merge branch 'master' of https://github.com/openseadragon/openseadragon into openseadragon-master
# Conflicts:
#	src/tiledimage.js
2022-06-28 14:11:02 +02:00
Ian Gilman
71e9d5775c Changelog for #2173 2022-06-20 13:59:58 -07:00
Ian Gilman
6494b49d67
Merge pull request #2173 from ahankinson/fix-iiif-id-field
Fixed: ID field parsing on IIIF tile sources
2022-06-20 13:58:14 -07:00
Andrew Hankinson
ddd375b378 Merge branch 'master' into fix-iiif-id-field 2022-06-18 15:17:20 +02:00
Andrew Hankinson
1b777c9e62 Fixed: remove redundant checks
Also fixes a JSDoc error for annotating optional parameters.
2022-06-18 15:16:48 +02:00
Andrew Hankinson
d35c0a6385 Fixed: Updated configure comment
Updated comment to make it clear that it's a static method. Also updated the example
to IIIF v2, since that's more widely used than v1.1.
2022-06-17 10:34:31 +02:00
Andrew Hankinson
86dabe624b Revert changes to ID field in configure 2022-06-17 10:23:13 +02:00
Andrew Hankinson
7a97d524f8 Improved testing data for IIIFv3
This commit adds a new set of tests for IIIFv3 Image API info
to the `formats` tests. These tests mirror the tests done for the v2
handler, but with updated 'info.json' files.

Image directories also needed to be changed to include the full width/height
parameters.

Also changed was moving the `iiif` test block up below formats, and adding a QUnit
module name. This allowed the tests to show up in the QUnit browser test.

All of the new tests were checked and pass.
2022-06-16 12:58:41 +02:00
Andrew Hankinson
820564dd3e Fixed: normalize ID property for IIIF tile source
This commit attempts to normalize all possible values of the "id" property for IIIF tile sources
into a single internal _id property.
2022-06-16 12:55:21 +02:00
Ian Gilman
9988fcebc1 Changelog for #2175 2022-06-14 14:29:14 -07:00
Ian Gilman
0114381ebe
Merge pull request #2175 from joedf/patch-2174
added navigatorElement, fix bug id-overwrite on element
2022-06-14 14:25:05 -07:00
Joe DF
650b899de3 added navigatorElement, fix bug id-overwrite on element 2022-06-14 12:56:34 -04:00
Andrew Hankinson
6eeccb530b Fixed: ID field parsing on IIIF tile sources
The IIIF specification allows for the ID field to be either with or without
an "@" prefix for IIIFv3. (See: https://iiif.io/api/image/3.0/) Currently OSD
will fail to parse an image block that uses the non-prefixed form.

This PR changes the IIIF tile source parsing to allow for both forms of the
`id` key.
2022-06-14 08:57:00 +02:00
Ian Gilman
bf395c1633 Changelog for #2166 2022-06-13 14:17:20 -07:00
Ian Gilman
d956b2ae9d
Merge pull request #2166 from joedf/patch-for-PR-1303
Patch for #1303
2022-06-13 13:49:17 -07:00
Ian Gilman
c20b2bbab9 Changelog for #2160 2022-06-09 15:44:03 -07:00
Ian Gilman
71a1f06e35
Merge pull request #2160 from joedf/patch-2
apply only zoom constraint by default for scroll events
2022-06-09 15:41:17 -07:00
Joachim de fourestier
3ca17c1508 missing period 2022-06-08 20:15:21 -04:00
Joachim de fourestier
ff4f88dc64 add some documentation 2022-06-08 20:05:43 -04:00
Ian Gilman
e8adefbe6e Minor fix to previous PR 2022-06-08 15:06:58 -07:00
Ian Gilman
4ce2bdcdd1
Merge pull request #2172 from openseadragon/copyright
Updated copyright to 2022
2022-06-08 15:03:15 -07:00
Ian Gilman
f31179c9ce Updated copyright to 2022 2022-06-08 15:02:29 -07:00
Ian Gilman
c1c380fa8f Started version 3.2.0 2022-06-07 14:06:11 -07:00
Ian Gilman
ee3fc2bd79 Version 3.1.0 2022-06-07 14:00:35 -07:00
Ian Gilman
2afc028ab2 JSDoc fixes 2022-06-07 13:56:58 -07:00
Ian Gilman
db9dcdb2cc Package-lock 2022-06-07 13:42:55 -07:00
Jirka
7b759558b1 Add tile reference to imagejob options. 2022-06-07 14:53:18 +02:00
Aiosa
1d99a2d6be
Merge branch 'openseadragon:master' into master 2022-06-07 14:48:33 +02:00
Ian Gilman
2007ba7ea5
Merge pull request #2165 from openseadragon/dependabot/npm_and_yarn/grunt-1.5.3
Bump grunt from 1.5.2 to 1.5.3
2022-05-31 13:58:07 -07:00
Joe DF
df0e598e38 fix typo 2022-05-29 21:38:38 -04:00
Joe DF
3661d6cae5 remove auto code 2022-05-29 21:31:29 -04:00
Joe DF
9772901d71 Don't overwrite the element's id if it has one already 2022-05-29 21:30:48 -04:00
Joe DF
4a877d60f7 remove unneeded code, not sure how it got there 2022-05-29 21:23:22 -04:00
Joe DF
ca368797b0 restructure again to make less confusing, less duplicate code 2022-05-29 21:18:28 -04:00
Joe DF
d4dfcd2288 fix inconsistent open-close braces, add warn when using element even when id provided 2022-05-29 20:53:11 -04:00
Joe DF
21146b6b2c Merge remote-tracking branch 'cameronbaney/add-element-option-navigator' into patch-for-PR-1303 2022-05-29 20:33:23 -04:00
dependabot[bot]
e15c65ac09
Bump grunt from 1.5.2 to 1.5.3
Bumps [grunt](https://github.com/gruntjs/grunt) from 1.5.2 to 1.5.3.
- [Release notes](https://github.com/gruntjs/grunt/releases)
- [Changelog](https://github.com/gruntjs/grunt/blob/main/CHANGELOG)
- [Commits](https://github.com/gruntjs/grunt/compare/v1.5.2...v1.5.3)

---
updated-dependencies:
- dependency-name: grunt
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-26 00:12:47 +00:00
Joe DF
5b7be6be05 implement fixes from iangilman 2022-05-19 16:52:56 -04:00
Ian Gilman
995be3c37c Changelog for #2162 2022-05-18 15:39:02 -07:00
Ian Gilman
15ef58a8f5
Merge pull request #2162 from pearcetm/imagetilesource-bugfix
Bugfix for imagetilesource _freeupCanvasMemory
2022-05-18 15:33:47 -07:00
pearcetm
af26fdbff1
Bugfix for imagetilesource _freeupCanvasMemory 2022-05-18 12:26:19 -04:00
Joe DF
325f65fe5c attempt no.2 to fix #2160 2022-05-18 11:16:28 -04:00
Joe DF
7d6437b2cd Revert "apply only zoom constraint by default for scroll events"
This reverts commit a6d1472134.
2022-05-18 10:48:58 -04:00
Ian Gilman
a27b511ad3 Changelog for #2158 2022-05-12 13:55:42 -07:00
Ian Gilman
f3f20fd30d
Merge pull request #2158 from cavenel/master
Fix wrong center point on pinch zoom
2022-05-12 13:54:26 -07:00
Joe DF
a6d1472134 apply only zoom constraint by default for scroll events 2022-05-12 15:31:51 -04:00
Christophe Avenel
f1865c3878
Fix wrong center point on touch zoom
When doing pinch to zoom, we need to do pan first and then zoom, so that the center point is correct.
Otherwise, the pan will computed on the unzoomed coordinates, giving an impression of zooming toward the center
2022-05-12 10:45:47 +02:00
Ian Gilman
165aaebd4c Changelog for #2155 2022-05-10 13:51:58 -07:00
Ian Gilman
bfc4bc553a
Merge pull request #2155 from samwilson/typos
Fix duplicated word: "the the"
2022-05-10 13:51:05 -07:00
Aiosa
6e80e2d184
Merge branch 'openseadragon:master' into master 2022-05-06 16:52:24 +02:00
Ian Gilman
fe3b1c5a0d Changelog for #2153 2022-05-05 14:04:34 -07:00
Ian Gilman
ad7f3449bb
Merge pull request #2153 from devbyjonah/deprecated_Alias
added warning for deprecated method buttons()
2022-05-05 14:02:06 -07:00
Sam Wilson
1700e2f060 Fix duplicated word: "the the"
From https://gerrit.wikimedia.org/r/c/mediawiki/extensions/ProofreadPage/+/789330
2022-05-05 20:43:38 +08:00
Jirka
8a2c998cb9 Finish on image job now accepts request argument. Further comments cleanup. Deprecation message for image property in tile loaded event. Removal of downloadTileFinish(). More robust aborting that cleans up an image properties when aborted (not done until now). 2022-05-04 15:16:13 +02:00
Aiosa
150e750ece
Merge branch 'openseadragon:master' into master 2022-05-04 13:40:06 +02:00
Ian Gilman
2b13120fcc Changelog for #2152 2022-05-03 14:41:56 -07:00
Ian Gilman
c0674b2924
Merge pull request #2152 from joedf/patch-1
fix typos for dragToPan in OpenSeadragon.Options
2022-05-03 14:40:48 -07:00
Ian Gilman
569b2fdf41
Merge pull request #2150 from openseadragon/dependabot/npm_and_yarn/grunt-1.5.2
Bump grunt from 1.4.1 to 1.5.2
2022-05-03 14:35:54 -07:00
devbyjonah
5ed4d5f630 added warning for deprecated method buttons() 2022-05-02 19:14:39 -07:00
Ian Gilman
449c709dcc Changelog for #2145 2022-05-02 14:35:30 -07:00
Ian Gilman
3aca527360
Merge pull request #2145 from tdiprima/patch-1
updated conditional expression
2022-05-02 14:33:57 -07:00
Jirka
d82fd35323 Fix comments on #2148: part 2. Better commens on the new TileSource API. Deprecation if 'tile-loaded' image event parameter. Unwrap ImageJob and add userData property. 2022-04-29 23:45:01 +02:00
Joe DF
eaa1a93755
fix typos for dragToPan in OpenSeadragon.Options
I noticed "`gestureSettings`[Mouse]" was 3 more times, where I believe they should be `Touch`, `Pen`, and `Unknown`?
2022-04-29 14:05:24 -04:00
Jirka
45a7a4aaf3 Fix comments on #2148: hasTransparency as a property. Move '.image' tile property to be a getter instead. Rename 'ImageJob' data property from 'image' to 'data'. Repair comments related to #2148. 2022-04-29 18:41:43 +02:00
Aiosa
92ad2c5552
Merge branch 'openseadragon:master' into master 2022-04-29 17:40:14 +02:00
dependabot[bot]
9c6d22aa50
Bump grunt from 1.4.1 to 1.5.2
Bumps [grunt](https://github.com/gruntjs/grunt) from 1.4.1 to 1.5.2.
- [Release notes](https://github.com/gruntjs/grunt/releases)
- [Changelog](https://github.com/gruntjs/grunt/blob/main/CHANGELOG)
- [Commits](https://github.com/gruntjs/grunt/compare/v1.4.1...v1.5.2)

---
updated-dependencies:
- dependency-name: grunt
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-27 05:26:49 +00:00
Ian Gilman
229bfe7946 Changelog for #2147 2022-04-19 13:46:08 -07:00
Ian Gilman
a8233ca6e1
Merge pull request #2147 from Aiosa/mousetracker
Release handler and undefined releasePoint instance
2022-04-19 13:44:14 -07:00
jonasengelmann
62e24ac1ab ensure constructor backward compatibility 2022-04-19 16:43:00 +02:00
Jirka
4f79f29238 Move cache creation, image downloading process and transparency deduction to the TileSource instance to allow custom data fetching, caching, processing. 2022-04-16 21:19:54 +02:00
Jirka
b2eda881e8 Another problem with release handler: a point instace could be undefined. 2022-04-16 16:53:30 +02:00
Ian Gilman
3dc1fc87b1 Changelog for #2142 2022-04-15 14:16:06 -07:00
Ian Gilman
334e8fbc67
Merge pull request #2142 from Aiosa/master
Delegate error printing to the ajax caller.
2022-04-15 14:12:39 -07:00
Jirka
ec430779f4 Move open-failed error message to the handler, adjust test for the new message style. Add 'numberOfHandlers()' method for events. 2022-04-15 10:32:08 +02:00
Ian Gilman
3b2d456a25 Changelog for #2138 2022-04-14 15:03:24 -07:00
Ian Gilman
d8a8eff21a
Merge pull request #2138 from Aiosa/cache-key
Change Tile.cacheKey strategy
2022-04-14 15:00:35 -07:00
Ian Gilman
f70106e41b
Merge pull request #2144 from openseadragon/dependabot/npm_and_yarn/node-fetch-2.6.7
Bump node-fetch from 2.6.6 to 2.6.7
2022-04-13 13:50:14 -07:00
Ian Gilman
0976c67a29 Changelog for #2100 2022-04-13 13:49:06 -07:00
Tammy DiPrima
e1b651b66c
update expression
Code fails if element.style is undefined.
2022-04-13 13:33:44 -04:00
Jirka
3a84b9369b Clarify documentation on cache-key creation. 2022-04-13 10:47:48 +02:00
dependabot[bot]
e722c960bc
Bump node-fetch from 2.6.6 to 2.6.7
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.6 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.6...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-12 23:12:41 +00:00
Ian Gilman
2d7be96bdf
Merge pull request #2143 from openseadragon/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-04-12 16:11:47 -07:00
Ian Gilman
2d890fb7a1
Merge pull request #2100 from TanukiSharp/master
Changed full page sizing to 100% instead of compute fixed size (issue #2099)
2022-04-12 15:53:16 -07:00
dependabot[bot]
4679455720
Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-09 08:55:12 +00:00
Sebastien ROBERT
99f73c548c Changed full page sizing to 100vw/100vh instead of compute fixed size (issue 2099) 2022-04-08 08:23:25 +09:00
Jirka
1ec4d71db0 makeAjaxRequest(): delegate error message responsibility to the handler if any. 2022-04-07 17:56:14 +02:00
Jirka
a2b915cc6d Merge remote-tracking branch 'origin/cache-key' into cache-key 2022-04-07 14:53:20 +02:00
Jirka
ee2404afe3 Update Tile.prototype.getTileHashKey() documentation. Provide deprecation warning for cacheKey property - now it must be passed through Tile constructor. 2022-04-07 14:48:26 +02:00
Aiosa
29d16bd535
Merge branch 'openseadragon:master' into cache-key 2022-04-02 15:23:37 +02:00
jonasengelmann
eca51850e2 Merge branch 'master' of https://github.com/openseadragon/openseadragon 2022-04-01 11:14:55 +02:00
jonasengelmann
c16d1e3dff ensure backward compatibility 2022-04-01 10:06:18 +02:00
jonasengelmann
d62538f42e fixed white space 2022-03-31 23:50:38 +02:00
jonasengelmann
c2821b1775 set initial navigator animation time to viewport's 2022-03-31 23:45:46 +02:00
Ian Gilman
2c9d244023 Changelog for #2134 2022-03-31 13:55:53 -07:00
Ian Gilman
8e6369969b
Merge pull request #2134 from Aiosa/master
Docs clarification and solve #2094. Unwrap TiledImage closure.
2022-03-31 13:48:53 -07:00
jonasengelmann
ef8e7ad9c5 fixed typo 2022-03-30 23:41:43 +02:00
jonasengelmann
fb8bafc6a0 updated tests 2022-03-30 23:05:14 +02:00
jonasengelmann
dc2a1534d3 removed modulo for degrees to avoid spining 2022-03-30 22:59:29 +02:00
jonasengelmann
8746e8b243 fixed wrong getHomeBounds 2022-03-30 22:37:14 +02:00
Jirka
38e91f1fa5 Change coverage methods on TiledImage to be member methods. 2022-03-30 13:27:23 +02:00
jonasengelmann
1cbc2d96c1 fixed initial degree option 2022-03-29 19:18:25 +02:00
jonasengelmann
65957efe72 updated docs 2022-03-29 16:55:47 +02:00
jonasengelmann
8519e30a3a added viewport rotation animation 2022-03-29 16:50:18 +02:00
Jirka
2750100d24 Move cache-key generation to TileSource: user might need to override default behaviour in case of non-unique URL's (post data used). 2022-03-29 09:30:25 +02:00
Jirka
7f784835a7 Revert 'spacing change' for licence disclaimer (TiledImage), fix tests on drag-end event no longer firing when mouse does not move (PR #2064) 2022-03-25 12:30:18 +01:00
Jirka
20594e5a51 Stupid typo, added 'static' methods to a wrong class... 2022-03-23 14:25:36 +01:00
Jirka
aa0119be45 Rewrite TiledImage closure functions to be private class members. Fix tests that expect error message to appear in 'log' instead of 'error'. 2022-03-23 14:05:58 +01:00
Jirka
68126a82dc Update docs on POST data to reflect more accurately the behaviour.
Fix bug & implement propositions ~ issue #2094.
2022-03-23 10:22:13 +01:00
Ian Gilman
8506b8a486 Changelog for #2121 (for real) 2022-03-15 14:54:08 -07:00
Ian Gilman
fd8405dd6b Changelog for #2021 2022-03-15 14:52:17 -07:00
Ian Gilman
7e64d28197
Merge pull request #2121 from ronnymikalsen/fix/2117-contacts-points-in-mousetracker
fix: contacts points on touch devices
2022-03-15 14:49:51 -07:00
Ian Gilman
cf709b1c5c
Merge pull request #2132 from ronnymikalsen/fix/demo-iiif-tilesources
fix: change tileSources in demo for iiif
2022-03-15 14:46:47 -07:00
Ronny Mikalsen
576a0f9c33 fix: setting contacts to 0 if below 0 2022-03-14 14:26:11 +01:00
Ronny Mikalsen
01a9e3b168 fix: change tileSources in demo for iiif
Tile sources on wellcomelibrary.org is no longer available
2022-03-14 14:12:21 +01:00
Ian Gilman
116d0a7001 Changelog for #2120 2022-03-04 14:17:02 -08:00
Ian Gilman
7ee059d276 Merge branch 'master' of github.com:openseadragon/openseadragon 2022-03-04 14:14:50 -08:00
Ian Gilman
d175de1496
Merge pull request #2120 from claycoleman/allow-silencing-multi-image-warnings
Allow silencing multi-image warnings
2022-03-04 14:13:51 -08:00
Ronny Mikalsen
eeeccff1ba chore: revert code that should be in another PR 2022-03-02 10:12:06 +01:00
Ronny Mikalsen
0f984bd3b3 refactor: removed unnecessary code 2022-03-02 10:10:30 +01:00
Ian Gilman
5b87f9387e Changelog for #2116 2022-03-01 14:07:01 -08:00
Ian Gilman
3e5e12722a
Merge pull request #2116 from rvv-bouvet/fix/draw-tiles-without-canvas
fix: avoid crash when setting useCanvas to false
2022-03-01 14:03:49 -08:00
Clay Coleman
322a22cb68 Allow silencing multi-image warnings 2022-02-25 12:11:06 -06:00
Ronny Mikalsen
47cc04ff53 fix: contacts points on touch devices
Swiping fast multiple times makes contacts points in mousetracker to be out of sync for touch event

Fixes #2117
2022-02-22 14:24:10 +01:00
Ronny Valentin Vindenes
34fd856b4f fix: avoid crash when setting useCanvas to false 2022-02-22 12:31:32 +01:00
Ian Gilman
2b6c8dd622 Changelog for #2112 2022-02-18 14:23:03 -08:00
Ian Gilman
d4e03836dd
Merge pull request #2112 from shyamkumaryadav/doc-typo
Doc: small documentation fix
2022-02-18 14:19:02 -08:00
Shyamkumar Yadav
7532075aab
Doc: small documentation fix openseadragon#2111
line change from click to double-click
2022-02-18 09:49:24 +05:30
Shyamkumar Yadav
84257e3202 Doc: small documentation fix #2111 2022-02-12 23:34:40 +05:30
Ian Gilman
51e3ea7fa0 Changelog for #2072 and minor comment style change 2022-01-21 11:57:14 -08:00
Ian Gilman
b1ec71e91c
Merge pull request #2072 from Aiosa/master
Ajax POST data in the OpenSeadragon.
2022-01-21 11:53:07 -08:00
Jirka
63ecaafa51 Update documentation to be more explicit about post data string parameter format. 2022-01-20 18:03:08 +01:00
Jirka
bd6ec09458 Remove warning because loadTilesWithAjax flag is not passed to the TileSource 2022-01-13 10:05:37 +01:00
Jirka
e236ff0ea8 Forgot one 'allowPost' rename 2022-01-12 22:37:59 +01:00
Jirka
aacae1ca3f Reverted .json configuration changes made by npm. Added tests for PUSH functionality, new flag 'allowPost' to explicitly enable POST data, remove (-1) in the URL splitting. 2022-01-12 22:31:13 +01:00
Aiosa
745a788d84
Merge branch 'openseadragon:master' into master 2022-01-06 10:56:43 +01:00
Ian Gilman
055699a00a Changelog for #2075 2021-12-23 11:47:41 -08:00
Ian Gilman
fab395dc02
Merge pull request #2075 from TanukiSharp/master
Extends the fix for seams in transparent images to any browsers
2021-12-23 11:43:11 -08:00
Sebastien ROBERT
12939d5bb9 Removed the animation state and isSubPixelRoundingRule* functions (except isSubPixelRoundingRuleUnknown), changed timing when animating is set to false 2021-12-23 12:15:09 +09:00
Sebastien ROBERT
458a16ce1f Introduced animation state and testing it to determine rendering when at rest 2021-12-22 15:44:32 +09:00
Sebastien ROBERT
bfc0c4608e Fixed copy/paste mistake 2021-12-22 15:42:43 +09:00
Sebastien ROBERT
3fa67c317b Moved _shouldRoundPositionAndSize Drawer class member to drawTile() function argument 2021-12-22 14:16:11 +09:00
Sebastien ROBERT
2aebdbd066 Renamed subPixelRounding to subPixelRoundingForTransparency, changed fallback to '*', introduced SUBPIXEL_ROUNDING_OCCURRENCES numbers, added support for simple mode 2021-12-22 14:16:11 +09:00
Ian Gilman
5835b85d3f Merge branch 'master' of github.com:openseadragon/openseadragon 2021-12-17 15:09:04 -08:00
Ian Gilman
9ab6a5ac69 Fix after NPM package update 2021-12-17 15:03:56 -08:00
Ian Gilman
bdcd078b46 Updated NPM packages 2021-12-17 15:02:14 -08:00
Ian Gilman
24b3d1caef Changelogs for #2067, #2069, #2073 2021-12-17 14:56:50 -08:00
Ian Gilman
b1cf63eaff
Merge pull request #2073 from Abhishek-90/master
Changed Console.log in SRC
2021-12-17 14:51:40 -08:00
Ian Gilman
d9494c6d7f
Merge pull request #2069 from JachiOnuoha/JachiOnuoha-ArrowKeysBug
Fixed Arrow keys by pass panVertical/panHorizontal bug
2021-12-17 14:49:12 -08:00
Ian Gilman
c40a77f2de
Merge pull request #2067 from JachiOnuoha/JachiOnuoha
Fixed jsdocs issue and detecting when viewer is Fullscreen
2021-12-17 14:45:45 -08:00
Ian Gilman
9da3fb8da9 Started 3.0.1 changelog 2021-12-15 11:38:29 -08:00
Abhishek-90
77c47cdd09 Made changes in ReferenceStrip.js 2021-12-15 11:54:11 +05:30
Sebastien ROBERT
e5b608d86a Extends the fix for seams in transparent images to any browsers, making it configurable 2021-12-13 14:20:11 +09:00
Abhishek-90
200bd607d8 Changed Console.log in SRC 2021-12-10 19:12:14 +05:30
Aiosa
3782ea2284
Merge branch 'openseadragon:master' into master 2021-12-08 09:59:05 +01:00
Aiosa
a11b5ce602 Support for POST data in the ajax requests. 2021-12-08 09:54:14 +01:00
Jachimike Onuoha
46099f3dfb
Merge branch 'openseadragon:master' into JachiOnuoha 2021-12-07 13:27:42 -05:00
Jachimike Onuoha
0a06c5b6a4 Updated boolean logic for preventVerticalPan and preventHorizontalPan 2021-12-06 23:33:58 -05:00
Jachimike Onuoha
a42e08c1ed Minor documentation updates 2021-12-06 23:19:12 -05:00
Jachimike Onuoha
5b8a22e848
Merge branch 'openseadragon:master' into JachiOnuoha-ArrowKeysBug 2021-12-02 16:56:18 -05:00
Jachimike Onuoha
f84d241367 Corrected documentation and isFullScreen function 2021-12-02 16:55:07 -05:00
Jachimike Onuoha
1fde705785 Fixed Arrowkey panning bug 2021-12-02 14:45:55 -05:00
Jachimike Onuoha
2edf48e880 Temporary fix for arrow key panVertical bug 2021-11-30 17:43:11 -05:00
Jachimike Onuoha
0f1de455e2 Recreated panHorizontal & panVertical bug 2021-11-29 16:40:26 -05:00
Jachimike Onuoha
664b707e5f Added isFullscreen function to viewer.js 2021-11-29 15:33:37 -05:00
Jachimike Onuoha
45ee4cd7a9 Added jsdocs fixes as discussed in the issue 2021-11-28 19:46:45 -05:00
Cameron Baney
4301254fa0 Allow user to add element option for navigator 2017-09-05 14:05:36 -04:00
171 changed files with 23174 additions and 10197 deletions

1
.browserslistrc Normal file
View file

@ -0,0 +1 @@
defaults

View file

@ -1,14 +1,16 @@
{
"root": true,
"plugins": ["compat"],
"extends": [
"eslint:recommended"
"eslint:recommended",
"plugin:compat/recommended"
],
"env": {
"es6": false,
"es6": true,
"browser": true
},
"parserOptions": {
"ecmaVersion": 5,
"ecmaVersion": 6,
"sourceType": "script",
"ecmaFeatures": {
"globalReturn": false,

1
.gitignore vendored
View file

@ -8,3 +8,4 @@ instrumented/
/nbproject/private/
.directory
local-test
.DS_Store

View file

@ -1,6 +1,10 @@
# Specify dist until Travis CI default Runner OS updates to one
# with glibc version required by newer Node versions
# See: https://github.com/nodejs/node/issues/42351#issuecomment-1068424442
dist: jammy
language: node_js
sudo: false
node_js:
- "stable"
- lts/*
before_install:
- npm install -g grunt-cli

39
CITATION.cff Normal file
View file

@ -0,0 +1,39 @@
cff-version: 1.2.0
title: OpenSeadragon
message: "If you use this software, please cite it using the metadata from this file."
type: software
authors:
- given-names: Ian
family-names: Gilman
email: ian@iangilman.com
- given-names: Aseem
family-names: Kishore
- given-names: Chris
family-names: Thatcher
- given-names: Mark
family-names: Salsbery
- given-names: Antoine
family-names: Vandecreme
- given-names: Thomas
family-names: Pearce
identifiers:
- type: url
value: https://openseadragon.github.io/
description: Homepage
- type: url
value: https://github.com/openseadragon/openseadragon
description: Repository
repository-code: https://github.com/openseadragon/openseadragon
url: https://openseadragon.github.io/
abstract: "An open-source, web-based viewer for high-resolution zoomable images, implemented in pure JavaScript, for desktop and mobile."
keywords:
- javascript
- image
- zooming
- viewer
- image-viewer
- high-resolution
- iiif
license: BSD-3-Clause
version: 5.0.1
date-released: 2024-11-09

View file

@ -3,20 +3,20 @@
OpenSeadragon is truly a community project; we welcome your involvement!
When contributing, please attempt to match the code style already in the codebase.
However, we are in the process of changing our code style (see issue [#456](https://github.com/openseadragon/openseadragon/issues/456)), so avoid spaces inside parentheses and square brackets. Note that we use four spaces per indentation stop. For easier setup you can also install [EditorConfig](http://editorconfig.org/) if your IDE is supported. For more thoughts on code style, see [idiomatic.js](https://github.com/rwldrn/idiomatic.js/).
However, we are in the process of changing our code style (see issue [#456](https://github.com/openseadragon/openseadragon/issues/456)), so avoid spaces inside parentheses and square brackets. Note that we use four spaces per indentation stop. For easier setup you can also install [EditorConfig](https://editorconfig.org/) if your IDE is supported. For more thoughts on code style, see [idiomatic.js](https://github.com/rwldrn/idiomatic.js/).
When fixing bugs and adding features, when appropriate please also:
* Update related doc comments (we use [JSDoc 3](http://usejsdoc.org/))
* Update related doc comments (we use [JSDoc 3](https://jsdoc.app/))
* Add/update related unit tests
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.
If you're new to the project, check out our [good first issues](https://github.com/openseadragon/openseadragon/issues?labels=good+first+issue&page=1&state=open) for some places to dip your toe in the water.
If you're new to open source in general, check out [GitHub's open source intro guide](https://guides.github.com/activities/contributing-to-open-source/).
### 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:
All command-line operations for building and testing OpenSeadragon are scripted using [Grunt](https://gruntjs.com/) which is based on [Node.js](https://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`
@ -57,10 +57,14 @@ You can also publish the built version to the site-build repository. This assume
### Testing
Our tests are based on [QUnit](http://qunitjs.com/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer); they're both installed when you run `npm install`. To run on the command line:
Our tests are based on [QUnit](https://qunitjs.com/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer); they're both installed when you run `npm install`. To run on the command line:
grunt test
To test a specific module (`navigator` here) only:
grunt test --module="navigator"
If you wish to work interactively with the tests or test your changes:
grunt connect watch
@ -69,6 +73,12 @@ and open `http://localhost:8000/test/test.html` in your browser.
Another good page, if you want to interactively test out your changes, is `http://localhost:8000/test/demo/basic.html`.
> Note: corresponding npm commands for the above are:
> - npm run test
> - npm run test -- --module="navigator"
> - npm run dev
You can also get a report of the tests' code coverage:
grunt coverage

View file

@ -28,6 +28,7 @@ module.exports = function(grunt) {
coverageDir = 'coverage/' + dateFormat(new Date(), 'yyyymmdd-HHMMss'),
sources = [
"src/openseadragon.js",
"src/matrix3.js",
"src/fullscreen.js",
"src/eventsource.js",
"src/mousetracker.js",
@ -48,6 +49,8 @@ module.exports = function(grunt) {
"src/legacytilesource.js",
"src/imagetilesource.js",
"src/tilesourcecollection.js",
"src/priorityqueue.js",
"src/datatypeconvertor.js",
"src/button.js",
"src/buttongroup.js",
"src/rectangle.js",
@ -57,11 +60,14 @@ module.exports = function(grunt) {
"src/imageloader.js",
"src/tile.js",
"src/overlay.js",
"src/drawer.js",
"src/drawerbase.js",
"src/htmldrawer.js",
"src/canvasdrawer.js",
"src/webgldrawer.js",
"src/viewport.js",
"src/tiledimage.js",
"src/tilecache.js",
"src/world.js"
"src/world.js",
];
var banner = "//! <%= pkg.name %> <%= pkg.version %>\n" +
@ -75,6 +81,11 @@ module.exports = function(grunt) {
grunt.config.set('gitInfo', rev);
});
let moduleFilter = '';
if (grunt.option('module')) {
moduleFilter = '?module=' + grunt.option('module')
}
// ----------
// Project configuration.
grunt.initConfig({
@ -160,13 +171,16 @@ module.exports = function(grunt) {
qunit: {
normal: {
options: {
urls: [ "http://localhost:8000/test/test.html" ],
timeout: 10000
}
urls: [ "http://localhost:8000/test/test.html" + moduleFilter ],
timeout: 10000,
puppeteer: {
headless: 'new'
}
},
},
coverage: {
options: {
urls: [ "http://localhost:8000/test/coverage.html" ],
urls: [ "http://localhost:8000/test/coverage.html" + moduleFilter ],
coverage: {
src: ['src/*.js'],
htmlReport: coverageDir + '/html/',
@ -187,7 +201,12 @@ module.exports = function(grunt) {
server: {
options: {
port: 8000,
base: "."
base: {
path: ".",
options: {
stylesheet: 'style.css'
}
}
}
}
},
@ -197,7 +216,7 @@ module.exports = function(grunt) {
},
eslint: {
options: {
configFile: '.eslintrc.json'
overrideConfigFile: '.eslintrc.json'
},
target: sources
},

View file

@ -1,5 +1,5 @@
Copyright (C) 2009 CodePlex Foundation
Copyright (C) 2010-2013 OpenSeadragon contributors
Copyright (C) 2010-2024 OpenSeadragon contributors
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

View file

@ -1,18 +1,39 @@
# OpenSeadragon
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/openseadragon/openseadragon?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://secure.travis-ci.org/openseadragon/openseadragon.png?branch=master)](http://travis-ci.org/openseadragon/openseadragon)
<!-- [![Gitter][gitter-badge]][gitter]
[![Build Status][build-badge]][build] -->
An open-source, web-based viewer for zoomable images, implemented in pure JavaScript.
See it in action and get started using it at [http://openseadragon.github.io/](http://openseadragon.github.io/).
See it in action and get started using it at [https://openseadragon.github.io/][openseadragon].
## Stable Builds
See the [GitHub releases page](https://github.com/openseadragon/openseadragon/releases).
See the [GitHub releases page][github-releases].
## 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/](http://openseadragon.github.io/). If you want to modify OpenSeadragon and/or contribute to its development, read the [contributing guide](https://github.com/openseadragon/openseadragon/blob/master/CONTRIBUTING.md) for instructions.
If you want to use OpenSeadragon in your own projects, you can find the latest stable build, API documentation, and example code at [https://openseadragon.github.io/][openseadragon]. If you want to modify OpenSeadragon and/or contribute to its development, read the [contributing guide][github-contributing] for instructions.
## License
OpenSeadragon is released under the New BSD license. For details, see the [LICENSE.txt file](https://github.com/openseadragon/openseadragon/blob/master/LICENSE.txt).
OpenSeadragon is released under the New BSD license. For details, see the [LICENSE.txt file][github-license].
[openseadragon]: https://openseadragon.github.io/
<!-- [gitter-badge]: https://badges.gitter.im/Join%20Chat.svg
[gitter]: https://gitter.im/openseadragon/openseadragon?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[build-badge]: https://secure.travis-ci.org/openseadragon/openseadragon.png?branch=master
[build]: https://travis-ci.org/openseadragon/openseadragon -->
[github-releases]: https://github.com/openseadragon/openseadragon/releases
[github-contributing]: https://github.com/openseadragon/openseadragon/blob/master/CONTRIBUTING.md
[github-license]: https://github.com/openseadragon/openseadragon/blob/master/LICENSE.txt
## Sponsors
We are grateful for the (development or financial) contribution to the OpenSeadragon project.
<a href="https://www.bbmri-eric.eu"><img alt="BBMRI ERIC Logo" src="assets/logos/bbmri-logo.png" height="70" /></a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://www.pitt.edu/"><img alt="University of Pittsburgh Logo" src="assets/logos/pitt-logo.png" height="70" /></a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://www.stanford.edu/"><img alt="Stanford University Logo" src="assets/logos/stanford-logo.png" height="70" /></a>

BIN
assets/logos/bbmri-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
assets/logos/pitt-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View file

@ -1,7 +1,152 @@
OPENSEADRAGON CHANGELOG
=======================
3.0.0:
6.0.0: (in progress...)
* NEW BEHAVIOR: OpenSeadragon Data Pipeline Overhaul (#2407, #2643 @Aiosa)
* DEPRECATION: Properties on tile that manage drawer data, or store data to draw: Tile.[element|imgElement|style|context2D|getImage|getCanvasContext] and transitively Tile.getScaleForEdgeSmoothing
* DEPRECATION: TileSource data lifecycle handlers: system manages these automatically: TileSource.[createTileCache|destroyTileCache|getTileCacheData|getTileCacheDataAsImage|getTileCacheDataAsContext2D]
* Tiles data is driven by caches: tiles can have multiple caches and cache can reference multiple tiles.
* Data types & conversion pipeline: caches support automated conversion between types, and call optionally destructors. These are asynchronous.
* Data conversion reasoning: the system keeps costs of convertors and seeks the cheapest conversion to a target format (using Dijkstra).
* Async support: events can now await handlers. Added OpenSeadragon.Promise proxy object. This object supports also synchronous mode.
* Drawers define what data they are able to work with, and receive automatically data from one of the declared types.
* Drawers now store data only inside cache, and provide optional type convertors to move data into a format they can work with.
* TileSource equality operator. TileSource destructor support. TileSources now must output type of the data they download [context.finish].
* Zombies: data can outlive tiles, and be kept in the system to wait if they are not suddenly needed. Turned on automatically with TiledImage addition with `replace: true` and equality test success.
* ImagesLoadedPerFrame is boosted 10 times when system is fresh (reset / open) and then declines back to original value.
* CacheRecord supports 'internal cache' of 'SimpleCache' type. This cache can be used by drawers to hide complex types used for rendering. Such caches are stored internally on CacheRecord objects.
* CacheRecord drives asynchronous data management and ensures correct behavior through awaiting Promises.
* TileCache adds new methods for cache modification: renameCache, cloneCache, injectCache, replaceCache, restoreTilesThatShareOriginalCache, safeUnloadCache, unloadCacheForTile and more. Used internally within invalidation events
* Tiles have up to two 'originalCacheKey' and 'cacheKey' caches, which keep original data and target drawn data (if modified).
* Invalidation Pipeline: New event 'tile-invalidated' and requestInvalidate methods on World and TiledImage. Tiles get methods to modify data to draw, system prepares data for drawing and swaps them with the current main tile cache.
* New test suites for the new cache system, conversion pipeline and invalidation events.
* New testing/demo utilities (MockSeadragon, DrawerSwitcher for switching drawers in demos, getBuiltInDrawersForTest for testing all drawers), serialization guard in tests to remove circular references.
* New demos, demonstrating the new pipeline. New demos for older plugins to show how compatible new version is.
* Misc: updated CSS for dev server, new dev & test commands.
* New option: loadDestinationTilesOnAnimation. With it on, during animations, OSD loads tiles in the destination region, rather than the areas passed through on the way to the destination. This new feature is on by default. (#2686, #2690 @MichaelWGibson)
* Overlay wrapper elements now have a "openseadragon-overlay-wrapper" class. If the overlay element has an ID, the wrapper gets a variant on that ID, but if the overlay element does not have an ID, we no longer give the wrapper an ID. (#2698 @lokaesshwar)
* The functions the viewer uses to operate the zoom in and zoom out buttons are now accessible to be called programatically (#2702 @achu1998)
* Improved how OpenSeadragon is imported in various environments (#2644 @Aiosa)
* Improved documentation (#2676 @bennlich)
* Improved unit tests (#2640 @harshkg23)
* Fixed: Transparency detection didn't always work properly (#2636 @pcram-techcyte)
* Fixed: MouseTracker's hasGestureHandlers and hasScrollHandler values were not getting updated upon dynamically adding/removing handlers (#2649 @Seafret)
* Fixed: Sometimes images wouldn't update when you changed their opacity (#2652 @pearcetm)
* Fixed: Possible MouseTracker hash collision (#2657 @cff29546)
5.0.1:
* Improved overlay handling so it plays better with other libraries (#2582 @BeebBenjamin)
* WebGLDrawer now supports the imageSmoothingEnabled option (#2615 @pearcetm)
* Fixed: If you switched from WebGL drawer to canvas drawer, it didn't clean up properly (#2570 @pearcetm)
* Fixed: TiledImage.setClip would sometimes leave tiles unloaded (#2590 @pearcetm)
* Fixed: The WebGL drawer didn't support viewportMargins (#2600, #2606 @pearcetm)
* Fixed: If you set viewport rotation before flip, the navigator display region would be drawn wrong (#2619 @jbakarich)
* Fixed: In some cases, the WebGL drawer would draw the image in white (#2620 @sbarex)
* Fixed: If the user changed the page zoom or moved the window a different monitor, the image would disappear (#2627 @pearcetm)
5.0.0:
* BREAKING CHANGE: Dropped support for IE11 (#2300, #2361, #2553 @AndrewADev, @msalsbery)
* DEPRECATION: The OpenSeadragon.createCallback function is no longer recommended (#2367 @akansjain)
* The viewer now uses WebGL when available (#2310, #2462, #2466, #2468, #2469, #2472, #2478, #2488, #2492, #2521, #2537, #2557, #2558 @pearcetm, @Aiosa, @thec0keman)
* Added webp to supported image formats (#2455 @BeebBenjamin)
* Added avif to supported image formats (#2544 @msalsbery)
* Introduced maxTilesPerFrame option to allow loading more tiles simultaneously (#2387 @jetic83)
* Now when creating a viewer or navigator, we leave its position style alone if possible (#2393 @VIRAT9358)
* Added getter & setter for Viewport.maxZoomPixelRatio (#2506 @eug-L)
* Overlays are now positioned properly when the viewport is flipped (#2546 @BeebBenjamin)
* Added overlayPreserveContentDirection option to keep overlays readable when viewport is flipped (#2546 @BeebBenjamin)
* Test improvements (#2382 @AndrewADev)
* MouseTracker options documentation fixes (#2389 @msalsbery)
* Improved documentation and error message for Viewport.imageToViewportZoom (#2505 @eug-L)
* Fixed documentation typos (#2507 @frameflare)
* Additional documentation fixes (#2563 @msalsbery)
* Fixed: Sometimes if the viewport was flipped and the user zoomed in far enough, it would flip back (#2364 @SebDelile)
* Fixed: Two-finger tap on a Mac trackpad would zoom you out (#2431 @cavenel)
* Fixed: dragToPan gesture could not be disabled when flickEnabled was activated (#2464 @jonasengelmann)
* Fixed: placeholderFillStyle didn't work properly when the image was rotated (#2469 @pearcetm)
* Fixed: Sometimes exponential springs wouldn't ever settle (#2469 @pearcetm)
* Fixed: The navigator wouldn't update its tracking rectangle when the navigator was resized (#2491 @pearcetm)
* Fixed: The drawer would improperly crop when the viewport was flipped and a tiled image was rotated (#2511 @pearcetm, @eug-L)
* Fixed: Flipped viewport caused image to be flipped again when going fullscreen or resizing (#2518 @pearcetm)
* Fixed: Viewer ajax options (loadTilesWithAjax, ajaxHeaders, and ajaxWithCredentials) weren't being propogated to the navigator. (#2539 @eug-L)
4.1.1:
* Fixed: Strange behavior if IIIF sizes were not in ascending order (#2416 @lutzhelm)
4.1.0:
* NEW BEHAVIOR: When `navigatorRotate` is false, while the navigator image doesn't rotate, the red outline now does (#2356 @lcl45)
* The viewer no longer emits `canvas-key` events for both keydown and keypress events; canvas-key is now just for keydown, and the new `canvas-key-press` is for keypress (#2270 @hrghauri)
* You can now specify a priority when calling addHandler, to control when your event handler gets called relative to others (#2273 @Aiosa)
* Added tileRetryMax and tileRetryDelay options, so the viewer can retry loading failed tiles (#2238 @Ughuuu @paaddyy, #2334 @Ughuuu @Titan21)
* All of the viewers keyboard handling is now in response to keydown events (it used to be split between keydown and keypress) (#2291 @MohitBansal321)
* Added `canvas-focus` and `canvas-blur` events to Viewer (#2301 @MohitBansal321)
* You can now more easily add custom buttons to the viewer (#2306 @MohitBansal321)
* The fitBounds function now takes zoom constraints into account (#2293 @pearcetm)
* The viewer now has an `after-resize` event what happens after the viewport bounds have been updated, to complement the `resize` event which happens before (#2317 @pearcetm)
* IIIFTileSource now uses resolution level dimensions provided in the info.json "sizes" field for more accurate tile requests (#2337 @ruven)
* Added setAjaxHeaders method to Viewer and TiledImage (#2346 @uschmidt83)
* Improved documentation (#2297 @KevinBritten)
* Fixed: The `tile-loaded` event's completionCallback could be called more than once in some circumstances (#2282 @Aiosa, @pearcetm)
* Fixed: Navigator display rectangle was off if the page had `box-sizing: border-box` (#2276 @ambujsahu81)
* Fixed: Code that required identifying functions would fail for async functions (#2273 @Aiosa)
* Fixed: Reference strip click detection was not accurate for long reference strips (#2280 @damonsson)
* Fixed: Translation problems in some circumstances with cropping polygons enabled (#2316 @pearcetm)
* Fixed: The navigator area rectangle would grow larger when you zoom in very far (#2318 @donotloveshampo)
* Fixed: JSON with embedded XML was being incorrectly identified as XML (#2328 @craigberry)
* Fixed: Touch/pinch rotate was not working properly on some platforms (#2324 @rsimon, @pearcetm)
* Fixed: Navigator rotation didn't honor `immediately` parameter (#2333 @robertjcolley)
* Fixed: The navigator didn't update for its new size in certain circumstances (#2347 @pearcetm)
4.0.0:
* NEW BEHAVIOR: Setting the viewport rotation now animates by default (pass true for the new `immediately` parameter to disable) (#2136 @jonasengelmann)
* NEW BEHAVIOR: The auto resize now takes both width and height into account when scaling the contents proportionally to the viewer (#2256 @pearcetm)
* DEPRECATION: Don't access the viewport's degrees property directly anymore; instead use setRotation and getRotation (#2136 @jonasengelmann)
* New gesture: Double-click and drag to zoom (on by default for touch) (#2225 @HamzaTatheer)
* You can now provide a pivot point when rotating the viewport (#2233 #2253 @pearcetm)
* Improved the constraints that keep the image in the viewer, specifically when zoomed out a lot (#2160 @joedf, #2246 @pearcetm)
* You can now provide an element for the navigator (as an alternative to an ID) (#1303 @cameronbaney, #2166 #2175 @joedf)
* Now supporting IIIF "id" and "identifier" in addition to "@id" (#2173 @ahankinson)
* We now delegate tile fetching and caching to the TileSource, to allow for custom tile formats (#2148 @Aiosa)
* Added support for dynamic URLs from tile sources (#2247 @JohnReagan)
* The viewer now emits before-destroy and destroy events (#2239 @pearcetm)
* Auto resize detection is now more efficient (#2256 @pearcetm)
* Improved documentation (#2211 @shyamkumaryadav)
* Fixed: Cropping tiled images with polygons was broken (#2183 @altert)
* Fixed: Boundary constraints were wrong when the viewport was rotated (#2249 @pearcetm)
* Fixed: IIIF tile sizes would be calculated wrong on rare occasions (#2206 @filak)
* Fixed: Disabling buttons only changed their appearance, but they were still clickable (#2187 @pearcetm)
* Fixed: ImageTileSource produced an error having to do with getTileHashKey (#2190 @Aiosa)
* Fixed: On startup you would get an unnecessary "Viewer.buttons is deprecated" warning (#2201 @joedf, #2219 @jssullivan, #2212 @joedf)
3.1.0:
* Added subPixelRoundingForTransparency Viewer option to address seams that can appear in semi-transparent images (#2075 @TanukiSharp)
* Added Viewer.isAnimating() (#2075 @TanukiSharp)
* Added isFullScreen method to Viewer (#2067 @JachiOnuoha)
* Added option to include POST data when loading files via Ajax (#2072 @Aiosa)
* Exposed TiledImage's private functions for better maintainability (#2134 @Aiosa)
* Tile cache keys are now generated by the tile source, so it's easier to override them as needed (#2138 @Aiosa)
* Pinch to zoom now zooms around the center of the pinch, rather than the center of the viewer (#2158 @cavenel)
* Added fallback and deprecation warning for Viewer.buttons (which got changed to buttonGroup in 3.0.0) (#2153 @devbyjonah)
* Fixed an issue where turning off panVertical or panHorizontal would not affect the panning keyboard combos (#2069 @JachiOnuoha)
* Cleaned up console.logs so that errors and warnings use console.error and console.warn as appropriate (#2073 @Abhishek-90)
* Improved documentation (#2067 @JachiOnuoha, #2112 @shyamkumaryadav, #2152 @joedf, #2155 @samwilson)
* Fixed: Setting useCanvas to false would break the viewer (#2116 @rvv-bouvet)
* Allow silencing multi-image warnings on viewport coordinate conversion functions (#2120 @claycoleman)
* Fixed: Swiping fast multiple times made contact points in MouseTracker out of sync for touch events (#2121 @ronnymikalsen)
* Made MouseTracker more robust in certain scenarios (#2134, #2147 @Aiosa)
* Fixed an issue where full page mode wouldn't grow properly if you resized the window (#2100 @TanukiSharp)
* Now if you pass an error handler into makeAjaxRequest, it doesn't report errors into the console (#2142 @Aiosa)
* Fixed error caused by attaching MouseTracker to the page's document element (#2145 @tdiprima)
* Fixed an issue that would sometimes cause problems with freeing up ImageTileSource memory (#2162 @pearcetm)
3.0.0:
* BREAKING CHANGE: Dropped support for older browsers (IE < 11) (#1872 #1949 #1951 @msalsbery, #1950 @rmontroy)
* BREAKING CHANGE: Removed deprecated OpenSeadragon.getEvent function (#1949 @msalsbery)

10941
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,50 +1,53 @@
{
"name": "openseadragon",
"version": "3.0.0",
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
"keywords": [
"image",
"zoom",
"pan",
"openseadragon",
"seadragon",
"deepzoom",
"dzi",
"iiif",
"osm",
"tms"
],
"homepage": "https://openseadragon.github.io/",
"funding": "https://opencollective.com/openseadragon",
"bugs": {
"url": "https://github.com/openseadragon/openseadragon/issues"
},
"license": "BSD-3-Clause",
"files": [
"build/openseadragon/"
],
"main": "build/openseadragon/openseadragon.js",
"repository": {
"type": "git",
"url": "https://github.com/openseadragon/openseadragon.git"
},
"devDependencies": {
"grunt": "^1.1.0",
"grunt-contrib-clean": "^2.0.0",
"grunt-contrib-compress": "^1.6.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-connect": "^2.1.0",
"grunt-contrib-qunit": "^3.1.0",
"grunt-contrib-uglify": "^4.0.1",
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^23.0.0",
"grunt-git-describe": "^2.4.4",
"grunt-istanbul": "^0.8.0",
"grunt-text-replace": "^0.4.0",
"qunitjs": "2.4.1"
},
"scripts": {
"test": "grunt test",
"prepare": "grunt build"
}
"name": "openseadragon",
"version": "5.0.1",
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
"keywords": [
"image",
"zoom",
"pan",
"openseadragon",
"seadragon",
"deepzoom",
"dzi",
"iiif",
"osm",
"tms"
],
"homepage": "https://openseadragon.github.io/",
"funding": "https://opencollective.com/openseadragon",
"bugs": {
"url": "https://github.com/openseadragon/openseadragon/issues"
},
"license": "BSD-3-Clause",
"files": [
"build/openseadragon/"
],
"main": "build/openseadragon/openseadragon.js",
"repository": {
"type": "git",
"url": "https://github.com/openseadragon/openseadragon.git"
},
"devDependencies": {
"eslint-plugin-compat": "^4.1.2",
"grunt": "^1.6.1",
"grunt-contrib-clean": "^2.0.1",
"grunt-contrib-compress": "^2.0.0",
"grunt-contrib-concat": "^2.1.0",
"grunt-contrib-connect": "^3.0.0",
"grunt-contrib-qunit": "^7.0.1",
"grunt-contrib-uglify": "^5.0.1",
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^24.0.1",
"grunt-git-describe": "^2.4.4",
"grunt-istanbul": "^0.8.0",
"grunt-text-replace": "^0.4.0",
"qunit": "^2.19.4"
},
"scripts": {
"test": "grunt test",
"prepare": "grunt build",
"build": "grunt build",
"dev": "grunt dev"
}
}

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Button
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -167,13 +167,6 @@ $.Button = function( options ) {
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 );
@ -398,6 +391,7 @@ $.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.
disable: function(){
this.notifyGroupExit();
this.element.disabled = true;
this.tracker.setTracking(false);
$.setElementOpacity( this.element, 0.2, true );
},
@ -406,6 +400,7 @@ $.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.
*/
enable: function(){
this.element.disabled = false;
this.tracker.setTracking(true);
$.setElementOpacity( this.element, 1.0, true );
this.notifyGroupEnter();
},

View file

@ -2,7 +2,7 @@
* OpenSeadragon - ButtonGroup
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -112,6 +112,17 @@ $.ButtonGroup = function( options ) {
/** @lends OpenSeadragon.ButtonGroup.prototype */
$.ButtonGroup.prototype = {
/**
* Adds the given button to this button group.
*
* @function
* @param {OpenSeadragon.Button} button
*/
addButton: function( button ){
this.buttons.push(button);
this.element.appendChild(button.element);
},
/**
* TODO: Figure out why this is used on the public API and if a more useful
* api can be created.

1054
src/canvasdrawer.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Control
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -74,6 +74,7 @@ $.ControlAnchor = {
* @param {Element} container - the element to control will be anchored too.
*/
$.Control = function ( element, options, container ) {
var parent = element.parentNode;
if (typeof options === 'number')
{
@ -150,6 +151,7 @@ $.Control = function ( element, options, container ) {
} else {
parent.appendChild( this.wrapper );
}
};
/** @lends OpenSeadragon.Control.prototype */
@ -169,7 +171,7 @@ $.Control.prototype = {
/**
* Determines if the control is currently visible.
* @function
* @return {Boolean} true if currently visible, false otherwise.
* @returns {Boolean} true if currently visible, false otherwise.
*/
isVisible: function() {
return this.wrapper.style.display !== "none";
@ -192,11 +194,7 @@ $.Control.prototype = {
* @param {Number} opactiy - a value between 1 and 0 inclusively.
*/
setOpacity: function( opacity ) {
if ( this.element[ $.SIGNAL ] && $.Browser.vendor === $.BROWSERS.IE ) {
$.setElementOpacity( this.element, opacity, true );
} else {
$.setElementOpacity( this.wrapper, opacity, true );
}
$.setElementOpacity( this.wrapper, opacity, true );
}
};

View file

@ -2,7 +2,7 @@
* OpenSeadragon - ControlDock
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -59,7 +59,9 @@
if( this.element ){
this.element = $.getElement( this.element );
this.element.appendChild( this.container );
this.element.style.position = 'relative';
if( $.getElementStyle(this.element).position === 'static' ){
this.element.style.position = 'relative';
}
this.container.style.width = '100%';
this.container.style.height = '100%';
}
@ -149,7 +151,7 @@
/**
* @function
* @return {OpenSeadragon.ControlDock} Chainable.
* @returns {OpenSeadragon.ControlDock} Chainable.
*/
removeControl: function ( element ) {
element = $.getElement( element );
@ -165,7 +167,7 @@
/**
* @function
* @return {OpenSeadragon.ControlDock} Chainable.
* @returns {OpenSeadragon.ControlDock} Chainable.
*/
clearControls: function () {
while ( this.controls.length > 0 ) {
@ -178,7 +180,7 @@
/**
* @function
* @return {Boolean}
* @returns {Boolean}
*/
areControlsEnabled: function () {
var i;
@ -195,7 +197,7 @@
/**
* @function
* @return {OpenSeadragon.ControlDock} Chainable.
* @returns {OpenSeadragon.ControlDock} Chainable.
*/
setControlsEnabled: function( enabled ) {
var i;

488
src/datatypeconvertor.js Normal file
View file

@ -0,0 +1,488 @@
/*
* OpenSeadragon.convertor (static property)
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2024 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($){
/**
* modified from https://gist.github.com/Prottoy2938/66849e04b0bac459606059f5f9f3aa1a
* @private
*/
class WeightedGraph {
constructor() {
this.adjacencyList = {};
this.vertices = {};
}
/**
* Add vertex to graph
* @param vertex unique vertex ID
* @return {boolean} true if inserted, false if exists (no-op)
*/
addVertex(vertex) {
if (!this.vertices[vertex]) {
this.vertices[vertex] = new $.PriorityQueue.Node(0, vertex);
this.adjacencyList[vertex] = [];
return true;
}
return false;
}
/**
* Add edge to graph
* @param vertex1 id, must exist by calling addVertex()
* @param vertex2 id, must exist by calling addVertex()
* @param weight
* @param transform function that transforms on path vertex1 -> vertex2
* @return {boolean} true if new edge, false if replaced existing
*/
addEdge(vertex1, vertex2, weight, transform) {
if (weight < 0) {
$.console.error("WeightedGraph: negative weights will make for invalid shortest path computation!");
}
const outgoingPaths = this.adjacencyList[vertex1],
replacedEdgeIndex = outgoingPaths.findIndex(edge => edge.target === this.vertices[vertex2]),
newEdge = { target: this.vertices[vertex2], origin: this.vertices[vertex1], weight, transform };
if (replacedEdgeIndex < 0) {
this.adjacencyList[vertex1].push(newEdge);
return true;
}
this.adjacencyList[vertex1][replacedEdgeIndex] = newEdge;
return false;
}
/**
* @return {{path: ConversionStep[], cost: number}|undefined} cheapest path from start to finish
*/
dijkstra(start, finish) {
let path = []; //to return at end
if (start === finish) {
return {path: path, cost: 0};
}
const nodes = new OpenSeadragon.PriorityQueue();
let smallestNode;
//build up initial state
for (let vertex in this.vertices) {
vertex = this.vertices[vertex];
if (vertex.value === start) {
vertex.key = 0; //keys are known distances
nodes.insertNode(vertex);
} else {
vertex.key = Infinity;
delete vertex.index;
}
vertex._previous = null;
}
// as long as there is something to visit
while (nodes.getCount() > 0) {
smallestNode = nodes.remove();
if (smallestNode.value === finish) {
break;
}
const neighbors = this.adjacencyList[smallestNode.value];
for (let neighborKey in neighbors) {
let edge = neighbors[neighborKey];
//relax node
let newCost = smallestNode.key + edge.weight;
let nextNeighbor = edge.target;
if (newCost < nextNeighbor.key) {
nextNeighbor._previous = smallestNode;
//key change
nodes.decreaseKey(nextNeighbor, newCost);
}
}
}
if (!smallestNode || !smallestNode._previous || smallestNode.value !== finish) {
return undefined; //no path
}
let finalCost = smallestNode.key; //final weight last node
// done, build the shortest path
while (smallestNode._previous) {
//backtrack
const to = smallestNode.value,
parent = smallestNode._previous,
from = parent.value;
path.push(this.adjacencyList[from].find(x => x.target.value === to));
smallestNode = parent;
}
return {
path: path.reverse(),
cost: finalCost
};
}
}
/**
* Edge.transform function on the conversion path in OpenSeadragon.converter.getConversionPath().
* It can be also conversion to undefined if used as destructor implementation.
*
* @callback TypeConvertor
* @memberof OpenSeadragon
* @param {OpenSeadragon.Tile} tile reference tile that owns the data
* @param {any} data data in the input format
* @returns {any} data in the output format
*/
/**
* Destructor called every time a data type is to be destroyed or converted to another type.
*
* @callback TypeDestructor
* @memberof OpenSeadragon
* @param {any} data data in the format the destructor is registered for
* @returns {any} can return any value that is carried over to the caller if desirable.
* Note: not used by the OSD cache system.
*/
/**
* Node on the conversion path in OpenSeadragon.converter.getConversionPath().
*
* @typedef {Object} ConversionStep
* @memberof OpenSeadragon
* @param {OpenSeadragon.PriorityQueue.Node} target - Target node of the conversion step.
* Its value is the target format.
* @param {OpenSeadragon.PriorityQueue.Node} origin - Origin node of the conversion step.
* Its value is the origin format.
* @param {number} weight cost of the conversion
* @param {TypeConvertor} transform the conversion itself
*/
/**
* Class that orchestrates automated data types conversion. Do not instantiate
* this class, use OpenSeadragon.convertor - a global instance, instead.
* @class DataTypeConvertor
* @memberOf OpenSeadragon
*/
$.DataTypeConvertor = class {
constructor() {
this.graph = new WeightedGraph();
this.destructors = {};
this.copyings = {};
// Teaching OpenSeadragon built-in conversions:
const imageCreator = (tile, url) => new $.Promise((resolve, reject) => {
if (!$.supportsAsync) {
throw "Not supported in sync mode!";
}
const img = new Image();
img.onerror = img.onabort = reject;
img.onload = () => resolve(img);
img.src = url;
});
const canvasContextCreator = (tile, imageData) => {
const canvas = document.createElement( 'canvas' );
canvas.width = imageData.width;
canvas.height = imageData.height;
const context = canvas.getContext('2d', { willReadFrequently: true });
context.drawImage( imageData, 0, 0 );
return context;
};
this.learn("context2d", "webImageUrl", (tile, ctx) => ctx.canvas.toDataURL(), 1, 2);
this.learn("image", "webImageUrl", (tile, image) => image.url);
this.learn("image", "context2d", canvasContextCreator, 1, 1);
this.learn("url", "image", imageCreator, 1, 1);
//Copies
this.learn("image", "image", (tile, image) => imageCreator(tile, image.src), 1, 1);
this.learn("url", "url", (tile, url) => url, 0, 1); //strings are immutable, no need to copy
this.learn("context2d", "context2d", (tile, ctx) => canvasContextCreator(tile, ctx.canvas));
/**
* Free up canvas memory
* (iOS 12 or higher on 2GB RAM device has only 224MB canvas memory,
* and Safari keeps canvas until its height and width will be set to 0).
*/
this.learnDestroy("context2d", ctx => {
ctx.canvas.width = 0;
ctx.canvas.height = 0;
});
}
/**
* Unique identifier (unlike toString.call(x)) to be guessed
* from the data value. This type guess is more strict than
* OpenSeadragon.type() implementation, but for most type recognition
* this test relies on the output of OpenSeadragon.type().
*
* Note: although we try to implement the type guessing, do
* not rely on this functionality! Prefer explicit type declaration.
*
* @function guessType
* @param x object to get unique identifier for
* - can be array, in that case, alphabetically-ordered list of inner unique types
* is returned (null, undefined are ignored)
* - if $.isPlainObject(x) is true, then the object can define
* getType function to specify its type
* - otherwise, toString.call(x) is applied to get the parameter description
* @return {string} unique variable descriptor
*/
guessType( x ) {
if (Array.isArray(x)) {
const types = [];
for (let item of x) {
if (item === undefined || item === null) {
continue;
}
const type = this.guessType(item);
if (!types.includes(type)) {
types.push(type);
}
}
types.sort();
return `Array [${types.join(",")}]`;
}
const guessType = $.type(x);
if (guessType === "dom-node") {
//distinguish nodes
return guessType.nodeName.toLowerCase();
}
if (guessType === "object") {
if ($.isFunction(x.getType)) {
return x.getType();
}
}
return guessType;
}
/**
* Teach the system to convert data type 'from' -> 'to'
* @param {string} from unique ID of the data item 'from'
* @param {string} to unique ID of the data item 'to'
* @param {OpenSeadragon.TypeConvertor} callback convertor that takes two arguments: a tile reference, and
* a data object of a type 'from'; and converts this data object to type 'to'. It can return also the value
* wrapped in a Promise (returned in resolve) or it can be async function.
* @param {Number} [costPower=0] positive cost class of the conversion, smaller or equal than 7.
* Should reflect the actual cost of the conversion:
* - if nothing must be done and only reference is retrieved (or a constant operation done),
* return 0 (default)
* - if a linear amount of work is necessary,
* return 1
* ... and so on, basically the number in O() complexity power exponent (for simplification)
* @param {Number} [costMultiplier=1] multiplier of the cost class, e.g. O(3n^2) would
* use costPower=2, costMultiplier=3; can be between 1 and 10^5
*/
learn(from, to, callback, costPower = 0, costMultiplier = 1) {
$.console.assert(costPower >= 0 && costPower <= 7, "[DataTypeConvertor] Conversion costPower must be between <0, 7>.");
$.console.assert($.isFunction(callback), "[DataTypeConvertor:learn] Callback must be a valid function!");
if (from === to) {
this.copyings[to] = callback;
} else {
//we won't know if somebody added multiple edges, though it will choose some edge anyway
costPower++;
costMultiplier = Math.min(Math.max(costMultiplier, 1), 10 ^ 5);
this.graph.addVertex(from);
this.graph.addVertex(to);
this.graph.addEdge(from, to, costPower * 10 ^ 5 + costMultiplier, callback);
this._known = {}; //invalidate precomputed paths :/
}
}
/**
* Teach the system to destroy data type 'type'
* for example, textures loaded to GPU have to be also manually removed when not needed anymore.
* Needs to be defined only when the created object has extra deletion process.
* @param {string} type
* @param {OpenSeadragon.TypeDestructor} callback destructor, receives the object created,
* it is basically a type conversion to 'undefined' - thus the type.
*/
learnDestroy(type, callback) {
this.destructors[type] = callback;
}
/**
* Convert data item x of type 'from' to any of the 'to' types, chosen is the cheapest known conversion.
* Data is destroyed upon conversion. For different behavior, implement your conversion using the
* path rules obtained from getConversionPath().
* Note: conversion DOES NOT COPY data if [to] contains type 'from' (e.g., the cheapest conversion is no conversion).
* It automatically calls destructor on immediate types, but NOT on the x and the result. You should call these
* manually if these should be destroyed.
* @param {OpenSeadragon.Tile} tile
* @param {any} data data item to convert
* @param {string} from data item type
* @param {string} to desired type(s)
* @return {OpenSeadragon.Promise<?>} promise resolution with type 'to' or undefined if the conversion failed
*/
convert(tile, data, from, ...to) {
const conversionPath = this.getConversionPath(from, to);
if (!conversionPath) {
$.console.error(`[OpenSeadragon.convertor.convert] Conversion ${from} ---> ${to} cannot be done!`);
return $.Promise.resolve();
}
const stepCount = conversionPath.length,
_this = this;
const step = (x, i, destroy = true) => {
if (i >= stepCount) {
return $.Promise.resolve(x);
}
let edge = conversionPath[i];
let y = edge.transform(tile, x);
if (y === undefined) {
$.console.error(`[OpenSeadragon.convertor.convert] data mid result undefined value (while converting using %s)`, edge);
return $.Promise.resolve();
}
//node.value holds the type string
if (destroy) {
_this.destroy(x, edge.origin.value);
}
const result = $.type(y) === "promise" ? y : $.Promise.resolve(y);
return result.then(res => step(res, i + 1));
};
//destroy only mid-results, but not the original value
return step(data, 0, false);
}
/**
* Copy the data item given.
* @param {OpenSeadragon.Tile} tile
* @param {any} data data item to convert
* @param {string} type data type
* @return {OpenSeadragon.Promise<?>|undefined} promise resolution with data passed from constructor
*/
copy(tile, data, type) {
const copyTransform = this.copyings[type];
if (copyTransform) {
const y = copyTransform(tile, data);
return $.type(y) === "promise" ? y : $.Promise.resolve(y);
}
$.console.warn(`[OpenSeadragon.convertor.copy] is not supported with type %s`, type);
return $.Promise.resolve(undefined);
}
/**
* Destroy the data item given.
* @param {string} type data type
* @param {any} data
* @return {OpenSeadragon.Promise<any>|undefined} promise resolution with data passed from constructor, or undefined
* if not such conversion exists
*/
destroy(data, type) {
const destructor = this.destructors[type];
if (destructor) {
const y = destructor(data);
return $.type(y) === "promise" ? y : $.Promise.resolve(y);
}
return undefined;
}
/**
* Get possible system type conversions and cache result.
* @param {string} from data item type
* @param {string|string[]} to array of accepted types
* @return {ConversionStep[]|undefined} array of required conversions (returns empty array
* for from===to), or undefined if the system cannot convert between given types.
* Each object has 'transform' function that converts between neighbouring types, such
* that x = arr[i].transform(x) is valid input for convertor arr[i+1].transform(), e.g.
* arr[i+1].transform(arr[i].transform( ... )) is a valid conversion procedure.
*
* Note: if a function is returned, it is a callback called once the data is ready.
*/
getConversionPath(from, to) {
let bestConvertorPath, selectedType;
let knownFrom = this._known[from];
if (!knownFrom) {
this._known[from] = knownFrom = {};
}
if (Array.isArray(to)) {
$.console.assert(to.length > 0, "[getConversionPath] conversion 'to' type must be defined.");
let bestCost = Infinity;
//FIXME: pre-compute all paths in 'to' array? could be efficient for multiple
// type system, but overhead for simple use cases... now we just use the first type if costs unknown
selectedType = to[0];
for (const outType of to) {
const conversion = knownFrom[outType];
if (conversion && bestCost > conversion.cost) {
bestConvertorPath = conversion;
bestCost = conversion.cost;
selectedType = outType;
}
}
} else {
$.console.assert(typeof to === "string", "[getConversionPath] conversion 'to' type must be defined.");
bestConvertorPath = knownFrom[to];
selectedType = to;
}
if (!bestConvertorPath) {
bestConvertorPath = this.graph.dijkstra(from, selectedType);
this._known[from][selectedType] = bestConvertorPath;
}
return bestConvertorPath ? bestConvertorPath.path : undefined;
}
/**
* Return a list of known conversion types
* @return {string[]}
*/
getKnownTypes() {
return Object.keys(this.graph.vertices);
}
/**
* Check whether given type is known to the convertor
* @param {string} type type to test
* @return {boolean}
*/
existsType(type) {
return !!this.graph.vertices[type];
}
};
/**
* Static convertor available throughout OpenSeadragon.
*
* Built-in conversions include types:
* - context2d canvas 2d context
* - image HTMLImage element
* - url url string carrying or pointing to 2D raster data
* - canvas HTMLCanvas element
*
* @type OpenSeadragon.DataTypeConvertor
* @memberOf OpenSeadragon
*/
$.convertor = new $.DataTypeConvertor();
}(OpenSeadragon));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - DisplayRect
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are

View file

@ -1,760 +0,0 @@
/*
* OpenSeadragon - Drawer
*
* 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 Drawer
* @memberof OpenSeadragon
* @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}.
* @param {Object} options - Options for this Drawer.
* @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer.
* @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport.
* @param {Element} options.element - Parent element.
* @param {Number} [options.debugGridColor] - See debugGridColor in {@link OpenSeadragon.Options} for details.
*/
$.Drawer = function( options ) {
$.console.assert( options.viewer, "[Drawer] options.viewer is required" );
//backward compatibility for positional args while preferring more
//idiomatic javascript options object as the only argument
var args = arguments;
if( !$.isPlainObject( options ) ){
options = {
source: args[ 0 ], // Reference to Viewer tile source.
viewport: args[ 1 ], // Reference to Viewer viewport.
element: args[ 2 ] // Parent element.
};
}
$.console.assert( options.viewport, "[Drawer] options.viewport is required" );
$.console.assert( options.element, "[Drawer] options.element is required" );
if ( options.source ) {
$.console.error( "[Drawer] options.source is no longer accepted; use TiledImage instead" );
}
this.viewer = options.viewer;
this.viewport = options.viewport;
this.debugGridColor = typeof options.debugGridColor === 'string' ? [options.debugGridColor] : options.debugGridColor || $.DEFAULT_SETTINGS.debugGridColor;
if (options.opacity) {
$.console.error( "[Drawer] options.opacity is no longer accepted; set the opacity on the TiledImage instead" );
}
this.useCanvas = $.supportsCanvas && ( this.viewer ? this.viewer.useCanvas : true );
/**
* The parent element of this Drawer instance, passed in when the Drawer was created.
* The parent of {@link OpenSeadragon.Drawer#canvas}.
* @member {Element} container
* @memberof OpenSeadragon.Drawer#
*/
this.container = $.getElement( options.element );
/**
* A &lt;canvas&gt; element if the browser supports them, otherwise a &lt;div&gt; element.
* Child element of {@link OpenSeadragon.Drawer#container}.
* @member {Element} canvas
* @memberof OpenSeadragon.Drawer#
*/
this.canvas = $.makeNeutralElement( this.useCanvas ? "canvas" : "div" );
/**
* 2d drawing context for {@link OpenSeadragon.Drawer#canvas} if it's a &lt;canvas&gt; element, otherwise null.
* @member {Object} context
* @memberof OpenSeadragon.Drawer#
*/
this.context = this.useCanvas ? this.canvas.getContext( "2d" ) : null;
/**
* Sketch canvas used to temporarily draw tiles which cannot be drawn directly
* to the main canvas due to opacity. Lazily initialized.
*/
this.sketchCanvas = null;
this.sketchContext = null;
/**
* @member {Element} element
* @memberof OpenSeadragon.Drawer#
* @deprecated Alias for {@link OpenSeadragon.Drawer#container}.
*/
this.element = this.container;
// We force our container to ltr because our drawing math doesn't work in rtl.
// This issue only affects our canvas renderer, but we do it always for consistency.
// Note that this means overlays you want to be rtl need to be explicitly set to rtl.
this.container.dir = 'ltr';
// check canvas available width and height, set canvas width and height such that the canvas backing store is set to the proper pixel density
if (this.useCanvas) {
var viewportSize = this._calculateCanvasSize();
this.canvas.width = viewportSize.x;
this.canvas.height = viewportSize.y;
}
this.canvas.style.width = "100%";
this.canvas.style.height = "100%";
this.canvas.style.position = "absolute";
$.setElementOpacity( this.canvas, this.opacity, true );
// Allow pointer events to pass through the canvas element so implicit
// pointer capture works on touch devices
$.setElementPointerEventsNone( this.canvas );
$.setElementTouchActionNone( this.canvas );
// explicit left-align
this.container.style.textAlign = "left";
this.container.appendChild( this.canvas );
// Image smoothing for canvas rendering (only if canvas is used).
// Canvas default is "true", so this will only be changed if user specified "false".
this._imageSmoothingEnabled = true;
};
/** @lends OpenSeadragon.Drawer.prototype */
$.Drawer.prototype = {
// deprecated
addOverlay: function( element, location, placement, onDraw ) {
$.console.error("drawer.addOverlay is deprecated. Use viewer.addOverlay instead.");
this.viewer.addOverlay( element, location, placement, onDraw );
return this;
},
// deprecated
updateOverlay: function( element, location, placement ) {
$.console.error("drawer.updateOverlay is deprecated. Use viewer.updateOverlay instead.");
this.viewer.updateOverlay( element, location, placement );
return this;
},
// deprecated
removeOverlay: function( element ) {
$.console.error("drawer.removeOverlay is deprecated. Use viewer.removeOverlay instead.");
this.viewer.removeOverlay( element );
return this;
},
// deprecated
clearOverlays: function() {
$.console.error("drawer.clearOverlays is deprecated. Use viewer.clearOverlays instead.");
this.viewer.clearOverlays();
return this;
},
/**
* This function converts the given point from to the drawer coordinate by
* multiplying it with the pixel density.
* This function does not take rotation into account, thus assuming provided
* point is at 0 degree.
* @param {OpenSeadragon.Point} point - the pixel point to convert
*/
viewportCoordToDrawerCoord: function(point) {
var vpPoint = this.viewport.pixelFromPointNoRotate(point, true);
return new $.Point(
vpPoint.x * $.pixelDensityRatio,
vpPoint.y * $.pixelDensityRatio
);
},
/**
* This function will create multiple polygon paths on the drawing context by provided polygons,
* then clip the context to the paths.
* @param {OpenSeadragon.Point[][]} polygons - an array of polygons. A polygon is an array of OpenSeadragon.Point
* @param {Boolean} useSketch - Whether to use the sketch canvas or not.
*/
clipWithPolygons: function (polygons, useSketch) {
if (!this.useCanvas) {
return;
}
var context = this._getContext(useSketch);
context.beginPath();
polygons.forEach(function (polygon) {
polygon.forEach(function (coord, i) {
context[i === 0 ? 'moveTo' : 'lineTo'](coord.x, coord.y);
});
});
context.clip();
},
/**
* Set the opacity of the drawer.
* @param {Number} opacity
* @return {OpenSeadragon.Drawer} Chainable.
*/
setOpacity: function( opacity ) {
$.console.error("drawer.setOpacity is deprecated. Use tiledImage.setOpacity instead.");
var world = this.viewer.world;
for (var i = 0; i < world.getItemCount(); i++) {
world.getItemAt( i ).setOpacity( opacity );
}
return this;
},
/**
* Get the opacity of the drawer.
* @returns {Number}
*/
getOpacity: function() {
$.console.error("drawer.getOpacity is deprecated. Use tiledImage.getOpacity instead.");
var world = this.viewer.world;
var maxOpacity = 0;
for (var i = 0; i < world.getItemCount(); i++) {
var opacity = world.getItemAt( i ).getOpacity();
if ( opacity > maxOpacity ) {
maxOpacity = opacity;
}
}
return maxOpacity;
},
// deprecated
needsUpdate: function() {
$.console.error( "[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead." );
return this.viewer.world.needsDraw();
},
// deprecated
numTilesLoaded: function() {
$.console.error( "[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead." );
return this.viewer.tileCache.numTilesLoaded();
},
// deprecated
reset: function() {
$.console.error( "[Drawer.reset] this function is deprecated. Use World.resetItems instead." );
this.viewer.world.resetItems();
return this;
},
// deprecated
update: function() {
$.console.error( "[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead." );
this.clear();
this.viewer.world.draw();
return this;
},
/**
* @return {Boolean} True if rotation is supported.
*/
canRotate: function() {
return this.useCanvas;
},
/**
* Destroy the drawer (unload current loaded tiles)
*/
destroy: function() {
//force unloading of current canvas (1x1 will be gc later, trick not necessarily needed)
this.canvas.width = 1;
this.canvas.height = 1;
this.sketchCanvas = null;
this.sketchContext = null;
},
/**
* Clears the Drawer so it's ready to draw another frame.
*/
clear: function() {
this.canvas.innerHTML = "";
if ( this.useCanvas ) {
var viewportSize = this._calculateCanvasSize();
if( this.canvas.width !== viewportSize.x ||
this.canvas.height !== viewportSize.y ) {
this.canvas.width = viewportSize.x;
this.canvas.height = viewportSize.y;
this._updateImageSmoothingEnabled(this.context);
if ( this.sketchCanvas !== null ) {
var sketchCanvasSize = this._calculateSketchCanvasSize();
this.sketchCanvas.width = sketchCanvasSize.x;
this.sketchCanvas.height = sketchCanvasSize.y;
this._updateImageSmoothingEnabled(this.sketchContext);
}
}
this._clear();
}
},
_clear: function (useSketch, bounds) {
if (!this.useCanvas) {
return;
}
var context = this._getContext(useSketch);
if (bounds) {
context.clearRect(bounds.x, bounds.y, bounds.width, bounds.height);
} else {
var canvas = context.canvas;
context.clearRect(0, 0, canvas.width, canvas.height);
}
},
/**
* Scale from OpenSeadragon viewer rectangle to drawer rectangle
* (ignoring rotation)
* @param {OpenSeadragon.Rect} rectangle - The rectangle in viewport coordinate system.
* @return {OpenSeadragon.Rect} Rectangle in drawer coordinate system.
*/
viewportToDrawerRectangle: function(rectangle) {
var topLeft = this.viewport.pixelFromPointNoRotate(rectangle.getTopLeft(), true);
var size = this.viewport.deltaPixelsFromPointsNoRotate(rectangle.getSize(), true);
return new $.Rect(
topLeft.x * $.pixelDensityRatio,
topLeft.y * $.pixelDensityRatio,
size.x * $.pixelDensityRatio,
size.y * $.pixelDensityRatio
);
},
/**
* Draws the given tile.
* @param {OpenSeadragon.Tile} tile - The tile to draw.
* @param {Function} drawingHandler - Method for firing the drawing event if using canvas.
* drawingHandler({context, tile, rendered})
* @param {Boolean} useSketch - Whether to use the sketch canvas or not.
* where <code>rendered</code> is the context with the pre-drawn image.
* @param {Float} [scale=1] - Apply a scale to tile position and size. Defaults to 1.
* @param {OpenSeadragon.Point} [translate] A translation vector to offset tile position
*/
drawTile: function(tile, drawingHandler, useSketch, scale, translate) {
$.console.assert(tile, '[Drawer.drawTile] tile is required');
$.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');
if (this.useCanvas) {
var context = this._getContext(useSketch);
scale = scale || 1;
tile.drawCanvas(context, drawingHandler, scale, translate);
} else {
tile.drawHTML( this.canvas );
}
},
_getContext: function( useSketch ) {
var context = this.context;
if ( useSketch ) {
if (this.sketchCanvas === null) {
this.sketchCanvas = document.createElement( "canvas" );
var sketchCanvasSize = this._calculateSketchCanvasSize();
this.sketchCanvas.width = sketchCanvasSize.x;
this.sketchCanvas.height = sketchCanvasSize.y;
this.sketchContext = this.sketchCanvas.getContext( "2d" );
// If the viewport is not currently rotated, the sketchCanvas
// will have the same size as the main canvas. However, if
// the viewport get rotated later on, we will need to resize it.
if (this.viewport.getRotation() === 0) {
var self = this;
this.viewer.addHandler('rotate', function resizeSketchCanvas() {
if (self.viewport.getRotation() === 0) {
return;
}
self.viewer.removeHandler('rotate', resizeSketchCanvas);
var sketchCanvasSize = self._calculateSketchCanvasSize();
self.sketchCanvas.width = sketchCanvasSize.x;
self.sketchCanvas.height = sketchCanvasSize.y;
});
}
this._updateImageSmoothingEnabled(this.sketchContext);
}
context = this.sketchContext;
}
return context;
},
// private
saveContext: function( useSketch ) {
if (!this.useCanvas) {
return;
}
this._getContext( useSketch ).save();
},
// private
restoreContext: function( useSketch ) {
if (!this.useCanvas) {
return;
}
this._getContext( useSketch ).restore();
},
// private
setClip: function(rect, useSketch) {
if (!this.useCanvas) {
return;
}
var context = this._getContext( useSketch );
context.beginPath();
context.rect(rect.x, rect.y, rect.width, rect.height);
context.clip();
},
// private
drawRectangle: function(rect, fillStyle, useSketch) {
if (!this.useCanvas) {
return;
}
var context = this._getContext( useSketch );
context.save();
context.fillStyle = fillStyle;
context.fillRect(rect.x, rect.y, rect.width, rect.height);
context.restore();
},
/**
* Blends the sketch canvas in the main canvas.
* @param {Object} options The options
* @param {Float} options.opacity The opacity of the blending.
* @param {Float} [options.scale=1] The scale at which tiles were drawn on
* the sketch. Default is 1.
* Use scale to draw at a lower scale and then enlarge onto the main canvas.
* @param {OpenSeadragon.Point} [options.translate] A translation vector
* that was used to draw the tiles
* @param {String} [options.compositeOperation] - How the image is
* composited onto other images; see compositeOperation in
* {@link OpenSeadragon.Options} for possible values.
* @param {OpenSeadragon.Rect} [options.bounds] The part of the sketch
* canvas to blend in the main canvas. If specified, options.scale and
* options.translate get ignored.
*/
blendSketch: function(opacity, scale, translate, compositeOperation) {
var options = opacity;
if (!$.isPlainObject(options)) {
options = {
opacity: opacity,
scale: scale,
translate: translate,
compositeOperation: compositeOperation
};
}
if (!this.useCanvas || !this.sketchCanvas) {
return;
}
opacity = options.opacity;
compositeOperation = options.compositeOperation;
var bounds = options.bounds;
this.context.save();
this.context.globalAlpha = opacity;
if (compositeOperation) {
this.context.globalCompositeOperation = compositeOperation;
}
if (bounds) {
// Internet Explorer, Microsoft Edge, and Safari have problems
// when you call context.drawImage with negative x or y
// or x + width or y + height greater than the canvas width or height respectively.
if (bounds.x < 0) {
bounds.width += bounds.x;
bounds.x = 0;
}
if (bounds.x + bounds.width > this.canvas.width) {
bounds.width = this.canvas.width - bounds.x;
}
if (bounds.y < 0) {
bounds.height += bounds.y;
bounds.y = 0;
}
if (bounds.y + bounds.height > this.canvas.height) {
bounds.height = this.canvas.height - bounds.y;
}
this.context.drawImage(
this.sketchCanvas,
bounds.x,
bounds.y,
bounds.width,
bounds.height,
bounds.x,
bounds.y,
bounds.width,
bounds.height
);
} else {
scale = options.scale || 1;
translate = options.translate;
var position = translate instanceof $.Point ?
translate : new $.Point(0, 0);
var widthExt = 0;
var heightExt = 0;
if (translate) {
var widthDiff = this.sketchCanvas.width - this.canvas.width;
var heightDiff = this.sketchCanvas.height - this.canvas.height;
widthExt = Math.round(widthDiff / 2);
heightExt = Math.round(heightDiff / 2);
}
this.context.drawImage(
this.sketchCanvas,
position.x - widthExt * scale,
position.y - heightExt * scale,
(this.canvas.width + 2 * widthExt) * scale,
(this.canvas.height + 2 * heightExt) * scale,
-widthExt,
-heightExt,
this.canvas.width + 2 * widthExt,
this.canvas.height + 2 * heightExt
);
}
this.context.restore();
},
// private
drawDebugInfo: function(tile, count, i, tiledImage) {
if ( !this.useCanvas ) {
return;
}
var colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length;
var context = this.context;
context.save();
context.lineWidth = 2 * $.pixelDensityRatio;
context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';
context.strokeStyle = this.debugGridColor[colorIndex];
context.fillStyle = this.debugGridColor[colorIndex];
if ( this.viewport.degrees !== 0 ) {
this._offsetForRotation({degrees: this.viewport.degrees});
}
if (tiledImage.getRotation(true) % 360 !== 0) {
this._offsetForRotation({
degrees: tiledImage.getRotation(true),
point: tiledImage.viewport.pixelFromPointNoRotate(
tiledImage._getRotationPoint(true), true)
});
}
if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){
if(tiledImage._drawer.viewer.viewport.getFlip()) {
tiledImage._drawer._flip();
}
}
context.strokeRect(
tile.position.x * $.pixelDensityRatio,
tile.position.y * $.pixelDensityRatio,
tile.size.x * $.pixelDensityRatio,
tile.size.y * $.pixelDensityRatio
);
var tileCenterX = (tile.position.x + (tile.size.x / 2)) * $.pixelDensityRatio;
var tileCenterY = (tile.position.y + (tile.size.y / 2)) * $.pixelDensityRatio;
// Rotate the text the right way around.
context.translate( tileCenterX, tileCenterY );
context.rotate( Math.PI / 180 * -this.viewport.degrees );
context.translate( -tileCenterX, -tileCenterY );
if( tile.x === 0 && tile.y === 0 ){
context.fillText(
"Zoom: " + this.viewport.getZoom(),
tile.position.x * $.pixelDensityRatio,
(tile.position.y - 30) * $.pixelDensityRatio
);
context.fillText(
"Pan: " + this.viewport.getBounds().toString(),
tile.position.x * $.pixelDensityRatio,
(tile.position.y - 20) * $.pixelDensityRatio
);
}
context.fillText(
"Level: " + tile.level,
(tile.position.x + 10) * $.pixelDensityRatio,
(tile.position.y + 20) * $.pixelDensityRatio
);
context.fillText(
"Column: " + tile.x,
(tile.position.x + 10) * $.pixelDensityRatio,
(tile.position.y + 30) * $.pixelDensityRatio
);
context.fillText(
"Row: " + tile.y,
(tile.position.x + 10) * $.pixelDensityRatio,
(tile.position.y + 40) * $.pixelDensityRatio
);
context.fillText(
"Order: " + i + " of " + count,
(tile.position.x + 10) * $.pixelDensityRatio,
(tile.position.y + 50) * $.pixelDensityRatio
);
context.fillText(
"Size: " + tile.size.toString(),
(tile.position.x + 10) * $.pixelDensityRatio,
(tile.position.y + 60) * $.pixelDensityRatio
);
context.fillText(
"Position: " + tile.position.toString(),
(tile.position.x + 10) * $.pixelDensityRatio,
(tile.position.y + 70) * $.pixelDensityRatio
);
if ( this.viewport.degrees !== 0 ) {
this._restoreRotationChanges();
}
if (tiledImage.getRotation(true) % 360 !== 0) {
this._restoreRotationChanges();
}
if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){
if(tiledImage._drawer.viewer.viewport.getFlip()) {
tiledImage._drawer._flip();
}
}
context.restore();
},
// private
debugRect: function(rect) {
if ( this.useCanvas ) {
var context = this.context;
context.save();
context.lineWidth = 2 * $.pixelDensityRatio;
context.strokeStyle = this.debugGridColor[0];
context.fillStyle = this.debugGridColor[0];
context.strokeRect(
rect.x * $.pixelDensityRatio,
rect.y * $.pixelDensityRatio,
rect.width * $.pixelDensityRatio,
rect.height * $.pixelDensityRatio
);
context.restore();
}
},
/**
* Turns image smoothing on or off for this viewer. Note: Ignored in some (especially older) browsers that do not support this property.
*
* @function
* @param {Boolean} [imageSmoothingEnabled] - Whether or not the image is
* drawn smoothly on the canvas; see imageSmoothingEnabled in
* {@link OpenSeadragon.Options} for more explanation.
*/
setImageSmoothingEnabled: function(imageSmoothingEnabled){
if ( this.useCanvas ) {
this._imageSmoothingEnabled = imageSmoothingEnabled;
this._updateImageSmoothingEnabled(this.context);
this.viewer.forceRedraw();
}
},
// private
_updateImageSmoothingEnabled: function(context){
context.msImageSmoothingEnabled = this._imageSmoothingEnabled;
context.imageSmoothingEnabled = this._imageSmoothingEnabled;
},
/**
* Get the canvas size
* @param {Boolean} sketch If set to true return the size of the sketch canvas
* @returns {OpenSeadragon.Point} The size of the canvas
*/
getCanvasSize: function(sketch) {
var canvas = this._getContext(sketch).canvas;
return new $.Point(canvas.width, canvas.height);
},
getCanvasCenter: function() {
return new $.Point(this.canvas.width / 2, this.canvas.height / 2);
},
// private
_offsetForRotation: function(options) {
var point = options.point ?
options.point.times($.pixelDensityRatio) :
this.getCanvasCenter();
var context = this._getContext(options.useSketch);
context.save();
context.translate(point.x, point.y);
if(this.viewer.viewport.flipped){
context.rotate(Math.PI / 180 * -options.degrees);
context.scale(-1, 1);
} else{
context.rotate(Math.PI / 180 * options.degrees);
}
context.translate(-point.x, -point.y);
},
// private
_flip: function(options) {
options = options || {};
var point = options.point ?
options.point.times($.pixelDensityRatio) :
this.getCanvasCenter();
var context = this._getContext(options.useSketch);
context.translate(point.x, 0);
context.scale(-1, 1);
context.translate(-point.x, 0);
},
// private
_restoreRotationChanges: function(useSketch) {
var context = this._getContext(useSketch);
context.restore();
},
// private
_calculateCanvasSize: function() {
var pixelDensityRatio = $.pixelDensityRatio;
var viewportSize = this.viewport.getContainerSize();
return {
// canvas width and height are integers
x: Math.round(viewportSize.x * pixelDensityRatio),
y: Math.round(viewportSize.y * pixelDensityRatio)
};
},
// private
_calculateSketchCanvasSize: function() {
var canvasSize = this._calculateCanvasSize();
if (this.viewport.getRotation() === 0) {
return canvasSize;
}
// If the viewport is rotated, we need a larger sketch canvas in order
// to support edge smoothing.
var sketchCanvasSize = Math.ceil(Math.sqrt(
canvasSize.x * canvasSize.x +
canvasSize.y * canvasSize.y));
return {
x: sketchCanvasSize,
y: sketchCanvasSize
};
}
};
}( OpenSeadragon ));

426
src/drawerbase.js Normal file
View file

@ -0,0 +1,426 @@
/*
* OpenSeadragon - DrawerBase
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2024 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( $ ){
/**
* @typedef BaseDrawerOptions
* @memberOf OpenSeadragon
* @property {boolean} [usePrivateCache=false] specify whether the drawer should use
* detached (=internal) cache object in case it has to perform custom type conversion atop
* what cache performs. In that case, drawer must implement internalCacheCreate() which gets data in one
* of formats the drawer declares as supported. This method must return object to be used during drawing.
* You should probably implement also internalCacheFree() to provide cleanup logics.
*
* @property {boolean} [preloadCache=true]
* When internalCacheCreate is used, it can be applied offline (asynchronously) during data processing = preloading,
* or just in time before rendering (if necessary). Preloading supports
*/
const OpenSeadragon = $; // (re)alias back to OpenSeadragon for JSDoc
/**
* @class OpenSeadragon.DrawerBase
* @classdesc Base class for Drawers that handle rendering of tiles for an {@link OpenSeadragon.Viewer}.
* @param {Object} options - Options for this Drawer.
* @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer.
* @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport.
* @param {HTMLElement} options.element - Parent element.
* @abstract
*/
OpenSeadragon.DrawerBase = class DrawerBase{
constructor(options){
$.console.assert( options.viewer, "[Drawer] options.viewer is required" );
$.console.assert( options.viewport, "[Drawer] options.viewport is required" );
$.console.assert( options.element, "[Drawer] options.element is required" );
this._id = this.getType() + $.now();
this.viewer = options.viewer;
this.viewport = options.viewport;
this.debugGridColor = typeof options.debugGridColor === 'string' ? [options.debugGridColor] : options.debugGridColor || $.DEFAULT_SETTINGS.debugGridColor;
this.options = $.extend({}, this.defaultOptions, options.options);
this.container = $.getElement( options.element );
this._renderingTarget = this._createDrawingElement();
this.canvas.style.width = "100%";
this.canvas.style.height = "100%";
this.canvas.style.position = "absolute";
// set canvas.style.left = 0 so the canvas is positioned properly in ltr and rtl html
this.canvas.style.left = "0";
$.setElementOpacity( this.canvas, this.viewer.opacity, true );
// Allow pointer events to pass through the canvas element so implicit
// pointer capture works on touch devices
$.setElementPointerEventsNone( this.canvas );
$.setElementTouchActionNone( this.canvas );
// explicit left-align
this.container.style.textAlign = "left";
this.container.appendChild( this.canvas );
this._checkInterfaceImplementation();
this.setInternalCacheNeedsRefresh(); // initializes stamp
}
/**
* Retrieve default options for the current drawer.
* The base implementation provides default shared options.
* Overrides should enumerate all defaults or extend from this implementation.
* return $.extend({}, super.options, { ... custom drawer instance options ... });
* @returns {BaseDrawerOptions} common options
*/
get defaultOptions() {
return {
usePrivateCache: false,
preloadCache: true,
};
}
// protect the canvas member with a getter
get canvas(){
return this._renderingTarget;
}
get element(){
$.console.error('Drawer.element is deprecated. Use Drawer.container instead.');
return this.container;
}
/**
* Get unique drawer ID
* @return {string}
*/
getId() {
return this._id;
}
/**
* @abstract
* @returns {String | undefined} What type of drawer this is. Must be overridden by extending classes.
*/
getType(){
$.console.error('Drawer.getType must be implemented by child class');
return undefined;
}
/**
* Retrieve required data formats the data must be converted to.
* This list MUST BE A VALID SUBSET OF getSupportedDataFormats()
* @abstract
* @return {string[]}
*/
getRequiredDataFormats() {
return this.getSupportedDataFormats();
}
/**
* Retrieve data types
* @abstract
* @return {string[]}
*/
getSupportedDataFormats() {
throw "Drawer.getSupportedDataFormats must define its supported rendering data types!";
}
/**
* Check a particular cache record is compatible.
* This function _MUST_ be called: if it returns a falsey
* value, the rendering _MUST NOT_ proceed. It should
* await next animation frames and check again for availability.
* @param {OpenSeadragon.Tile} tile
* @return {any|undefined} undefined if cache not available, compatible data otherwise.
*/
getDataToDraw(tile) {
const cache = tile.getCache(tile.cacheKey);
if (!cache) {
$.console.warn("Attempt to draw tile %s when not cached!", tile);
return undefined;
}
const dataCache = cache.getDataForRendering(this, tile);
return dataCache && dataCache.data;
}
/**
* @abstract
* @returns {Boolean} Whether the drawer implementation is supported by the browser. Must be overridden by extending classes.
*/
static isSupported() {
$.console.error('Drawer.isSupported must be implemented by child class');
}
/**
* @abstract
* @returns {Element} the element to draw into
* @private
*/
_createDrawingElement() {
$.console.error('Drawer._createDrawingElement must be implemented by child class');
return null;
}
/**
* @abstract
* @param {Array} tiledImages - An array of TiledImages that are ready to be drawn.
* @private
*/
draw(tiledImages) {
$.console.error('Drawer.draw must be implemented by child class');
}
/**
* @abstract
* @returns {Boolean} True if rotation is supported.
*/
canRotate() {
$.console.error('Drawer.canRotate must be implemented by child class');
}
/**
* @abstract
*/
destroy() {
$.console.error('Drawer.destroy must be implemented by child class');
}
/**
* Destroy internal cache. Should be called within destroy() when
* usePrivateCache is set to true. Ensures cleanup of anything created
* by internalCacheCreate(...).
*/
destroyInternalCache() {
this.viewer.tileCache.clearDrawerInternalCache(this);
}
/**
* @param {TiledImage} tiledImage the tiled image that is calling the function
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
* @private
*/
minimumOverlapRequired(tiledImage) {
return false;
}
/**
* @abstract
* @param {Boolean} [imageSmoothingEnabled] - Whether or not the image is
* drawn smoothly on the canvas; see imageSmoothingEnabled in
* {@link OpenSeadragon.Options} for more explanation.
*/
setImageSmoothingEnabled(imageSmoothingEnabled){
$.console.error('Drawer.setImageSmoothingEnabled must be implemented by child class');
}
/**
* Optional public API to draw a rectangle (e.g. for debugging purposes)
* Child classes can override this method if they wish to support this
* @param {OpenSeadragon.Rect} rect
*/
drawDebuggingRect(rect) {
$.console.warn('[drawer].drawDebuggingRect is not implemented by this drawer');
}
// Deprecated functions
clear(){
$.console.warn('[drawer].clear() is deprecated. The drawer is responsible for clearing itself as needed before drawing tiles.');
}
/**
* If options.usePrivateCache is true, this method MUST RETURN the private cache content
* @param {OpenSeadragon.CacheRecord} cache
* @param {OpenSeadragon.Tile} tile
* @return any
*/
internalCacheCreate(cache, tile) {}
/**
* It is possible to perform any necessary cleanup on internal cache, necessary if you
* need to clean up some memory (e.g. destroy canvas by setting with & height to 0).
* @param {*} data object returned by internalCacheCreate(...)
*/
internalCacheFree(data) {}
/**
* Call to invalidate internal cache. It will be rebuilt. With synchronous converions,
* it will be rebuilt immediatelly. With asynchronous, it will be rebuilt once invalidation
* routine happens, e.g. you should call also requestInvalidate() if you need to happen
* it as soon as possible.
*/
setInternalCacheNeedsRefresh() {
this._dataNeedsRefresh = $.now();
}
// Private functions
/**
* Ensures that child classes have provided implementations for public API methods
* draw, canRotate, destroy, and setImageSmoothinEnabled. Throws an exception if the original
* placeholder methods are still in place.
* @private
*
*/
_checkInterfaceImplementation(){
if (this._createDrawingElement === $.DrawerBase.prototype._createDrawingElement) {
throw(new Error("[drawer]._createDrawingElement must be implemented by child class"));
}
if (this.draw === $.DrawerBase.prototype.draw) {
throw(new Error("[drawer].draw must be implemented by child class"));
}
if (this.canRotate === $.DrawerBase.prototype.canRotate) {
throw(new Error("[drawer].canRotate must be implemented by child class"));
}
if (this.destroy === $.DrawerBase.prototype.destroy) {
throw(new Error("[drawer].destroy must be implemented by child class"));
}
if (this.setImageSmoothingEnabled === $.DrawerBase.prototype.setImageSmoothingEnabled) {
throw(new Error("[drawer].setImageSmoothingEnabled must be implemented by child class"));
}
}
// Utility functions
/**
* Scale from OpenSeadragon viewer rectangle to drawer rectangle
* (ignoring rotation)
* @param {OpenSeadragon.Rect} rectangle - The rectangle in viewport coordinate system.
* @returns {OpenSeadragon.Rect} Rectangle in drawer coordinate system.
*/
viewportToDrawerRectangle(rectangle) {
var topLeft = this.viewport.pixelFromPointNoRotate(rectangle.getTopLeft(), true);
var size = this.viewport.deltaPixelsFromPointsNoRotate(rectangle.getSize(), true);
return new $.Rect(
topLeft.x * $.pixelDensityRatio,
topLeft.y * $.pixelDensityRatio,
size.x * $.pixelDensityRatio,
size.y * $.pixelDensityRatio
);
}
/**
* This function converts the given point from to the drawer coordinate by
* multiplying it with the pixel density.
* This function does not take rotation into account, thus assuming provided
* point is at 0 degree.
* @param {OpenSeadragon.Point} point - the pixel point to convert
* @returns {OpenSeadragon.Point} Point in drawer coordinate system.
*/
viewportCoordToDrawerCoord(point) {
var vpPoint = this.viewport.pixelFromPointNoRotate(point, true);
return new $.Point(
vpPoint.x * $.pixelDensityRatio,
vpPoint.y * $.pixelDensityRatio
);
}
// Internal utility functions
/**
* Calculate width and height of the canvas based on viewport dimensions
* and pixelDensityRatio
* @private
* @returns {OpenSeadragon.Point} {x, y} size of the canvas
*/
_calculateCanvasSize() {
var pixelDensityRatio = $.pixelDensityRatio;
var viewportSize = this.viewport.getContainerSize();
return new OpenSeadragon.Point( Math.round(viewportSize.x * pixelDensityRatio), Math.round(viewportSize.y * pixelDensityRatio));
}
/**
* Called by implementations to fire the tiled-image-drawn event (used by tests)
* @private
*/
_raiseTiledImageDrawnEvent(tiledImage, tiles){
if(!this.viewer) {
return;
}
/**
* Raised when a tiled image is drawn to the canvas. Used internally for testing.
* The update-viewport event is preferred if you want to know when a frame has been drawn.
*
* @event tiled-image-drawn
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.
* @property {Array} tiles - An array of Tile objects that were drawn.
* @property {?Object} userData - Arbitrary subscriber-defined object.
* @private
*/
this.viewer.raiseEvent( 'tiled-image-drawn', {
tiledImage: tiledImage,
tiles: tiles,
});
}
/**
* Called by implementations to fire the drawer-error event
* @private
*/
_raiseDrawerErrorEvent(tiledImage, errorMessage){
if(!this.viewer) {
return;
}
/**
* Raised when a tiled image is drawn to the canvas. Used internally for testing.
* The update-viewport event is preferred if you want to know when a frame has been drawn.
*
* @event drawer-error
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.
* @property {OpenSeadragon.DrawerBase} drawer - The drawer that raised the error.
* @property {String} error - A message describing the error.
* @property {?Object} userData - Arbitrary subscriber-defined object.
* @protected
*/
this.viewer.raiseEvent( 'drawer-error', {
tiledImage: tiledImage,
drawer: this,
error: errorMessage,
});
}
};
}( OpenSeadragon ));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - DziTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -124,10 +124,11 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
* @function
* @param {Object|XMLDocument} data - the raw configuration
* @param {String} url - the url the data was retrieved from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @param {String} postData - HTTP POST data in k=v&k2=v2... form or null
* @returns {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function( data, url ){
configure: function( data, url, postData ){
var options;
@ -166,6 +167,14 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
},
/**
* Equality comparator
*/
equals: function(otherSource) {
return this.tilesUrl === otherSource.tilesUrl;
},
/**
* @function
* @param {Number} level

View file

@ -2,7 +2,7 @@
* OpenSeadragon - EventSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -37,9 +37,19 @@
/**
* Event handler method signature used by all OpenSeadragon events.
*
* @callback EventHandler
* @typedef {function(OpenSeadragon.Event): void} OpenSeadragon.EventHandler
* @memberof OpenSeadragon
* @param {Object} event - See individual events for event-specific properties.
* @param {OpenSeadragon.Event} event - The event object containing event-specific properties.
* @returns {void} This handler does not return a value.
*/
/**
* Event handler method signature used by all OpenSeadragon events.
*
* @typedef {function(OpenSeadragon.Event): Promise<void>} OpenSeadragon.AsyncEventHandler
* @memberof OpenSeadragon
* @param {OpenSeadragon.Event} event - The event object containing event-specific properties.
* @returns {Promise<void>} This handler does not return a value.
*/
@ -51,6 +61,7 @@
*/
$.EventSource = function() {
this.events = {};
this._rejectedEventList = {};
};
/** @lends OpenSeadragon.EventSource.prototype */
@ -58,62 +69,79 @@ $.EventSource.prototype = {
/**
* Add an event handler to be triggered only once (or a given number of times)
* for a given event.
* for a given event. It is not removable with removeHandler().
* @function
* @param {String} eventName - Name of event to register.
* @param {OpenSeadragon.EventHandler} handler - Function to call when event
* @param {OpenSeadragon.EventHandler|OpenSeadragon.AsyncEventHandler} handler - Function to call when event
* is triggered.
* @param {Object} [userData=null] - Arbitrary object to be passed unchanged
* to the handler.
* @param {Number} [times=1] - The number of times to handle the event
* before removing it.
* @param {Number} [priority=0] - Handler priority. By default, all priorities are 0. Higher number = priority.
* @returns {Boolean} - True if the handler was added, false if it was rejected
*/
addOnceHandler: function(eventName, handler, userData, times) {
var self = this;
addOnceHandler: function(eventName, handler, userData, times, priority) {
const self = this;
times = times || 1;
var count = 0;
var onceHandler = function(event) {
let count = 0;
const onceHandler = function(event) {
count++;
if (count === times) {
self.removeHandler(eventName, onceHandler);
}
handler(event);
return handler(event);
};
this.addHandler(eventName, onceHandler, userData);
return this.addHandler(eventName, onceHandler, userData, priority);
},
/**
* 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 {OpenSeadragon.EventHandler|OpenSeadragon.AsyncEventHandler} handler - Function to call when event is triggered.
* @param {Object} [userData=null] - Arbitrary object to be passed unchanged to the handler.
* @param {Number} [priority=0] - Handler priority. By default, all priorities are 0. Higher number = priority.
* @returns {Boolean} - True if the handler was added, false if it was rejected
*/
addHandler: function ( eventName, handler, userData ) {
var events = this.events[ eventName ];
addHandler: function ( eventName, handler, userData, priority ) {
if(Object.prototype.hasOwnProperty.call(this._rejectedEventList, eventName)){
$.console.error(`Error adding handler for ${eventName}. ${this._rejectedEventList[eventName]}`);
return false;
}
let events = this.events[ eventName ];
if ( !events ) {
this.events[ eventName ] = events = [];
}
if ( handler && $.isFunction( handler ) ) {
events[ events.length ] = { handler: handler, userData: userData || null };
let index = events.length,
event = { handler: handler, userData: userData || null, priority: priority || 0 };
events[ index ] = event;
while ( index > 0 && events[ index - 1 ].priority < events[ index ].priority ) {
events[ index ] = events[ index - 1 ];
events[ index - 1 ] = event;
index--;
}
}
return true;
},
/**
* 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.
* @param {OpenSeadragon.EventHandler|OpenSeadragon.AsyncEventHandler} handler - Function to be removed.
*/
removeHandler: function ( eventName, handler ) {
var events = this.events[ eventName ],
handlers = [],
i;
const events = this.events[ eventName ],
handlers = [];
if ( !events ) {
return;
}
if ( $.isArray( events ) ) {
for ( i = 0; i < events.length; i++ ) {
for ( let i = 0; i < events.length; i++ ) {
if ( events[i].handler !== handler ) {
handlers.push( events[ i ] );
}
@ -122,6 +150,18 @@ $.EventSource.prototype = {
}
},
/**
* Get the amount of handlers registered for a given event.
* @param {String} eventName - Name of event to inspect.
* @returns {number} amount of events
*/
numberOfHandlers: function (eventName) {
const events = this.events[ eventName ];
if ( !events ) {
return 0;
}
return events.length;
},
/**
* Remove all event handlers for a given event type. If no type is given all
@ -133,7 +173,7 @@ $.EventSource.prototype = {
if ( eventName ){
this.events[ eventName ] = [];
} else{
for ( var eventType in this.events ) {
for ( let eventType in this.events ) {
this.events[ eventType ] = [];
}
}
@ -144,8 +184,8 @@ $.EventSource.prototype = {
* @function
* @param {String} eventName - Name of event to get handlers for.
*/
getHandler: function ( eventName ) {
var events = this.events[ eventName ];
getHandler: function ( eventName) {
let events = this.events[ eventName ];
if ( !events || !events.length ) {
return null;
}
@ -153,9 +193,8 @@ $.EventSource.prototype = {
[ events[ 0 ] ] :
Array.apply( null, events );
return function ( source, args ) {
var i,
length = events.length;
for ( i = 0; i < length; i++ ) {
let length = events.length;
for ( let i = 0; i < length; i++ ) {
if ( events[ i ] ) {
args.eventSource = source;
args.userData = events[ i ].userData;
@ -166,23 +205,106 @@ $.EventSource.prototype = {
},
/**
* Trigger an event, optionally passing additional information.
* Get a function which iterates the list of all handlers registered for a given event,
* calling the handler for each and awaiting async ones.
* @function
* @param {String} eventName - Name of event to get handlers for.
* @param {any} bindTarget - Bound target to return with the promise on finish
*/
getAwaitingHandler: function ( eventName, bindTarget ) {
let events = this.events[ eventName ];
if ( !events || !events.length ) {
return null;
}
events = events.length === 1 ?
[ events[ 0 ] ] :
Array.apply( null, events );
return function ( source, args ) {
// We return a promise that gets resolved after all the events finish.
// Returning loop result is not correct, loop promises chain dynamically
// and outer code could process finishing logics in the middle of event loop.
return new $.Promise(resolve => {
const length = events.length;
function loop(index) {
if ( index >= length || !events[ index ] ) {
resolve(bindTarget);
return null;
}
args.eventSource = source;
args.userData = events[ index ].userData;
let result = events[ index ].handler( args );
result = (!result || $.type(result) !== "promise") ? $.Promise.resolve() : result;
return result.then(() => loop(index + 1));
}
loop(0);
});
};
},
/**
* Trigger an event, optionally passing additional information. Does not await async handlers, i.e.
* OpenSeadragon.AsyncEventHandler.
* @function
* @param {String} eventName - Name of event to register.
* @param {Object} eventArgs - Event-specific data.
* @returns {Boolean} True if the event was fired, false if it was rejected because of rejectEventHandler(eventName)
*/
raiseEvent: function( eventName, eventArgs ) {
//uncomment if you want to get a log of all events
//$.console.log( eventName );
var handler = this.getHandler( eventName );
//$.console.log( "Event fired:", eventName );
if ( handler ) {
if ( !eventArgs ) {
eventArgs = {};
}
handler( this, eventArgs );
if(Object.prototype.hasOwnProperty.call(this._rejectedEventList, eventName)){
$.console.error(`Error adding handler for ${eventName}. ${this._rejectedEventList[eventName]}`);
return false;
}
const handler = this.getHandler( eventName );
if ( handler ) {
handler( this, eventArgs || {} );
}
return true;
},
/**
* Trigger an event, optionally passing additional information.
* This events awaits every asynchronous or promise-returning function, i.e.
* OpenSeadragon.AsyncEventHandler.
* @param {String} eventName - Name of event to register.
* @param {Object} eventArgs - Event-specific data.
* @param {?} [bindTarget = null] - Promise-resolved value on the event finish
* @return {OpenSeadragon.Promise|undefined} - Promise resolved upon the event completion.
*/
raiseEventAwaiting: function ( eventName, eventArgs, bindTarget = null ) {
//uncomment if you want to get a log of all events
//$.console.log( "Awaiting event fired:", eventName );
const awaitingHandler = this.getAwaitingHandler(eventName, bindTarget);
if (awaitingHandler) {
return awaitingHandler(this, eventArgs || {});
}
return $.Promise.resolve(bindTarget);
},
/**
* Set an event name as being disabled, and provide an optional error message
* to be printed to the console
* @param {String} eventName - Name of the event
* @param {String} [errorMessage] - Optional string to print to the console
* @private
*/
rejectEventHandler(eventName, errorMessage = ''){
this._rejectedEventList[eventName] = errorMessage;
},
/**
* Explicitly allow an event handler to be added for this event type, undoing
* the effects of rejectEventHandler
* @param {String} eventName - Name of the event
* @private
*/
allowEventHandler(eventName){
delete this._rejectedEventList[eventName];
}
};

View file

@ -2,7 +2,7 @@
* OpenSeadragon - full-screen support functions
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -67,10 +67,14 @@
return document.fullscreenElement;
};
fullScreenApi.requestFullScreen = function( element ) {
return element.requestFullscreen();
return element.requestFullscreen().catch(function (msg) {
$.console.error('Fullscreen request failed: ', msg);
});
};
fullScreenApi.exitFullScreen = function() {
document.exitFullscreen();
document.exitFullscreen().catch(function (msg) {
$.console.error('Error while exiting fullscreen: ', msg);
});
};
fullScreenApi.fullScreenEventName = "fullscreenchange";
fullScreenApi.fullScreenErrorEventName = "fullscreenerror";

288
src/htmldrawer.js Normal file
View file

@ -0,0 +1,288 @@
/*
* OpenSeadragon - HTMLDrawer
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2024 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( $ ){
const OpenSeadragon = $; // alias back for JSDoc
/**
* @class OpenSeadragon.HTMLDrawer
* @extends OpenSeadragon.DrawerBase
* @classdesc HTML-based implementation of DrawerBase for an {@link OpenSeadragon.Viewer}.
* @param {Object} options - Options for this Drawer.
* @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer.
* @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport.
* @param {Element} options.element - Parent element.
* @param {Number} [options.debugGridColor] - See debugGridColor in {@link OpenSeadragon.Options} for details.
*/
class HTMLDrawer extends OpenSeadragon.DrawerBase{
constructor(options){
super(options);
/**
* The HTML element (div) that this drawer uses for drawing
* @member {Element} canvas
* @memberof OpenSeadragon.HTMLDrawer#
*/
/**
* The parent element of this Drawer instance, passed in when the Drawer was created.
* The parent of {@link OpenSeadragon.WebGLDrawer#canvas}.
* @member {Element} container
* @memberof OpenSeadragon.HTMLDrawer#
*/
// Reject listening for the tile-drawing event, which this drawer does not fire
this.viewer.rejectEventHandler("tile-drawing", "The HTMLDrawer does not raise the tile-drawing event");
// Since the tile-drawn event is fired by this drawer, make sure handlers can be added for it
this.viewer.allowEventHandler("tile-drawn");
// works with canvas & image objects
function _prepareTile(tile, data) {
const element = $.makeNeutralElement( "div" );
const imgElement = data.cloneNode();
imgElement.style.msInterpolationMode = "nearest-neighbor";
imgElement.style.width = "100%";
imgElement.style.height = "100%";
const style = element.style;
style.position = "absolute";
return {
element, imgElement, style, data
};
}
// The actual placing logics will not happen at draw event, but when the cache is created:
$.convertor.learn("context2d", HTMLDrawer.canvasCacheType, (t, d) => _prepareTile(t, d.canvas), 1, 1);
$.convertor.learn("image", HTMLDrawer.imageCacheType, _prepareTile, 1, 1);
// Also learn how to move back, since these elements can be just used as-is
$.convertor.learn(HTMLDrawer.canvasCacheType, "context2d", (t, d) => d.data.getContext('2d'), 1, 3);
$.convertor.learn(HTMLDrawer.imageCacheType, "image", (t, d) => d.data, 1, 3);
function _freeTile(data) {
if ( data.imgElement && data.imgElement.parentNode ) {
data.imgElement.parentNode.removeChild( data.imgElement );
}
if ( data.element && data.element.parentNode ) {
data.element.parentNode.removeChild( data.element );
}
}
$.convertor.learnDestroy(HTMLDrawer.canvasCacheType, _freeTile);
$.convertor.learnDestroy(HTMLDrawer.imageCacheType, _freeTile);
}
static get imageCacheType() {
return 'htmlDrawer[image]';
}
static get canvasCacheType() {
return 'htmlDrawer[canvas]';
}
/**
* @returns {Boolean} always true
*/
static isSupported() {
return true;
}
/**
*
* @returns 'html'
*/
getType(){
return 'html';
}
getSupportedDataFormats() {
return [HTMLDrawer.imageCacheType, HTMLDrawer.canvasCacheType];
}
/**
* @param {TiledImage} tiledImage the tiled image that is calling the function
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
* @private
*/
minimumOverlapRequired(tiledImage) {
return true;
}
/**
* create the HTML element (e.g. canvas, div) that the image will be drawn into
* @returns {Element} the div to draw into
*/
_createDrawingElement(){
return $.makeNeutralElement("div");
}
/**
* Draws the TiledImages
*/
draw(tiledImages) {
var _this = this;
this._prepareNewFrame(); // prepare to draw a new frame
tiledImages.forEach(function(tiledImage){
if (tiledImage.opacity !== 0) {
_this._drawTiles(tiledImage);
}
});
}
/**
* @returns {Boolean} False - rotation is not supported.
*/
canRotate() {
return false;
}
/**
* Destroy the drawer (unload current loaded tiles)
*/
destroy() {
this.container.removeChild(this.canvas);
}
/**
* This function is ignored by the HTML Drawer. Implementing it is required by DrawerBase.
* @param {Boolean} [imageSmoothingEnabled] - Whether or not the image is
* drawn smoothly on the canvas; see imageSmoothingEnabled in
* {@link OpenSeadragon.Options} for more explanation.
*/
setImageSmoothingEnabled(){
// noop - HTML Drawer does not deal with this property
}
/**
* Clears the Drawer so it's ready to draw another frame.
* @private
*
*/
_prepareNewFrame() {
this.canvas.innerHTML = "";
}
/**
* Draws a TiledImage.
* @private
*
*/
_drawTiles( tiledImage ) {
var lastDrawn = tiledImage.getTilesToDraw().map(info => info.tile);
if (tiledImage.opacity === 0 || (lastDrawn.length === 0 && !tiledImage.placeholderFillStyle)) {
return;
}
// Iterate over the tiles to draw, and draw them
for (var i = lastDrawn.length - 1; i >= 0; i--) {
var tile = lastDrawn[ i ];
this._drawTile( tile );
if( this.viewer ){
/**
* Raised when a tile is drawn to the canvas. Only valid for
* context2d and html drawers.
*
* @event tile-drawn
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.
* @property {OpenSeadragon.Tile} tile
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'tile-drawn', {
tiledImage: tiledImage,
tile: tile
});
}
}
}
/**
* Draws the given tile.
* @private
* @param {OpenSeadragon.Tile} tile - The tile to draw.
* @param {Function} drawingHandler - Method for firing the drawing event if using canvas.
* drawingHandler({context, tile, rendered})
*/
_drawTile( tile ) {
$.console.assert(tile, '[Drawer._drawTile] tile is required');
let container = this.canvas;
if ( !tile.loaded ) {
$.console.warn(
"Attempting to draw tile %s when it's not yet loaded.",
tile.toString()
);
return;
}
//EXPERIMENTAL - trying to figure out how to scale the container
// content during animation of the container size.
const dataObject = this.getDataToDraw(tile);
if (!dataObject) {
return;
}
if ( dataObject.element.parentNode !== container ) {
container.appendChild( dataObject.element );
}
if ( dataObject.imgElement.parentNode !== dataObject.element ) {
dataObject.element.appendChild( dataObject.imgElement );
}
dataObject.style.top = tile.position.y + "px";
dataObject.style.left = tile.position.x + "px";
dataObject.style.height = tile.size.y + "px";
dataObject.style.width = tile.size.x + "px";
if (tile.flipped) {
dataObject.style.transform = "scaleX(-1)";
}
$.setElementOpacity( dataObject.element, tile.opacity );
}
}
$.HTMLDrawer = HTMLDrawer;
}( OpenSeadragon ));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - IIIFTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -51,8 +51,11 @@ $.IIIFTileSource = function( options ){
$.extend( true, this, options );
if ( !( this.height && this.width && this['@id'] ) ) {
throw new Error( 'IIIF required parameters not provided.' );
/* Normalizes v3-style 'id' keys to an "_id" internal property */
this._id = this["@id"] || this["id"] || this['identifier'] || null;
if ( !( this.height && this.width && this._id) ) {
throw new Error( 'IIIF required parameters (width, height, or id) not provided.' );
}
options.tileSizePerScaleFactor = {};
@ -131,13 +134,25 @@ $.IIIFTileSource = function( options ){
if (!options.maxLevel && !this.emulateLegacyImagePyramid) {
if (!this.scale_factors) {
options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2)));
options.maxLevel = Number(Math.round(Math.log(Math.max(this.width, this.height), 2)));
} else {
var maxScaleFactor = Math.max.apply(null, this.scale_factors);
options.maxLevel = Math.round(Math.log(maxScaleFactor) * Math.LOG2E);
}
}
// Create an array with our exact resolution sizes if these have been supplied
if( this.sizes ) {
var sizeLength = this.sizes.length;
if ( (sizeLength === options.maxLevel) || (sizeLength === options.maxLevel + 1) ) {
this.levelSizes = this.sizes.slice().sort(( size1, size2 ) => size1.width - size2.width);
// Need to take into account that the list may or may not include the full resolution size
if( sizeLength === options.maxLevel ) {
this.levelSizes.push( {width: this.width, height: this.height} );
}
}
}
$.TileSource.apply( this, [ options ] );
};
@ -147,7 +162,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
* this tile source.
* @function
* @param {Object|Array} data
* @param {String} optional - url
* @param {String} [url] - url
*/
supports: function( data, url ) {
@ -180,35 +195,43 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
},
/**
* A static function used to prepare an incoming IIIF Image API info.json
* response for processing by the tile handler. Normalizes data for all
* versions of IIIF (1.0, 1.1, 2.x, 3.x) and returns a data object that
* may be passed to the IIIFTileSource.
*
* @function
* @static
* @param {Object} data - the raw configuration
* @example <caption>IIIF 1.1 Info Looks like this</caption>
* @param {String} url - the url configuration was retrieved from
* @param {String} postData - HTTP POST data in k=v&k2=v2... form or null
* @returns {Object} A normalized IIIF data object
* @example <caption>IIIF 2.x Info Looks like this</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"
* "@context": "http://iiif.io/api/image/2/context.json",
* "@id": "http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C",
* "protocol": "http://iiif.io/api/image",
* "height": 1024,
* "width": 775,
* "tiles" : [{"width":256, "scaleFactors":[1,2,4,8]}],
* "profile": ["http://iiif.io/api/image/2/level1.json", {
* "qualities": [ "native", "bitonal", "grey", "color" ],
* "formats": [ "jpg", "png", "gif" ]
* }]
* }
*/
configure: function( data, url ){
configure: function( data, url, postData ){
// Try to deduce our version and fake it upwards if needed
if ( !$.isPlainObject(data) ) {
var options = configureFromXml10( data );
options['@context'] = "http://iiif.io/api/image/1.0/context.json";
options['@id'] = url.replace('/info.xml', '');
options["@id"] = url.replace('/info.xml', '');
options.version = 1;
return options;
} else {
if ( !data['@context'] ) {
data['@context'] = 'http://iiif.io/api/image/1.0/context.json';
data['@id'] = url.replace('/info.json', '');
data["@id"] = url.replace('/info.json', '');
data.version = 1;
} else {
var context = data['@context'];
@ -237,12 +260,10 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
$.console.error('Data has a @context property which contains no known IIIF context URI.');
}
}
if ( !data['@id'] && data['id'] ) {
data['@id'] = data['id'];
}
if(data.preferredFormats) {
if (data.preferredFormats) {
for (var f = 0; f < data.preferredFormats.length; f++ ) {
if ( OpenSeadragon.imageFormatSupported(data.preferredFormats[f]) ) {
if ( $.imageFormatSupported(data.preferredFormats[f]) ) {
data.tileFormat = data.preferredFormats[f];
break;
}
@ -324,7 +345,17 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
}
}
return $.TileSource.prototype.getNumTiles.call(this, level);
// Use supplied list of scaled resolution sizes if these exist
if( this.levelSizes ) {
var levelSize = this.levelSizes[level];
var x = Math.ceil( levelSize.width / this.getTileWidth(level) ),
y = Math.ceil( levelSize.height / this.getTileHeight(level) );
return new $.Point( x, y );
}
// Otherwise call default TileSource->getNumTiles() function
else {
return $.TileSource.prototype.getNumTiles.call(this, level);
}
},
@ -339,6 +370,34 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
return new $.Point(0, 0);
}
// Use supplied list of scaled resolution sizes if these exist
if( this.levelSizes ) {
var validPoint = point.x >= 0 && point.x <= 1 &&
point.y >= 0 && point.y <= 1 / this.aspectRatio;
$.console.assert(validPoint, "[TileSource.getTileAtPoint] must be called with a valid point.");
var widthScaled = this.levelSizes[level].width;
var pixelX = point.x * widthScaled;
var pixelY = point.y * widthScaled;
var x = Math.floor(pixelX / this.getTileWidth(level));
var y = Math.floor(pixelY / this.getTileHeight(level));
// When point.x == 1 or point.y == 1 / this.aspectRatio we want to
// return the last tile of the row/column
if (point.x >= 1) {
x = this.getNumTiles(level).x - 1;
}
var EPSILON = 1e-15;
if (point.y >= 1 / this.aspectRatio - EPSILON) {
y = this.getNumTiles(level).y - 1;
}
return new $.Point(x, y);
}
// Otherwise call default TileSource->getTileAtPoint() function
return $.TileSource.prototype.getTileAtPoint.call(this, level, point);
},
@ -366,10 +425,9 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
var IIIF_ROTATION = '0',
//## 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 ),
levelWidth,
levelHeight,
//## iiif region
tileWidth,
@ -387,10 +445,21 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
iiifQuality,
uri;
// Use supplied list of scaled resolution sizes if these exist
if( this.levelSizes ) {
levelWidth = this.levelSizes[level].width;
levelHeight = this.levelSizes[level].height;
}
// Otherwise calculate the sizes ourselves
else {
levelWidth = Math.ceil( this.width * scale );
levelHeight = Math.ceil( this.height * scale );
}
tileWidth = this.getTileWidth(level);
tileHeight = this.getTileHeight(level);
iiifTileSizeWidth = Math.ceil( tileWidth / scale );
iiifTileSizeHeight = Math.ceil( tileHeight / scale );
iiifTileSizeWidth = Math.round( tileWidth / scale );
iiifTileSizeHeight = Math.round( tileHeight / scale );
if (this.version === 1) {
iiifQuality = "native." + this.tileFormat;
} else {
@ -417,8 +486,8 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
} else {
iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' );
}
iiifSizeW = Math.ceil( iiifTileW * scale );
iiifSizeH = Math.ceil( iiifTileH * scale );
iiifSizeW = Math.min( tileWidth, levelWidth - (x * tileWidth) );
iiifSizeH = Math.min( tileHeight, levelHeight - (y * tileHeight) );
if ( this.version === 2 && iiifSizeW === this.width ) {
iiifSize = "full";
} else if ( this.version === 3 && iiifSizeW === this.width && iiifSizeH === this.height ) {
@ -429,11 +498,18 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
iiifSize = iiifSizeW + ",";
}
}
uri = [ this['@id'], iiifRegion, iiifSize, IIIF_ROTATION, iiifQuality ].join( '/' );
uri = [ this._id, iiifRegion, iiifSize, IIIF_ROTATION, iiifQuality ].join( '/' );
return uri;
},
/**
* Equality comparator
*/
equals: function(otherSource) {
return this._id === otherSource._id;
},
__testonly__: {
canBeTiled: canBeTiled,
constructLevels: constructLevels
@ -444,8 +520,11 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
/**
* Determine whether arbitrary tile requests can be made against a service with the given profile
* @function
* @param {array} profile - IIIF profile array
* @throws {Error}
* @param {Object} options
* @param {Array|String} options.profile
* @param {Number} options.version
* @param {String[]} options.extraFeatures
* @returns {Boolean}
*/
function canBeTiled ( options ) {
var level0Profiles = [
@ -477,7 +556,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
var levels = [];
for(var i = 0; i < options.sizes.length; i++) {
levels.push({
url: options['@id'] + '/full/' + options.sizes[i].width + ',' +
url: options._id + '/full/' + options.sizes[i].width + ',' +
(options.version === 3 ? options.sizes[i].height : '') +
'/0/default.' + options.tileFormat,
width: options.sizes[i].width,

View file

@ -2,7 +2,7 @@
* OpenSeadragon - ImageLoader
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -35,134 +35,130 @@
(function($){
/**
* @private
* @class ImageJob
* @classdesc Handles downloading of a single image.
*
* @memberof OpenSeadragon
* @param {Object} options - Options for this ImageJob.
* @param {String} [options.src] - URL of image to download.
* @param {Tile} [options.tile] - Tile that belongs the data to.
* @param {TileSource} [options.source] - Image loading strategy
* @param {String} [options.loadWithAjax] - Whether to load this image with AJAX.
* @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX.
* @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX requests.
* @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads
* @param {String} [options.postData] - HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getTilePostData) or null
* @param {Function} [options.callback] - Called once image has been downloaded.
* @param {Function} [options.abort] - Called when this image job is aborted.
* @param {Number} [options.timeout] - The max number of milliseconds that this image job may take to complete.
* @param {Number} [options.tries] - Actual number of the current try.
*/
function ImageJob (options) {
$.ImageJob = function(options) {
$.extend(true, this, {
timeout: $.DEFAULT_SETTINGS.timeout,
jobId: null
jobId: null,
tries: 0
}, options);
/**
* Image object which will contain downloaded image.
* @member {Image} image
* Data object which will contain downloaded image data.
* @member {Image|*} data data object, by default an Image object (depends on TileSource)
* @memberof OpenSeadragon.ImageJob#
*/
this.image = null;
}
this.data = null;
ImageJob.prototype = {
errorMsg: null,
/**
* User workspace to populate with helper variables
* @member {*} userData to append custom data and avoid namespace collision
* @memberof OpenSeadragon.ImageJob#
*/
this.userData = {};
/**
* Error message holder
* @member {string} error message
* @memberof OpenSeadragon.ImageJob#
* @private
*/
this.errorMsg = null;
};
$.ImageJob.prototype = {
/**
* Starts the image job.
* @method
* @memberof OpenSeadragon.ImageJob#
*/
start: function(){
start: function() {
this.tries++;
var self = this;
var selfAbort = this.abort;
this.image = new Image();
this.image.onload = function(){
self.finish(true);
};
this.image.onabort = this.image.onerror = function() {
self.errorMsg = "Image load aborted";
self.finish(false);
};
this.jobId = window.setTimeout(function(){
self.errorMsg = "Image load exceeded timeout (" + self.timeout + " ms)";
self.finish(false);
this.jobId = window.setTimeout(function () {
self.fail("Image load exceeded timeout (" + self.timeout + " ms)", null);
}, this.timeout);
// Load the tile with an AJAX request if the loadWithAjax option is
// set. Otherwise load the image by setting the source proprety of the image object.
if (this.loadWithAjax) {
this.request = $.makeAjaxRequest({
url: this.src,
withCredentials: this.ajaxWithCredentials,
headers: this.ajaxHeaders,
responseType: "arraybuffer",
success: function(request) {
var blb;
// Make the raw data into a blob.
// BlobBuilder fallback adapted from
// http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility
try {
blb = new window.Blob([request.response]);
} catch (e) {
var BlobBuilder = (
window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder
);
if (e.name === 'TypeError' && BlobBuilder) {
var bb = new BlobBuilder();
bb.append(request.response);
blb = bb.getBlob();
}
}
// If the blob is empty for some reason consider the image load a failure.
if (blb.size === 0) {
self.errorMsg = "Empty image response.";
self.finish(false);
}
// Create a URL for the blob data and make it the source of the image object.
// This will still trigger Image.onload to indicate a successful tile load.
var url = (window.URL || window.webkitURL).createObjectURL(blb);
self.image.src = url;
},
error: function(request) {
self.errorMsg = "Image load aborted - XHR error";
self.finish(false);
}
});
// Provide a function to properly abort the request.
this.abort = function() {
self.request.abort();
// Call the existing abort function if available
if (typeof selfAbort === "function") {
selfAbort();
}
};
} else {
if (this.crossOriginPolicy !== false) {
this.image.crossOrigin = this.crossOriginPolicy;
this.abort = function() {
self.source.downloadTileAbort(self);
if (typeof selfAbort === "function") {
selfAbort();
}
};
this.image.src = this.src;
}
this.source.downloadTileStart(this);
},
finish: function(successful) {
this.image.onload = this.image.onerror = this.image.onabort = null;
if (!successful) {
this.image = null;
/**
* Finish this job.
* @param {*} data data that has been downloaded
* @param {XMLHttpRequest} request reference to the request if used
* @param {string} dataType data type identifier
* fallback compatibility behavior: dataType treated as errorMessage if data is falsey value
* @memberof OpenSeadragon.ImageJob#
*/
finish: function(data, request, dataType) {
if (!this.jobId) {
return;
}
// old behavior, no deprecation due to possible finish calls with invalid data item (e.g. different error)
if (data === null || data === undefined || data === false) {
this.fail(dataType || "[downloadTileStart->finish()] Retrieved data is invalid!", request);
return;
}
this.data = data;
this.request = request;
this.errorMsg = null;
this.dataType = dataType;
if (this.jobId) {
window.clearTimeout(this.jobId);
}
this.callback(this);
}
},
/**
* Finish this job as a failure.
* @param {string} errorMessage description upon failure
* @param {XMLHttpRequest} request reference to the request if used
*/
fail: function(errorMessage, request) {
this.data = null;
this.request = request;
this.errorMsg = errorMessage;
this.dataType = null;
if (this.jobId) {
window.clearTimeout(this.jobId);
this.jobId = null;
}
this.callback(this);
}
};
/**
@ -180,6 +176,7 @@ $.ImageLoader = function(options) {
jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit,
timeout: $.DEFAULT_SETTINGS.timeout,
jobQueue: [],
failedTiles: [],
jobsInProgress: 0
}, options);
@ -193,38 +190,61 @@ $.ImageLoader.prototype = {
* @method
* @param {Object} options - Options for this job.
* @param {String} [options.src] - URL of image to download.
* @param {Tile} [options.tile] - Tile that belongs the data to. The tile instance
* is not internally used and serves for custom TileSources implementations.
* @param {TileSource} [options.source] - Image loading strategy
* @param {String} [options.loadWithAjax] - Whether to load this image with AJAX.
* @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX.
* @param {String|Boolean} [options.crossOriginPolicy] - CORS policy to use for downloads
* @param {String} [options.postData] - POST parameters (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getTilePostData) or null
* @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX
* requests.
* requests.
* @param {Function} [options.callback] - Called once image has been downloaded.
* @param {Function} [options.abort] - Called when this image job is aborted.
* @returns {boolean} true if job was immediatelly started, false if queued
*/
addJob: function(options) {
var _this = this,
complete = function(job) {
completeJob(_this, job, options.callback);
},
if (!options.source) {
$.console.error('ImageLoader.prototype.addJob() requires [options.source]. ' +
'TileSource since new API defines how images are fetched. Creating a dummy TileSource.');
var implementation = $.TileSource.prototype;
options.source = {
downloadTileStart: implementation.downloadTileStart,
downloadTileAbort: implementation.downloadTileAbort
};
}
const _this = this,
jobOptions = {
src: options.src,
tile: options.tile || {},
source: options.source,
loadWithAjax: options.loadWithAjax,
ajaxHeaders: options.loadWithAjax ? options.ajaxHeaders : null,
crossOriginPolicy: options.crossOriginPolicy,
ajaxWithCredentials: options.ajaxWithCredentials,
callback: complete,
postData: options.postData,
callback: (job) => completeJob(_this, job, options.callback),
abort: options.abort,
timeout: this.timeout
},
newJob = new ImageJob(jobOptions);
newJob = new $.ImageJob(jobOptions);
if ( !this.jobLimit || this.jobsInProgress < this.jobLimit ) {
newJob.start();
this.jobsInProgress++;
return true;
}
else {
this.jobQueue.push( newJob );
}
this.jobQueue.push( newJob );
return false;
},
/**
* @returns {boolean} true if a job can be submitted
*/
canAcceptNewJob() {
return !this.jobLimit || this.jobsInProgress < this.jobLimit;
},
/**
@ -244,7 +264,8 @@ $.ImageLoader.prototype = {
};
/**
* Cleans up ImageJob once completed.
* Cleans up ImageJob once completed. Restarts job after tileRetryDelay seconds if failed
* but max tileRetryMax times
* @method
* @private
* @param loader - ImageLoader used to start job.
@ -252,17 +273,30 @@ $.ImageLoader.prototype = {
* @param callback - Called once cleanup is finished.
*/
function completeJob(loader, job, callback) {
var nextJob;
if (job.errorMsg && job.data === null && job.tries < 1 + loader.tileRetryMax) {
loader.failedTiles.push(job);
}
let nextJob;
loader.jobsInProgress--;
if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) {
if (loader.canAcceptNewJob() && loader.jobQueue.length > 0) {
nextJob = loader.jobQueue.shift();
nextJob.start();
loader.jobsInProgress++;
}
callback(job.image, job.errorMsg, job.request);
if (loader.tileRetryMax > 0 && loader.jobQueue.length === 0) {
if (loader.canAcceptNewJob() && loader.failedTiles.length > 0) {
nextJob = loader.failedTiles.shift();
setTimeout(function () {
nextJob.start();
}, loader.tileRetryDelay);
loader.jobsInProgress++;
}
}
callback(job.data, job.errorMsg, job.request, job.dataType);
}
}(OpenSeadragon));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - ImageTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -31,250 +31,235 @@
* 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 ImageTileSource
* @classdesc The ImageTileSource allows a simple image to be loaded
* into an OpenSeadragon Viewer.
* There are 2 ways to open an ImageTileSource:
* 1. viewer.open({type: 'image', url: fooUrl});
* 2. viewer.open(new OpenSeadragon.ImageTileSource({url: fooUrl}));
*
* With the first syntax, the crossOriginPolicy, ajaxWithCredentials and
* useCanvas options are inherited from the viewer if they are not
* specified directly in the options object.
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
* @param {Object} options Options object.
* @param {String} options.url URL of the image
* @param {Boolean} [options.buildPyramid=true] If set to true (default), a
* pyramid will be built internally to provide a better downsampling.
* @param {String|Boolean} [options.crossOriginPolicy=false] Valid values are
* 'Anonymous', 'use-credentials', and false. If false, image requests will
* not use CORS preventing internal pyramid building for images from other
* domains.
* @param {String|Boolean} [options.ajaxWithCredentials=false] Whether to set
* the withCredentials XHR flag for AJAX requests (when loading tile sources).
* @param {Boolean} [options.useCanvas=true] Set to false to prevent any use
* of the canvas API.
*/
$.ImageTileSource = class extends $.TileSource {
/**
* @class ImageTileSource
* @classdesc The ImageTileSource allows a simple image to be loaded
* into an OpenSeadragon Viewer.
* There are 2 ways to open an ImageTileSource:
* 1. viewer.open({type: 'image', url: fooUrl});
* 2. viewer.open(new OpenSeadragon.ImageTileSource({url: fooUrl}));
*
* With the first syntax, the crossOriginPolicy, ajaxWithCredentials and
* useCanvas options are inherited from the viewer if they are not
* specified directly in the options object.
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
* @param {Object} options Options object.
* @param {String} options.url URL of the image
* @param {Boolean} [options.buildPyramid=true] If set to true (default), a
* pyramid will be built internally to provide a better downsampling.
* @param {String|Boolean} [options.crossOriginPolicy=false] Valid values are
* 'Anonymous', 'use-credentials', and false. If false, image requests will
* not use CORS preventing internal pyramid building for images from other
* domains.
* @param {String|Boolean} [options.ajaxWithCredentials=false] Whether to set
* the withCredentials XHR flag for AJAX requests (when loading tile sources).
* @param {Boolean} [options.useCanvas=true] Set to false to prevent any use
* of the canvas API.
*/
$.ImageTileSource = function (options) {
options = $.extend({
constructor(props) {
super($.extend({
buildPyramid: true,
crossOriginPolicy: false,
ajaxWithCredentials: false,
useCanvas: true
}, options);
$.TileSource.apply(this, [options]);
}, props));
}
};
/**
* Determine if the data and/or url imply the image service is supported by
* this tile source.
* @function
* @param {Object|Array} data
* @param {String} url - optional
*/
supports(data, url) {
return data.type && data.type === "image";
}
/**
*
* @function
* @param {Object} options - the options
* @param {String} dataUrl - the url the image was retrieved from, if any.
* @param {String} postData - HTTP POST data in k=v&k2=v2... form or null
* @returns {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure(options, dataUrl, postData) {
return options;
}
/**
* Responsible for retrieving, and caching the
* image metadata pertinent to this TileSources implementation.
* @function
* @param {String} url
* @throws {Error}
*/
getImageInfo(url) {
const image = new Image(),
_this = this;
$.extend($.ImageTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ImageTileSource.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.type && data.type === "image";
},
/**
*
* @function
* @param {Object} options - the options
* @param {String} dataUrl - the url the image was retrieved from, if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function (options, dataUrl) {
return options;
},
/**
* Responsible for retrieving, and caching the
* image metadata pertinent to this TileSources implementation.
* @function
* @param {String} url
* @throws {Error}
*/
getImageInfo: function (url) {
var image = this._image = new Image();
var _this = this;
if (this.crossOriginPolicy) {
image.crossOrigin = this.crossOriginPolicy;
}
if (this.ajaxWithCredentials) {
image.useCredentials = this.ajaxWithCredentials;
}
if (this.crossOriginPolicy) {
image.crossOrigin = this.crossOriginPolicy;
}
if (this.ajaxWithCredentials) {
image.useCredentials = this.ajaxWithCredentials;
}
$.addEvent(image, 'load', function () {
_this.width = image.naturalWidth;
_this.height = image.naturalHeight;
_this.aspectRatio = _this.width / _this.height;
_this.dimensions = new $.Point(_this.width, _this.height);
_this._tileWidth = _this.width;
_this._tileHeight = _this.height;
_this.tileOverlap = 0;
_this.minLevel = 0;
_this.image = image;
_this.levels = _this._buildLevels(image);
_this.maxLevel = _this.levels.length - 1;
$.addEvent(image, 'load', function () {
_this.width = image.naturalWidth;
_this.height = image.naturalHeight;
_this.aspectRatio = _this.width / _this.height;
_this.dimensions = new $.Point(_this.width, _this.height);
_this._tileWidth = _this.width;
_this._tileHeight = _this.height;
_this.tileOverlap = 0;
_this.minLevel = 0;
_this.levels = _this._buildLevels();
_this.maxLevel = _this.levels.length - 1;
_this.ready = true;
_this.ready = true;
// Note: this event is documented elsewhere, in TileSource
_this.raiseEvent('ready', {tileSource: _this});
});
// Note: this event is documented elsewhere, in TileSource
_this.raiseEvent('ready', {tileSource: _this});
$.addEvent(image, 'error', function () {
_this.image = null;
// Note: this event is documented elsewhere, in TileSource
_this.raiseEvent('open-failed', {
message: "Error loading image at " + url,
source: url
});
});
$.addEvent(image, 'error', function () {
// Note: this event is documented elsewhere, in TileSource
_this.raiseEvent('open-failed', {
message: "Error loading image at " + url,
source: url
});
});
image.src = url;
}
/**
* @function
* @param {Number} level
*/
getLevelScale(level) {
let levelScale = NaN;
if (level >= this.minLevel && level <= this.maxLevel) {
levelScale =
this.levels[level].width /
this.levels[this.maxLevel].width;
}
return levelScale;
}
/**
* @function
* @param {Number} level
*/
getNumTiles(level) {
if (this.getLevelScale(level)) {
return new $.Point(1, 1);
}
return new $.Point(0, 0);
}
/**
* Retrieves a tile url
* @function
* @param {Number} level Level of the tile
* @param {Number} x x coordinate of the tile
* @param {Number} y y coordinate of the tile
*/
getTileUrl(level, x, y) {
if (level === this.maxLevel) {
return this.url; //for original image, preserve url
}
//make up url by positional args
return `${this.url}?l=${level}&x=${x}&y=${y}`;
}
image.src = url;
},
/**
* @function
* @param {Number} level
*/
getLevelScale: function (level) {
var levelScale = NaN;
if (level >= this.minLevel && level <= this.maxLevel) {
levelScale =
this.levels[level].width /
this.levels[this.maxLevel].width;
}
return levelScale;
},
/**
* @function
* @param {Number} level
*/
getNumTiles: function (level) {
var scale = this.getLevelScale(level);
if (scale) {
return new $.Point(1, 1);
} else {
return new $.Point(0, 0);
}
},
/**
* Retrieves a tile url
* @function
* @param {Number} level Level of the tile
* @param {Number} x x coordinate of the tile
* @param {Number} y y coordinate of the tile
*/
getTileUrl: function (level, x, y) {
var url = null;
if (level >= this.minLevel && level <= this.maxLevel) {
url = this.levels[level].url;
}
return url;
},
/**
* Retrieves a tile context 2D
* @function
* @param {Number} level Level of the tile
* @param {Number} x x coordinate of the tile
* @param {Number} y y coordinate of the tile
*/
getContext2D: function (level, x, y) {
var context = null;
if (level >= this.minLevel && level <= this.maxLevel) {
context = this.levels[level].context2D;
}
return context;
},
/**
* Destroys ImageTileSource
* @function
*/
destroy: function () {
this._freeupCanvasMemory();
},
/**
* Equality comparator
*/
equals(otherSource) {
return this.url === otherSource.url;
}
// private
//
// Builds the different levels of the pyramid if possible
// (i.e. if canvas API enabled and no canvas tainting issue).
_buildLevels: function () {
var levels = [{
url: this._image.src,
width: this._image.naturalWidth,
height: this._image.naturalHeight
}];
getTilePostData(level, x, y) {
return {level: level, x: x, y: y};
}
if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) {
// We don't need the image anymore. Allows it to be GC.
delete this._image;
return levels;
}
/**
* Retrieves a tile context 2D
* @deprecated
*/
getContext2D(level, x, y) {
$.console.error('Using [TiledImage.getContext2D] (for plain images only) is deprecated. ' +
'Use overridden downloadTileStart (https://openseadragon.github.io/examples/advanced-data-model/) instead.');
return this._createContext2D();
}
var currentWidth = this._image.naturalWidth;
var currentHeight = this._image.naturalHeight;
downloadTileStart(job) {
const tileData = job.postData;
if (tileData.level === this.maxLevel) {
job.finish(this.image, null, "image");
return;
}
if (tileData.level >= this.minLevel && tileData.level <= this.maxLevel) {
const levelData = this.levels[tileData.level];
const context = this._createContext2D(this.image, levelData.width, levelData.height);
job.finish(context, null, "context2d");
return;
}
job.fail(`Invalid level ${tileData.level} for plain image source. Did you forget to set buildPyramid=true?`);
}
var bigCanvas = document.createElement("canvas");
var bigContext = bigCanvas.getContext("2d");
downloadTileAbort(job) {
//no-op
}
bigCanvas.width = currentWidth;
bigCanvas.height = currentHeight;
bigContext.drawImage(this._image, 0, 0, currentWidth, currentHeight);
// We cache the context of the highest level because the browser
// is a lot faster at downsampling something it already has
// downsampled before.
levels[0].context2D = bigContext;
// We don't need the image anymore. Allows it to be GC.
delete this._image;
// private
//
// Builds the different levels of the pyramid if possible
// (i.e. if canvas API enabled and no canvas tainting issue).
_buildLevels(image) {
const levels = [{
url: image.src,
width: image.naturalWidth,
height: image.naturalHeight
}];
if ($.isCanvasTainted(bigCanvas)) {
// If the canvas is tainted, we can't compute the pyramid.
return levels;
}
// We build smaller levels until either width or height becomes
// 1 pixel wide.
while (currentWidth >= 2 && currentHeight >= 2) {
currentWidth = Math.floor(currentWidth / 2);
currentHeight = Math.floor(currentHeight / 2);
var smallCanvas = document.createElement("canvas");
var smallContext = smallCanvas.getContext("2d");
smallCanvas.width = currentWidth;
smallCanvas.height = currentHeight;
smallContext.drawImage(bigCanvas, 0, 0, currentWidth, currentHeight);
levels.splice(0, 0, {
context2D: smallContext,
width: currentWidth,
height: currentHeight
});
bigCanvas = smallCanvas;
bigContext = smallContext;
}
if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) {
return levels;
},
/**
* Free up canvas memory
* (iOS 12 or higher on 2GB RAM device has only 224MB canvas memory,
* and Safari keeps canvas until its height and width will be set to 0).
* @function
*/
_freeupCanvasMemory: function () {
for (var i = 0; i < this.levels.length; i++) {
this.levels[i].context2D.canvas.height = 0;
this.levels[i].context2D.canvas.width = 0;
}
},
});
}
let currentWidth = image.naturalWidth,
currentHeight = image.naturalHeight;
// We build smaller levels until either width or height becomes
// 2 pixel wide.
while (currentWidth >= 2 && currentHeight >= 2) {
currentWidth = Math.floor(currentWidth / 2);
currentHeight = Math.floor(currentHeight / 2);
levels.push({
width: currentWidth,
height: currentHeight,
});
}
return levels.reverse();
}
_createContext2D(data, w, h) {
const canvas = document.createElement("canvas"),
context = canvas.getContext("2d");
canvas.width = w;
canvas.height = h;
context.drawImage(data, 0, 0, w, h);
return context;
}
};
}(OpenSeadragon));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - LegacyTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -122,10 +122,11 @@ $.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenS
* @function
* @param {Object|XMLDocument} configuration - the raw configuration
* @param {String} dataUrl - the url the data was retrieved from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @param {String} postData - HTTP POST data in k=v&k2=v2... form or null
* @returns {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function( configuration, dataUrl ){
configure: function( configuration, dataUrl, postData ){
var options;
@ -186,6 +187,21 @@ $.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenS
url = this.levels[ level ].url;
}
return url;
},
/**
* Equality comparator
*/
equals: function (otherSource) {
if (!otherSource.levels || otherSource.levels.length !== this.levels.length) {
return false;
}
for (let i = this.minLevel; i <= this.maxLevel; i++) {
if (this.levels[i].url !== otherSource.levels[i].url) {
return false;
}
}
return true;
}
} );

209
src/matrix3.js Normal file
View file

@ -0,0 +1,209 @@
/*
* OpenSeadragon - Mat3
*
* Copyright (C) 2010-2024 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.
*
*/
/*
* Portions of this source file are taken from WegGL Fundamentals:
*
* Copyright 2012, Gregg Tavares.
* 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 Gregg Tavares. nor the names of his
* 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( $ ){
// Modified from https://webglfundamentals.org/webgl/lessons/webgl-2d-matrices.html
/**
*
*
* @class Mat3
* @classdesc A left-to-right matrix representation, useful for affine transforms for
* positioning tiles for drawing
*
* @memberof OpenSeadragon
*
* @param {Array} [values] - Initial values for the matrix
*
**/
class Mat3{
constructor(values){
if(!values) {
values = [
0, 0, 0,
0, 0, 0,
0, 0, 0
];
}
this.values = values;
}
/**
* @function makeIdentity
* @memberof OpenSeadragon.Mat3
* @static
* @returns {OpenSeadragon.Mat3} an identity matrix
*/
static makeIdentity(){
return new Mat3([
1, 0, 0,
0, 1, 0,
0, 0, 1
]);
}
/**
* @function makeTranslation
* @memberof OpenSeadragon.Mat3
* @static
* @param {Number} tx The x value of the translation
* @param {Number} ty The y value of the translation
* @returns {OpenSeadragon.Mat3} A translation matrix
*/
static makeTranslation(tx, ty) {
return new Mat3([
1, 0, 0,
0, 1, 0,
tx, ty, 1,
]);
}
/**
* @function makeRotation
* @memberof OpenSeadragon.Mat3
* @static
* @param {Number} angleInRadians The desired rotation angle, in radians
* @returns {OpenSeadragon.Mat3} A rotation matrix
*/
static makeRotation(angleInRadians) {
var c = Math.cos(angleInRadians);
var s = Math.sin(angleInRadians);
return new Mat3([
c, -s, 0,
s, c, 0,
0, 0, 1,
]);
}
/**
* @function makeScaling
* @memberof OpenSeadragon.Mat3
* @static
* @param {Number} sx The x value of the scaling
* @param {Number} sy The y value of the scaling
* @returns {OpenSeadragon.Mat3} A scaling matrix
*/
static makeScaling(sx, sy) {
return new Mat3([
sx, 0, 0,
0, sy, 0,
0, 0, 1,
]);
}
/**
* @alias multiply
* @memberof! OpenSeadragon.Mat3
* @param {OpenSeadragon.Mat3} other the matrix to multiply with
* @returns {OpenSeadragon.Mat3} The result of matrix multiplication
*/
multiply(other) {
let a = this.values;
let b = other.values;
var a00 = a[0 * 3 + 0];
var a01 = a[0 * 3 + 1];
var a02 = a[0 * 3 + 2];
var a10 = a[1 * 3 + 0];
var a11 = a[1 * 3 + 1];
var a12 = a[1 * 3 + 2];
var a20 = a[2 * 3 + 0];
var a21 = a[2 * 3 + 1];
var a22 = a[2 * 3 + 2];
var b00 = b[0 * 3 + 0];
var b01 = b[0 * 3 + 1];
var b02 = b[0 * 3 + 2];
var b10 = b[1 * 3 + 0];
var b11 = b[1 * 3 + 1];
var b12 = b[1 * 3 + 2];
var b20 = b[2 * 3 + 0];
var b21 = b[2 * 3 + 1];
var b22 = b[2 * 3 + 2];
return new Mat3([
b00 * a00 + b01 * a10 + b02 * a20,
b00 * a01 + b01 * a11 + b02 * a21,
b00 * a02 + b01 * a12 + b02 * a22,
b10 * a00 + b11 * a10 + b12 * a20,
b10 * a01 + b11 * a11 + b12 * a21,
b10 * a02 + b11 * a12 + b12 * a22,
b20 * a00 + b21 * a10 + b22 * a20,
b20 * a01 + b21 * a11 + b22 * a21,
b20 * a02 + b21 * a12 + b22 * a22,
]);
}
}
$.Mat3 = Mat3;
}( OpenSeadragon ));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - MouseTracker
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -57,16 +57,16 @@
* @param {Boolean} [options.startDisabled=false]
* If true, event tracking on the element will not start until
* {@link OpenSeadragon.MouseTracker.setTracking|setTracking} is called.
* @param {Number} options.clickTimeThreshold
* @param {Number} [options.clickTimeThreshold=300]
* The number of milliseconds within which a pointer down-up event combination
* will be treated as a click gesture.
* @param {Number} options.clickDistThreshold
* @param {Number} [options.clickDistThreshold=5]
* The maximum distance allowed between a pointer down event and a pointer up event
* to be treated as a click gesture.
* @param {Number} options.dblClickTimeThreshold
* @param {Number} [options.dblClickTimeThreshold=300]
* The number of milliseconds within which two pointer down-up event combinations
* will be treated as a double-click gesture.
* @param {Number} options.dblClickDistThreshold
* @param {Number} [options.dblClickDistThreshold=20]
* The maximum distance allowed between two pointer click events
* to be treated as a click gesture.
* @param {Number} [options.stopDelay=50]
@ -135,7 +135,7 @@
};
}
this.hash = Math.random(); // An unique hash for this tracker.
this.hash = uniqueHash(); // An unique hash for this tracker.
/**
* The element for which pointer events are being monitored.
* @member {Element} element
@ -165,8 +165,8 @@
this.dblClickTimeThreshold = options.dblClickTimeThreshold || $.DEFAULT_SETTINGS.dblClickTimeThreshold;
/**
* The maximum distance allowed between two pointer click events
* to be treated as a click gesture.
* @member {Number} clickDistThreshold
* to be treated as a double-click gesture.
* @member {Number} dblClickDistThreshold
* @memberof OpenSeadragon.MouseTracker#
*/
this.dblClickDistThreshold = options.dblClickDistThreshold || $.DEFAULT_SETTINGS.dblClickDistThreshold;
@ -277,13 +277,6 @@
sentDragEvent: false
};
this.hasGestureHandlers = !!( this.pressHandler || this.nonPrimaryPressHandler ||
this.releaseHandler || this.nonPrimaryReleaseHandler ||
this.clickHandler || this.dblClickHandler ||
this.dragHandler || this.dragEndHandler ||
this.pinchHandler );
this.hasScrollHandler = !!this.scrollHandler;
if ( $.MouseTracker.havePointerEvents ) {
$.setElementPointerEvents( this.element, 'auto' );
}
@ -357,7 +350,7 @@
getActivePointersListByType: function ( type ) {
var delegate = THIS[ this.hash ],
i,
len = delegate.activePointersLists.length,
len = delegate ? delegate.activePointersLists.length : 0,
list;
for ( i = 0; i < len; i++ ) {
@ -367,7 +360,9 @@
}
list = new $.MouseTracker.GesturePointList( type );
delegate.activePointersLists.push( list );
if(delegate){
delegate.activePointersLists.push( list );
}
return list;
},
@ -389,6 +384,30 @@
return count;
},
/**
* Do we currently have any assigned gesture handlers.
* @returns {Boolean} Do we currently have any assigned gesture handlers.
*/
get hasGestureHandlers() {
return !!(this.pressHandler ||
this.nonPrimaryPressHandler ||
this.releaseHandler ||
this.nonPrimaryReleaseHandler ||
this.clickHandler ||
this.dblClickHandler ||
this.dragHandler ||
this.dragEndHandler ||
this.pinchHandler);
},
/**
* Do we currently have a scroll handler.
* @returns {Boolean} Do we currently have a scroll handler.
*/
get hasScrollHandler() {
return !!this.scrollHandler;
},
/**
* Implement or assign implementation to these handlers during or after
* calling the constructor.
@ -1114,10 +1133,9 @@
/**
* Detect available mouse wheel event name.
*/
$.MouseTracker.wheelEventName = ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version > 8 ) ||
( 'onwheel' in document.createElement( 'div' ) ) ? 'wheel' : // Modern browsers support 'wheel'
document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least 'mousewheel'
'DOMMouseScroll'; // Assume old Firefox
$.MouseTracker.wheelEventName = ( 'onwheel' in document.createElement( 'div' ) ) ? 'wheel' : // Modern browsers support 'wheel'
document.onmousewheel !== undefined ? 'mousewheel' : // Webkit (and unsupported IE) support at least 'mousewheel'
'DOMMouseScroll'; // Assume old Firefox (deprecated)
/**
* Detect browser pointer device event model(s) and build appropriate list of events to subscribe to.
@ -1130,7 +1148,7 @@
}
if ( window.PointerEvent ) {
// IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents)
// W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents)
$.MouseTracker.havePointerEvents = true;
$.MouseTracker.subscribeEvents.push( "pointerenter", "pointerleave", "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" );
// Pointer events capture support
@ -1403,7 +1421,6 @@
--this.contacts;
if (this.contacts < 0) {
$.console.warn('GesturePointList.removeContact() Implausible contacts value');
this.contacts = 0;
}
}
@ -1670,7 +1687,6 @@
/**
* Gets a W3C Pointer Events model compatible pointer type string from a DOM pointer event.
* IE10 used a long integer value, but the W3C specification (and IE11+) use a string "mouse", "touch", "pen", etc.
*
* Note: Called for both pointer events and legacy mouse events
* ($.MouseTracker.havePointerEvents determines which)
@ -1678,14 +1694,7 @@
* @inner
*/
function getPointerType( event ) {
if ( $.MouseTracker.havePointerEvents ) {
// Note: IE pointer events bug - sends invalid pointerType on lostpointercapture events
// and possibly other events. We rely on sane, valid property values in DOM events, so for
// IE, when the pointerType is missing, we'll default to 'mouse'...should be right most of the time
return event.pointerType || (( $.Browser.vendor === $.BROWSERS.IE ) ? 'mouse' : '');
} else {
return 'mouse';
}
return $.MouseTracker.havePointerEvents && event.pointerType ? event.pointerType : 'mouse';
}
@ -2071,7 +2080,7 @@
// y-index scrolling.
// event.deltaMode: 0=pixel, 1=line, 2=page
// TODO: Deltas in pixel mode should be accumulated then a scroll value computed after $.DEFAULT_SETTINGS.pixelsPerWheelLine threshold reached
nDelta = event.deltaY < 0 ? 1 : -1;
nDelta = event.deltaY ? (event.deltaY < 0 ? 1 : -1) : 0;
eventInfo = {
originalEvent: event,
@ -2553,15 +2562,14 @@
};
// Most browsers implicitly capture touch pointer events
// Note no IE versions have element.hasPointerCapture() so no implicit
// pointer capture possible
// Note no IE versions (unsupported) have element.hasPointerCapture() so
// no implicit pointer capture possible
// var implicitlyCaptured = ($.MouseTracker.havePointerEvents &&
// event.target.hasPointerCapture &&
// $.Browser.vendor !== $.BROWSERS.IE) ?
// event.target.hasPointerCapture(event.pointerId) : false;
var implicitlyCaptured = $.MouseTracker.havePointerEvents &&
gPoint.type === 'touch' &&
$.Browser.vendor !== $.BROWSERS.IE;
gPoint.type === 'touch';
//$.console.log('pointerdown ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
@ -2823,10 +2831,7 @@
// If child element relinquishes capture to a parent we may get here
// from a pointerleave event while a pointerup event will never be received.
// In that case, we'll clean up the contact count
if ( (pointsList.type === 'mouse' || pointsList.type === 'pen') &&
pointsList.contacts > 0 ) {
pointsList.removeContact();
}
pointsList.removeContact();
listLength = pointsList.removeById( gPoint.id );
} else {
@ -3290,13 +3295,12 @@
gPoint = updateGPoint;
} else {
// Initialize for tracking and add to the tracking list (no pointerenter event occurred before this)
$.console.warn('pointerdown event on untracked pointer');
// NOTE: pointerdown event on untracked pointer
gPoint.captured = false; // Handled by updatePointerCaptured()
gPoint.insideElementPressed = true;
gPoint.insideElement = true;
gPoint.originalTarget = eventInfo.originalEvent.target;
startTrackingPointer( pointsList, gPoint );
return;
}
pointsList.addContact();
@ -3440,8 +3444,8 @@
releasePoint = updateGPoint.currentPos;
releaseTime = updateGPoint.currentTime;
} else {
// should never get here...we'll start to track pointer anyway
$.console.warn('updatePointerUp(): pointerup on untracked gPoint');
// NOTE: updatePointerUp(): pointerup on untracked gPoint
// ...we'll start to track pointer again
gPoint.captured = false; // Handled by updatePointerCaptured()
gPoint.insideElementPressed = false;
gPoint.insideElement = true;
@ -3464,7 +3468,7 @@
if ( pointsList.contacts === 0 ) {
// Release (pressed in our element)
if ( tracker.releaseHandler ) {
if ( tracker.releaseHandler && releasePoint ) {
tracker.releaseHandler(
{
eventSource: tracker,
@ -3566,7 +3570,7 @@
eventInfo.shouldReleaseCapture = false;
// Release (pressed in another element)
if ( tracker.releaseHandler ) {
if ( tracker.releaseHandler && releasePoint ) {
tracker.releaseHandler(
{
eventSource: tracker,
@ -3777,4 +3781,19 @@
}
}
/**
* @function
* @private
* @inner
*/
function uniqueHash( ) {
let uniqueId = Date.now().toString(36) + Math.random().toString(36).substring(2);
while (uniqueId in THIS) {
// rehash when not unique
uniqueId = Date.now().toString(36) + Math.random().toString(36).substring(2);
}
return uniqueId;
}
}(OpenSeadragon));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Navigator
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -45,7 +45,9 @@
* @memberof OpenSeadragon
* @extends OpenSeadragon.Viewer
* @extends OpenSeadragon.EventSource
* @param {Object} options
* @param {Object} options - Navigator options
* @param {Element} [options.element] - An element to use for the navigator.
* @param {String} [options.id] - Id of the element to use for the navigator. However, this is ignored if {@link options.element} is provided.
*/
$.Navigator = function( options ){
@ -55,8 +57,31 @@ $.Navigator = function( options ){
navigatorSize;
//We may need to create a new element and id if they did not
//provide the id for the existing element
if( !options.id ){
//provide the id for the existing element or the element itself
if( options.element || options.id ){
if ( options.element ) {
if ( options.id ){
$.console.warn("Given option.id for Navigator was ignored since option.element was provided and is being used instead.");
}
// Don't overwrite the element's id if it has one already
if ( options.element.id ) {
options.id = options.element.id;
} else {
options.id = 'navigator-' + $.now();
}
this.element = options.element;
} else {
this.element = document.getElementById( options.id );
}
options.controlOptions = {
anchor: $.ControlAnchor.NONE,
attachToViewer: false,
autoFade: false
};
} else {
options.id = 'navigator-' + $.now();
this.element = $.makeNeutralElement( "div" );
options.controlOptions = {
@ -82,14 +107,6 @@ $.Navigator = function( options ){
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';
@ -107,8 +124,9 @@ $.Navigator = function( options ){
showSequenceControl: false,
immediateRender: true,
blendTime: 0,
animationTime: 0,
autoResize: options.autoResize,
animationTime: options.animationTime,
// disable autoResize since resize behavior is implemented differently by the navigator
autoResize: false,
// prevent resizing the navigator from adding unwanted space around the image
minZoomImageRatio: 1.0,
background: options.background,
@ -152,9 +170,6 @@ $.Navigator = function( options ){
style.border = borderWidth + 'px solid ' + options.displayRegionColor;
style.margin = '0px';
style.padding = '0px';
//TODO: IE doesn't 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.
@ -163,9 +178,9 @@ $.Navigator = function( options ){
style['float'] = 'left'; //Webkit
style.cssFloat = 'left'; //Firefox
style.styleFloat = 'left'; //IE
style.zIndex = 999999999;
style.cursor = 'default';
style.boxSizing = 'content-box';
}( this.displayRegion.style, this.borderWidth ));
$.setElementPointerEventsNone( this.displayRegion );
$.setElementTouchActionNone( this.displayRegion );
@ -205,19 +220,19 @@ $.Navigator = function( options ){
this.displayRegionContainer.appendChild(this.displayRegion);
this.element.getElementsByTagName('div')[0].appendChild(this.displayRegionContainer);
function rotate(degrees) {
function rotate(degrees, immediately) {
_setTransformRotate(_this.displayRegionContainer, degrees);
_setTransformRotate(_this.displayRegion, -degrees);
_this.viewport.setRotation(degrees);
_this.viewport.setRotation(degrees, immediately);
}
if (options.navigatorRotate) {
var degrees = options.viewer.viewport ?
options.viewer.viewport.getRotation() :
options.viewer.degrees || 0;
rotate(degrees);
rotate(degrees, true);
options.viewer.addHandler("rotate", function (args) {
rotate(args.degrees);
rotate(args.degrees, args.immediately);
});
}
@ -291,8 +306,9 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
this.viewport.resize( containerSize, true );
this.viewport.goHome(true);
this.oldContainerSize = containerSize;
this.drawer.clear();
this.world.update();
this.world.draw();
this.update(this.viewer.viewport);
}
}
},
@ -305,6 +321,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
this.width = width;
this.element.style.width = typeof (width) === "number" ? (width + 'px') : width;
this._resizeWithViewer = false;
this.updateSize();
},
/**
@ -315,6 +332,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
this.height = height;
this.element.style.height = typeof (height) === "number" ? (height + 'px') : height;
this._resizeWithViewer = false;
this.updateSize();
},
/**
@ -329,7 +347,6 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
},
setDisplayTransform: function(rule) {
setElementTransform(this.displayRegion, rule);
setElementTransform(this.canvas, rule);
setElementTransform(this.element, rule);
},
@ -337,7 +354,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
/**
* 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.
* @param {OpenSeadragon.Viewport} [viewport] The viewport to display. Default: the viewport this navigator is tracking.
*/
update: function( viewport ) {
@ -348,6 +365,10 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
topleft,
bottomright;
if(!viewport){
viewport = this.viewer.viewport;
}
viewerSize = $.getElementSize( this.viewer.element );
if ( this._resizeWithViewer && viewerSize.x && viewerSize.y && !viewerSize.equals( this.oldViewerSize ) ) {
this.oldViewerSize = viewerSize;
@ -376,15 +397,20 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
bottomright = this.viewport.pixelFromPointNoRotate(bounds.getBottomRight(), false)
.minus( this.totalBorderWidths );
if (!this.navigatorRotate) {
var degrees = viewport.getRotation(true);
_setTransformRotate(this.displayRegion, -degrees);
}
//update style for navigator-box
var style = this.displayRegion.style;
style.display = this.world.getItemCount() ? 'block' : 'none';
style.top = Math.round( topleft.y ) + 'px';
style.left = Math.round( topleft.x ) + 'px';
style.top = topleft.y.toFixed(2) + "px";
style.left = topleft.x.toFixed(2) + "px";
var width = Math.abs( topleft.x - bottomright.x );
var height = Math.abs( topleft.y - bottomright.y );
var width = bottomright.x - topleft.x;
var height = bottomright.y - topleft.y;
// make sure width and height are non-negative so IE doesn't throw
style.width = Math.round( Math.max( width, 0 ) ) + 'px';
style.height = Math.round( Math.max( height, 0 ) ) + 'px';

View file

@ -2,7 +2,7 @@
* OpenSeadragon
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -163,6 +163,10 @@
* The colors of grids in debug mode. Each tiled image's grid uses a consecutive color.
* If there are more tiled images than provided colors, the color vector is recycled.
*
* @property {Boolean} [silenceMultiImageWarnings=false]
* Silences warnings when calling viewport coordinate functions with multi-image.
* Useful when you're overlaying multiple images on top of one another.
*
* @property {Number} [blendTime=0]
* Specifies the duration of animation as higher or lower level tiles are
* replacing the existing tile.
@ -186,6 +190,16 @@
* Zoom level to use when image is first opened or the home button is clicked.
* If 0, adjusts to fit viewer.
*
* @property {String|DrawerImplementation|Array} [drawer = ['webgl', 'canvas', 'html']]
* Which drawer to use. Valid strings are 'webgl', 'canvas', and 'html'. Valid drawer
* implementations are constructors of classes that extend OpenSeadragon.DrawerBase.
* An array of strings and/or constructors can be used to indicate the priority
* of different implementations, which will be tried in order based on browser support.
*
* @property {Object} drawerOptions
* Options to pass to the selected drawer implementation. For details
* please see {@link OpenSeadragon.DrawerOptions}.
*
* @property {Number} [opacity=1]
* Default proportional opacity of the tiled images (1=opaque, 0=hidden)
* Hidden images do not draw and only load when preloading is allowed.
@ -200,21 +214,37 @@
* For complete list of modes, please @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation/ globalCompositeOperation}
*
* @property {Boolean} [imageSmoothingEnabled=true]
* Image smoothing for canvas rendering (only if canvas is used). Note: Ignored
* Image smoothing for rendering (only if the canvas or webgl drawer is used). Note: Ignored
* by some (especially older) browsers which do not support this canvas property.
* This property can be changed in {@link Viewer.Drawer.setImageSmoothingEnabled}.
* This property can be changed in {@link Viewer.DrawerBase.setImageSmoothingEnabled}.
*
* @property {String|CanvasGradient|CanvasPattern|Function} [placeholderFillStyle=null]
* Draws a colored rectangle behind the tile if it is not loaded yet.
* You can pass a CSS color value like "#FF8800".
* When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern.
*
* @property {Object} [subPixelRoundingForTransparency=null]
* Determines when subpixel rounding should be applied for tiles when rendering images that support transparency.
* This property is a subpixel rounding enum values dictionary [{@link BROWSERS}] --> {@link SUBPIXEL_ROUNDING_OCCURRENCES}.
* The key is a {@link BROWSERS} value, and the value is one of {@link SUBPIXEL_ROUNDING_OCCURRENCES},
* indicating, for a given browser, when to apply subpixel rounding.
* Key '*' is the fallback value for any browser not specified in the dictionary.
* This property has a simple mode, and one can set it directly to
* {@link SUBPIXEL_ROUNDING_OCCURRENCES.NEVER}, {@link SUBPIXEL_ROUNDING_OCCURRENCES.ONLY_AT_REST} or {@link SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS}
* in order to apply this rule for all browser. The values {@link SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS} would be equivalent to { '*', SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS }.
* The default is {@link SUBPIXEL_ROUNDING_OCCURRENCES.NEVER} for all browsers, for backward compatibility reason.
*
* @property {Number} [degrees=0]
* Initial rotation.
*
* @property {Boolean} [flipped=false]
* Initial flip state.
*
* @property {Boolean} [overlayPreserveContentDirection=true]
* When the viewport is flipped (by pressing 'f'), the overlay is flipped using ScaleX.
* Normally, this setting (default true) keeps the overlay's content readable by flipping it back.
* To make the content flip with the overlay, set overlayPreserveContentDirection to false.
*
* @property {Number} [minZoomLevel=null]
*
* @property {Number} [maxZoomLevel=null]
@ -275,6 +305,12 @@
* @property {Number} [rotationIncrement=90]
* The number of degrees to rotate right or left when the rotate buttons or keyboard shortcuts are activated.
*
* @property {Number} [maxTilesPerFrame=1]
* The number of tiles loaded per frame. As the frame rate of the client's machine is usually high (e.g., 50 fps),
* one tile per frame should be a good choice. However, for large screens or lower frame rates, the number of
* loaded tiles per frame can be adjusted here. Reasonable values might be 2 or 3 tiles per frame.
* (Note that the actual frame rate is given by the client's browser and machine).
*
* @property {Number} [pixelsPerWheelLine=40]
* For pixel-resolution scrolling devices, the number of pixels equal to one scroll line.
*
@ -317,8 +353,11 @@
*
* @property {Number} [animationTime=1.2]
* Specifies the animation duration per each {@link OpenSeadragon.Spring}
* which occur when the image is dragged or zoomed.
* which occur when the image is dragged, zoomed or rotated.
*
* @property {Boolean} [loadDestinationTilesOnAnimation=true]
* If true, tiles are loaded only at the destination of an animation.
* If false, tiles are loaded along the animation path during the animation.
* @property {OpenSeadragon.GestureSettings} [gestureSettingsMouse]
* Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings})
* @property {Boolean} [gestureSettingsMouse.dragToPan=true] - Pan on drag gesture
@ -326,6 +365,9 @@
* @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture
* @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true
* then clickToZoom should be set to false to prevent multiple zooms.
* @property {Boolean} [gestureSettingsMouse.dblClickDragToZoom=false] - Zoom on dragging through
* double-click gesture ( single click and next click to drag). Note: If set to true
* then clickToZoom should be set to false to prevent multiple zooms.
* @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture
* @property {Boolean} [gestureSettingsMouse.zoomToRefPoint=true] - If zoomToRefPoint is true, the zoom is centered at the pointer position. Otherwise,
* the zoom is centered at the canvas center.
@ -336,11 +378,15 @@
*
* @property {OpenSeadragon.GestureSettings} [gestureSettingsTouch]
* Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings})
* @property {Boolean} [gestureSettingsMouse.dragToPan=true] - Pan on drag gesture
* @property {Boolean} [gestureSettingsTouch.dragToPan=true] - Pan on drag gesture
* @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture
* @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true
* then clickToZoom should be set to false to prevent multiple zooms.
* @property {Boolean} [gestureSettingsTouch.dblClickDragToZoom=true] - Zoom on dragging through
* double-click gesture ( single click and next click to drag). Note: If set to true
* then clickToZoom should be set to false to prevent multiple zooms.
* @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture
* @property {Boolean} [gestureSettingsTouch.zoomToRefPoint=true] - If zoomToRefPoint is true, the zoom is centered at the pointer position. Otherwise,
* the zoom is centered at the canvas center.
@ -351,7 +397,7 @@
*
* @property {OpenSeadragon.GestureSettings} [gestureSettingsPen]
* Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings})
* @property {Boolean} [gestureSettingsMouse.dragToPan=true] - Pan on drag gesture
* @property {Boolean} [gestureSettingsPen.dragToPan=true] - Pan on drag gesture
* @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture
* @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true
@ -366,11 +412,14 @@
*
* @property {OpenSeadragon.GestureSettings} [gestureSettingsUnknown]
* Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings})
* @property {Boolean} [gestureSettingsMouse.dragToPan=true] - Pan on drag gesture
* @property {Boolean} [gestureSettingsUnknown.dragToPan=true] - Pan on drag gesture
* @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture
* @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true
* then clickToZoom should be set to false to prevent multiple zooms.
* @property {Boolean} [gestureSettingsUnknown.dblClickDragToZoom=false] - Zoom on dragging through
* double-click gesture ( single click and next click to drag). Note: If set to true
* then clickToZoom should be set to false to prevent multiple zooms.
* @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture
* @property {Boolean} [gestureSettingsUnknown.zoomToRefPoint=true] - If zoomToRefPoint is true, the zoom is centered at the pointer position. Otherwise,
* the zoom is centered at the canvas center.
@ -385,6 +434,9 @@
* @property {Number} [zoomPerScroll=1.2]
* The "zoom distance" per mouse scroll or touch pinch. <em><strong>Note:</strong> Setting this to 1.0 effectively disables the mouse-wheel zoom feature (also see gestureSettings[Mouse|Touch|Pen].scrollToZoom}).</em>
*
* @property {Number} [zoomPerDblClickDrag=1.2]
* The "zoom distance" per double-click mouse drag. <em><strong>Note:</strong> Setting this to 1.0 effectively disables the double-click-drag-to-Zoom feature (also see gestureSettings[Mouse|Touch|Pen].dblClickDragToZoom).</em>
*
* @property {Number} [zoomPerSecond=1.0]
* Sets the zoom amount per second when zoomIn/zoomOut buttons are pressed and held.
* The value is a factor of the current zoom, so 1.0 (the default) disables zooming when the zoomIn/zoomOut buttons
@ -395,6 +447,11 @@
* @property {Boolean} [showNavigator=false]
* Set to true to make the navigator minimap appear.
*
* @property {Element} [navigatorElement=null]
* The element to hold the navigator minimap.
* If an element is specified, the Id option (see navigatorId) is ignored.
* If no element nor ID is specified, a div element will be generated accordingly.
*
* @property {String} [navigatorId=navigator-GENERATED DATE]
* The ID of a div to hold the navigator minimap.
* If an ID is specified, the navigatorPosition, navigatorSizeRatio, navigatorMaintainSizeRatio, navigator[Top|Left|Height|Width] and navigatorAutoFade options will be ignored.
@ -462,8 +519,14 @@
* @property {Number} [timeout=30000]
* The max number of milliseconds that an image job may take to complete.
*
* @property {Number} [tileRetryMax=0]
* The max number of retries when a tile download fails. By default it's 0, so retries are disabled.
*
* @property {Number} [tileRetryDelay=2500]
* Milliseconds to wait after each tile retry if tileRetryMax is set.
*
* @property {Boolean} [useCanvas=true]
* Set to false to not use an HTML canvas element for image rendering even if canvas is supported.
* Deprecated. Use the `drawer` option to specify preferred renderer.
*
* @property {Number} [minPixelRatio=0.5]
* The higher the minPixelRatio, the lower the quality of the image that
@ -526,50 +589,50 @@
* viewing the first image and the 'next' button will wrap to the first
* image when viewing the last image.
*
* @property {String} zoomInButton
* Set the id of the custom 'Zoom in' button to use.
*@property {String|Element} zoomInButton
* Set the id or element of the custom 'Zoom in' button to use.
* This is useful to have a custom button anywhere in the web page.<br>
* To only change the button images, consider using
* {@link OpenSeadragon.Options.navImages}
*
* @property {String} zoomOutButton
* Set the id of the custom 'Zoom out' button to use.
* @property {String|Element} zoomOutButton
* Set the id or element of the custom 'Zoom out' button to use.
* This is useful to have a custom button anywhere in the web page.<br>
* To only change the button images, consider using
* {@link OpenSeadragon.Options.navImages}
*
* @property {String} homeButton
* Set the id of the custom 'Go home' button to use.
* @property {String|Element} homeButton
* Set the id or element of the custom 'Go home' button to use.
* This is useful to have a custom button anywhere in the web page.<br>
* To only change the button images, consider using
* {@link OpenSeadragon.Options.navImages}
*
* @property {String} fullPageButton
* Set the id of the custom 'Toggle full page' button to use.
* @property {String|Element} fullPageButton
* Set the id or element of the custom 'Toggle full page' button to use.
* This is useful to have a custom button anywhere in the web page.<br>
* To only change the button images, consider using
* {@link OpenSeadragon.Options.navImages}
*
* @property {String} rotateLeftButton
* Set the id of the custom 'Rotate left' button to use.
* @property {String|Element} rotateLeftButton
* Set the id or element of the custom 'Rotate left' button to use.
* This is useful to have a custom button anywhere in the web page.<br>
* To only change the button images, consider using
* {@link OpenSeadragon.Options.navImages}
*
* @property {String} rotateRightButton
* Set the id of the custom 'Rotate right' button to use.
* @property {String|Element} rotateRightButton
* Set the id or element of the custom 'Rotate right' button to use.
* This is useful to have a custom button anywhere in the web page.<br>
* To only change the button images, consider using
* {@link OpenSeadragon.Options.navImages}
*
* @property {String} previousButton
* Set the id of the custom 'Previous page' button to use.
* @property {String|Element} previousButton
* Set the id or element of the custom 'Previous page' button to use.
* This is useful to have a custom button anywhere in the web page.<br>
* To only change the button images, consider using
* {@link OpenSeadragon.Options.navImages}
*
* @property {String} nextButton
* Set the id of the custom 'Next page' button to use.
* @property {String|Element} nextButton
* Set the id or element of the custom 'Next page' button to use.
* This is useful to have a custom button anywhere in the web page.<br>
* To only change the button images, consider using
* {@link OpenSeadragon.Options.navImages}
@ -648,6 +711,26 @@
* @property {Object} [ajaxHeaders={}]
* A set of headers to include when making AJAX requests for tile sources or tiles.
*
* @property {Boolean} [splitHashDataForPost=false]
* Allows to treat _first_ hash ('#') symbol as a separator for POST data:
* URL to be opened by a {@link OpenSeadragon.TileSource} can thus look like: http://some.url#postdata=here.
* The whole URL is used to fetch image info metadata and it is then split to 'http://some.url' and
* 'postdata=here'; post data is given to the {@link OpenSeadragon.TileSource} of the choice and can be further
* used within tile requests (see TileSource methods).
* NOTE: {@link OpenSeadragon.TileSource.prototype.configure} return value should contain the post data
* if you want to use it later - so that it is given to your constructor later.
* NOTE: usually, post data is expected to be ampersand-separated (just like GET parameters), and is NOT USED
* to fetch tile image data unless explicitly programmed, or if loadTilesWithAjax=false 4
* (but it is still used for the initial image info request).
* NOTE: passing POST data from URL by this feature only supports string values, however,
* TileSource can send any data using POST as long as the header is correct
* (@see OpenSeadragon.TileSource.prototype.getTilePostData)
*
* @property {Boolean} [callTileLoadedWithCachedData=false]
* tile-loaded event is called only for tiles that downloaded new data or
* their data is stored in the original form in a suplementary cache object.
* Caches that render directly from re-used cache does not trigger this event again,
* as possible modifications would be applied twice.
*/
/**
@ -685,6 +768,20 @@
*
*/
/**
* @typedef {Object.<string, Object>} DrawerOptions - give the renderer options (both shared - BaseDrawerOptions, and custom).
* Supports arbitrary keys: you can register any drawer on the OpenSeadragon namespace, it will get automatically recognized
* and its getType() implementation will define what key to specify the options with.
* @memberof OpenSeadragon
* @property {BaseDrawerOptions} [webgl] - options if the WebGLDrawer is used.
* @property {BaseDrawerOptions} [canvas] - options if the CanvasDrawer is used.
* @property {BaseDrawerOptions} [html] - options if the HTMLDrawer is used.
* @property {BaseDrawerOptions} [custom] - options if a custom drawer is used.
*
* //Note: if you want to add change options for target drawer change type to {BaseDrawerOptions & MyDrawerOpts}
*/
/**
* The names for the image resources used for the image navigation buttons.
*
@ -779,14 +876,20 @@ function OpenSeadragon( options ){
* @private
*/
var class2type = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regexp',
'[object Object]': 'object'
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object AsyncFunction]': 'function',
'[object Promise]': 'promise',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regexp',
'[object Object]': 'object',
'[object HTMLUnknownElement]': 'dom-node',
'[object HTMLImageElement]': 'image',
'[object HTMLCanvasElement]': 'canvas',
'[object CanvasRenderingContext2D]': 'context2d'
},
// Save a reference to some core methods
toString = Object.prototype.toString,
@ -802,7 +905,6 @@ function OpenSeadragon( options ){
return $.type(obj) === "function";
};
/**
* Taken from jQuery 1.6.1
* @function isArray
@ -888,7 +990,7 @@ function OpenSeadragon( options ){
/**
* Shim around Object.freeze. Does nothing if Object.freeze is not supported.
* @param {Object} obj The object to freeze.
* @return {Object} obj The frozen object.
* @returns {Object} obj The frozen object.
*/
$.freezeObject = function(obj) {
if (Object.freeze) {
@ -981,11 +1083,20 @@ function OpenSeadragon( options ){
return supported >= 3;
}());
/**
* If true, OpenSeadragon uses async execution, else it uses synchronous execution.
* Note that disabling async means no plugins that use Promises / async will work with OSD.
* @member {boolean}
* @memberof OpenSeadragon
*/
$.supportsAsync = true;
/**
* A ratio comparing the device screen's pixel density to the canvas's backing store pixel density,
* clamped to a minimum of 1. Defaults to 1 if canvas isn't supported by the browser.
* @member {Number} pixelDensityRatio
* @function getCurrentPixelDensityRatio
* @memberof OpenSeadragon
* @returns {Number}
*/
$.getCurrentPixelDensityRatio = function() {
if ( $.supportsCanvas ) {
@ -1003,6 +1114,8 @@ function OpenSeadragon( options ){
};
/**
* A ratio comparing the device screen's pixel density to the canvas's backing store pixel density,
* clamped to a minimum of 1. Defaults to 1 if canvas isn't supported by the browser.
* @member {Number} pixelDensityRatio
* @memberof OpenSeadragon
*/
@ -1067,8 +1180,19 @@ function OpenSeadragon( options ){
if ( options !== null || options !== undefined ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
var descriptor = Object.getOwnPropertyDescriptor(options, name);
if (descriptor !== undefined) {
if (descriptor.get || descriptor.set) {
Object.defineProperty(target, name, descriptor);
continue;
}
copy = descriptor.value;
} else {
$.console.warn('Could not copy inherited property "' + name + '".');
continue;
}
// Prevent never-ending loop
if ( target === copy ) {
@ -1077,6 +1201,8 @@ function OpenSeadragon( options ){
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( OpenSeadragon.isPlainObject( copy ) || ( copyIsArray = OpenSeadragon.isArray( copy ) ) ) ) {
src = target[ name ];
if ( copyIsArray ) {
copyIsArray = false;
clone = src && OpenSeadragon.isArray( src ) ? src : [];
@ -1129,6 +1255,8 @@ function OpenSeadragon( options ){
ajaxWithCredentials: false,
loadTilesWithAjax: false,
ajaxHeaders: {},
splitHashDataForPost: false,
callTileLoadedWithCachedData: false,
//PAN AND ZOOM SETTINGS AND CONSTRAINTS
panHorizontal: true,
@ -1150,11 +1278,13 @@ function OpenSeadragon( options ){
dblClickDistThreshold: 20,
springStiffness: 6.5,
animationTime: 1.2,
loadDestinationTilesOnAnimation: true,
gestureSettingsMouse: {
dragToPan: true,
scrollToZoom: true,
clickToZoom: true,
dblClickToZoom: false,
dblClickDragToZoom: false,
pinchToZoom: false,
zoomToRefPoint: true,
flickEnabled: false,
@ -1167,6 +1297,7 @@ function OpenSeadragon( options ){
scrollToZoom: false,
clickToZoom: false,
dblClickToZoom: true,
dblClickDragToZoom: true,
pinchToZoom: true,
zoomToRefPoint: true,
flickEnabled: true,
@ -1179,6 +1310,7 @@ function OpenSeadragon( options ){
scrollToZoom: false,
clickToZoom: true,
dblClickToZoom: false,
dblClickDragToZoom: false,
pinchToZoom: false,
zoomToRefPoint: true,
flickEnabled: false,
@ -1191,6 +1323,7 @@ function OpenSeadragon( options ){
scrollToZoom: false,
clickToZoom: false,
dblClickToZoom: true,
dblClickDragToZoom: false,
pinchToZoom: true,
zoomToRefPoint: true,
flickEnabled: true,
@ -1200,6 +1333,7 @@ function OpenSeadragon( options ){
},
zoomPerClick: 2,
zoomPerScroll: 1.2,
zoomPerDblClickDrag: 1.2,
zoomPerSecond: 1.0,
blendTime: 0,
alwaysBlend: false,
@ -1215,6 +1349,7 @@ function OpenSeadragon( options ){
preserveImageSizeOnResize: false, // requires autoResize=true
minScrollDeltaTime: 50,
rotationIncrement: 90,
maxTilesPerFrame: 1,
//DEFAULT CONTROL SETTINGS
showSequenceControl: true, //SEQUENCE
@ -1235,6 +1370,7 @@ function OpenSeadragon( options ){
//VIEWPORT NAVIGATOR SETTINGS
showNavigator: false,
navigatorElement: null,
navigatorId: null,
navigatorPosition: null,
navigatorSizeRatio: 0.2,
@ -1255,14 +1391,36 @@ function OpenSeadragon( options ){
degrees: 0,
// INITIAL FLIP STATE
flipped: false,
flipped: false,
overlayPreserveContentDirection: true,
// APPEARANCE
opacity: 1,
preload: false,
compositeOperation: null,
imageSmoothingEnabled: true,
placeholderFillStyle: null,
opacity: 1, // to be passed into each TiledImage
compositeOperation: null, // to be passed into each TiledImage
// DRAWER SETTINGS
drawer: ['webgl', 'canvas', 'html'], // prefer using webgl, then canvas (i.e. context2d), then fallback to html
drawerOptions: {
webgl: {
},
canvas: {
},
html: {
},
custom: {
}
},
// TILED IMAGE SETTINGS
preload: false, // to be passed into each TiledImage
imageSmoothingEnabled: true, // to be passed into each TiledImage
placeholderFillStyle: null, // to be passed into each TiledImage
subPixelRoundingForTransparency: null, // to be passed into each TiledImage
//REFERENCE STRIP SETTINGS
showReferenceStrip: false,
@ -1285,7 +1443,8 @@ function OpenSeadragon( options ){
imageLoaderLimit: 0,
maxImageCacheCount: 200,
timeout: 30000,
useCanvas: true, // Use canvas element for drawing if available
tileRetryMax: 0,
tileRetryDelay: 2500,
//INTERFACE RESOURCE SETTINGS
prefixUrl: "/images/",
@ -1348,19 +1507,11 @@ function OpenSeadragon( options ){
//DEVELOPER SETTINGS
debugMode: false,
debugGridColor: ['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666']
debugGridColor: ['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666'],
silenceMultiImageWarnings: false
},
/**
* TODO: get rid of this. I can't see how it's required at all. Looks
* like an early legacy code artifact.
* @static
* @ignore
*/
SIGNAL: "----seadragon----",
/**
* Returns a function which invokes the method as if it were a method belonging to the object.
* @function
@ -1403,6 +1554,20 @@ function OpenSeadragon( options ){
CHROMEEDGE: 7
},
/**
* An enumeration of when subpixel rounding should occur.
* @static
* @type {Object}
* @property {Number} NEVER Never apply subpixel rounding for transparency.
* @property {Number} ONLY_AT_REST Do not apply subpixel rounding for transparency during animation (panning, zoom, rotation) and apply it once animation is over.
* @property {Number} ALWAYS Apply subpixel rounding for transparency during animation and when animation is over.
*/
SUBPIXEL_ROUNDING_OCCURRENCES: {
NEVER: 0,
ONLY_AT_REST: 1,
ALWAYS: 2
},
/**
* Keep track of which {@link Viewer}s have been created.
* - Key: {@link Element} to which a Viewer is attached.
@ -1587,8 +1752,8 @@ function OpenSeadragon( options ){
/**
* Compute the modulo of a number but makes sure to always return
* a positive value.
* @param {Number} number the number to computes the modulo of
* a positive value (also known as Euclidean modulo).
* @param {Number} number the number to compute the modulo of
* @param {Number} modulo the modulo
* @returns {Number} the result of the modulo of number
*/
@ -1600,6 +1765,7 @@ function OpenSeadragon( options ){
return result;
},
/**
* Determines if a point is within the bounding rectangle of the given element (hit-test).
* @function
@ -1939,7 +2105,7 @@ function OpenSeadragon( options ){
*/
setElementPointerEvents: function( element, value ) {
element = $.getElement( element );
if ( typeof element.style.pointerEvents !== 'undefined' ) {
if (typeof element.style !== 'undefined' && typeof element.style.pointerEvents !== 'undefined' ) {
element.style.pointerEvents = value;
}
},
@ -2048,7 +2214,7 @@ function OpenSeadragon( options ){
* @param {Boolean} [options.capture]
* @param {Boolean} [options.passive]
* @param {Boolean} [options.once]
* @return {String} The protocol (http:, https:, file:, ftp: ...)
* @returns {String} The protocol (http:, https:, file:, ftp: ...)
*/
normalizeEventListenerOptions: function (options) {
var opts;
@ -2158,42 +2324,6 @@ function OpenSeadragon( options ){
},
/**
* Similar to OpenSeadragon.delegate, but it does not immediately call
* the method on the object, returning a function which can be called
* repeatedly to delegate the method. It also allows additional arguments
* to be passed during construction which will be added during each
* invocation, and each invocation can add additional arguments as well.
*
* @function
* @param {Object} object
* @param {Function} method
* @param [args] any additional arguments are passed as arguments to the
* created callback
* @returns {Function}
*/
createCallback: function( object, method ) {
//TODO: This pattern is painful to use and debug. It's much cleaner
// to use pinning plus anonymous functions. Get rid of this
// pattern!
var initialArgs = [],
i;
for ( i = 2; i < arguments.length; i++ ) {
initialArgs.push( arguments[ i ] );
}
return function() {
var args = initialArgs.concat( [] ),
i;
for ( i = 0; i < arguments.length; i++ ) {
args.push( arguments[ i ] );
}
return method.apply( object, args );
};
},
/**
* Retrieves the value of a url parameter from the window.location string.
* @function
@ -2212,7 +2342,7 @@ function OpenSeadragon( options ){
* @function
* @private
* @param {String} url The url to retrieve the protocol from.
* @return {String} The protocol (http:, https:, file:, ftp: ...)
* @returns {String} The protocol (http:, https:, file:, ftp: ...)
*/
getUrlProtocol: function( url ) {
var match = url.match(/^([a-z]+:)\/\//i);
@ -2226,53 +2356,38 @@ function OpenSeadragon( options ){
/**
* Create an XHR object
* @private
* @param {type} [local] If set to true, the XHR will be file: protocol
* compatible if possible (but may raise a warning in the browser).
* @param {type} [local] Deprecated. Ignored (IE/ActiveXObject file protocol no longer supported).
* @returns {XMLHttpRequest}
*/
createAjaxRequest: function( local ) {
// IE11 does not support window.ActiveXObject so we just try to
// create one to see if it is supported.
// See: http://msdn.microsoft.com/en-us/library/ie/dn423948%28v=vs.85%29.aspx
var supportActiveX;
try {
/* global ActiveXObject:true */
supportActiveX = !!new ActiveXObject( "Microsoft.XMLHTTP" );
} catch( e ) {
supportActiveX = false;
}
if ( supportActiveX ) {
if ( window.XMLHttpRequest ) {
$.createAjaxRequest = function( local ) {
if ( local ) {
return new ActiveXObject( "Microsoft.XMLHTTP" );
}
return new XMLHttpRequest();
};
} else {
$.createAjaxRequest = function() {
return new ActiveXObject( "Microsoft.XMLHTTP" );
};
}
} else if ( window.XMLHttpRequest ) {
createAjaxRequest: function() {
if ( window.XMLHttpRequest ) {
$.createAjaxRequest = function() {
return new XMLHttpRequest();
};
return new XMLHttpRequest();
} else {
throw new Error( "Browser doesn't support XMLHttpRequest." );
}
return $.createAjaxRequest( local );
},
/**
* Makes an AJAX request.
* @param {String} url - the url to request
* @param {Function} onSuccess
* @param {Function} onError
* @throws {Error}
* @returns {XMLHttpRequest}
* @deprecated deprecated way of calling this function
*//**
* Makes an AJAX request.
* @param {Object} options
* @param {String} options.url - the url to request
* @param {Function} options.success - a function to call on a successful response
* @param {Function} options.error - a function to call on when an error occurs
* @param {Object} options.headers - headers to add to the AJAX request
* @param {String} options.responseType - the response type of the the AJAX request
* @param {String} options.responseType - the response type of the AJAX request
* @param {String} options.postData - HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getTilePostData), GET method used if null
* @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials
* @throws {Error}
* @returns {XMLHttpRequest}
@ -2281,6 +2396,7 @@ function OpenSeadragon( options ){
var withCredentials;
var headers;
var responseType;
var postData;
// Note that our preferred API is that you pass in a single object; the named
// arguments are for legacy support.
@ -2290,11 +2406,14 @@ function OpenSeadragon( options ){
withCredentials = url.withCredentials;
headers = url.headers;
responseType = url.responseType || null;
postData = url.postData || null;
url = url.url;
} else {
$.console.warn("OpenSeadragon.makeAjaxRequest() deprecated usage!");
}
var protocol = $.getUrlProtocol( url );
var request = $.createAjaxRequest( protocol === "file:" );
var request = $.createAjaxRequest();
if ( !$.isFunction( onSuccess ) ) {
throw new Error( "makeAjaxRequest requires a success callback" );
@ -2313,17 +2432,18 @@ function OpenSeadragon( options ){
protocol !== "https:" )) {
onSuccess( request );
} else {
$.console.log( "AJAX request returned %d: %s", request.status, url );
if ( $.isFunction( onError ) ) {
onError( request );
} else {
$.console.error( "AJAX request returned %d: %s", request.status, url );
}
}
}
};
var method = postData ? "POST" : "GET";
try {
request.open( "GET", url, true );
request.open( method, url, true );
if (responseType) {
request.responseType = responseType;
@ -2341,9 +2461,9 @@ function OpenSeadragon( options ){
request.withCredentials = true;
}
request.send(null);
request.send(postData);
} catch (e) {
$.console.log( "%s while making AJAX request: %s", e.name, e.message );
$.console.error( "%s while making AJAX request: %s", e.name, e.message );
request.onreadystatechange = function(){};
@ -2462,17 +2582,6 @@ function OpenSeadragon( options ){
return xmlDoc;
};
} else if ( window.ActiveXObject ) {
$.parseXml = function( string ) {
var xmlDoc = null;
xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
xmlDoc.async = false;
xmlDoc.loadXML( string );
return xmlDoc;
};
} else {
throw new Error( "Browser doesn't support XML DOM." );
}
@ -2509,26 +2618,31 @@ function OpenSeadragon( options ){
* Preexisting formats that are not being updated are left unchanged.
* By default, the defined formats are
* <pre><code>{
* avif: true,
* bmp: false,
* jpeg: true,
* jpg: true,
* png: true,
* tif: false,
* wdp: false
* wdp: false,
* webp: true
* }
* </code></pre>
* @function
* @example
* // sets webp as supported and png as unsupported
* setImageFormatsSupported({webp: true, png: false});
* // sets bmp as supported and png as unsupported
* setImageFormatsSupported({bmp: true, png: false});
* @param {Object} formats An object containing format extensions as
* keys and booleans as values.
*/
setImageFormatsSupported: function(formats) {
//TODO: how to deal with this within the data pipeline?
// $.console.warn("setImageFormatsSupported method is deprecated. You should check that" +
// " the system supports your TileSources by implementing corresponding data type convertors.");
// eslint-disable-next-line no-use-before-define
$.extend(FILEFORMATS, formats);
}
},
});
@ -2575,12 +2689,14 @@ function OpenSeadragon( options ){
var FILEFORMATS = {
avif: true,
bmp: false,
jpeg: true,
jpg: true,
png: true,
tif: false,
wdp: false
wdp: false,
webp: true
},
URLPARAMS = {};
@ -2595,6 +2711,10 @@ function OpenSeadragon( options ){
//console.error( 'appVersion: ' + navigator.appVersion );
//console.error( 'userAgent: ' + navigator.userAgent );
//TODO navigator.appName is deprecated. Should be 'Netscape' for all browsers
// but could be dropped at any time
// See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/appName
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
switch( navigator.appName ){
case "Microsoft Internet Explorer":
if( !!window.attachEvent &&
@ -2680,8 +2800,8 @@ function OpenSeadragon( options ){
//determine if this browser supports element.style.opacity
$.Browser.opacity = true;
if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 11 ) {
$.console.error('Internet Explorer versions < 11 are not supported by OpenSeadragon');
if ( $.Browser.vendor === $.BROWSERS.IE ) {
$.console.error('Internet Explorer is not supported by OpenSeadragon');
}
})();
@ -2788,21 +2908,143 @@ function OpenSeadragon( options ){
}
}
/**
* @template T
* @typedef {function(): OpenSeadragon.Promise<T>} AsyncNullaryFunction
* Represents an asynchronous function that takes no arguments and returns a promise of type T.
*/
/**
* @template T, A
* @typedef {function(A): OpenSeadragon.Promise<T>} AsyncUnaryFunction
* Represents an asynchronous function that:
* @param {A} arg - The single argument of type A.
* @returns {OpenSeadragon.Promise<T>} A promise that resolves to a value of type T.
*/
/**
* @template T, A, B
* @typedef {function(A, B): OpenSeadragon.Promise<T>} AsyncBinaryFunction
* Represents an asynchronous function that:
* @param {A} arg1 - The first argument of type A.
* @param {B} arg2 - The second argument of type B.
* @returns {OpenSeadragon.Promise<T>} A promise that resolves to a value of type T.
*/
/**
* Promise proxy in OpenSeadragon, enables $.supportsAsync feature.
* This proxy is also necessary because OperaMini does not implement Promises (checks fail).
* @type {PromiseConstructor}
*/
$.Promise = window["Promise"] && $.supportsAsync ? window["Promise"] : class {
constructor(handler) {
this._error = false;
this.__value = undefined;
try {
// Make sure to unwrap all nested promises!
handler(
(value) => {
while (value instanceof $.Promise) {
value = value._value;
}
this._value = value;
},
(error) => {
while (error instanceof $.Promise) {
error = error._value;
}
this._value = error;
this._error = true;
}
);
} catch (e) {
this._value = e;
this._error = true;
}
}
then(handler) {
if (!this._error) {
try {
this._value = handler(this._value);
} catch (e) {
this._value = e;
this._error = true;
}
}
return this;
}
catch(handler) {
if (this._error) {
try {
this._value = handler(this._value);
this._error = false;
} catch (e) {
this._value = e;
this._error = true;
}
}
return this;
}
get _value() {
return this.__value;
}
set _value(val) {
if (val && val.constructor === this.constructor) {
val = val._value; //unwrap
}
this.__value = val;
}
static resolve(value) {
return new this((resolve) => resolve(value));
}
static reject(error) {
return new this((_, reject) => reject(error));
}
static all(functions) {
return new this((resolve) => {
// no async support, just execute them
return resolve(functions.map(fn => fn()));
});
}
static race(functions) {
if (functions.length < 1) {
return this.resolve();
}
// no async support, just execute the first
return new this((resolve) => {
return resolve(functions[0]());
});
}
};
}(OpenSeadragon));
// Universal Module Definition, supports CommonJS, AMD and simple script tag
(function (root, factory) {
(function (root, $) {
if (typeof define === 'function' && define.amd) {
// expose as amd module
define([], factory);
define([], function () {
return $;
});
} else if (typeof module === 'object' && module.exports) {
// expose as commonjs module
module.exports = factory();
module.exports = $;
} else {
if (!root) {
root = typeof window === 'object' && window;
if (!root) {
$.console.error("OpenSeadragon must run in browser environment!");
}
}
// expose as window.OpenSeadragon
root.OpenSeadragon = factory();
root.OpenSeadragon = $;
}
}(this, function () {
return OpenSeadragon;
}));
}(this, OpenSeadragon));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - OsmTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -122,10 +122,11 @@ $.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
* @function
* @param {Object} data - the raw configuration
* @param {String} url - the url the data was retrieved from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @param {String} postData - HTTP POST data in k=v&k2=v2... form or null
* @returns {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function( data, url ){
configure: function( data, url, postData ){
return data;
},
@ -138,6 +139,13 @@ $.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
*/
getTileUrl: function( level, x, y ) {
return this.tilesUrl + (level - 8) + "/" + x + "/" + y + ".png";
},
/**
* Equality comparator
*/
equals: function(otherSource) {
return this.tilesUrl === otherSource.tilesUrl;
}
});

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Overlay
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -128,8 +128,18 @@
};
}
this.elementWrapper = document.createElement('div');
this.element = options.element;
this.style = options.element.style;
this.elementWrapper.appendChild(this.element);
if (this.element.id) {
this.elementWrapper.id = "overlay-wrapper-" + this.element.id; // Unique ID if element has one
}
// Always add a class for styling & selection
this.elementWrapper.classList.add("openseadragon-overlay-wrapper");
this.style = this.elementWrapper.style;
this._init(options);
};
@ -196,7 +206,7 @@
* @function
*/
destroy: function() {
var element = this.element;
var element = this.elementWrapper;
var style = this.style;
if (element.parentNode) {
@ -241,7 +251,7 @@
* @param {Element} container
*/
drawHTML: function(container, viewport) {
var element = this.element;
var element = this.elementWrapper;
if (element.parentNode !== container) {
//save the source parent for later if we need it
element.prevElementParent = element.parentNode;
@ -252,43 +262,57 @@
this.style.position = "absolute";
// this.size is used by overlays which don't get scaled in at
// least one direction when this.checkResize is set to false.
this.size = $.getElementSize(element);
this.size = $.getElementSize(this.elementWrapper);
}
var positionAndSize = this._getOverlayPositionAndSize(viewport);
var position = positionAndSize.position;
var size = this.size = positionAndSize.size;
var rotate = positionAndSize.rotate;
var outerScale = "";
if (viewport.overlayPreserveContentDirection) {
outerScale = viewport.flipped ? " scaleX(-1)" : " scaleX(1)";
}
var rotate = viewport.flipped ? -positionAndSize.rotate : positionAndSize.rotate;
var scale = viewport.flipped ? " scaleX(-1)" : "";
// 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, this.element);
} else {
var style = this.style;
var innerStyle = this.element.style;
innerStyle.display = "block";
style.left = position.x + "px";
style.top = position.y + "px";
if (this.width !== null) {
style.width = size.x + "px";
innerStyle.width = size.x + "px";
}
if (this.height !== null) {
style.height = size.y + "px";
innerStyle.height = size.y + "px";
}
var transformOriginProp = $.getCssPropertyWithVendorPrefix(
'transformOrigin');
var transformProp = $.getCssPropertyWithVendorPrefix(
'transform');
if (transformOriginProp && transformProp) {
if (rotate) {
if (rotate && !viewport.flipped) {
innerStyle[transformProp] = "";
style[transformOriginProp] = this._getTransformOrigin();
style[transformProp] = "rotate(" + rotate + "deg)";
} else if (!rotate && viewport.flipped) {
innerStyle[transformProp] = outerScale;
style[transformOriginProp] = this._getTransformOrigin();
style[transformProp] = scale;
} else if (rotate && viewport.flipped){
innerStyle[transformProp] = outerScale;
style[transformOriginProp] = this._getTransformOrigin();
style[transformProp] = "rotate(" + rotate + "deg)" + scale;
} else {
innerStyle[transformProp] = "";
style[transformOriginProp] = "";
style[transformProp] = "";
}
}
style.display = 'block';
style.display = 'flex';
}
},
@ -299,21 +323,24 @@
this.adjust(position, size);
var rotate = 0;
if (viewport.degrees &&
if (viewport.getRotation(true) &&
this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) {
// BOUNDING_BOX is only valid if both directions get scaled.
// Get replaced by EXACT otherwise.
if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX &&
this.width !== null && this.height !== null) {
var rect = new $.Rect(position.x, position.y, size.x, size.y);
var boundingBox = this._getBoundingBox(rect, viewport.degrees);
var boundingBox = this._getBoundingBox(rect, viewport.getRotation(true));
position = boundingBox.getTopLeft();
size = boundingBox.getSize();
} else {
rotate = viewport.degrees;
rotate = viewport.getRotation(true);
}
}
if (viewport.flipped) {
position.x = (viewport.getContainerSize().x - position.x);
}
return {
position: position,
size: size,
@ -337,7 +364,7 @@
}
if (this.checkResize &&
(this.width === null || this.height === null)) {
var eltSize = this.size = $.getElementSize(this.element);
var eltSize = this.size = $.getElementSize(this.elementWrapper);
if (this.width === null) {
width = eltSize.x;
}
@ -447,7 +474,7 @@
// private
_adjustBoundsForRotation: function(viewport, bounds) {
if (!viewport ||
viewport.degrees === 0 ||
viewport.getRotation(true) === 0 ||
this.rotationMode === $.OverlayRotationMode.EXACT) {
return bounds;
}
@ -467,7 +494,7 @@
}
// NO_ROTATION case
return bounds.rotate(-viewport.degrees,
return bounds.rotate(-viewport.getRotation(true),
this._getPlacementPoint(bounds));
}
};

View file

@ -1,7 +1,7 @@
/*
* OpenSeadragon - Placement
*
* Copyright (C) 2010-2016 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Point
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are

362
src/priorityqueue.js Normal file
View file

@ -0,0 +1,362 @@
/*
* OpenSeadragon - Queue
*
* Copyright (C) 2024 OpenSeadragon contributors (modified)
* Copyright (C) Google Inc., The Closure Library Authors.
* https://github.com/google/closure-library
*
* SPDX-License-Identifier: Apache-2.0
*/
(function($) {
/**
* @class PriorityQueue
* @classdesc Fast priority queue. Implemented as a Heap.
*/
$.PriorityQueue = class {
/**
* @param {?OpenSeadragon.PriorityQueue} optHeap Optional Heap or
* Object to initialize heap with.
*/
constructor(optHeap = undefined) {
/**
* The nodes of the heap.
*
* This is a densely packed array containing all nodes of the heap, using
* the standard flat representation of a tree as an array (i.e. element [0]
* at the top, with [1] and [2] as the second row, [3] through [6] as the
* third, etc). Thus, the children of element `i` are `2i+1` and `2i+2`, and
* the parent of element `i` is `⌊(i-1)/2⌋`.
*
* The only invariant is that children's keys must be greater than parents'.
*
* @private
*/
this.nodes_ = [];
if (optHeap) {
this.insertAll(optHeap);
}
}
/**
* Insert the given value into the heap with the given key.
* @param {K} key The key.
* @param {V} value The value.
*/
insert(key, value) {
this.insertNode(new Node(key, value));
}
/**
* Insert node item.
* @param node
*/
insertNode(node) {
const nodes = this.nodes_;
node.index = nodes.length;
nodes.push(node);
this.moveUp_(node.index);
}
/**
* Adds multiple key-value pairs from another Heap or Object
* @param {?OpenSeadragon.PriorityQueue} heap Object containing the data to add.
*/
insertAll(heap) {
let keys, values;
if (heap instanceof $.PriorityQueue) {
keys = heap.getKeys();
values = heap.getValues();
// If it is a heap and the current heap is empty, I can rely on the fact
// that the keys/values are in the correct order to put in the underlying
// structure.
if (this.getCount() <= 0) {
const nodes = this.nodes_;
for (let i = 0; i < keys.length; i++) {
const node = new Node(keys[i], values[i]);
node.index = nodes.length;
nodes.push(node);
}
return;
}
} else {
throw "insertAll supports only OpenSeadragon.PriorityQueue object!";
}
for (let i = 0; i < keys.length; i++) {
this.insert(keys[i], values[i]);
}
}
/**
* Retrieves and removes the root value of this heap.
* @return {Node} The root node item removed from the root of the heap. Returns
* undefined if the heap is empty.
*/
remove() {
const nodes = this.nodes_;
const count = nodes.length;
const rootNode = nodes[0];
if (count <= 0) {
return undefined;
} else if (count == 1) { // eslint-disable-line
nodes.length = 0;
} else {
nodes[0] = nodes.pop();
if (nodes[0]) {
nodes[0].index = 0;
}
this.moveDown_(0);
}
if (rootNode) {
delete rootNode.index;
}
return rootNode;
}
/**
* Retrieves but does not remove the root value of this heap.
* @return {V} The value at the root of the heap. Returns
* undefined if the heap is empty.
*/
peek() {
const nodes = this.nodes_;
if (nodes.length == 0) { // eslint-disable-line
return undefined;
}
return nodes[0].value;
}
/**
* Retrieves but does not remove the key of the root node of this heap.
* @return {string} The key at the root of the heap. Returns undefined if the
* heap is empty.
*/
peekKey() {
return this.nodes_[0] && this.nodes_[0].key;
}
/**
* Move the node up in hierarchy
* @param {Node} node the node
* @param {K} key new ley, must be smaller than current key
*/
decreaseKey(node, key) {
if (node.index === undefined) {
node.key = key;
this.insertNode(node);
} else {
node.key = key;
this.moveUp_(node.index);
}
}
/**
* Moves the node at the given index down to its proper place in the heap.
* @param {number} index The index of the node to move down.
* @private
*/
moveDown_(index) {
const nodes = this.nodes_;
const count = nodes.length;
// Save the node being moved down.
const node = nodes[index];
// While the current node has a child.
while (index < (count >> 1)) {
const leftChildIndex = this.getLeftChildIndex_(index);
const rightChildIndex = this.getRightChildIndex_(index);
// Determine the index of the smaller child.
const smallerChildIndex = rightChildIndex < count &&
nodes[rightChildIndex].key < nodes[leftChildIndex].key ?
rightChildIndex :
leftChildIndex;
// If the node being moved down is smaller than its children, the node
// has found the correct index it should be at.
if (nodes[smallerChildIndex].key > node.key) {
break;
}
// If not, then take the smaller child as the current node.
nodes[index] = nodes[smallerChildIndex];
nodes[index].index = index;
index = smallerChildIndex;
}
nodes[index] = node;
if (node) {
node.index = index;
}
}
/**
* Moves the node at the given index up to its proper place in the heap.
* @param {number} index The index of the node to move up.
* @private
*/
moveUp_(index) {
const nodes = this.nodes_;
const node = nodes[index];
// While the node being moved up is not at the root.
while (index > 0) {
// If the parent is greater than the node being moved up, move the parent
// down.
const parentIndex = this.getParentIndex_(index);
if (nodes[parentIndex].key > node.key) {
nodes[index] = nodes[parentIndex];
nodes[index].index = index;
index = parentIndex;
} else {
break;
}
}
nodes[index] = node;
if (node) {
node.index = index;
}
}
/**
* Gets the index of the left child of the node at the given index.
* @param {number} index The index of the node to get the left child for.
* @return {number} The index of the left child.
* @private
*/
getLeftChildIndex_(index) {
return index * 2 + 1;
}
/**
* Gets the index of the right child of the node at the given index.
* @param {number} index The index of the node to get the right child for.
* @return {number} The index of the right child.
* @private
*/
getRightChildIndex_(index) {
return index * 2 + 2;
}
/**
* Gets the index of the parent of the node at the given index.
* @param {number} index The index of the node to get the parent for.
* @return {number} The index of the parent.
* @private
*/
getParentIndex_(index) {
return (index - 1) >> 1;
}
/**
* Gets the values of the heap.
* @return {!Array<*>} The values in the heap.
*/
getValues() {
const nodes = this.nodes_;
const rv = [];
const l = nodes.length;
for (let i = 0; i < l; i++) {
rv.push(nodes[i].value);
}
return rv;
}
/**
* Gets the keys of the heap.
* @return {!Array<string>} The keys in the heap.
*/
getKeys() {
const nodes = this.nodes_;
const rv = [];
const l = nodes.length;
for (let i = 0; i < l; i++) {
rv.push(nodes[i].key);
}
return rv;
}
/**
* Whether the heap contains the given value.
* @param {V} val The value to check for.
* @return {boolean} Whether the heap contains the value.
*/
containsValue(val) {
return this.nodes_.some((node) => node.value == val); // eslint-disable-line
}
/**
* Whether the heap contains the given key.
* @param {string} key The key to check for.
* @return {boolean} Whether the heap contains the key.
*/
containsKey(key) {
return this.nodes_.some((node) => node.value == key); // eslint-disable-line
}
/**
* Clones a heap and returns a new heap
* @return {!OpenSeadragon.PriorityQueue} A new Heap with the same key-value pairs.
*/
clone() {
return new $.PriorityQueue(this);
}
/**
* The number of key-value pairs in the map
* @return {number} The number of pairs.
*/
getCount() {
return this.nodes_.length;
}
/**
* Returns true if this heap contains no elements.
* @return {boolean} Whether this heap contains no elements.
*/
isEmpty() {
return this.nodes_.length === 0;
}
/**
* Removes all elements from the heap.
*/
clear() {
this.nodes_.length = 0;
}
};
$.PriorityQueue.Node = class {
constructor(key, value) {
/**
* The key.
* @type {K}
* @private
*/
this.key = key;
/**
* The value.
* @type {V}
* @private
*/
this.value = value;
/**
* The node index value. Updated in the heap.
* @type {number}
* @private
*/
this.index = 0;
}
clone() {
return new Node(this.key, this.value);
}
};
}(OpenSeadragon));

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Profiler
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Rect
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -230,7 +230,7 @@ $.Rect.prototype = {
* Returns the width and height component as a vector OpenSeadragon.Point
* @function
* @returns {OpenSeadragon.Point} The 2 dimensional vector representing the
* the width and height of the rectangle.
* width and height of the rectangle.
*/
getSize: function() {
return new $.Point(this.width, this.height);
@ -240,7 +240,7 @@ $.Rect.prototype = {
* 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'.
* @returns {Boolean} 'true' if all components are equal, otherwise 'false'.
*/
equals: function(other) {
return (other instanceof $.Rect) &&
@ -287,7 +287,7 @@ $.Rect.prototype = {
* Returns the smallest rectangle that will contain this and the given
* rectangle bounding boxes.
* @param {OpenSeadragon.Rect} rect
* @return {OpenSeadragon.Rect} The new rectangle.
* @returns {OpenSeadragon.Rect} The new rectangle.
*/
union: function(rect) {
var thisBoundingBox = this.getBoundingBox();
@ -313,7 +313,7 @@ $.Rect.prototype = {
* Returns the bounding box of the intersection of this rectangle with the
* given rectangle.
* @param {OpenSeadragon.Rect} rect
* @return {OpenSeadragon.Rect} the bounding box of the intersection
* @returns {OpenSeadragon.Rect} the bounding box of the intersection
* or null if the rectangles don't intersect.
*/
intersection: function(rect) {
@ -441,7 +441,7 @@ $.Rect.prototype = {
* @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}
* @returns {OpenSeadragon.Rect}
*/
rotate: function(degrees, pivot) {
degrees = $.positiveModulo(degrees, 360);

View file

@ -2,7 +2,7 @@
* OpenSeadragon - ReferenceStrip
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -46,7 +46,7 @@ var THIS = {};
*
* This idea is a reexpression of the idea of dzi collections
* which allows a clearer algorithm to reuse the tile sources already
* supported by OpenSeadragon, in heterogenious or homogenious
* supported by OpenSeadragon, in heterogeneous or homogeneous
* sequences just like mixed groups already supported by the viewer
* for the purpose of image sequnces.
*
@ -193,7 +193,6 @@ $.ReferenceStrip = function ( options ) {
element.style.display = 'inline';
element.style['float'] = 'left'; //Webkit
element.style.cssFloat = 'left'; //Firefox
element.style.styleFloat = 'left'; //IE
element.style.padding = '2px';
$.setElementTouchActionNone( element );
$.setElementPointerEventsNone( element );
@ -267,7 +266,7 @@ $.ReferenceStrip.prototype = {
*/
update: function () {
if ( THIS[this.id].animating ) {
$.console.log( 'image reference strip update' );
// $.console.log( 'image reference strip update' );
return true;
}
return false;
@ -300,7 +299,8 @@ function onStripClick( event ) {
var page;
if ( 'horizontal' === this.scroll ) {
page = Math.floor(event.position.x / this.panelWidth);
// +4px fix to solve problem with precision on thumbnail selection if there is a lot of them
page = Math.floor(event.position.x / (this.panelWidth + 4));
} else {
page = Math.floor(event.position.y / this.panelHeight);
}
@ -454,7 +454,7 @@ function loadPanels( strip, viewerSize, scroll ) {
animationTime: 0,
loadTilesWithAjax: strip.viewer.loadTilesWithAjax,
ajaxHeaders: strip.viewer.ajaxHeaders,
useCanvas: strip.useCanvas
drawer: 'canvas', //always use canvas for the reference strip
} );
// Allow pointer events to pass through miniViewer's canvas/container
// elements so implicit pointer capture works on touch devices

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Spring
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -206,12 +206,13 @@ $.Spring.prototype = {
/**
* @function
* @returns true if the value got updated, false otherwise
* @returns true if the spring is still updating its value, false if it is
* already at the target value.
*/
update: function() {
this.current.time = $.now();
var startValue, targetValue;
let startValue, targetValue;
if (this._exponential) {
startValue = this.start._logValue;
targetValue = this.target._logValue;
@ -220,24 +221,25 @@ $.Spring.prototype = {
targetValue = this.target.value;
}
var currentValue = (this.current.time >= this.target.time) ?
targetValue :
startValue +
( targetValue - startValue ) *
transform(
this.springStiffness,
( this.current.time - this.start.time ) /
( this.target.time - this.start.time )
);
var oldValue = this.current.value;
if (this._exponential) {
this.current.value = Math.exp(currentValue);
if(this.current.time >= this.target.time){
this.current.value = this.target.value;
} else {
this.current.value = currentValue;
let currentValue = startValue +
( targetValue - startValue ) *
transform(
this.springStiffness,
( this.current.time - this.start.time ) /
( this.target.time - this.start.time )
);
if (this._exponential) {
this.current.value = Math.exp(currentValue);
} else {
this.current.value = currentValue;
}
}
return oldValue !== this.current.value;
return this.current.value !== this.target.value;
},
/**

View file

@ -2,7 +2,7 @@
* OpenSeadragon - getString/setString
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -83,7 +83,7 @@ $.extend( $, /** @lends OpenSeadragon */{
string = container[ props[ i ] ];
if ( typeof ( string ) !== "string" ) {
$.console.log( "Untranslated source string:", prop );
$.console.error( "Untranslated source string:", prop );
string = ""; // FIXME: this breaks gettext()-style convention, which would return source
}

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Tile
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -44,16 +44,19 @@
* coordinates.
* @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.
* @param {CanvasRenderingContext2D} context2D The context2D of this tile if it
* is provided directly by the tile source.
* @param {String|Function} url The URL of this tile's image or a function that returns a url.
* @param {CanvasRenderingContext2D} [context2D=undefined] The context2D of this tile if it
* * is provided directly by the tile source. Deprecated: use Tile::addCache(...) instead.
* @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request .
* @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable).
* @param {OpenSeadragon.Rect} sourceBounds The portion of the tile to use as the source of the
* drawing operation, in pixels. Note that this only works when drawing with canvas; when drawing
* with HTML the entire tile is always used.
* drawing operation, in pixels. Note that this only works when drawing with canvas; when drawing
* with HTML the entire tile is always used.
* @param {String} postData HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getTilePostData) or null
* @param {String} cacheKey key to act as a tile cache, must be unique for tiles with unique image data
*/
$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders, sourceBounds) {
$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders, sourceBounds, postData, cacheKey) {
/**
* The zoom level this tile belongs to.
* @member {Number} level
@ -79,11 +82,17 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
*/
this.bounds = bounds;
/**
* The portion of the tile to use as the source of the drawing operation, in pixels. Note that
* this only works when drawing with canvas; when drawing with HTML the entire tile is always used.
* @member {OpenSeadragon.Rect} sourceBounds
* @memberof OpenSeadragon.Tile#
*/
* Where this tile fits, in normalized coordinates, after positioning
* @member {OpenSeadragon.Rect} positionedBounds
* @memberof OpenSeadragon.Tile#
*/
this.positionedBounds = new OpenSeadragon.Rect(bounds.x, bounds.y, bounds.width, bounds.height);
/**
* The portion of the tile to use as the source of the drawing operation, in pixels. Note that
* this only works when drawing with canvas; when drawing with HTML the entire tile is always used.
* @member {OpenSeadragon.Rect} sourceBounds
* @memberof OpenSeadragon.Tile#
*/
this.sourceBounds = sourceBounds;
/**
* Is this tile a part of a sparse image? Also has this tile failed to load?
@ -92,17 +101,29 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
*/
this.exists = exists;
/**
* The URL of this tile's image.
* @member {String} url
* Private property to hold string url or url retriever function.
* Consumers should access via Tile.getUrl()
* @member {String|Function} url
* @memberof OpenSeadragon.Tile#
* @private
*/
this._url = url;
/**
* Post parameters for this tile. For example, it can be an URL-encoded string
* in k1=v1&k2=v2... format, or a JSON, or a FormData instance... or null if no POST request used
* @member {String} postData HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getTilePostData) or null
* @memberof OpenSeadragon.Tile#
*/
this.url = url;
this.postData = postData;
/**
* The context2D of this tile if it is provided directly by the tile source.
* @member {CanvasRenderingContext2D} context2D
* @memberOf OpenSeadragon.Tile#
*/
this.context2D = context2D;
if (context2D) {
this.context2D = context2D;
}
/**
* Whether to load this tile's image with an AJAX request.
* @member {Boolean} loadWithAjax
@ -116,16 +137,16 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
* @memberof OpenSeadragon.Tile#
*/
this.ajaxHeaders = ajaxHeaders;
/**
* The unique cache key for this tile.
* @member {String} cacheKey
* @memberof OpenSeadragon.Tile#
*/
if (this.ajaxHeaders) {
this.cacheKey = this.url + "+" + JSON.stringify(this.ajaxHeaders);
} else {
this.cacheKey = this.url;
if (cacheKey === undefined) {
$.console.warn("Tile constructor needs 'cacheKey' variable: creation tile cache" +
" in Tile class is deprecated. TileSource.prototype.getTileHashKey will be used.");
cacheKey = $.TileSource.prototype.getTileHashKey(level, x, y, url, ajaxHeaders, postData);
}
this._cKey = cacheKey || "";
this._ocKey = cacheKey || "";
/**
* Is this tile loaded?
* @member {Boolean} loaded
@ -138,32 +159,6 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
* @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
@ -197,9 +192,9 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
/**
* The squared distance of this tile to the viewport center.
* Use for comparing tiles.
* @private
* @member {Number} squaredDistance
* @memberof OpenSeadragon.Tile#
* @private
*/
this.squaredDistance = null;
/**
@ -209,6 +204,13 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
*/
this.visibility = null;
/**
* The transparency indicator of this tile.
* @member {Boolean} hasTransparency true if tile contains transparency for correct rendering
* @memberof OpenSeadragon.Tile#
*/
this.hasTransparency = false;
/**
* Whether this tile is currently being drawn.
* @member {Boolean} beingDrawn
@ -236,6 +238,32 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
* @memberof OpenSeadragon.Tile#
*/
this.isBottomMost = false;
/**
* Owner of this tile. Do not change this property manually.
* @member {OpenSeadragon.TiledImage}
* @memberof OpenSeadragon.Tile#
*/
this.tiledImage = null;
/**
* Array of cached tile data associated with the tile.
* @member {Object}
* @private
*/
this._caches = {};
/**
* Processing flag, exempt the tile from removal when there are ongoing updates
* @member {Boolean|Number}
* @private
*/
this.processing = false;
/**
* Processing promise, resolves when the tile exits processing, or
* resolves immediatelly if not in the processing state.
* @member {OpenSeadragon.Promise}
* @private
*/
this.processingPromise = $.Promise.resolve();
};
/** @lends OpenSeadragon.Tile.prototype */
@ -251,172 +279,439 @@ $.Tile.prototype = {
return this.level + "/" + this.x + "_" + this.y;
},
// private
_hasTransparencyChannel: function() {
return !!this.context2D || this.url.match('.png');
/**
* The unique main cache key for this tile. Created automatically
* from the given tiledImage.source.getTileHashKey(...) implementation.
* @member {String} cacheKey
* @memberof OpenSeadragon.Tile#
*/
get cacheKey() {
return this._cKey;
},
set cacheKey(value) {
if (value === this.cacheKey) {
return;
}
const cache = this.getCache(value);
if (!cache) {
// It's better to first set cache, then change the key to existing one. Warn if otherwise.
$.console.warn("[Tile.cacheKey] should not be set manually. Use addCache() with setAsMain=true.");
}
this._updateMainCacheKey(value);
},
/**
* Renders the tile in an html container.
* @function
* @param {Element} container
* By default equal to tile.cacheKey, marks a cache associated with this tile
* that holds the cache original data (it was loaded with). In case you
* change the tile data, the tile original data should be left with the cache
* 'originalCacheKey' and the new, modified data should be stored in cache 'cacheKey'.
* This key is used in cache resolution: in case new tile data is requested, if
* this cache key exists in the cache it is loaded.
* @member {String} originalCacheKey
* @memberof OpenSeadragon.Tile#
*/
drawHTML: function( container ) {
if (!this.cacheImageRecord) {
$.console.warn(
'[Tile.drawHTML] attempting to draw tile %s when it\'s not cached',
this.toString());
return;
}
if ( !this.loaded ) {
$.console.warn(
"Attempting to draw tile %s when it's not yet loaded.",
this.toString()
);
return;
}
//EXPERIMENTAL - trying to figure out how to scale the container
// content during animation of the container size.
if ( !this.element ) {
this.element = $.makeNeutralElement( "div" );
this.imgElement = this.cacheImageRecord.getImage().cloneNode();
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";
}
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";
if (this.flipped) {
this.style.transform = "scaleX(-1)";
}
$.setElementOpacity( this.element, this.opacity );
set originalCacheKey(value) {
throw "Original Cache Key cannot be managed manually!";
},
get originalCacheKey() {
return this._ocKey;
},
/**
* Renders the tile in a canvas-based context.
* @function
* @param {Canvas} context
* @param {Function} drawingHandler - Method for firing the drawing event.
* drawingHandler({context, tile, rendered})
* where <code>rendered</code> is the context with the pre-drawn image.
* @param {Number} [scale=1] - Apply a scale to position and size
* @param {OpenSeadragon.Point} [translate] - A translation vector
* The Image object for this tile.
* @member {Object} image
* @memberof OpenSeadragon.Tile#
* @deprecated
* @returns {Image}
*/
drawCanvas: function( context, drawingHandler, scale, translate ) {
get image() {
$.console.error("[Tile.image] property has been deprecated. Use [Tile.getData] instead.");
return this.getImage();
},
var position = this.position.times($.pixelDensityRatio),
size = this.size.times($.pixelDensityRatio),
rendered;
/**
* The URL of this tile's image.
* @member {String} url
* @memberof OpenSeadragon.Tile#
* @deprecated
* @returns {String}
*/
get url() {
$.console.error("[Tile.url] property has been deprecated. Use [Tile.getUrl] instead.");
return this.getUrl();
},
if (!this.context2D && !this.cacheImageRecord) {
$.console.warn(
'[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached',
this.toString());
return;
/**
* The HTML div element for this tile
* @member {Element} element
* @memberof OpenSeadragon.Tile#
* @deprecated
*/
get element() {
$.console.error("Tile::element property is deprecated. Use cache API instead. Moreover, this property might be unstable.");
const cache = this.getCache();
if (!cache || !cache.loaded) {
return null;
}
if (cache.type !== OpenSeadragon.HTMLDrawer.canvasCacheType || cache.type !== OpenSeadragon.HTMLDrawer.imageCacheType) {
$.console.error("Access to HtmlDrawer property via Tile instance: HTMLDrawer must be used!");
return null;
}
return cache.data.element;
},
/**
* The HTML img element for this tile.
* @member {Element} imgElement
* @memberof OpenSeadragon.Tile#
* @deprecated
*/
get imgElement() {
$.console.error("Tile::imgElement property is deprecated. Use cache API instead. Moreover, this property might be unstable.");
const cache = this.getCache();
if (!cache || !cache.loaded) {
return null;
}
if (cache.type !== OpenSeadragon.HTMLDrawer.canvasCacheType || cache.type !== OpenSeadragon.HTMLDrawer.imageCacheType) {
$.console.error("Access to HtmlDrawer property via Tile instance: HTMLDrawer must be used!");
return null;
}
return cache.data.imgElement;
},
/**
* The alias of this.element.style.
* @member {String} style
* @memberof OpenSeadragon.Tile#
* @deprecated
*/
get style() {
$.console.error("Tile::style property is deprecated. Use cache API instead. Moreover, this property might be unstable.");
const cache = this.getCache();
if (!cache || !cache.loaded) {
return null;
}
if (cache.type !== OpenSeadragon.HTMLDrawer.canvasCacheType || cache.type !== OpenSeadragon.HTMLDrawer.imageCacheType) {
$.console.error("Access to HtmlDrawer property via Tile instance: HTMLDrawer must be used!");
return null;
}
return cache.data.style;
},
/**
* Get the Image object for this tile.
* @returns {?Image}
*/
getImage: function() {
$.console.error("[Tile.getImage] property has been deprecated. Use 'tile-invalidated' routine event instead.");
//this method used to ensure the underlying data model conformed to given type - convert instead of getData()
const cache = this.getCache(this.cacheKey);
if (!cache) {
return undefined;
}
cache.transformTo("image");
return cache.data;
},
/**
* Get the url string for this tile.
* @returns {String}
*/
getUrl: function() {
if (typeof this._url === 'function') {
return this._url();
}
rendered = this.context2D || this.cacheImageRecord.getRenderedContext();
return this._url;
},
if ( !this.loaded || !rendered ){
$.console.warn(
"Attempting to draw tile %s when it's not yet loaded.",
this.toString()
);
/**
* Get the CanvasRenderingContext2D instance for tile image data drawn
* onto Canvas if enabled and available
* @returns {CanvasRenderingContext2D|undefined}
*/
getCanvasContext: function() {
$.console.error("[Tile.getCanvasContext] property has been deprecated. Use 'tile-invalidated' routine event instead.");
//this method used to ensure the underlying data model conformed to given type - convert instead of getData()
const cache = this.getCache(this.cacheKey);
if (!cache) {
return undefined;
}
cache.transformTo("context2d");
return cache.data;
},
return;
/**
* The context2D of this tile if it is provided directly by the tile source.
* @deprecated
* @type {CanvasRenderingContext2D}
*/
get context2D() {
$.console.error("[Tile.context2D] property has been deprecated. Use 'tile-invalidated' routine event instead.");
return this.getCanvasContext();
},
/**
* The context2D of this tile if it is provided directly by the tile source.
* @deprecated
*/
set context2D(value) {
$.console.error("[Tile.context2D] property has been deprecated. Use 'tile-invalidated' routine event instead.");
const cache = this._caches[this.cacheKey];
if (cache) {
this.removeCache(this.cacheKey);
}
this.addCache(this.cacheKey, value, 'context2d', true, false);
},
/**
* The default cache for this tile.
* @deprecated
* @type OpenSeadragon.CacheRecord
*/
get cacheImageRecord() {
$.console.error("[Tile.cacheImageRecord] property has been deprecated. Use Tile::getCache.");
return this.getCache(this.cacheKey);
},
/**
* The default cache for this tile.
* @deprecated
*/
set cacheImageRecord(value) {
$.console.error("[Tile.cacheImageRecord] property has been deprecated. Use Tile::addCache.");
const cache = this._caches[this.cacheKey];
if (cache) {
this.removeCache(this.cacheKey);
}
context.save();
if (value) {
if (value.loaded) {
this.addCache(this.cacheKey, value.data, value.type, true, false);
} else {
value.await().then(x => this.addCache(this.cacheKey, x, value.type, true, false));
}
}
},
context.globalAlpha = this.opacity;
/**
* Cache key for main cache that is 'cache-equal', but different from original cache key
* @return {string}
* @private
*/
buildDistinctMainCacheKey: function () {
return this.cacheKey === this.originalCacheKey ? "mod://" + this.originalCacheKey : this.cacheKey;
},
if (typeof scale === 'number' && scale !== 1) {
// draw tile at a different scale
position = position.times(scale);
size = size.times(scale);
/**
* Read tile cache data object (CacheRecord)
* @param {string} [key=this.cacheKey] cache key to read that belongs to this tile
* @return {OpenSeadragon.CacheRecord}
*/
getCache: function(key = this._cKey) {
const cache = this._caches[key];
if (cache) {
cache.withTileReference(this);
}
return cache;
},
/**
* Create tile cache for given data object.
*
* Using `setAsMain` updates also main tile cache key - the main cache key used to draw this tile.
* In that case, the cache should be ready to be rendered immediatelly (converted to one of the supported formats
* of the currently employed drawer).
*
* NOTE: if the existing cache already exists,
* data parameter is ignored and inherited from the existing cache object.
* WARNING: if you override main tile cache key to point to a different cache, the invalidation routine
* will no longer work. If you need to modify tile main data, prefer to use invalidation routine instead.
*
* @param {string} key cache key, if unique, new cache object is created, else existing cache attached
* @param {*} data this data will be IGNORED if cache already exists; therefore if
* `typeof data === 'function'` holds (both async and normal functions), the data is called to obtain
* the data item: this is an optimization to load data only when necessary.
* @param {string} [type=undefined] data type, will be guessed if not provided (not recommended),
* if data is a callback the type is a mandatory field, not setting it results in undefined behaviour
* @param {boolean} [setAsMain=false] if true, the key will be set as the tile.cacheKey,
* no effect if key === this.cacheKey
* @param [_safely=true] private
* @returns {OpenSeadragon.CacheRecord|null} - The cache record the tile was attached to.
*/
addCache: function(key, data, type = undefined, setAsMain = false, _safely = true) {
const tiledImage = this.tiledImage;
if (!tiledImage) {
return null; //async can access outside its lifetime
}
if (translate instanceof $.Point) {
// shift tile position slightly
position = position.plus(translate);
if (!type) {
if (!this.__typeWarningReported) {
$.console.warn(this, "[Tile.addCache] called without type specification. " +
"Automated deduction is potentially unsafe: prefer specification of data type explicitly.");
this.__typeWarningReported = true;
}
if (typeof data === 'function') {
$.console.error("[TileCache.cacheTile] options.data as a callback requires type argument! Current is " + type);
}
type = $.convertor.guessType(data);
}
//if we are supposed to be rendering fully opaque rectangle,
//ie its done fading or fading is turned off, and if we are drawing
//an image with an alpha channel, then the only way
//to avoid seeing the tile underneath is to clear the rectangle
if (context.globalAlpha === 1 && this._hasTransparencyChannel()) {
//clearing only the inside of the rectangle occupied
//by the png prevents edge flikering
context.clearRect(
position.x,
position.y,
size.x,
size.y
);
const overwritesMainCache = key === this.cacheKey;
if (_safely && (overwritesMainCache || setAsMain)) {
// Need to get the supported type for rendering out of the active drawer.
const supportedTypes = tiledImage.viewer.drawer.getSupportedDataFormats();
const conversion = $.convertor.getConversionPath(type, supportedTypes);
$.console.assert(conversion, "[Tile.addCache] data was set for the default tile cache we are unable" +
`to render. Make sure OpenSeadragon.convertor was taught to convert ${type} to (one of): ${conversion.toString()}`);
}
// This gives the application a chance to make image manipulation
// changes as we are rendering the image
drawingHandler({context: context, tile: this, rendered: rendered});
var sourceWidth, sourceHeight;
if (this.sourceBounds) {
sourceWidth = Math.min(this.sourceBounds.width, rendered.canvas.width);
sourceHeight = Math.min(this.sourceBounds.height, rendered.canvas.height);
} else {
sourceWidth = rendered.canvas.width;
sourceHeight = rendered.canvas.height;
const cachedItem = tiledImage._tileCache.cacheTile({
data: data,
dataType: type,
tile: this,
cacheKey: key,
cutoff: tiledImage.source.getClosestLevel(),
});
const havingRecord = this._caches[key];
if (havingRecord !== cachedItem) {
this._caches[key] = cachedItem;
if (havingRecord) {
havingRecord.removeTile(this);
tiledImage._tileCache.safeUnloadCache(havingRecord);
}
}
context.translate(position.x + size.x / 2, 0);
if (this.flipped) {
context.scale(-1, 1);
// Update cache key if differs and main requested
if (!overwritesMainCache && setAsMain) {
this._updateMainCacheKey(key);
}
context.drawImage(
rendered.canvas,
0,
0,
sourceWidth,
sourceHeight,
-size.x / 2,
position.y,
size.x,
size.y
);
return cachedItem;
},
context.restore();
/**
* Add cache object to the tile
*
* @param {string} key cache key, if unique, new cache object is created, else existing cache attached
* @param {OpenSeadragon.CacheRecord} cache the cache object to attach to this tile
* @param {boolean} [setAsMain=false] if true, the key will be set as the tile.cacheKey,
* no effect if key === this.cacheKey
* @param [_safely=true] private
* @returns {OpenSeadragon.CacheRecord|null} - Returns cache parameter reference if attached.
*/
setCache(key, cache, setAsMain = false, _safely = true) {
const tiledImage = this.tiledImage;
if (!tiledImage) {
return null; //async can access outside its lifetime
}
const overwritesMainCache = key === this.cacheKey;
if (_safely) {
$.console.assert(cache instanceof $.CacheRecord, "[Tile.setCache] cache must be a CacheRecord object!");
if (overwritesMainCache || setAsMain) {
// Need to get the supported type for rendering out of the active drawer.
const supportedTypes = tiledImage.viewer.drawer.getSupportedDataFormats();
const conversion = $.convertor.getConversionPath(cache.type, supportedTypes);
$.console.assert(conversion, "[Tile.setCache] data was set for the default tile cache we are unable" +
`to render. Make sure OpenSeadragon.convertor was taught to convert ${cache.type} to (one of): ${conversion.toString()}`);
}
}
const havingRecord = this._caches[key];
if (havingRecord !== cache) {
this._caches[key] = cache;
cache.addTile(this); // keep reference bidirectional
if (havingRecord) {
havingRecord.removeTile(this);
tiledImage._tileCache.safeUnloadCache(havingRecord);
}
}
// Update cache key if differs and main requested
if (!overwritesMainCache && setAsMain) {
this._updateMainCacheKey(key);
}
return cache;
},
/**
* Sets the main cache key for this tile and
* performs necessary updates
* @param value
* @private
*/
_updateMainCacheKey: function(value) {
let ref = this._caches[this._cKey];
if (ref) {
// make sure we free drawer internal cache if people change cache key externally
ref.destroyInternalCache();
}
this._cKey = value;
},
/**
* Get the number of caches available to this tile
* @returns {number} number of caches
*/
getCacheSize: function() {
return Object.values(this._caches).length;
},
/**
* Free tile cache. Removes by default the cache record if no other tile uses it.
* @param {string} key cache key, required
* @param {boolean} [freeIfUnused=true] set to false if zombie should be created
* @return {OpenSeadragon.CacheRecord|undefined} reference to the cache record if it was removed,
* undefined if removal was refused to perform (e.g. does not exist, it is an original data target etc.)
*/
removeCache: function(key, freeIfUnused = true) {
const deleteTarget = this._caches[key];
if (!deleteTarget) {
// try to erase anyway in case the cache got stuck in memory
this.tiledImage._tileCache.unloadCacheForTile(this, key, freeIfUnused, true);
return undefined;
}
const currentMainKey = this.cacheKey,
originalDataKey = this.originalCacheKey,
sameBuiltinKeys = currentMainKey === originalDataKey;
if (!sameBuiltinKeys && originalDataKey === key) {
$.console.warn("[Tile.removeCache] original data must not be manually deleted: other parts of the code might rely on it!",
"If you want the tile not to preserve the original data, toggle of data perseverance in tile.setData().");
return undefined;
}
if (currentMainKey === key) {
if (!sameBuiltinKeys && this._caches[originalDataKey]) {
// if we have original data let's revert back
this._updateMainCacheKey(originalDataKey);
} else {
$.console.warn("[Tile.removeCache] trying to remove the only cache that can be used to draw the tile!",
"If you want to remove the main cache, first set different cache as main with tile.addCache()");
return undefined;
}
}
if (this.tiledImage._tileCache.unloadCacheForTile(this, key, freeIfUnused, false)) {
//if we managed to free tile from record, we are sure we decreased cache count
delete this._caches[key];
}
return deleteTarget;
},
/**
* Get the ratio between current and original size.
* @function
* @return {Float}
* @deprecated
* @returns {number}
*/
getScaleForEdgeSmoothing: function() {
var context;
if (this.cacheImageRecord) {
context = this.cacheImageRecord.getRenderedContext();
} else if (this.context2D) {
context = this.context2D;
} else {
// getCanvasContext is deprecated and so should be this method.
$.console.warn("[Tile.getScaleForEdgeSmoothing] is deprecated, the following error is the consequence:");
const context = this.getCanvasContext();
if (!context) {
$.console.warn(
'[Tile.drawCanvas] attempting to get tile scale %s when tile\'s not cached',
this.toString());
@ -430,15 +725,15 @@ $.Tile.prototype = {
* Needed to avoid swimming and twitching.
* @function
* @param {Number} [scale=1] - Scale to be applied to position.
* @return {OpenSeadragon.Point}
* @returns {OpenSeadragon.Point}
*/
getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) {
// The translation vector must have positive values, otherwise the image goes a bit off
// the sketch canvas to the top and left and we must use negative coordinates to repaint it
// to the main canvas. In that case, some browsers throw:
// INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.
var x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2));
var y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2));
const x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2));
const y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2));
return new $.Point(x, y).minus(
this.position
.times($.pixelDensityRatio)
@ -450,21 +745,59 @@ $.Tile.prototype = {
},
/**
* Removes tile from its container.
* Reflect that a cache object was renamed. Called internally from TileCache.
* Do NOT call manually.
* @function
* @private
*/
unload: function() {
if ( this.imgElement && this.imgElement.parentNode ) {
this.imgElement.parentNode.removeChild( this.imgElement );
reflectCacheRenamed: function (oldKey, newKey) {
let cache = this._caches[oldKey];
if (!cache) {
return; // nothing to fix
}
if ( this.element && this.element.parentNode ) {
this.element.parentNode.removeChild( this.element );
// Do update via private refs, old key no longer exists in cache
if (oldKey === this._ocKey) {
this._ocKey = newKey;
}
if (oldKey === this._cKey) {
this._cKey = newKey;
}
// Working key is never updated, it will be invalidated (but do not dereference cache, just fix the pointers)
this._caches[newKey] = cache;
delete this._caches[oldKey];
},
this.element = null;
this.imgElement = null;
/**
* Check if two tiles are data-equal
* @param {OpenSeadragon.Tile} tile
*/
equals(tile) {
return this._ocKey === tile._ocKey;
},
/**
* Removes tile from the system: it will still be present in the
* OSD memory, but marked as loaded=false, and its data will be erased.
* @param {boolean} [erase=false]
*/
unload: function(erase = false) {
if (!this.loaded) {
return;
}
this.tiledImage._tileCache.unloadTile(this, erase);
},
/**
* this method shall be called only by cache system when the tile is already empty of data
* @private
*/
_unload: function () {
this.tiledImage = null;
this._caches = {};
this._cacheSize = 0;
this.loaded = false;
this.loading = false;
this._cKey = this._ocKey;
}
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
* OpenSeadragon - TileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -55,7 +55,8 @@
* @param {Object} options
* You can either specify a URL, or literally define the TileSource (by specifying
* width, height, tileSize, tileOverlap, minLevel, and maxLevel). For the former,
* the extending class is expected to implement 'getImageInfo' and 'configure'.
* the extending class is expected to implement 'supports' and 'configure'.
* Note that _in this case, the child class of getImageInfo() is ignored!_
* For the latter, the construction is assumed to occur through
* the extending classes implementation of 'configure'.
* @param {String} [options.url]
@ -69,6 +70,10 @@
* the XHR's withCredentials (for accessing secure data).
* @param {Object} [options.ajaxHeaders]
* A set of headers to include in AJAX requests.
* @param {Boolean} [options.splitHashDataForPost]
* First occurrence of '#' in the options.url is used to split URL
* and the latter part is treated as POST data (applies to getImageInfo(...))
* Does not work if getImageInfo() is overridden and used (see the options description)
* @param {Number} [options.width]
* Width of the source image at max resolution in pixels.
* @param {Number} [options.height]
@ -136,6 +141,12 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
} );
}
/**
* Retrieve context2D of this tile source
* @memberOf OpenSeadragon.TileSource
* @function getContext2D
*/
/**
* Ratio of width to height
* @member {Number} aspectRatio
@ -167,6 +178,8 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
* @memberof OpenSeadragon.TileSource#
*/
// TODO potentially buggy behavior: what if .url is used by child class before it calls super constructor?
// this can happen if old JS class definition is used
if( 'string' === $.type( arguments[ 0 ] ) ){
this.url = arguments[0];
}
@ -367,6 +380,7 @@ $.TileSource.prototype = {
point.y >= 0 && point.y <= 1 / this.aspectRatio;
$.console.assert(validPoint, "[TileSource.getTileAtPoint] must be called with a valid point.");
var widthScaled = this.dimensions.x * this.getLevelScale(level);
var pixelX = point.x * widthScaled;
var pixelY = point.y * widthScaled;
@ -421,6 +435,13 @@ $.TileSource.prototype = {
/**
* Responsible for retrieving, and caching the
* image metadata pertinent to this TileSources implementation.
* There are three scenarios of opening a tile source: providing a parseable string, plain object, or an URL.
* This method is only called by OSD if the TileSource configuration is a non-parseable string (~url).
*
* The string can contain a hash `#` symbol, followed by
* key=value arguments. If this is the case, this method sends this
* data as a POST body.
*
* @function
* @param {String} url
* @throws {Error}
@ -445,6 +466,15 @@ $.TileSource.prototype = {
}
}
var postData = null;
if (this.splitHashDataForPost) {
var hashIdx = url.indexOf("#");
if (hashIdx !== -1) {
postData = url.substring(hashIdx + 1);
url = url.substr(0, hashIdx);
}
}
callback = function( data ){
if( typeof (data) === "string" ) {
data = $.parseXml( data );
@ -466,7 +496,7 @@ $.TileSource.prototype = {
return;
}
options = $TileSource.prototype.configure.apply( _this, [ data, url ]);
options = $TileSource.prototype.configure.apply( _this, [ data, url, postData ]);
if (options.ajaxWithCredentials === undefined) {
options.ajaxWithCredentials = _this.ajaxWithCredentials;
}
@ -501,6 +531,7 @@ $.TileSource.prototype = {
// request info via xhr asynchronously.
$.makeAjaxRequest( {
url: url,
postData: postData,
withCredentials: this.ajaxWithCredentials,
headers: this.ajaxHeaders,
success: function( xhr ) {
@ -516,7 +547,7 @@ $.TileSource.prototype = {
exception rather than the second one raised when we try to access xhr.status
*/
try {
msg = "HTTP " + xhr.status + " attempting to load TileSource";
msg = "HTTP " + xhr.status + " attempting to load TileSource: " + url;
} catch ( e ) {
var formattedExc;
if ( typeof ( exc ) === "undefined" || !exc.toString ) {
@ -525,9 +556,11 @@ $.TileSource.prototype = {
formattedExc = exc.toString();
}
msg = formattedExc + " attempting to load TileSource";
msg = formattedExc + " attempting to load TileSource: " + url;
}
$.console.error(msg);
/***
* Raised when an error occurs loading a TileSource.
*
@ -537,11 +570,14 @@ $.TileSource.prototype = {
* @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.
* @property {String} message
* @property {String} source
* @property {String} postData - HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getTilePostData) or null
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( 'open-failed', {
message: msg,
source: url
source: url,
postData: postData
});
}
});
@ -550,23 +586,34 @@ $.TileSource.prototype = {
},
/**
* Responsible determining if a the particular TileSource supports the
* Responsible for determining if the particular TileSource supports the
* data format ( and allowed to apply logic against the url the data was
* loaded from, if any ). Overriding implementations are expected to do
* something smart with data and / or url to determine support. Also
* understand that iteration order of TileSources is not guarunteed so
* understand that iteration order of TileSources is not guaranteed so
* please make sure your data or url is expressive enough to ensure a simple
* and sufficient mechanisim for clear determination.
* and sufficient mechanism for clear determination.
* @function
* @param {String|Object|Array|Document} data
* @param {String} url - the url the data was loaded
* from if any.
* @return {Boolean}
* @returns {Boolean}
*/
supports: function( data, url ) {
return false;
},
/**
* Check whether two tileSources are equal. This is used for example
* when replacing tile-sources, which turns on the zombie cache before
* old item removal.
* @param {OpenSeadragon.TileSource} otherSource
* @returns {Boolean}
*/
equals: function (otherSource) {
return false;
},
/**
* Responsible for parsing and configuring the
* image metadata pertinent to this TileSources implementation.
@ -578,14 +625,27 @@ $.TileSource.prototype = {
* @param {String|Object|Array|Document} data
* @param {String} url - the url the data was loaded
* from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
* @param {String} postData - HTTP POST data in k=v&k2=v2... form or null value obtained from
* the protocol URL after '#' sign if flag splitHashDataForPost set to 'true'
* @returns {Object} options - A dictionary of keyword arguments sufficient
* to configure the tile source constructor (include all values you want to
* instantiate the TileSource subclass with - what _options_ object should contain).
* @throws {Error}
*/
configure: function( data, url ) {
configure: function( data, url, postData ) {
throw new Error( "Method not implemented." );
},
/**
* Shall this source need to free some objects
* upon unloading, it must be done here. For example, canvas
* size must be set to 0 for safari to free.
* @param {OpenSeadragon.Viewer} viewer
*/
destroy: function ( viewer ) {
//no-op
},
/**
* Responsible for retrieving the url which will return an image for the
* region specified by the given x, y, and level components.
@ -597,12 +657,44 @@ $.TileSource.prototype = {
* @param {Number} level
* @param {Number} x
* @param {Number} y
* @returns {String|Function} url - A string for the url or a function that returns a url string.
* @throws {Error}
*/
getTileUrl: function( level, x, y ) {
throw new Error( "Method not implemented." );
},
/**
* Must use AJAX in order to work, i.e. loadTilesWithAjax = true is set.
* If a value is returned, ajax issues POST request to the tile url.
* If null is returned, ajax issues GET request.
* The return value must comply to the header 'content type'.
*
* Examples (USED HEADER --> getTilePostData CODE):
* 'Content-type': 'application/x-www-form-urlencoded' -->
* return "key1=value=1&key2=value2";
*
* 'Content-type': 'application/x-www-form-urlencoded' -->
* return JSON.stringify({key: "value", number: 5});
*
* 'Content-type': 'multipart/form-data' -->
* let result = new FormData();
* result.append("data", myData);
* return result;
*
* IMPORTANT: in case you move all the logic on image fetching
* to post data, you must re-define 'getTileHashKey(...)' to
* stay unique for different tile images.
*
* @param {Number} level
* @param {Number} x
* @param {Number} y
* @returns {*|null} post data to send with tile configuration request
*/
getTilePostData: function( level, x, y ) {
return null;
},
/**
* Responsible for retrieving the headers which will be attached to the image request for the
* region specified by the given x, y, and level components.
@ -610,6 +702,11 @@ $.TileSource.prototype = {
* The headers returned here will override headers specified at the Viewer or TiledImage level.
* Specifying a falsy value for a header will clear its existing value set at the Viewer or
* TiledImage level (if any).
*
* Note that the headers of existing tiles don't automatically change when this function
* returns updated headers. To do that, you need to call {@link OpenSeadragon.Viewer#setAjaxHeaders}
* and propagate the changes.
*
* @function
* @param {Number} level
* @param {Number} x
@ -620,6 +717,38 @@ $.TileSource.prototype = {
return {};
},
/**
* The tile cache object is uniquely determined by this key and used to lookup
* the image data in cache: keys should be different if images are different.
*
* You can return falsey tile cache key, in which case the tile will
* be created without invoking ImageJob --- but with data=null. Then,
* you are responsible for manually creating the cache data. This is useful
* particularly if you want to use empty TiledImage with client-side derived data
* only. The default tile-cache key is then called "" - an empty string.
*
* Note: default behaviour does not take into account post data.
* @param {Number} level tile level it was fetched with
* @param {Number} x x-coordinate in the pyramid level
* @param {Number} y y-coordinate in the pyramid level
* @param {String} url the tile was fetched with
* @param {Object} ajaxHeaders the tile was fetched with
* @param {*} postData data the tile was fetched with (type depends on getTilePostData(..) return type)
* @return {?String} can return the cache key or null, in that case an empty cache is initialized
* without downloading any data for internal use: user has to define the cache contents manually, via
* the cache interface of this class.
*/
getTileHashKey: function(level, x, y, url, ajaxHeaders, postData) {
function withHeaders(hash) {
return ajaxHeaders ? hash + "+" + JSON.stringify(ajaxHeaders) : hash;
}
if (typeof url !== "string") {
return withHeaders(level + "/" + x + "_" + y);
}
return withHeaders(url);
},
/**
* @function
* @param {Number} level
@ -634,6 +763,211 @@ $.TileSource.prototype = {
y >= 0 &&
x < numTiles.x &&
y < numTiles.y;
},
/**
* Decide whether tiles have transparency: this is crucial for correct images blending.
* Overriden on a tile level by setting tile.hasTransparency = true;
* @param context2D unused, deprecated argument
* @param url tile.getUrl() value for given tile
* @param ajaxHeaders tile.ajaxHeaders value for given tile
* @param post tile.post value for given tile
* @returns {boolean} true if the image has transparency
*/
hasTransparency: function(context2D, url, ajaxHeaders, post) {
return url.match('.png');
},
/**
* Download tile data.
* Note that if you override this function, you should override also downloadTileAbort().
* @param {ImageJob} context job context that you have to call finish(...) on.
* @param {String} [context.src] - URL of image to download.
* @param {String} [context.loadWithAjax] - Whether to load this image with AJAX.
* @param {String} [context.ajaxHeaders] - Headers to add to the image request if using AJAX.
* @param {Boolean} [context.ajaxWithCredentials] - Whether to set withCredentials on AJAX requests.
* @param {String} [context.crossOriginPolicy] - CORS policy to use for downloads
* @param {?String|?Object} [context.postData] - HTTP POST data (usually but not necessarily
* in k=v&k2=v2... form, see TileSource::getTilePostData) or null
* @param {*} [context.userData] - Empty object to attach your own data and helper variables to.
* @param {Function} [context.finish] - Should be called unless abort() was executed upon successful
* data retrieval.
* Usage: context.finish(data, request, dataType=undefined). Pass the downloaded data object
* add also reference to an ajax request if used. Optionally, specify what data type the data is.
* @param {Function} [context.fail] - Should be called unless abort() was executed upon unsuccessful request.
* Usage: context.fail(errMessage, request). Provide error message in case of failure,
* add also reference to an ajax request if used.
* @param {Function} [context.abort] - Called automatically when the job times out.
* Usage: if you decide to abort the request (no fail/finish will be called), call context.abort().
* @param {Function} [context.callback] Private parameter. Called automatically once image has been downloaded
* (triggered by finish).
* @param {Number} [context.timeout] Private parameter. The max number of milliseconds that
* this image job may take to complete.
* @param {string} [context.errorMsg] Private parameter. The final error message, default null (set by finish).
*/
downloadTileStart: function (context) {
const dataStore = context.userData,
image = new Image();
dataStore.image = image;
dataStore.request = null;
const finalize = function(error) {
if (error || !image) {
context.fail(error || "[downloadTileStart] Image load failed: undefined Image instance.",
dataStore.request);
return;
}
image.onload = image.onerror = image.onabort = null;
context.finish(image, dataStore.request, "image");
};
image.onload = function () {
finalize();
};
image.onabort = image.onerror = function() {
finalize("[downloadTileStart] Image load aborted.");
};
// Load the tile with an AJAX request if the loadWithAjax option is
// set. Otherwise load the image by setting the source property of the image object.
if (context.loadWithAjax) {
dataStore.request = $.makeAjaxRequest({
url: context.src,
withCredentials: context.ajaxWithCredentials,
headers: context.ajaxHeaders,
responseType: "arraybuffer",
postData: context.postData,
success: function(request) {
var blb;
// Make the raw data into a blob.
// BlobBuilder fallback adapted from
// http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility
try {
blb = new window.Blob([request.response]);
} catch (e) {
const BlobBuilder = (
window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder
);
if (e.name === 'TypeError' && BlobBuilder) {
const bb = new BlobBuilder();
bb.append(request.response);
blb = bb.getBlob();
}
}
// If the blob is empty for some reason consider the image load a failure.
if (blb.size === 0) {
finalize("[downloadTileStart] Empty image response.");
} else {
// Create a URL for the blob data and make it the source of the image object.
// This will still trigger Image.onload to indicate a successful tile load.
image.src = (window.URL || window.webkitURL).createObjectURL(blb);
}
},
error: function(request) {
finalize("[downloadTileStart] Image load aborted - XHR error");
}
});
} else {
if (context.crossOriginPolicy !== false) {
image.crossOrigin = context.crossOriginPolicy;
}
image.src = context.src;
}
},
/**
* Provide means of aborting the execution.
* Note that if you override this function, you should override also downloadTileStart().
* Note that calling job.abort() would create an infinite loop!
*
* @param {ImageJob} context job, the same object as with downloadTileStart(..)
* @param {*} [context.userData] - Empty object to attach (and mainly read) your own data.
*/
downloadTileAbort: function (context) {
if (context.userData.request) {
context.userData.request.abort();
}
var image = context.userData.image;
if (context.userData.image) {
image.onload = image.onerror = image.onabort = null;
}
},
/**
* Create cache object from the result of the download process. The
* cacheObject parameter should be used to attach the data to, there are no
* conventions on how it should be stored - all the logic is implemented within *TileCache() functions.
*
* Note that
* - data is cached automatically as cacheObject.data
* - if you override any of *TileCache() functions, you should override all of them.
* - these functions might be called over shared cache object managed by other TileSources simultaneously.
* @param {OpenSeadragon.CacheRecord} cacheObject context cache object
* @param {*} data image data, the data sent to ImageJob.prototype.finish(), by default an Image object
* @param {OpenSeadragon.Tile} tile instance the cache was created with
* @deprecated
*/
createTileCache: function(cacheObject, data, tile) {
$.console.error("[TileSource.createTileCache] has been deprecated. Use cache API of a tile instead.");
//no-op, we create the cache automatically
},
/**
* Cache object destructor, unset all properties you created to allow GC collection.
* Note that if you override any of *TileCache() functions, you should override all of them.
* Note that these functions might be called over shared cache object managed by other TileSources simultaneously.
* Original cache data is cacheObject.data, but do not delete it manually! It is taken care for,
* you might break things.
* @param {OpenSeadragon.CacheRecord} cacheObject context cache object
* @deprecated
*/
destroyTileCache: function (cacheObject) {
$.console.error("[TileSource.destroyTileCache] has been deprecated. Use cache API of a tile instead.");
//no-op, handled internally
},
/**
* Raw data getter, should return anything that is compatible with the system, or undefined
* if the system can handle it.
* @param {OpenSeadragon.CacheRecord} cacheObject context cache object
* @returns {OpenSeadragon.Promise<?>} cache data
* @deprecated
*/
getTileCacheData: function(cacheObject) {
$.console.error("[TileSource.getTileCacheData] has been deprecated. Use cache API of a tile instead.");
return cacheObject.getDataAs(undefined, false);
},
/**
* Compatibility image element getter
* - plugins might need image representation of the data
* - div HTML rendering relies on image element presence
* Note that if you override any of *TileCache() functions, you should override all of them.
* Note that these functions might be called over shared cache object managed by other TileSources simultaneously.
* @param {OpenSeadragon.CacheRecord} cacheObject context cache object
* @returns {Image} cache data as an Image
* @deprecated
*/
getTileCacheDataAsImage: function(cacheObject) {
$.console.error("[TileSource.getTileCacheDataAsImage] has been deprecated. Use cache API of a tile instead.");
return cacheObject.getImage();
},
/**
* Compatibility context 2D getter
* - most heavily used rendering method is a canvas-based approach,
* convert the data to a canvas and return it's 2D context
* Note that if you override any of *TileCache() functions, you should override all of them.
* @param {OpenSeadragon.CacheRecord} cacheObject context cache object
* @returns {CanvasRenderingContext2D} context of the canvas representation of the cache data
* @deprecated
*/
getTileCacheDataAsContext2D: function(cacheObject) {
$.console.error("[TileSource.getTileCacheDataAsContext2D] has been deprecated. Use cache API of a tile instead.");
return cacheObject.getRenderedContext();
}
};
@ -665,7 +999,7 @@ function processResponse( xhr ){
throw new Error( $.getString( "Errors.Status", status, statusText ) );
}
if( responseText.match(/\s*<.*/) ){
if( responseText.match(/^\s*<.*/) ){
try{
data = ( xhr.responseXML && xhr.responseXML.documentElement ) ?
xhr.responseXML :

View file

@ -2,7 +2,7 @@
* OpenSeadragon - TileSourceCollection
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are

View file

@ -2,7 +2,7 @@
* OpenSeadragon - TmsTileSource
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -111,10 +111,11 @@ $.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
* @function
* @param {Object} data - the raw configuration
* @param {String} url - the url the data was retrieved from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @param {String} postData - HTTP POST data in k=v&k2=v2... form or null
* @returns {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function( data, url ){
configure: function( data, url, postData ){
return data;
},
@ -130,6 +131,13 @@ $.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead
var yTiles = this.getNumTiles( level ).y - 1;
return this.tilesUrl + level + "/" + x + "/" + (yTiles - y) + ".png";
},
/**
* Equality comparator
*/
equals: function (otherSource) {
return this.tilesUrl === otherSource.tilesUrl;
}
});

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
* OpenSeadragon - Viewport
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -54,6 +54,7 @@
* @param {Number} [options.maxZoomLevel] - See maxZoomLevel in {@link OpenSeadragon.Options}.
* @param {Number} [options.degrees] - See degrees in {@link OpenSeadragon.Options}.
* @param {Boolean} [options.homeFillsViewer] - See homeFillsViewer in {@link OpenSeadragon.Options}.
* @param {Boolean} [options.silenceMultiImageWarnings] - See silenceMultiImageWarnings in {@link OpenSeadragon.Options}.
*/
$.Viewport = function( options ) {
@ -85,6 +86,9 @@ $.Viewport = function( options ) {
delete options.margins;
options.initialDegrees = options.degrees;
delete options.degrees;
$.extend( true, this, {
//required settings
@ -93,22 +97,24 @@ $.Viewport = function( options ) {
//internal state properties
zoomPoint: null,
viewer: null,
rotationPivot: null,
viewer: null,
//configurable options
springStiffness: $.DEFAULT_SETTINGS.springStiffness,
animationTime: $.DEFAULT_SETTINGS.animationTime,
minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,
maxZoomPixelRatio: $.DEFAULT_SETTINGS.maxZoomPixelRatio,
visibilityRatio: $.DEFAULT_SETTINGS.visibilityRatio,
wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel,
minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel,
degrees: $.DEFAULT_SETTINGS.degrees,
flipped: $.DEFAULT_SETTINGS.flipped,
homeFillsViewer: $.DEFAULT_SETTINGS.homeFillsViewer
springStiffness: $.DEFAULT_SETTINGS.springStiffness,
animationTime: $.DEFAULT_SETTINGS.animationTime,
minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,
maxZoomPixelRatio: $.DEFAULT_SETTINGS.maxZoomPixelRatio,
visibilityRatio: $.DEFAULT_SETTINGS.visibilityRatio,
wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel,
minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel,
initialDegrees: $.DEFAULT_SETTINGS.degrees,
flipped: $.DEFAULT_SETTINGS.flipped,
homeFillsViewer: $.DEFAULT_SETTINGS.homeFillsViewer,
silenceMultiImageWarnings: $.DEFAULT_SETTINGS.silenceMultiImageWarnings
}, options );
@ -131,9 +137,16 @@ $.Viewport = function( options ) {
animationTime: this.animationTime
});
this.degreesSpring = new $.Spring({
initial: options.initialDegrees,
springStiffness: this.springStiffness,
animationTime: this.animationTime
});
this._oldCenterX = this.centerSpringX.current.value;
this._oldCenterY = this.centerSpringY.current.value;
this._oldZoom = this.zoomSpring.current.value;
this._oldDegrees = this.degreesSpring.current.value;
this._setContentBounds(new $.Rect(0, 0, 1, 1), 1);
@ -143,11 +156,24 @@ $.Viewport = function( options ) {
/** @lends OpenSeadragon.Viewport.prototype */
$.Viewport.prototype = {
// deprecated
get degrees () {
$.console.warn('Accessing [Viewport.degrees] is deprecated. Use viewport.getRotation instead.');
return this.getRotation();
},
// deprecated
set degrees (degrees) {
$.console.warn('Setting [Viewport.degrees] is deprecated. Use viewport.rotateTo, viewport.rotateBy, or viewport.setRotation instead.');
this.rotateTo(degrees);
},
/**
* Updates the viewport's home bounds and constraints for the given content size.
* @function
* @param {OpenSeadragon.Point} contentSize - size of the content in content units
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:reset-size
*/
resetContentSize: function(contentSize) {
@ -182,7 +208,7 @@ $.Viewport.prototype = {
this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times(
contentFactor);
this._contentBounds = bounds.rotate(this.degrees).getBoundingBox();
this._contentBounds = bounds.rotate(this.getRotation()).getBoundingBox();
this._contentSize = this._contentBounds.getSize().times(contentFactor);
this._contentAspectRatio = this._contentSize.x / this._contentSize.y;
@ -365,7 +391,7 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.
*/
getBounds: function(current) {
return this.getBoundsNoRotate(current).rotate(-this.getRotation());
return this.getBoundsNoRotate(current).rotate(-this.getRotation(current));
},
/**
@ -397,7 +423,7 @@ $.Viewport.prototype = {
*/
getBoundsWithMargins: function(current) {
return this.getBoundsNoRotateWithMargins(current).rotate(
-this.getRotation(), this.getCenter(current));
-this.getRotation(current), this.getCenter(current));
},
/**
@ -457,7 +483,7 @@ $.Viewport.prototype = {
);
newZoomPixel = this._pixelFromPoint(this.zoomPoint, bounds);
deltaZoomPixels = newZoomPixel.minus( oldZoomPixel );
deltaZoomPixels = newZoomPixel.minus( oldZoomPixel ).rotate(-this.getRotation(true));
deltaZoomPoints = deltaZoomPixels.divide( this._containerInnerSize.x * zoom );
return centerTarget.plus( deltaZoomPoints );
@ -486,52 +512,78 @@ $.Viewport.prototype = {
* @function
* @private
* @param {OpenSeadragon.Rect} bounds
* @return {OpenSeadragon.Rect} constrained bounds.
* @returns {OpenSeadragon.Rect} constrained bounds.
*/
_applyBoundaryConstraints: function(bounds) {
var newBounds = new $.Rect(
bounds.x,
bounds.y,
bounds.width,
bounds.height);
var newBounds = this.viewportToViewerElementRectangle(bounds).getBoundingBox();
var cb = this.viewportToViewerElementRectangle(this._contentBoundsNoRotate).getBoundingBox();
var xConstrained = false;
var yConstrained = false;
if (this.wrapHorizontal) {
//do nothing
} else {
var horizontalThreshold = this.visibilityRatio * newBounds.width;
var boundsRight = newBounds.x + newBounds.width;
var contentRight = this._contentBoundsNoRotate.x + this._contentBoundsNoRotate.width;
var leftDx = this._contentBoundsNoRotate.x - boundsRight + horizontalThreshold;
var rightDx = contentRight - newBounds.x - horizontalThreshold;
var contentRight = cb.x + cb.width;
if (horizontalThreshold > this._contentBoundsNoRotate.width) {
var horizontalThreshold, leftDx, rightDx;
if (newBounds.width > cb.width) {
horizontalThreshold = this.visibilityRatio * cb.width;
} else {
horizontalThreshold = this.visibilityRatio * newBounds.width;
}
leftDx = cb.x - boundsRight + horizontalThreshold;
rightDx = contentRight - newBounds.x - horizontalThreshold;
if (horizontalThreshold > cb.width) {
newBounds.x += (leftDx + rightDx) / 2;
xConstrained = true;
} else if (rightDx < 0) {
newBounds.x += rightDx;
xConstrained = true;
} else if (leftDx > 0) {
newBounds.x += leftDx;
xConstrained = true;
}
}
if (this.wrapVertical) {
//do nothing
} else {
var verticalThreshold = this.visibilityRatio * newBounds.height;
var boundsBottom = newBounds.y + newBounds.height;
var contentBottom = this._contentBoundsNoRotate.y + this._contentBoundsNoRotate.height;
var topDy = this._contentBoundsNoRotate.y - boundsBottom + verticalThreshold;
var bottomDy = contentBottom - newBounds.y - verticalThreshold;
var contentBottom = cb.y + cb.height;
if (verticalThreshold > this._contentBoundsNoRotate.height) {
var verticalThreshold, topDy, bottomDy;
if (newBounds.height > cb.height) {
verticalThreshold = this.visibilityRatio * cb.height;
} else{
verticalThreshold = this.visibilityRatio * newBounds.height;
}
topDy = cb.y - boundsBottom + verticalThreshold;
bottomDy = contentBottom - newBounds.y - verticalThreshold;
if (verticalThreshold > cb.height) {
newBounds.y += (topDy + bottomDy) / 2;
yConstrained = true;
} else if (bottomDy < 0) {
newBounds.y += bottomDy;
yConstrained = true;
} else if (topDy > 0) {
newBounds.y += topDy;
yConstrained = true;
}
}
return newBounds;
var constraintApplied = xConstrained || yConstrained;
var newViewportBounds = constraintApplied ? this.viewerElementToViewportRectangle(newBounds) : bounds.clone();
newViewportBounds.xConstrained = xConstrained;
newViewportBounds.yConstrained = yConstrained;
newViewportBounds.constraintApplied = constraintApplied;
return newViewportBounds;
},
/**
@ -564,8 +616,8 @@ $.Viewport.prototype = {
* zooming and panning to the closest acceptable zoom and location.
* @function
* @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:constrain
* @returns {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:constrain if constraints were applied
*/
applyConstraints: function(immediately) {
var actualZoom = this.getZoom();
@ -575,17 +627,13 @@ $.Viewport.prototype = {
this.zoomTo(constrainedZoom, this.zoomPoint, immediately);
}
var bounds = this.getBoundsNoRotate();
var constrainedBounds = this._applyBoundaryConstraints(bounds);
this._raiseConstraintsEvent(immediately);
var constrainedBounds = this.getConstrainedBounds(false);
if (bounds.x !== constrainedBounds.x ||
bounds.y !== constrainedBounds.y ||
immediately) {
this.fitBounds(
constrainedBounds.rotate(-this.getRotation()),
immediately);
if(constrainedBounds.constraintApplied){
this.fitBounds(constrainedBounds, immediately);
this._raiseConstraintsEvent(immediately);
}
return this;
},
@ -593,7 +641,7 @@ $.Viewport.prototype = {
* Equivalent to {@link OpenSeadragon.Viewport#applyConstraints}
* @function
* @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:constrain
*/
ensureVisible: function(immediately) {
@ -605,7 +653,7 @@ $.Viewport.prototype = {
* @private
* @param {OpenSeadragon.Rect} bounds
* @param {Object} options (immediately=false, constraints=false)
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
_fitBounds: function(bounds, options) {
options = options || {};
@ -635,45 +683,53 @@ $.Viewport.prototype = {
newBounds.y = center.y - newBounds.height / 2;
var newZoom = 1.0 / newBounds.width;
if (constraints) {
var newBoundsAspectRatio = newBounds.getAspectRatio();
var newConstrainedZoom = this._applyZoomConstraints(newZoom);
if (newZoom !== newConstrainedZoom) {
newZoom = newConstrainedZoom;
newBounds.width = 1.0 / newZoom;
newBounds.x = center.x - newBounds.width / 2;
newBounds.height = newBounds.width / newBoundsAspectRatio;
newBounds.y = center.y - newBounds.height / 2;
}
newBounds = this._applyBoundaryConstraints(newBounds);
center = newBounds.getCenter();
this._raiseConstraintsEvent(immediately);
}
if (immediately) {
this.panTo(center, true);
return this.zoomTo(newZoom, null, true);
this.zoomTo(newZoom, null, true);
if(constraints){
this.applyConstraints(true);
}
return this;
}
this.panTo(this.getCenter(true), true);
this.zoomTo(this.getZoom(true), null, true);
var currentCenter = this.getCenter(true);
var currentZoom = this.getZoom(true);
this.panTo(currentCenter, true);
this.zoomTo(currentZoom, null, true);
var oldBounds = this.getBounds();
var oldZoom = this.getZoom();
if (oldZoom === 0 || Math.abs(newZoom / oldZoom - 1) < 0.00000001) {
this.zoomTo(newZoom, true);
return this.panTo(center, immediately);
this.zoomTo(newZoom, null, true);
this.panTo(center, immediately);
if(constraints){
this.applyConstraints(false);
}
return this;
}
newBounds = newBounds.rotate(-this.getRotation());
var referencePoint = newBounds.getTopLeft().times(newZoom)
.minus(oldBounds.getTopLeft().times(oldZoom))
.divide(newZoom - oldZoom);
if(constraints){
this.panTo(center, false);
return this.zoomTo(newZoom, referencePoint, immediately);
newZoom = this._applyZoomConstraints(newZoom);
this.zoomTo(newZoom, null, false);
var constrainedBounds = this.getConstrainedBounds();
this.panTo(currentCenter, true);
this.zoomTo(currentZoom, null, true);
this.fitBounds(constrainedBounds);
} else {
var rotatedNewBounds = newBounds.rotate(-this.getRotation());
var referencePoint = rotatedNewBounds.getTopLeft().times(newZoom)
.minus(oldBounds.getTopLeft().times(oldZoom))
.divide(newZoom - oldZoom);
this.zoomTo(newZoom, referencePoint, immediately);
}
return this;
},
/**
@ -686,7 +742,7 @@ $.Viewport.prototype = {
* @function
* @param {OpenSeadragon.Rect} bounds
* @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
fitBounds: function(bounds, immediately) {
return this._fitBounds(bounds, {
@ -705,7 +761,7 @@ $.Viewport.prototype = {
* @function
* @param {OpenSeadragon.Rect} bounds
* @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
fitBoundsWithConstraints: function(bounds, immediately) {
return this._fitBounds(bounds, {
@ -717,7 +773,7 @@ $.Viewport.prototype = {
/**
* Zooms so the image just fills the viewer vertically.
* @param {Boolean} immediately
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
fitVertically: function(immediately) {
var box = new $.Rect(
@ -731,7 +787,7 @@ $.Viewport.prototype = {
/**
* Zooms so the image just fills the viewer horizontally.
* @param {Boolean} immediately
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
fitHorizontally: function(immediately) {
var box = new $.Rect(
@ -747,7 +803,10 @@ $.Viewport.prototype = {
* Returns bounds taking constraints into account
* Added to improve constrained panning
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Rect} The bounds in viewport coordinates after applying constraints. The returned $.Rect
* contains additional properties constraintsApplied, xConstrained and yConstrained.
* These flags indicate whether the viewport bounds were modified by the constraints
* of the viewer rectangle, and in which dimension(s).
*/
getConstrainedBounds: function(current) {
var bounds,
@ -764,7 +823,7 @@ $.Viewport.prototype = {
* @function
* @param {OpenSeadragon.Point} delta
* @param {Boolean} immediately
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:pan
*/
panBy: function( delta, immediately ) {
@ -779,7 +838,7 @@ $.Viewport.prototype = {
* @function
* @param {OpenSeadragon.Point} center
* @param {Boolean} immediately
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:pan
*/
panTo: function( center, immediately ) {
@ -814,7 +873,7 @@ $.Viewport.prototype = {
/**
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:zoom
*/
zoomBy: function(factor, refPoint, immediately) {
@ -829,7 +888,7 @@ $.Viewport.prototype = {
* @param {OpenSeadragon.Point} [refPoint] The point which will stay at
* the same screen location. Defaults to the viewport center.
* @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:zoom
*/
zoomTo: function(zoom, refPoint, immediately) {
@ -876,13 +935,90 @@ $.Viewport.prototype = {
* Rotates this viewport to the angle specified.
* @function
* @param {Number} degrees The degrees to set the rotation to.
* @return {OpenSeadragon.Viewport} Chainable.
* @param {Boolean} [immediately=false] Whether to animate to the new angle
* or rotate immediately.
* * @returns {OpenSeadragon.Viewport} Chainable.
*/
setRotation: function(degrees) {
setRotation: function(degrees, immediately) {
return this.rotateTo(degrees, null, immediately);
},
/**
* Gets the current rotation in degrees.
* @function
* @param {Boolean} [current=false] True for current rotation, false for target.
* @returns {Number} The current rotation in degrees.
*/
getRotation: function(current) {
return current ?
this.degreesSpring.current.value :
this.degreesSpring.target.value;
},
/**
* Rotates this viewport to the angle specified around a pivot point. Alias for rotateTo.
* @function
* @param {Number} degrees The degrees to set the rotation to.
* @param {OpenSeadragon.Point} [pivot] (Optional) point in viewport coordinates
* around which the rotation should be performed. Defaults to the center of the viewport.
* @param {Boolean} [immediately=false] Whether to animate to the new angle
* or rotate immediately.
* * @returns {OpenSeadragon.Viewport} Chainable.
*/
setRotationWithPivot: function(degrees, pivot, immediately) {
return this.rotateTo(degrees, pivot, immediately);
},
/**
* Rotates this viewport to the angle specified.
* @function
* @param {Number} degrees The degrees to set the rotation to.
* @param {OpenSeadragon.Point} [pivot] (Optional) point in viewport coordinates
* around which the rotation should be performed. Defaults to the center of the viewport.
* @param {Boolean} [immediately=false] Whether to animate to the new angle
* or rotate immediately.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
rotateTo: function(degrees, pivot, immediately){
if (!this.viewer || !this.viewer.drawer.canRotate()) {
return this;
}
this.degrees = $.positiveModulo(degrees, 360);
if (this.degreesSpring.target.value === degrees &&
this.degreesSpring.isAtTargetValue()) {
return this;
}
this.rotationPivot = pivot instanceof $.Point &&
!isNaN(pivot.x) &&
!isNaN(pivot.y) ?
pivot :
null;
if (immediately) {
if(this.rotationPivot){
var changeInDegrees = degrees - this._oldDegrees;
if(!changeInDegrees){
this.rotationPivot = null;
return this;
}
this._rotateAboutPivot(degrees);
} else{
this.degreesSpring.resetTo(degrees);
}
} else {
var normalizedFrom = $.positiveModulo(this.degreesSpring.current.value, 360);
var normalizedTo = $.positiveModulo(degrees, 360);
var diff = normalizedTo - normalizedFrom;
if (diff > 180) {
normalizedTo -= 360;
} else if (diff < -180) {
normalizedTo += 360;
}
var reverseDiff = normalizedFrom - normalizedTo;
this.degreesSpring.resetTo(degrees + reverseDiff);
this.degreesSpring.springTo(degrees);
}
this._setContentBounds(
this.viewer.world.getHomeBounds(),
this.viewer.world.getContentFactor());
@ -896,24 +1032,31 @@ $.Viewport.prototype = {
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {Number} degrees - The number of degrees the rotation was set to.
* @property {Boolean} immediately - Whether the rotation happened immediately or was animated
* @property {OpenSeadragon.Point} pivot - The point in viewport coordinates around which the rotation (if any) happened
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent('rotate', {degrees: degrees});
this.viewer.raiseEvent('rotate', {degrees: degrees, immediately: !!immediately, pivot: this.rotationPivot || this.getCenter()});
return this;
},
/**
* Gets the current rotation in degrees.
* Rotates this viewport by the angle specified.
* @function
* @return {Number} The current rotation in degrees.
* @param {Number} degrees The degrees by which to rotate the viewport.
* @param {OpenSeadragon.Point} [pivot] (Optional) point in viewport coordinates
* around which the rotation should be performed. Defaults to the center of the viewport.
* * @param {Boolean} [immediately=false] Whether to animate to the new angle
* or rotate immediately.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
getRotation: function() {
return this.degrees;
rotateBy: function(degrees, pivot, immediately){
return this.rotateTo(this.degreesSpring.target.value + degrees, pivot, immediately);
},
/**
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:resize
*/
resize: function( newContainerSize, maintain ) {
@ -935,7 +1078,10 @@ $.Viewport.prototype = {
if( this.viewer ){
/**
* Raised when the viewer is resized (see {@link OpenSeadragon.Viewport#resize}).
* Raised when a viewer resize operation is initiated (see {@link OpenSeadragon.Viewport#resize}).
* This event happens before the viewport bounds have been updated.
* See also {@link OpenSeadragon.Viewer#after-resize} which reflects
* the new viewport bounds following the resize action.
*
* @event resize
* @memberof OpenSeadragon.Viewer
@ -951,7 +1097,29 @@ $.Viewport.prototype = {
});
}
return this.fitBounds( newBounds, true );
var output = this.fitBounds( newBounds, true );
if( this.viewer ){
/**
* Raised after the viewer is resized (see {@link OpenSeadragon.Viewport#resize}).
* See also {@link OpenSeadragon.Viewer#resize} event which happens
* before the new bounds have been calculated and applied.
*
* @event after-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( 'after-resize', {
newContainerSize: newContainerSize,
maintain: maintain
});
}
return output;
},
// private
@ -963,30 +1131,70 @@ $.Viewport.prototype = {
},
/**
* Update the zoom and center (X and Y) springs.
* Update the zoom, degrees, and center (X and Y) springs.
* @function
* @returns {Boolean} True if any change has been made, false otherwise.
* @returns {Boolean} True if the viewport is still animating, false otherwise.
*/
update: function() {
var _this = this;
this._adjustCenterSpringsForZoomPoint(function() {
_this.zoomSpring.update();
});
if(this.degreesSpring.isAtTargetValue()){
this.rotationPivot = null;
}
this.centerSpringX.update();
this.centerSpringY.update();
if(this.rotationPivot){
this._rotateAboutPivot(true);
}
else{
this.degreesSpring.update();
}
var changed = this.centerSpringX.current.value !== this._oldCenterX ||
this.centerSpringY.current.value !== this._oldCenterY ||
this.zoomSpring.current.value !== this._oldZoom;
this.zoomSpring.current.value !== this._oldZoom ||
this.degreesSpring.current.value !== this._oldDegrees;
this._oldCenterX = this.centerSpringX.current.value;
this._oldCenterY = this.centerSpringY.current.value;
this._oldZoom = this.zoomSpring.current.value;
this._oldDegrees = this.degreesSpring.current.value;
return changed;
var isAnimating = changed ||
!this.zoomSpring.isAtTargetValue() ||
!this.centerSpringX.isAtTargetValue() ||
!this.centerSpringY.isAtTargetValue() ||
!this.degreesSpring.isAtTargetValue();
return isAnimating;
},
// private - pass true to use spring, or a number for degrees for immediate rotation
_rotateAboutPivot: function(degreesOrUseSpring){
var useSpring = degreesOrUseSpring === true;
var delta = this.rotationPivot.minus(this.getCenter());
this.centerSpringX.shiftBy(delta.x);
this.centerSpringY.shiftBy(delta.y);
if(useSpring){
this.degreesSpring.update();
} else {
this.degreesSpring.resetTo(degreesOrUseSpring);
}
var changeInDegrees = this.degreesSpring.current.value - this._oldDegrees;
var rdelta = delta.rotate(changeInDegrees * -1).times(-1);
this.centerSpringX.shiftBy(rdelta.x);
this.centerSpringY.shiftBy(rdelta.y);
},
// private
_adjustCenterSpringsForZoomPoint: function(zoomSpringHandler) {
if (this.zoomPoint) {
var oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true);
@ -1033,7 +1241,7 @@ $.Viewport.prototype = {
*/
deltaPixelsFromPoints: function(deltaPoints, current) {
return this.deltaPixelsFromPointsNoRotate(
deltaPoints.rotate(this.getRotation()),
deltaPoints.rotate(this.getRotation(current)),
current);
},
@ -1062,7 +1270,7 @@ $.Viewport.prototype = {
*/
deltaPointsFromPixels: function(deltaPixels, current) {
return this.deltaPointsFromPixelsNoRotate(deltaPixels, current)
.rotate(-this.getRotation());
.rotate(-this.getRotation(current));
},
/**
@ -1104,7 +1312,7 @@ $.Viewport.prototype = {
// private
_pixelFromPoint: function(point, bounds) {
return this._pixelFromPointNoRotate(
point.rotate(this.getRotation(), this.getCenter(true)),
point.rotate(this.getRotation(true), this.getCenter(true)),
bounds);
},
@ -1137,8 +1345,8 @@ $.Viewport.prototype = {
*/
pointFromPixel: function(pixel, current) {
return this.pointFromPixelNoRotate(pixel, current).rotate(
-this.getRotation(),
this.getCenter(true)
-this.getRotation(current),
this.getCenter(current)
);
},
@ -1159,7 +1367,7 @@ $.Viewport.prototype = {
* @param {(OpenSeadragon.Point|Number)} viewerX either a point or the 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.
* @returns {OpenSeadragon.Point} a point representing the coordinates in the image.
*/
viewportToImageCoordinates: function(viewerX, viewerY) {
if (viewerX instanceof $.Point) {
@ -1170,8 +1378,10 @@ $.Viewport.prototype = {
if (this.viewer) {
var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.viewportToImageCoordinates] is not accurate ' +
'with multi-image; use TiledImage.viewportToImageCoordinates instead.');
if (!this.silenceMultiImageWarnings) {
$.console.error('[Viewport.viewportToImageCoordinates] is not accurate ' +
'with multi-image; use TiledImage.viewportToImageCoordinates instead.');
}
} else if (count === 1) {
// It is better to use TiledImage.viewportToImageCoordinates
// because this._contentBoundsNoRotate can not be relied on
@ -1203,7 +1413,7 @@ $.Viewport.prototype = {
* @param {(OpenSeadragon.Point | Number)} imageX the point or the
* 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.
* @returns {OpenSeadragon.Point} a point representing the coordinates in the viewport.
*/
imageToViewportCoordinates: function(imageX, imageY) {
if (imageX instanceof $.Point) {
@ -1214,8 +1424,10 @@ $.Viewport.prototype = {
if (this.viewer) {
var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.imageToViewportCoordinates] is not accurate ' +
'with multi-image; use TiledImage.imageToViewportCoordinates instead.');
if (!this.silenceMultiImageWarnings) {
$.console.error('[Viewport.imageToViewportCoordinates] is not accurate ' +
'with multi-image; use TiledImage.imageToViewportCoordinates instead.');
}
} else if (count === 1) {
// It is better to use TiledImage.viewportToImageCoordinates
// because this._contentBoundsNoRotate can not be relied on
@ -1256,8 +1468,10 @@ $.Viewport.prototype = {
if (this.viewer) {
var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.imageToViewportRectangle] is not accurate ' +
'with multi-image; use TiledImage.imageToViewportRectangle instead.');
if (!this.silenceMultiImageWarnings) {
$.console.error('[Viewport.imageToViewportRectangle] is not accurate ' +
'with multi-image; use TiledImage.imageToViewportRectangle instead.');
}
} else if (count === 1) {
// It is better to use TiledImage.imageToViewportRectangle
// because this._contentBoundsNoRotate can not be relied on
@ -1304,8 +1518,10 @@ $.Viewport.prototype = {
if (this.viewer) {
var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.viewportToImageRectangle] is not accurate ' +
'with multi-image; use TiledImage.viewportToImageRectangle instead.');
if (!this.silenceMultiImageWarnings) {
$.console.error('[Viewport.viewportToImageRectangle] is not accurate ' +
'with multi-image; use TiledImage.viewportToImageRectangle instead.');
}
} else if (count === 1) {
// It is better to use TiledImage.viewportToImageCoordinates
// because this._contentBoundsNoRotate can not be relied on
@ -1469,8 +1685,10 @@ $.Viewport.prototype = {
if (this.viewer) {
var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.viewportToImageZoom] is not ' +
'accurate with multi-image.');
if (!this.silenceMultiImageWarnings) {
$.console.error('[Viewport.viewportToImageZoom] is not ' +
'accurate with multi-image.');
}
} else if (count === 1) {
// It is better to use TiledImage.viewportToImageZoom
// because this._contentBoundsNoRotate can not be relied on
@ -1493,7 +1711,7 @@ $.Viewport.prototype = {
* 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...
* Note: not accurate with multi-image.
* Note: not accurate with multi-image; use [TiledImage.imageToViewportZoom] for the specific image of interest.
* @function
* @param {Number} imageZoom The image zoom
* target zoom.
@ -1503,8 +1721,10 @@ $.Viewport.prototype = {
if (this.viewer) {
var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.imageToViewportZoom] is not accurate ' +
'with multi-image.');
if (!this.silenceMultiImageWarnings) {
$.console.error('[Viewport.imageToViewportZoom] is not accurate ' +
'with multi-image. Instead, use [TiledImage.imageToViewportZoom] for the specific image of interest');
}
} else if (count === 1) {
// It is better to use TiledImage.imageToViewportZoom
// because this._contentBoundsNoRotate can not be relied on
@ -1524,7 +1744,7 @@ $.Viewport.prototype = {
/**
* Toggles flip state and demands a new drawing on navigator and viewer objects.
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
toggleFlip: function() {
this.setFlip(!this.getFlip());
@ -1534,7 +1754,7 @@ $.Viewport.prototype = {
/**
* Get flip state stored on viewport.
* @function
* @return {Boolean} Flip state.
* @returns {Boolean} Flip state.
*/
getFlip: function() {
return this.flipped;
@ -1544,7 +1764,7 @@ $.Viewport.prototype = {
* Sets flip state according to the state input argument.
* @function
* @param {Boolean} state - Flip state to set.
* @return {OpenSeadragon.Viewport} Chainable.
* @returns {OpenSeadragon.Viewport} Chainable.
*/
setFlip: function( state ) {
if ( this.flipped === state ) {
@ -1569,7 +1789,41 @@ $.Viewport.prototype = {
*/
this.viewer.raiseEvent('flip', {flipped: state});
return this;
}
},
/**
* Gets current max zoom pixel ratio
* @function
* @returns {Number} Max zoom pixel ratio
*/
getMaxZoomPixelRatio: function() {
return this.maxZoomPixelRatio;
},
/**
* Sets max zoom pixel ratio
* @function
* @param {Number} ratio - Max zoom pixel ratio
* @param {Boolean} [applyConstraints=true] - Apply constraints after setting ratio;
* Takes effect only if current zoom is greater than set max zoom pixel ratio
* @param {Boolean} [immediately=false] - Whether to animate to new zoom
*/
setMaxZoomPixelRatio: function(ratio, applyConstraints = true, immediately = false) {
$.console.assert(!isNaN(ratio), "[Viewport.setMaxZoomPixelRatio] ratio must be a number");
if (isNaN(ratio)) {
return;
}
this.maxZoomPixelRatio = ratio;
if (applyConstraints) {
if (this.getZoom() > this.getMaxZoom()) {
this.applyConstraints(immediately);
}
}
},
};

1301
src/webgldrawer.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
* OpenSeadragon - World
*
* Copyright (C) 2009 CodePlex Foundation
* Copyright (C) 2010-2013 OpenSeadragon contributors
* Copyright (C) 2010-2024 OpenSeadragon contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -69,6 +69,7 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
/**
* Add the specified item.
* @param {OpenSeadragon.TiledImage} item - The item to add.
* @param {Object} options - Options affecting insertion.
* @param {Number} [options.index] - Index for the item. If not specified, goes at the top.
* @fires OpenSeadragon.World.event:add-item
* @fires OpenSeadragon.World.event:metrics-change
@ -231,6 +232,206 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
}
},
/**
* Forces the system consider all tiles across all tiled images
* as outdated, and fire tile update event on relevant tiles
* Detailed description is available within the 'tile-invalidated'
* event.
* @param {Boolean} [restoreTiles=true] if true, tile processing starts from the tile original data
* @param {number} [tStamp=OpenSeadragon.now()] optionally provide tStamp of the update event
* @function
* @fires OpenSeadragon.Viewer.event:tile-invalidated
* @return {OpenSeadragon.Promise<?>}
*/
requestInvalidate: function (restoreTiles = true, tStamp = $.now()) {
$.__updated = tStamp;
// const priorityTiles = this._items.map(item => item._lastDrawn.map(x => x.tile)).flat();
// const promise = this.requestTileInvalidateEvent(priorityTiles, tStamp, restoreTiles);
// return promise.then(() => this.requestTileInvalidateEvent(this.viewer.tileCache.getLoadedTilesFor(null), tStamp, restoreTiles));
// Tile-first retrieval fires computation on tiles that share cache, which are filtered out by processing property
return this.requestTileInvalidateEvent(this.viewer.tileCache.getLoadedTilesFor(null), tStamp, restoreTiles);
// Cache-first update tile retrieval is nicer since there might be many tiles sharing
// return this.requestTileInvalidateEvent(new Set(Object.values(this.viewer.tileCache._cachesLoaded)
// .map(c => !c._destroyed && c._tiles[0])), tStamp, restoreTiles);
},
/**
* Requests tile data update.
* @function OpenSeadragon.Viewer.prototype._updateSequenceButtons
* @private
* @param {Iterable<OpenSeadragon.Tile>} tilesToProcess tiles to update
* @param {Number} tStamp timestamp in milliseconds, if active timestamp of the same value is executing,
* changes are added to the cycle, else they await next iteration
* @param {Boolean} [restoreTiles=true] if true, tile processing starts from the tile original data
* @param {Boolean} [_allowTileUnloaded=false] internal flag for calling on tiles that come new to the system
* @fires OpenSeadragon.Viewer.event:tile-invalidated
* @return {OpenSeadragon.Promise<?>}
*/
requestTileInvalidateEvent: function(tilesToProcess, tStamp, restoreTiles = true, _allowTileUnloaded = false) {
if (!this.viewer.isOpen()) {
return $.Promise.resolve();
}
const tileList = [],
tileFinishResolvers = [];
for (const tile of tilesToProcess) {
// We allow re-execution on tiles that are in process but have too low processing timestamp,
// which must be solved by ensuring subsequent data calls in the suddenly outdated processing
// pipeline take no effect.
if (!tile || (!_allowTileUnloaded && !tile.loaded)) {
continue;
}
const tileCache = tile.getCache(tile.originalCacheKey);
if (tileCache.__invStamp && tileCache.__invStamp >= tStamp) {
continue;
}
for (let t of tileCache._tiles) {
// Mark all related tiles as processing and register callback to unmark later on
t.processing = tStamp;
t.processingPromise = new $.Promise((resolve) => {
tileFinishResolvers.push(() => {
t.processing = false;
resolve(t);
});
});
}
tileCache.__invStamp = tStamp;
tileList.push(tile);
}
if (!tileList.length) {
return $.Promise.resolve();
}
// We call the event on the parent viewer window no matter what
const eventTarget = this.viewer.viewer || this.viewer;
// However, we must pick the correct drawer reference (navigator VS viewer)
const drawer = this.viewer.drawer;
const jobList = tileList.map(tile => {
const tiledImage = tile.tiledImage;
const originalCache = tile.getCache(tile.originalCacheKey);
let workingCache = null;
const getWorkingCacheData = (type) => {
if (workingCache) {
return workingCache.getDataAs(type, false);
}
const targetCopyKey = restoreTiles ? tile.originalCacheKey : tile.cacheKey;
const origCache = tile.getCache(targetCopyKey);
if (!origCache) {
$.console.error("[Tile::getData] There is no cache available for tile with key %s", targetCopyKey);
return $.Promise.reject();
}
// Here ensure type is defined, rquired by data callbacks
type = type || origCache.type;
workingCache = new $.CacheRecord().withTileReference(tile);
return origCache.getDataAs(type, true).then(data => {
workingCache.addTile(tile, data, type);
return workingCache.data;
});
};
const setWorkingCacheData = (value, type) => {
if (!workingCache) {
workingCache = new $.CacheRecord().withTileReference(tile);
workingCache.addTile(tile, value, type);
return $.Promise.resolve();
}
return workingCache.setDataAs(value, type);
};
const atomicCacheSwap = () => {
if (workingCache) {
let newCacheKey = tile.buildDistinctMainCacheKey();
tiledImage._tileCache.injectCache({
tile: tile,
cache: workingCache,
targetKey: newCacheKey,
setAsMainCache: true,
tileAllowNotLoaded: tile.loading
});
} else if (restoreTiles) {
// If we requested restore, perform now
tiledImage._tileCache.restoreTilesThatShareOriginalCache(tile, tile.getCache(tile.originalCacheKey), true);
}
};
/**
* @event tile-invalidated
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.
* @property {OpenSeadragon.Tile} tile
* @property {AsyncNullaryFunction<boolean>} outdated - predicate that evaluates to true if the event
* is outdated and should not be longer processed (has no effect)
* @property {AsyncUnaryFunction<any, string>} getData - get data of desired type (string argument)
* @property {AsyncBinaryFunction<undefined, any, string>} setData - set data (any)
* and the type of the data (string)
* @property {function} resetData - function that deletes any previous data modification in the current
* execution pipeline
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
return eventTarget.raiseEventAwaiting('tile-invalidated', {
tile: tile,
tiledImage: tiledImage,
outdated: () => originalCache.__invStamp !== tStamp || (!tile.loaded && !tile.loading),
getData: getWorkingCacheData,
setData: setWorkingCacheData,
resetData: () => {
if (workingCache) {
workingCache.destroy();
workingCache = null;
}
}
}).then(_ => {
if (originalCache.__invStamp === tStamp && (tile.loaded || tile.loading)) {
if (workingCache) {
return workingCache.prepareForRendering(drawer).then(c => {
if (c && originalCache.__invStamp === tStamp) {
atomicCacheSwap();
originalCache.__invStamp = null;
}
});
}
// If we requested restore, perform now
if (restoreTiles) {
const freshOriginalCacheRef = tile.getCache(tile.originalCacheKey);
return freshOriginalCacheRef.prepareForRendering(drawer).then((c) => {
if (c && originalCache.__invStamp === tStamp) {
atomicCacheSwap();
originalCache.__invStamp = null;
}
});
}
// Preventive call to ensure we stay compatible
const freshMainCacheRef = tile.getCache();
return freshMainCacheRef.prepareForRendering(drawer).then(() => {
atomicCacheSwap();
originalCache.__invStamp = null;
});
} else if (workingCache) {
workingCache.destroy();
workingCache = null;
}
return null;
}).catch(e => {
$.console.error("Update routine error:", e);
});
});
return $.Promise.all(jobList).then(() => {
for (let resolve of tileFinishResolvers) {
resolve();
}
this.draw();
});
},
/**
* Clears all tiles and triggers updates for all items.
*/
@ -242,11 +443,14 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
/**
* Updates (i.e. animates bounds of) all items.
* @function
* @param viewportChanged Whether the viewport changed, which indicates that
* all TiledImages need to be updated.
*/
update: function() {
update: function(viewportChanged) {
var animated = false;
for ( var i = 0; i < this._items.length; i++ ) {
animated = this._items[i].update() || animated;
animated = this._items[i].update(viewportChanged) || animated;
}
return animated;
@ -256,11 +460,11 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
* Draws all items.
*/
draw: function() {
for ( var i = 0; i < this._items.length; i++ ) {
this._items[i].draw();
}
this.viewer.drawer.draw(this._items);
this._needsDraw = false;
for (let item of this._items) {
this._needsDraw = item.setDrawn() || this._needsDraw;
}
},
/**

View file

@ -77,7 +77,7 @@
options.minLevel = 0;
options.maxLevel = options.gridSize.length - 1;
OpenSeadragon.TileSource.apply(this, [options]);
$.TileSource.apply(this, [options]);
};
$.extend($.ZoomifyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ZoomifyTileSource.prototype */ {
@ -122,10 +122,11 @@
* @function
* @param {Object} data - the raw configuration
* @param {String} url - the url the data was retrieved from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient
* @param {String} postData - HTTP POST data in k=v&k2=v2... form or null
* @returns {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile sources constructor.
*/
configure: function(data, url) {
configure: function(data, url, postData) {
return data;
},
@ -142,6 +143,13 @@
result = Math.floor(num / 256);
return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.' + this.fileFormat;
},
/**
* Equality comparator
*/
equals: function (otherSource) {
return this.tilesUrl === otherSource.tilesUrl;
}
});

300
style.css Normal file
View file

@ -0,0 +1,300 @@
* {
margin: 0;
padding: 0;
outline: 0;
}
body {
padding: 80px 100px;
font: 13px "Helvetica Neue", "Lucida Grande", "Arial";
background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9));
background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9);
background-repeat: no-repeat;
color: #555;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3 {
font-size: 22px;
color: #343434;
}
h1 em, h2 em {
padding: 0 5px;
font-weight: normal;
}
h1 {
font-size: 60px;
}
h2 {
margin-top: 10px;
}
h3 {
margin: 5px 0 10px 0;
padding-bottom: 5px;
border-bottom: 1px solid #eee;
font-size: 18px;
}
ul li {
list-style: none;
}
ul li:hover {
cursor: pointer;
color: #2e2e2e;
}
ul li .path {
padding-left: 5px;
font-weight: bold;
}
ul li .line {
padding-right: 5px;
font-style: italic;
}
ul li:first-child .path {
padding-left: 0;
}
p {
line-height: 1.5;
}
a {
color: #555;
text-decoration: none;
}
a:hover {
color: #303030;
}
#stacktrace {
margin-top: 15px;
}
.directory h1 {
margin-bottom: 15px;
font-size: 18px;
}
ul#files {
width: 100%;
height: 100%;
overflow: hidden;
}
ul#files li {
float: left;
width: 30%;
line-height: 25px;
margin: 1px;
}
ul#files li a {
display: block;
height: 25px;
border: 1px solid transparent;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
overflow: hidden;
white-space: nowrap;
}
ul#files li a:focus,
ul#files li a:hover {
background: rgba(255,255,255,0.65);
border: 1px solid #ececec;
}
ul#files li a.highlight {
-webkit-transition: background .4s ease-in-out;
background: #ffff4f;
border-color: #E9DC51;
}
#search {
display: block;
position: fixed;
top: 20px;
right: 20px;
width: 90px;
-webkit-transition: width ease 0.2s, opacity ease 0.4s;
-moz-transition: width ease 0.2s, opacity ease 0.4s;
-webkit-border-radius: 32px;
-moz-border-radius: 32px;
-webkit-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
-moz-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
-webkit-font-smoothing: antialiased;
text-align: left;
font: 13px "Helvetica Neue", Arial, sans-serif;
padding: 4px 10px;
border: none;
background: transparent;
margin-bottom: 0;
outline: none;
opacity: 0.7;
color: #888;
}
#search:focus {
width: 120px;
opacity: 1.0;
}
/*views*/
#files span {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
text-indent: 10px;
}
#files .name {
background-repeat: no-repeat;
}
#files .icon .name {
text-indent: 28px;
}
/*tiles*/
.view-tiles .name {
width: 100%;
background-position: 8px 5px;
margin-left: 30px;
}
.view-tiles .size,
.view-tiles .date {
display: none;
}
.view-tiles a {
position: relative;
}
/*hack: reuse empty to find folders*/
#files .size:empty {
width: 20px;
height: 14px;
background-color: #f9d342; /* Folder color */
position: absolute;
border-radius: 4px;
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1); /* Optional shadow for effect */
display: block !important;
float: left;
left: 13px;
top: 5px;
}
#files .size:empty:before {
content: '';
position: absolute;
top: -2px;
left: 2px;
width: 12px;
height: 4px;
background-color: #f9d342;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
#files .size:empty:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 8px;
height: 4px;
background-color: #e8c233; /* Slightly darker shade for the tab */
border-top-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/*details*/
ul#files.view-details li {
float: none;
display: block;
width: 90%;
}
ul#files.view-details li.header {
height: 25px;
background: #000;
color: #fff;
font-weight: bold;
}
.view-details .header {
border-radius: 5px;
}
.view-details .name {
width: 60%;
background-position: 8px 5px;
}
.view-details .size {
width: 10%;
}
.view-details .date {
width: 30%;
}
.view-details .size,
.view-details .date {
text-align: right;
direction: rtl;
}
/*mobile*/
@media (max-width: 768px) {
body {
font-size: 13px;
line-height: 16px;
padding: 0;
}
#search {
position: static;
width: 100%;
font-size: 2em;
line-height: 1.8em;
text-indent: 10px;
border: 0;
border-radius: 0;
padding: 10px 0;
margin: 0;
}
#search:focus {
width: 100%;
border: 0;
opacity: 1;
}
.directory h1 {
font-size: 2em;
line-height: 1.5em;
color: #fff;
background: #000;
padding: 15px 10px;
margin: 0;
}
ul#files {
border-top: 1px solid #cacaca;
}
ul#files li {
float: none;
width: auto !important;
display: block;
border-bottom: 1px solid #cacaca;
font-size: 2em;
line-height: 1.2em;
text-indent: 0;
margin: 0;
}
ul#files li:nth-child(odd) {
background: #e0e0e0;
}
ul#files li a {
height: auto;
border: 0;
border-radius: 0;
padding: 15px 10px;
}
ul#files li a:focus,
ul#files li a:hover {
border: 0;
}
#files .header,
#files .size,
#files .date {
display: none !important;
}
#files .name {
float: none;
display: inline-block;
width: 100%;
text-indent: 0;
background-position: 0 50%;
}
#files .icon .name {
text-indent: 41px;
}
#files .size:empty {
top: 23px;
left: 5px;
}
}

View file

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>OpenSeadragon QUnit</title>
<link rel="stylesheet" href="/node_modules/qunitjs/qunit/qunit.css">
<link rel="stylesheet" href="/node_modules/qunit/qunit/qunit.css">
<link rel="stylesheet" href="/test/lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css">
<link rel="stylesheet" href="/test/helpers/test.css">
</head>
@ -15,7 +15,7 @@
var isCoverageTest = true;
</script>
<script src="/node_modules/qunitjs/qunit/qunit.js"></script>
<script src="/node_modules/qunit/qunit/qunit.js"></script>
<script src="/test/lib/jquery-1.9.1.min.js"></script>
<script src="/test/lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js"></script>
<script src="/test/lib/jquery.simulate.js"></script>
@ -58,6 +58,7 @@
<!-- Helpers -->
<script src="/test/helpers/legacy.mouse.shim.js"></script>
<script src="/test/helpers/mocks.js"></script>
<script src="/test/helpers/test.js"></script>
<script src="/test/helpers/touch.js"></script>
@ -65,6 +66,7 @@
<!-- Polyfill must be inserted first because it is testing functions
reassignments which could be done by other test. -->
<script src="/test/modules/polyfills.js"></script>
<script src="/test/modules/event-source.js"></script>
<script src="/test/modules/basic.js"></script>
<script src="/test/modules/strings.js"></script>
<script src="/test/modules/formats.js"></script>
@ -86,6 +88,7 @@
<script src="/test/modules/spring.js"></script>
<script src="/test/modules/rectangle.js"></script>
<script src="/test/modules/ajax-tiles.js"></script>
<script src="/test/modules/ajax-post-data.js"></script>
<script src="/test/modules/imageloader.js"></script>
<script src="/test/modules/iiif.js"></script>
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up)

View file

@ -18,7 +18,8 @@
"jpg",
"png",
"gif"
]
]
}
]
],
"xmp": "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n <rdf:Description rdf:about=\"\"\n xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"\n xmlns:aux=\"http://ns.adobe.com/exif/1.0/aux/\"\n xmlns:photoshop=\"http://ns.adobe.com/photoshop/1.0/\"\n xmlns:Iptc4xmpCore=\"http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/\"\n xmlns:tiff=\"http://ns.adobe.com/tiff/1.0/\"\n xmlns:exif=\"http://ns.adobe.com/exif/1.0/\"\n xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n xmp:CreatorTool=\"Capture One 11 Macintosh\"\n xmp:CreateDate=\"2019-08-21T20:54:20\"\n xmp:Rating=\"4\"\n aux:SerialNumber=\"GP001601\"\n aux:ImageNumber=\"30012\"\n aux:Firmware=\"IQ280, Factory Firmware: 8.05.36\"\n photoshop:CaptionWriter=\"\"\n photoshop:Headline=\"\"\n photoshop:City=\"\"\n photoshop:State=\"\"\n photoshop:Country=\"\"\n photoshop:Source=\"\"\n photoshop:Instructions=\"\"\n photoshop:AuthorsPosition=\"\"\n photoshop:TransmissionReference=\"\"\n photoshop:Credit=\"\"\n photoshop:LegacyIPTCDigest=\"B135BFFD6A4CFB049F834A3F370A9AE3\"\n photoshop:DateCreated=\"2019-08-21T20:54:20\"\n Iptc4xmpCore:Location=\"\"\n Iptc4xmpCore:IntellectualGenre=\"\"\n Iptc4xmpCore:CountryCode=\"\"\n tiff:ImageWidth=\"2088\"\n tiff:ImageLength=\"3000\"\n tiff:Compression=\"1\"\n tiff:PhotometricInterpretation=\"2\"\n tiff:Orientation=\"1\"\n tiff:SamplesPerPixel=\"3\"\n tiff:PlanarConfiguration=\"1\"\n tiff:XResolution=\"400/1\"\n tiff:YResolution=\"400/1\"\n tiff:ResolutionUnit=\"2\"\n tiff:Make=\"Phase One\"\n tiff:Model=\"IQ280\"\n tiff:Software=\"Capture One 11 Macintosh\"\n exif:ExifVersion=\"0230\"\n exif:PixelXDimension=\"2088\"\n exif:PixelYDimension=\"3000\"\n exif:ExposureTime=\"1/4\"\n exif:ExposureProgram=\"1\"\n exif:ShutterSpeedValue=\"2/1\"\n exif:MeteringMode=\"1\"\n exif:LightSource=\"255\"\n exif:FocalPlaneXResolution=\"63015385/32768\"\n exif:FocalPlaneYResolution=\"63015385/32768\"\n exif:FocalPlaneResolutionUnit=\"3\"\n exif:FileSource=\"3\"\n exif:SceneType=\"1\"\n exif:WhiteBalance=\"5\"\n exif:ImageUniqueID=\"00E058000075000004019E064100753C\">\n <Iptc4xmpCore:CreatorContactInfo\n Iptc4xmpCore:CiEmailWork=\"digicc@library.illinois.edu\"\n Iptc4xmpCore:CiTelWork=\"+1(217)2442062\"\n Iptc4xmpCore:CiAdrPcode=\"61801\"\n Iptc4xmpCore:CiUrlWork=\"http://www.library.illinois.edu/staff/preservation/digitization/\"\n Iptc4xmpCore:CiAdrExtadr=\"1408 W. Gregory Drive\"\n Iptc4xmpCore:CiAdrCity=\"Urbana\"\n Iptc4xmpCore:CiAdrCtry=\"United States\"\n Iptc4xmpCore:CiAdrRegion=\"Illinois\"/>\n <tiff:BitsPerSample>\n <rdf:Seq>\n <rdf:li>8 8 8</rdf:li>\n </rdf:Seq>\n </tiff:BitsPerSample>\n <exif:ISOSpeedRatings>\n <rdf:Seq>\n <rdf:li>50</rdf:li>\n </rdf:Seq>\n </exif:ISOSpeedRatings>\n <dc:creator>\n <rdf:Seq>\n <rdf:li>University of Illinois Library</rdf:li>\n </rdf:Seq>\n </dc:creator>\n </rdf:Description>\n </rdf:RDF>"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View file

@ -0,0 +1,15 @@
{
"@context": "http://iiif.io/api/image/3/context.json",
"id": "http://localhost:8000/test/data/iiif_3_0_sizes",
"protocol": "http://iiif.io/api/image",
"width": 6976,
"height": 5074,
"profile": "level0",
"sizes" : [
{"width" : 400, "height" : 291},
{"width" : 800, "height" : 582},
{"width" : 1600, "height" : 1164},
{"width" : 3200, "height": 2328},
{"width" : 6976, "height": 5074}
]
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View file

@ -0,0 +1,11 @@
{
"@context": "http://iiif.io/api/image/3/context.json",
"id": "http://localhost:8000/test/data/iiif_3_0_tiled",
"protocol": "http://iiif.io/api/image",
"height": 1024,
"width": 775,
"tiles" : [{"width":256, "scaleFactors":[1,2,4,8]}],
"profile": "level2",
"extraQualities": ["bitonal", "grey", "color"],
"extraFormats": ["jpg", "png", "gif" ]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 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

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