diva.js 6.0.1 → 7.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.clang-format +7 -0
- package/.github/workflows/npm-publish.yml +45 -0
- package/LICENSE +55 -0
- package/Makefile +75 -0
- package/README.md +15 -108
- package/elm.json +32 -0
- package/package.json +12 -59
- package/review/elm.json +52 -0
- package/review/src/ReviewConfig.elm +87 -0
- package/scripts/elm-esm.sh +40 -0
- package/scripts/minify-css.mjs +31 -0
- package/src/Filters.elm +1044 -0
- package/src/Main.elm +1217 -0
- package/src/Model.elm +213 -0
- package/src/Msg.elm +59 -0
- package/src/Utilities.elm +46 -0
- package/src/View/CollectionExplorer.elm +172 -0
- package/src/View/Helpers.elm +86 -0
- package/src/View/HtmlRenderer.elm +136 -0
- package/src/View/Icons.elm +159 -0
- package/src/View/ManifestInfoModal.elm +363 -0
- package/src/View/PageViewModal.elm +1046 -0
- package/src/View/Sidebar.elm +786 -0
- package/src/View/Toolbar.elm +189 -0
- package/src/View.elm +244 -0
- package/src/diva.ts +802 -0
- package/src/filters.ts +1843 -0
- package/src/styles/app.css +328 -0
- package/src/styles/collection.css +75 -0
- package/src/styles/modal.css +388 -0
- package/src/styles/sidebar.css +215 -0
- package/src/styles/theme.css +39 -0
- package/src/styles/toolbar.css +154 -0
- package/src/viewer-element.ts +1307 -0
- package/testing/index.html +52 -0
- package/testing/testing.html +231 -0
- package/tsconfig.json +12 -0
- package/AUTHORS +0 -22
- package/_site/diva.iml +0 -11
- package/build/diva.css +0 -554
- package/build/diva.css.map +0 -1
- package/build/diva.js +0 -9
- package/build/diva.js.map +0 -1
- package/build/plugins/download.js +0 -2
- package/build/plugins/download.js.map +0 -1
- package/build/plugins/manipulation.js +0 -2
- package/build/plugins/manipulation.js.map +0 -1
- package/build/plugins/metadata.js +0 -2
- package/build/plugins/metadata.js.map +0 -1
- package/diva.iml +0 -11
- package/index.html +0 -28
- package/karma.conf.js +0 -87
- package/source/css/_mixins.scss +0 -43
- package/source/css/_variables.scss +0 -50
- package/source/css/_viewer.scss +0 -462
- package/source/css/diva.scss +0 -15
- package/source/css/plugins/_manipulation.scss +0 -228
- package/source/css/plugins/_metadata.scss +0 -31
- package/source/img/adjust.svg +0 -11
- package/source/img/book-view.svg +0 -6
- package/source/img/close.svg +0 -6
- package/source/img/download.svg +0 -6
- package/source/img/from-fullscreen.svg +0 -8
- package/source/img/grid-fewer.svg +0 -6
- package/source/img/grid-more.svg +0 -6
- package/source/img/grid-view.svg +0 -6
- package/source/img/link.svg +0 -6
- package/source/img/metadata.svg +0 -9
- package/source/img/page-view.svg +0 -6
- package/source/img/to-fullscreen.svg +0 -11
- package/source/img/zoom-in.svg +0 -6
- package/source/img/zoom-out.svg +0 -7
- package/source/js/composite-image.js +0 -174
- package/source/js/diva-global.js +0 -7
- package/source/js/diva.js +0 -1543
- package/source/js/document-handler.js +0 -180
- package/source/js/document-layout.js +0 -286
- package/source/js/exceptions.js +0 -26
- package/source/js/gesture-events.js +0 -190
- package/source/js/grid-handler.js +0 -122
- package/source/js/iiif-source-adapter.js +0 -63
- package/source/js/image-cache.js +0 -113
- package/source/js/image-manifest.js +0 -157
- package/source/js/image-request-handler.js +0 -76
- package/source/js/interpolate-animation.js +0 -122
- package/source/js/page-layouts/book-layout.js +0 -161
- package/source/js/page-layouts/grid-layout.js +0 -97
- package/source/js/page-layouts/index.js +0 -38
- package/source/js/page-layouts/page-dimensions.js +0 -9
- package/source/js/page-layouts/singles-layout.js +0 -27
- package/source/js/page-overlay-manager.js +0 -102
- package/source/js/page-tools-overlay.js +0 -95
- package/source/js/parse-iiif-manifest.js +0 -302
- package/source/js/plugins/_filters.js +0 -679
- package/source/js/plugins/download.js +0 -83
- package/source/js/plugins/manipulation.js +0 -837
- package/source/js/plugins/metadata.js +0 -190
- package/source/js/renderer.js +0 -584
- package/source/js/settings-view.js +0 -30
- package/source/js/tile-coverage-map.js +0 -25
- package/source/js/toolbar.js +0 -572
- package/source/js/utils/dragscroll.js +0 -106
- package/source/js/utils/elt.js +0 -94
- package/source/js/utils/events.js +0 -190
- package/source/js/utils/get-scrollbar-width.js +0 -29
- package/source/js/utils/hash-params.js +0 -86
- package/source/js/utils/parse-label-value.js +0 -34
- package/source/js/utils/vanilla.kinetic.js +0 -527
- package/source/js/validation-runner.js +0 -177
- package/source/js/viewer-core.js +0 -1505
- package/source/js/viewport.js +0 -143
- package/test/_setup.js +0 -13
- package/test/composite-image_test.js +0 -94
- package/test/diva_test.js +0 -43
- package/test/hash-params_test.js +0 -221
- package/test/image-cache_test.js +0 -106
- package/test/main.js +0 -6
- package/test/manifests/beromunsterManifest.json +0 -15514
- package/test/manifests/iiifv2.json +0 -11032
- package/test/manifests/iiifv2pages.json +0 -30437
- package/test/manifests/iiifv3.json +0 -10965
- package/test/navigation_test.js +0 -355
- package/test/parse-iiif-manifest_test.js +0 -68
- package/test/public_test.js +0 -881
- package/test/settings_test.js +0 -487
- package/test/utils/book-layout_test.js +0 -148
- package/test/utils/elt_test.js +0 -102
- package/test/utils/events_test.js +0 -245
- package/test/utils/hash-params_test.js +0 -79
- package/test/utils/parse-label-value_test.js +0 -45
- package/test/z_plugins_test.js +0 -180
- package/webpack.config.js +0 -58
- package/webpack.config.test.js +0 -45
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import maxBy from 'lodash.maxby';
|
|
2
|
-
|
|
3
|
-
export default class GridHandler
|
|
4
|
-
{
|
|
5
|
-
constructor (viewerCore)
|
|
6
|
-
{
|
|
7
|
-
this._viewerCore = viewerCore;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// USER EVENTS
|
|
11
|
-
onDoubleClick (event, coords)
|
|
12
|
-
{
|
|
13
|
-
const position = this._viewerCore.getPagePositionAtViewportOffset(coords);
|
|
14
|
-
|
|
15
|
-
const layout = this._viewerCore.getCurrentLayout();
|
|
16
|
-
const viewport = this._viewerCore.getViewport();
|
|
17
|
-
const pageToViewportCenterOffset = layout.getPageToViewportCenterOffset(position.anchorPage, viewport);
|
|
18
|
-
|
|
19
|
-
this._viewerCore.reload({
|
|
20
|
-
inGrid: false,
|
|
21
|
-
goDirectlyTo: position.anchorPage,
|
|
22
|
-
horizontalOffset: pageToViewportCenterOffset.x + position.offset.left,
|
|
23
|
-
verticalOffset: pageToViewportCenterOffset.y + position.offset.top
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
onPinch ()
|
|
28
|
-
{
|
|
29
|
-
this._viewerCore.reload({inGrid: false});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// VIEW EVENTS
|
|
33
|
-
onViewWillLoad ()
|
|
34
|
-
{
|
|
35
|
-
// FIXME(wabain): Should something happen here?
|
|
36
|
-
/* No-op */
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
onViewDidLoad ()
|
|
40
|
-
{
|
|
41
|
-
// FIXME(wabain): Should something happen here?
|
|
42
|
-
/* No-op */
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
onViewDidUpdate (renderedPages, targetPage)
|
|
46
|
-
{
|
|
47
|
-
// return early if there are no rendered pages in view.
|
|
48
|
-
if (renderedPages.length === 0) return;
|
|
49
|
-
|
|
50
|
-
// calculate the visible pages from the rendered pages
|
|
51
|
-
let temp = this._viewerCore.viewerState.viewport.intersectionTolerance;
|
|
52
|
-
// without setting to 0, isPageVisible returns true for pages out of viewport by intersectionTolerance
|
|
53
|
-
this._viewerCore.viewerState.viewport.intersectionTolerance = 0;
|
|
54
|
-
let visiblePages = renderedPages.filter(index => this._viewerCore.viewerState.renderer.isPageVisible(index));
|
|
55
|
-
// reset back to original value after getting true visible pages
|
|
56
|
-
this._viewerCore.viewerState.viewport.intersectionTolerance = temp;
|
|
57
|
-
|
|
58
|
-
if (targetPage !== null)
|
|
59
|
-
{
|
|
60
|
-
this._viewerCore.setCurrentPages(targetPage, visiblePages);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Select the current page from the first row if it is fully visible, or from
|
|
65
|
-
// the second row if it is fully visible, or from the centermost row otherwise.
|
|
66
|
-
// If the current page is in that group then don't change it. Otherwise, set
|
|
67
|
-
// the current page to the group's first page.
|
|
68
|
-
|
|
69
|
-
const layout = this._viewerCore.getCurrentLayout();
|
|
70
|
-
const groups = [];
|
|
71
|
-
|
|
72
|
-
renderedPages.forEach(pageIndex =>
|
|
73
|
-
{
|
|
74
|
-
const group = layout.getPageInfo(pageIndex).group;
|
|
75
|
-
if (groups.length === 0 || group !== groups[groups.length - 1])
|
|
76
|
-
{
|
|
77
|
-
groups.push(group);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const viewport = this._viewerCore.getViewport();
|
|
82
|
-
let chosenGroup;
|
|
83
|
-
|
|
84
|
-
if (groups.length === 1 || groups[0].region.top >= viewport.top)
|
|
85
|
-
{
|
|
86
|
-
chosenGroup = groups[0];
|
|
87
|
-
}
|
|
88
|
-
else if (groups[1].region.bottom <= viewport.bottom)
|
|
89
|
-
{
|
|
90
|
-
chosenGroup = groups[1];
|
|
91
|
-
}
|
|
92
|
-
else
|
|
93
|
-
{
|
|
94
|
-
chosenGroup = getCentermostGroup(groups, viewport);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const currentPage = this._viewerCore.getSettings().activePageIndex;
|
|
98
|
-
|
|
99
|
-
const hasCurrentPage = chosenGroup.pages.some(page => page.index === currentPage);
|
|
100
|
-
|
|
101
|
-
if (!hasCurrentPage)
|
|
102
|
-
{
|
|
103
|
-
this._viewerCore.setCurrentPages(chosenGroup.pages[0].index, visiblePages);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
destroy ()
|
|
108
|
-
{
|
|
109
|
-
// No-op
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function getCentermostGroup (groups, viewport)
|
|
114
|
-
{
|
|
115
|
-
const viewportMiddle = viewport.top + viewport.height / 2;
|
|
116
|
-
|
|
117
|
-
return maxBy(groups, group =>
|
|
118
|
-
{
|
|
119
|
-
const groupMiddle = group.region.top + group.dimensions.height / 2;
|
|
120
|
-
return -Math.abs(viewportMiddle - groupMiddle);
|
|
121
|
-
});
|
|
122
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
export default class IIIFSourceAdapter
|
|
2
|
-
{
|
|
3
|
-
getPageImageURL (manifest, pageIndex, size)
|
|
4
|
-
{
|
|
5
|
-
let dimens;
|
|
6
|
-
|
|
7
|
-
if (!size || (size.width == null && size.height == null))
|
|
8
|
-
{
|
|
9
|
-
dimens = 'full';
|
|
10
|
-
}
|
|
11
|
-
else
|
|
12
|
-
{
|
|
13
|
-
dimens = (size.width == null ? '' : size.width) + ',' + (size.height == null ? '' : size.height);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const page = manifest.pages[pageIndex];
|
|
17
|
-
const quality = (page.api > 1.1) ? 'default' : 'native';
|
|
18
|
-
|
|
19
|
-
return encodeURI(page.url + 'full/' + dimens + '/0/' + quality + '.jpg');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
getTileImageURL (manifest, pageIndex, params)
|
|
23
|
-
{
|
|
24
|
-
const page = manifest.pages[pageIndex];
|
|
25
|
-
|
|
26
|
-
let height, width;
|
|
27
|
-
|
|
28
|
-
if (params.row === params.rowCount - 1)
|
|
29
|
-
{
|
|
30
|
-
height = page.d[params.zoomLevel].h - (params.rowCount - 1) * params.tileDimensions.height;
|
|
31
|
-
}
|
|
32
|
-
else
|
|
33
|
-
{
|
|
34
|
-
height = params.tileDimensions.height;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (params.col === params.colCount - 1)
|
|
38
|
-
{
|
|
39
|
-
width = page.d[params.zoomLevel].w - (params.colCount - 1) * params.tileDimensions.width;
|
|
40
|
-
}
|
|
41
|
-
else
|
|
42
|
-
{
|
|
43
|
-
width = params.tileDimensions.width;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const zoomDifference = Math.pow(2, manifest.maxZoom - params.zoomLevel);
|
|
47
|
-
|
|
48
|
-
let x = params.col * params.tileDimensions.width * zoomDifference;
|
|
49
|
-
let y = params.row * params.tileDimensions.height * zoomDifference;
|
|
50
|
-
|
|
51
|
-
if (page.hasOwnProperty('xoffset'))
|
|
52
|
-
{
|
|
53
|
-
x += page.xoffset;
|
|
54
|
-
y += page.yoffset;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const region = [x, y, width * zoomDifference, height * zoomDifference].join(',');
|
|
58
|
-
|
|
59
|
-
const quality = (page.api > 1.1) ? 'default' : 'native';
|
|
60
|
-
|
|
61
|
-
return encodeURI(page.url + region + '/' + width + ',' + height + '/0/' + quality + '.jpg');
|
|
62
|
-
}
|
|
63
|
-
}
|
package/source/js/image-cache.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
const debug = require('debug')('diva:ImageCache');
|
|
2
|
-
|
|
3
|
-
/* FIXME(wabain): The caching strategy here is completely
|
|
4
|
-
* arbitrary and the implementation isn't especially efficient.
|
|
5
|
-
*/
|
|
6
|
-
const DEFAULT_MAX_KEYS = 100;
|
|
7
|
-
|
|
8
|
-
export default class ImageCache
|
|
9
|
-
{
|
|
10
|
-
constructor (options)
|
|
11
|
-
{
|
|
12
|
-
options = options || { maxKeys: DEFAULT_MAX_KEYS };
|
|
13
|
-
this.maxKeys = options.maxKeys || DEFAULT_MAX_KEYS;
|
|
14
|
-
|
|
15
|
-
this._held = {};
|
|
16
|
-
this._urls = {};
|
|
17
|
-
this._lru = [];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
get (url)
|
|
21
|
-
{
|
|
22
|
-
const record = this._urls[url];
|
|
23
|
-
return record ? record.img : null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
has (url)
|
|
27
|
-
{
|
|
28
|
-
return !!this._urls[url];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
put (url, img)
|
|
32
|
-
{
|
|
33
|
-
let record = this._urls[url];
|
|
34
|
-
if (record)
|
|
35
|
-
{
|
|
36
|
-
// FIXME: Does this make sense for this use case?
|
|
37
|
-
record.img = img;
|
|
38
|
-
this._promote(record);
|
|
39
|
-
}
|
|
40
|
-
else
|
|
41
|
-
{
|
|
42
|
-
record = {
|
|
43
|
-
img: img,
|
|
44
|
-
url: url
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
this._urls[url] = record;
|
|
48
|
-
this._tryEvict(1);
|
|
49
|
-
this._lru.unshift(record);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
_promote (record)
|
|
54
|
-
{
|
|
55
|
-
const index = this._lru.indexOf(record);
|
|
56
|
-
this._lru.splice(index, 1);
|
|
57
|
-
this._lru.unshift(record);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
_tryEvict (extraCapacity)
|
|
61
|
-
{
|
|
62
|
-
const allowedEntryCount = this.maxKeys - extraCapacity;
|
|
63
|
-
|
|
64
|
-
if (this._lru.length <= allowedEntryCount)
|
|
65
|
-
return;
|
|
66
|
-
|
|
67
|
-
let evictionIndex = this._lru.length - 1;
|
|
68
|
-
|
|
69
|
-
for (;;)
|
|
70
|
-
{
|
|
71
|
-
const target = this._lru[evictionIndex];
|
|
72
|
-
|
|
73
|
-
if (!this._held[target.url])
|
|
74
|
-
{
|
|
75
|
-
debug('Evicting image %s', target.url);
|
|
76
|
-
this._lru.splice(evictionIndex, 1);
|
|
77
|
-
delete this._urls[target.url];
|
|
78
|
-
|
|
79
|
-
if (this._lru.length <= allowedEntryCount)
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (evictionIndex === 0)
|
|
84
|
-
{
|
|
85
|
-
/* istanbul ignore next */
|
|
86
|
-
debug.enabled && debug('Cache overfull by %s (all entries are being held)',
|
|
87
|
-
this._lru.length - allowedEntryCount);
|
|
88
|
-
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
evictionIndex--;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
acquire (url)
|
|
97
|
-
{
|
|
98
|
-
this._held[url] = (this._held[url] || 0) + 1;
|
|
99
|
-
this._promote(this._urls[url]);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
release (url)
|
|
103
|
-
{
|
|
104
|
-
const count = this._held[url];
|
|
105
|
-
|
|
106
|
-
if (count > 1)
|
|
107
|
-
this._held[url]--;
|
|
108
|
-
else
|
|
109
|
-
delete this._held[url];
|
|
110
|
-
|
|
111
|
-
this._tryEvict(0);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import parseIIIFManifest from './parse-iiif-manifest';
|
|
2
|
-
import IIIFSourceAdapter from "./iiif-source-adapter";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export default class ImageManifest
|
|
6
|
-
{
|
|
7
|
-
constructor (data, urlAdapter)
|
|
8
|
-
{
|
|
9
|
-
// Save all the data we need
|
|
10
|
-
this.pages = data.pgs;
|
|
11
|
-
this.maxZoom = data.max_zoom;
|
|
12
|
-
this.maxRatio = data.dims.max_ratio;
|
|
13
|
-
this.minRatio = data.dims.min_ratio;
|
|
14
|
-
this.itemTitle = data.item_title;
|
|
15
|
-
this.metadata = data.metadata;
|
|
16
|
-
|
|
17
|
-
// Only given for IIIF manifests
|
|
18
|
-
this.paged = !!data.paged;
|
|
19
|
-
|
|
20
|
-
// These are arrays, the index corresponding to the zoom level
|
|
21
|
-
this._maxWidths = data.dims.max_w;
|
|
22
|
-
this._maxHeights = data.dims.max_h;
|
|
23
|
-
this._averageWidths = data.dims.a_wid;
|
|
24
|
-
this._averageHeights = data.dims.a_hei;
|
|
25
|
-
this._totalHeights = data.dims.t_hei;
|
|
26
|
-
this._totalWidths = data.dims.t_wid;
|
|
27
|
-
|
|
28
|
-
this._urlAdapter = urlAdapter;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
static fromIIIF (iiifManifest)
|
|
32
|
-
{
|
|
33
|
-
const data = parseIIIFManifest(iiifManifest);
|
|
34
|
-
return new ImageManifest(data, new IIIFSourceAdapter());
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
isPageValid (pageIndex, showNonPagedPages)
|
|
38
|
-
{
|
|
39
|
-
if (!showNonPagedPages && this.paged && !this.pages[pageIndex].paged)
|
|
40
|
-
{
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return pageIndex >= 0 && pageIndex < this.pages.length;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
getMaxPageDimensions (pageIndex)
|
|
48
|
-
{
|
|
49
|
-
const maxDims = this.pages[pageIndex].d[this.maxZoom];
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
height: maxDims.h,
|
|
53
|
-
width: maxDims.w
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
getPageDimensionsAtZoomLevel (pageIndex, zoomLevel)
|
|
58
|
-
{
|
|
59
|
-
const maxDims = this.pages[pageIndex].d[this.maxZoom];
|
|
60
|
-
|
|
61
|
-
const scaleRatio = getScaleRatio(this.maxZoom, zoomLevel);
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
height: maxDims.h * scaleRatio,
|
|
65
|
-
width: maxDims.w * scaleRatio
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Returns a URL for the image of the given page. The optional size
|
|
71
|
-
* parameter supports setting the image width or height (default is
|
|
72
|
-
* full-sized).
|
|
73
|
-
*/
|
|
74
|
-
getPageImageURL (pageIndex, size)
|
|
75
|
-
{
|
|
76
|
-
return this._urlAdapter.getPageImageURL(this, pageIndex, size);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Return an array of tile objects for the specified page and integer zoom level
|
|
81
|
-
*/
|
|
82
|
-
getPageImageTiles (pageIndex, zoomLevel, tileDimensions)
|
|
83
|
-
{
|
|
84
|
-
const page = this.pages[pageIndex];
|
|
85
|
-
|
|
86
|
-
if (!isFinite(zoomLevel) || zoomLevel % 1 !== 0)
|
|
87
|
-
{
|
|
88
|
-
throw new TypeError('Zoom level must be an integer: ' + zoomLevel);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const rows = Math.ceil(page.d[zoomLevel].h / tileDimensions.height);
|
|
92
|
-
const cols = Math.ceil(page.d[zoomLevel].w / tileDimensions.width);
|
|
93
|
-
|
|
94
|
-
const tiles = [];
|
|
95
|
-
|
|
96
|
-
let row, col, url;
|
|
97
|
-
|
|
98
|
-
for (row = 0; row < rows; row++)
|
|
99
|
-
{
|
|
100
|
-
for (col = 0; col < cols; col++)
|
|
101
|
-
{
|
|
102
|
-
url = this._urlAdapter.getTileImageURL(this, pageIndex, {
|
|
103
|
-
row: row,
|
|
104
|
-
col: col,
|
|
105
|
-
rowCount: rows,
|
|
106
|
-
colCount: cols,
|
|
107
|
-
zoomLevel: zoomLevel,
|
|
108
|
-
tileDimensions: tileDimensions
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// FIXME: Dimensions should account for partial tiles (e.g. the
|
|
112
|
-
// last row and column in a tiled image)
|
|
113
|
-
tiles.push({
|
|
114
|
-
row: row,
|
|
115
|
-
col: col,
|
|
116
|
-
zoomLevel: zoomLevel,
|
|
117
|
-
dimensions: {
|
|
118
|
-
height: tileDimensions.height,
|
|
119
|
-
width: tileDimensions.width
|
|
120
|
-
},
|
|
121
|
-
offset: {
|
|
122
|
-
top: row * tileDimensions.height,
|
|
123
|
-
left: col * tileDimensions.width
|
|
124
|
-
},
|
|
125
|
-
url: url
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
zoomLevel: zoomLevel,
|
|
132
|
-
rows: rows,
|
|
133
|
-
cols: cols,
|
|
134
|
-
tiles: tiles
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
ImageManifest.prototype.getMaxWidth = zoomedPropertyGetter('_maxWidths');
|
|
140
|
-
ImageManifest.prototype.getMaxHeight = zoomedPropertyGetter('_maxHeights');
|
|
141
|
-
ImageManifest.prototype.getAverageWidth = zoomedPropertyGetter('_averageWidths');
|
|
142
|
-
ImageManifest.prototype.getAverageHeight = zoomedPropertyGetter('_averageHeights');
|
|
143
|
-
ImageManifest.prototype.getTotalWidth = zoomedPropertyGetter('_totalWidths');
|
|
144
|
-
ImageManifest.prototype.getTotalHeight = zoomedPropertyGetter('_totalHeights');
|
|
145
|
-
|
|
146
|
-
function zoomedPropertyGetter (privateName)
|
|
147
|
-
{
|
|
148
|
-
return function (zoomLevel)
|
|
149
|
-
{
|
|
150
|
-
return this[privateName][zoomLevel];
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function getScaleRatio (sourceZoomLevel, targetZoomLevel)
|
|
155
|
-
{
|
|
156
|
-
return 1 / Math.pow(2, sourceZoomLevel - targetZoomLevel);
|
|
157
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handler for the request for an image tile
|
|
3
|
-
*
|
|
4
|
-
* @param url
|
|
5
|
-
* @param callback
|
|
6
|
-
* @constructor
|
|
7
|
-
*/
|
|
8
|
-
export default class ImageRequestHandler
|
|
9
|
-
{
|
|
10
|
-
constructor (options)
|
|
11
|
-
{
|
|
12
|
-
this._url = options.url;
|
|
13
|
-
this._callback = options.load;
|
|
14
|
-
this._errorCallback = options.error;
|
|
15
|
-
this.timeoutTime = options.timeoutTime || 0;
|
|
16
|
-
this._aborted = this._complete = false;
|
|
17
|
-
|
|
18
|
-
//Use a timeout to allow the requests to be debounced (as they are in renderer)
|
|
19
|
-
this.timeout = setTimeout(() => {
|
|
20
|
-
// Initiate the request
|
|
21
|
-
this._image = new Image();
|
|
22
|
-
this._image.crossOrigin = "anonymous";
|
|
23
|
-
this._image.onload = this._handleLoad.bind(this);
|
|
24
|
-
this._image.onerror = this._handleError.bind(this);
|
|
25
|
-
this._image.src = options.url;
|
|
26
|
-
|
|
27
|
-
}, this.timeoutTime);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
abort ()
|
|
31
|
-
{
|
|
32
|
-
clearTimeout(this.timeout);
|
|
33
|
-
|
|
34
|
-
// FIXME
|
|
35
|
-
// People on the Internet say that doing this {{should/should not}} abort the request. I believe
|
|
36
|
-
// it corresponds to what the WHATWG HTML spec says should happen when the UA
|
|
37
|
-
// updates the image data if selected source is null.
|
|
38
|
-
//
|
|
39
|
-
// Sources:
|
|
40
|
-
//
|
|
41
|
-
// https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element
|
|
42
|
-
// http://stackoverflow.com/questions/7390888/does-changing-the-src-attribute-of-an-image-stop-the-image-from-downloading
|
|
43
|
-
if (this._image)
|
|
44
|
-
{
|
|
45
|
-
this._image.onload = this._image.onerror = null;
|
|
46
|
-
|
|
47
|
-
this._image.src = '';
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this._aborted = true;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
_handleLoad ()
|
|
54
|
-
{
|
|
55
|
-
if (this._aborted)
|
|
56
|
-
{
|
|
57
|
-
console.error('ImageRequestHandler invoked on cancelled request for ' + this._url);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (this._complete)
|
|
62
|
-
{
|
|
63
|
-
console.error('ImageRequestHandler invoked on completed request for ' + this._url);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this._complete = true;
|
|
68
|
-
|
|
69
|
-
this._callback(this._image);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
_handleError ()
|
|
73
|
-
{
|
|
74
|
-
this._errorCallback(this._image);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
// TODO: requestAnimationFrame fallback
|
|
2
|
-
|
|
3
|
-
export default {
|
|
4
|
-
animate,
|
|
5
|
-
easing: {
|
|
6
|
-
linear: linearEasing,
|
|
7
|
-
cubic: inOutCubicEasing
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
let now;
|
|
12
|
-
|
|
13
|
-
if (typeof performance !== 'undefined' && performance.now)
|
|
14
|
-
{
|
|
15
|
-
now = () => { return performance.now(); };
|
|
16
|
-
}
|
|
17
|
-
else
|
|
18
|
-
{
|
|
19
|
-
now = () => { return Date.now(); };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
function animate (options)
|
|
24
|
-
{
|
|
25
|
-
const durationMs = options.duration;
|
|
26
|
-
const parameters = options.parameters;
|
|
27
|
-
const onUpdate = options.onUpdate;
|
|
28
|
-
const onEnd = options.onEnd;
|
|
29
|
-
|
|
30
|
-
// Setup
|
|
31
|
-
// Times are in milliseconds from a basically arbitrary start
|
|
32
|
-
const start = now();
|
|
33
|
-
const end = start + durationMs;
|
|
34
|
-
|
|
35
|
-
const tweenFns = {};
|
|
36
|
-
const values = {};
|
|
37
|
-
const paramKeys = Object.keys(parameters);
|
|
38
|
-
|
|
39
|
-
paramKeys.forEach(key => {
|
|
40
|
-
const config = parameters[key];
|
|
41
|
-
tweenFns[key] = interpolate(config.from, config.to, config.easing || inOutCubicEasing);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Run it!
|
|
45
|
-
let requestId = requestAnimationFrame(update);
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
cancel()
|
|
49
|
-
{
|
|
50
|
-
if (requestId !== null)
|
|
51
|
-
{
|
|
52
|
-
cancelAnimationFrame(requestId);
|
|
53
|
-
handleAnimationCompletion({
|
|
54
|
-
interrupted: true
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
function update()
|
|
61
|
-
{
|
|
62
|
-
const current = now();
|
|
63
|
-
const elapsed = Math.min((current - start) / durationMs, 1);
|
|
64
|
-
|
|
65
|
-
updateValues(elapsed);
|
|
66
|
-
onUpdate(values);
|
|
67
|
-
|
|
68
|
-
if (current < end)
|
|
69
|
-
{
|
|
70
|
-
requestId = requestAnimationFrame(update);
|
|
71
|
-
}
|
|
72
|
-
else
|
|
73
|
-
{
|
|
74
|
-
handleAnimationCompletion({
|
|
75
|
-
interrupted: false
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function updateValues(elapsed)
|
|
81
|
-
{
|
|
82
|
-
paramKeys.forEach(key => {
|
|
83
|
-
values[key] = tweenFns[key](elapsed);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function handleAnimationCompletion(info)
|
|
88
|
-
{
|
|
89
|
-
requestId = null;
|
|
90
|
-
|
|
91
|
-
if (onEnd)
|
|
92
|
-
onEnd(info);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function interpolate(start, end, easing)
|
|
97
|
-
{
|
|
98
|
-
return (elapsed) => { return start + (end - start) * easing(elapsed); };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Easing functions. inOutCubicEasing is the default, but
|
|
103
|
-
* others are given for convenience.
|
|
104
|
-
*
|
|
105
|
-
**/
|
|
106
|
-
function linearEasing(e)
|
|
107
|
-
{
|
|
108
|
-
return e;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/* jshint ignore:start */
|
|
112
|
-
function inOutQuadEasing (e)
|
|
113
|
-
{
|
|
114
|
-
return e < .5 ? 2 * e * e : -1+(4-2 * e) * e
|
|
115
|
-
}
|
|
116
|
-
/* jshint ignore:end */
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
function inOutCubicEasing (t)
|
|
120
|
-
{
|
|
121
|
-
return t < 0.5 ? 4 * t * t * t : ( t - 1 ) * ( 2 * t - 2 ) * ( 2 * t - 2 ) + 1;
|
|
122
|
-
}
|