diva.js 6.0.2 → 7.2.4
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 -114
- 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/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/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 -573
- 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 -1514
- 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,180 +0,0 @@
|
|
|
1
|
-
import maxBy from 'lodash.maxby';
|
|
2
|
-
import PageToolsOverlay from './page-tools-overlay';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export default class DocumentHandler
|
|
6
|
-
{
|
|
7
|
-
constructor (viewerCore)
|
|
8
|
-
{
|
|
9
|
-
this._viewerCore = viewerCore;
|
|
10
|
-
this._viewerState = viewerCore.getInternalState();
|
|
11
|
-
this._overlays = [];
|
|
12
|
-
|
|
13
|
-
if (this._viewerCore.getPageTools().length)
|
|
14
|
-
{
|
|
15
|
-
const numPages = viewerCore.getSettings().numPages;
|
|
16
|
-
|
|
17
|
-
for (let i = 0; i < numPages; i++)
|
|
18
|
-
{
|
|
19
|
-
const overlay = new PageToolsOverlay(i, viewerCore);
|
|
20
|
-
this._overlays.push(overlay);
|
|
21
|
-
this._viewerCore.addPageOverlay(overlay);
|
|
22
|
-
|
|
23
|
-
// create dummy label for width calculation
|
|
24
|
-
// this is necessary because the _pageToolsElem is only created on mount
|
|
25
|
-
// so there's no other way to get its width before the pages are loaded
|
|
26
|
-
// (which we need to avoid their width temporarily being 0 while loading)
|
|
27
|
-
let dummyLabel = document.createElement('span');
|
|
28
|
-
dummyLabel.innerHTML = viewerCore.settings.manifest.pages[i].l;
|
|
29
|
-
dummyLabel.classList.add('diva-page-labels');
|
|
30
|
-
dummyLabel.setAttribute('style', 'display: inline-block;');
|
|
31
|
-
document.body.appendChild(dummyLabel);
|
|
32
|
-
let labelWidth = dummyLabel.clientWidth;
|
|
33
|
-
document.body.removeChild(dummyLabel);
|
|
34
|
-
|
|
35
|
-
overlay.labelWidth = labelWidth;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// USER EVENTS
|
|
41
|
-
onDoubleClick (event, coords)
|
|
42
|
-
{
|
|
43
|
-
const settings = this._viewerCore.getSettings();
|
|
44
|
-
const newZoomLevel = event.ctrlKey ? settings.zoomLevel - 1 : settings.zoomLevel + 1;
|
|
45
|
-
|
|
46
|
-
const position = this._viewerCore.getPagePositionAtViewportOffset(coords);
|
|
47
|
-
this._viewerCore.zoom(newZoomLevel, position);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
onPinch (event, coords, startDistance, endDistance)
|
|
51
|
-
{
|
|
52
|
-
// FIXME: Do this check in a way which is less spaghetti code-y
|
|
53
|
-
const viewerState = this._viewerCore.getInternalState();
|
|
54
|
-
const settings = this._viewerCore.getSettings();
|
|
55
|
-
|
|
56
|
-
let newZoomLevel = Math.log(Math.pow(2, settings.zoomLevel) * endDistance / (startDistance * Math.log(2))) / Math.log(2);
|
|
57
|
-
newZoomLevel = Math.max(settings.minZoomLevel, newZoomLevel);
|
|
58
|
-
newZoomLevel = Math.min(settings.maxZoomLevel, newZoomLevel);
|
|
59
|
-
|
|
60
|
-
if (newZoomLevel === settings.zoomLevel)
|
|
61
|
-
{
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const position = this._viewerCore.getPagePositionAtViewportOffset(coords);
|
|
66
|
-
|
|
67
|
-
const layout = this._viewerCore.getCurrentLayout();
|
|
68
|
-
const centerOffset = layout.getPageToViewportCenterOffset(position.anchorPage, viewerState.viewport);
|
|
69
|
-
const scaleRatio = 1 / Math.pow(2, settings.zoomLevel - newZoomLevel);
|
|
70
|
-
|
|
71
|
-
this._viewerCore.reload({
|
|
72
|
-
zoomLevel: newZoomLevel,
|
|
73
|
-
goDirectlyTo: position.anchorPage,
|
|
74
|
-
horizontalOffset: (centerOffset.x - position.offset.left) + position.offset.left * scaleRatio,
|
|
75
|
-
verticalOffset: (centerOffset.y - position.offset.top) + position.offset.top * scaleRatio
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// VIEW EVENTS
|
|
80
|
-
onViewWillLoad ()
|
|
81
|
-
{
|
|
82
|
-
this._viewerCore.publish('DocumentWillLoad', this._viewerCore.getSettings());
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
onViewDidLoad ()
|
|
86
|
-
{
|
|
87
|
-
// TODO: Should only be necessary to handle changes on view update, not
|
|
88
|
-
// initial load
|
|
89
|
-
this._handleZoomLevelChange();
|
|
90
|
-
|
|
91
|
-
const currentPageIndex = this._viewerCore.getSettings().activePageIndex;
|
|
92
|
-
const fileName = this._viewerCore.getPageName(currentPageIndex);
|
|
93
|
-
this._viewerCore.publish("DocumentDidLoad", currentPageIndex, fileName);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
onViewDidUpdate (renderedPages, targetPage)
|
|
97
|
-
{
|
|
98
|
-
const currentPage = (targetPage !== null) ?
|
|
99
|
-
targetPage :
|
|
100
|
-
getCentermostPage(renderedPages, this._viewerCore.getCurrentLayout(), this._viewerCore.getViewport());
|
|
101
|
-
|
|
102
|
-
// calculate the visible pages from the rendered pages
|
|
103
|
-
let temp = this._viewerState.viewport.intersectionTolerance;
|
|
104
|
-
// without setting to 0, isPageVisible returns true for pages out of viewport by intersectionTolerance
|
|
105
|
-
this._viewerState.viewport.intersectionTolerance = 0;
|
|
106
|
-
let visiblePages = renderedPages.filter(index => this._viewerState.renderer.isPageVisible(index));
|
|
107
|
-
// reset back to original value after getting true visible pages
|
|
108
|
-
this._viewerState.viewport.intersectionTolerance = temp;
|
|
109
|
-
|
|
110
|
-
// Don't change the current page if there is no page in the viewport
|
|
111
|
-
// FIXME: Would be better to fall back to the page closest to the viewport
|
|
112
|
-
if (currentPage !== null)
|
|
113
|
-
{
|
|
114
|
-
this._viewerCore.setCurrentPages(currentPage, visiblePages);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (targetPage !== null)
|
|
118
|
-
{
|
|
119
|
-
this._viewerCore.publish("ViewerDidJump", targetPage);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
this._handleZoomLevelChange();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
_handleZoomLevelChange ()
|
|
126
|
-
{
|
|
127
|
-
const viewerState = this._viewerState;
|
|
128
|
-
const zoomLevel = viewerState.options.zoomLevel;
|
|
129
|
-
|
|
130
|
-
// If this is not the initial load, trigger the zoom events
|
|
131
|
-
if (viewerState.oldZoomLevel !== zoomLevel && viewerState.oldZoomLevel >= 0)
|
|
132
|
-
{
|
|
133
|
-
if (viewerState.oldZoomLevel < zoomLevel)
|
|
134
|
-
{
|
|
135
|
-
this._viewerCore.publish("ViewerDidZoomIn", zoomLevel);
|
|
136
|
-
}
|
|
137
|
-
else
|
|
138
|
-
{
|
|
139
|
-
this._viewerCore.publish("ViewerDidZoomOut", zoomLevel);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
this._viewerCore.publish("ViewerDidZoom", zoomLevel);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
viewerState.oldZoomLevel = zoomLevel;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
destroy ()
|
|
149
|
-
{
|
|
150
|
-
this._overlays.forEach((overlay) =>
|
|
151
|
-
{
|
|
152
|
-
this._viewerCore.removePageOverlay(overlay);
|
|
153
|
-
}, this);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function getCentermostPage (renderedPages, layout, viewport)
|
|
158
|
-
{
|
|
159
|
-
const centerY = viewport.top + (viewport.height / 2);
|
|
160
|
-
const centerX = viewport.left + (viewport.width / 2);
|
|
161
|
-
|
|
162
|
-
// Find the minimum distance from the viewport center to a page.
|
|
163
|
-
// Compute minus the squared distance from viewport center to the page's border.
|
|
164
|
-
// http://gamedev.stackexchange.com/questions/44483/how-do-i-calculate-distance-between-a-point-and-an-axis-aligned-rectangle
|
|
165
|
-
const centerPage = maxBy(renderedPages, pageIndex =>
|
|
166
|
-
{
|
|
167
|
-
const dims = layout.getPageDimensions(pageIndex);
|
|
168
|
-
const imageOffset = layout.getPageOffset(pageIndex, {includePadding: true});
|
|
169
|
-
|
|
170
|
-
const midX = imageOffset.left + (dims.width / 2);
|
|
171
|
-
const midY = imageOffset.top + (dims.height / 2);
|
|
172
|
-
|
|
173
|
-
const dx = Math.max(Math.abs(centerX - midX) - (dims.width / 2), 0);
|
|
174
|
-
const dy = Math.max(Math.abs(centerY - midY) - (dims.height / 2), 0);
|
|
175
|
-
|
|
176
|
-
return -(dx * dx + dy * dy);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
return centerPage != null ? centerPage : null;
|
|
180
|
-
}
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Translate page layouts, as generated by page-layouts, into an
|
|
3
|
-
* object which computes layout information for the document as
|
|
4
|
-
* a whole.
|
|
5
|
-
*/
|
|
6
|
-
export default class DocumentLayout
|
|
7
|
-
{
|
|
8
|
-
constructor (config, zoomLevel)
|
|
9
|
-
{
|
|
10
|
-
const computedLayout = getComputedLayout(config, zoomLevel);
|
|
11
|
-
|
|
12
|
-
this.dimensions = computedLayout.dimensions;
|
|
13
|
-
this.pageGroups = computedLayout.pageGroups;
|
|
14
|
-
this._pageLookup = getPageLookup(computedLayout.pageGroups);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {Object} PageInfo
|
|
19
|
-
* @property {number} index
|
|
20
|
-
* @property {{index, dimensions, pages, region, padding}} group
|
|
21
|
-
* @property {{height: number, width: number}} dimensions
|
|
22
|
-
* @property {{top: number, left: number}} groupOffset
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @param pageIndex
|
|
27
|
-
* @returns {PageInfo|null}
|
|
28
|
-
*/
|
|
29
|
-
getPageInfo (pageIndex)
|
|
30
|
-
{
|
|
31
|
-
return this._pageLookup[pageIndex] || null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Get the dimensions of a page
|
|
36
|
-
*
|
|
37
|
-
* @param pageIndex
|
|
38
|
-
* @returns {{height: number, width: number}}
|
|
39
|
-
*/
|
|
40
|
-
getPageDimensions (pageIndex)
|
|
41
|
-
{
|
|
42
|
-
if (!this._pageLookup || !this._pageLookup[pageIndex])
|
|
43
|
-
return null;
|
|
44
|
-
|
|
45
|
-
const region = getPageRegionFromPageInfo(this._pageLookup[pageIndex]);
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
height: region.bottom - region.top,
|
|
49
|
-
width: region.right - region.left
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// TODO(wabain): Get rid of this; it's a subset of the page region, so
|
|
54
|
-
// give that instead
|
|
55
|
-
/**
|
|
56
|
-
* Get the top-left coordinates of a page, including*** padding
|
|
57
|
-
*
|
|
58
|
-
* @param pageIndex
|
|
59
|
-
* @param options
|
|
60
|
-
* @returns {{top: number, left: number} | null}
|
|
61
|
-
*/
|
|
62
|
-
getPageOffset (pageIndex, options)
|
|
63
|
-
{
|
|
64
|
-
const region = this.getPageRegion(pageIndex, options);
|
|
65
|
-
|
|
66
|
-
if (!region)
|
|
67
|
-
return null;
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
top: region.top,
|
|
71
|
-
left: region.left
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
getPageRegion (pageIndex, options)
|
|
76
|
-
{
|
|
77
|
-
const pageInfo = this._pageLookup[pageIndex];
|
|
78
|
-
|
|
79
|
-
if (!pageInfo)
|
|
80
|
-
return null;
|
|
81
|
-
|
|
82
|
-
const region = getPageRegionFromPageInfo(pageInfo);
|
|
83
|
-
const padding = pageInfo.group.padding;
|
|
84
|
-
|
|
85
|
-
if (options && options.includePadding)
|
|
86
|
-
{
|
|
87
|
-
return {
|
|
88
|
-
top: region.top + padding.top,
|
|
89
|
-
left: region.left + padding.left,
|
|
90
|
-
bottom: region.bottom,
|
|
91
|
-
right: region.right
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
top: region.top,
|
|
97
|
-
left: region.left,
|
|
98
|
-
// need to account for plugin icons below the page, see
|
|
99
|
-
// https://github.com/DDMAL/diva.js/issues/436
|
|
100
|
-
bottom: region.bottom + padding.top,
|
|
101
|
-
right: region.right
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Get the distance from the top-right of the page to the center of the
|
|
107
|
-
* specified viewport region
|
|
108
|
-
*
|
|
109
|
-
* @param pageIndex
|
|
110
|
-
* @param viewport {{top: number, left: number, bottom: number, right: number}}
|
|
111
|
-
* @returns {{x: number, y: number}}
|
|
112
|
-
*/
|
|
113
|
-
getPageToViewportCenterOffset (pageIndex, viewport)
|
|
114
|
-
{
|
|
115
|
-
const scrollLeft = viewport.left;
|
|
116
|
-
const elementWidth = viewport.right - viewport.left;
|
|
117
|
-
|
|
118
|
-
const offset = this.getPageOffset(pageIndex);
|
|
119
|
-
|
|
120
|
-
const x = scrollLeft - offset.left + parseInt(elementWidth / 2, 10);
|
|
121
|
-
|
|
122
|
-
const scrollTop = viewport.top;
|
|
123
|
-
const elementHeight = viewport.bottom - viewport.top;
|
|
124
|
-
|
|
125
|
-
const y = scrollTop - offset.top + parseInt(elementHeight / 2, 10);
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
x: x,
|
|
129
|
-
y: y
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function getPageRegionFromPageInfo (page)
|
|
135
|
-
{
|
|
136
|
-
const top = page.groupOffset.top + page.group.region.top;
|
|
137
|
-
const bottom = top + page.dimensions.height;
|
|
138
|
-
const left = page.groupOffset.left + page.group.region.left;
|
|
139
|
-
const right = left + page.dimensions.width;
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
top: top,
|
|
143
|
-
bottom: bottom,
|
|
144
|
-
left: left,
|
|
145
|
-
right: right
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function getPageLookup (pageGroups)
|
|
150
|
-
{
|
|
151
|
-
const pageLookup = {};
|
|
152
|
-
|
|
153
|
-
pageGroups.forEach(group => {
|
|
154
|
-
group.pages.forEach(page => {
|
|
155
|
-
pageLookup[page.index] = {
|
|
156
|
-
index: page.index,
|
|
157
|
-
group: group,
|
|
158
|
-
dimensions: page.dimensions,
|
|
159
|
-
groupOffset: page.groupOffset
|
|
160
|
-
};
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
return pageLookup;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function getComputedLayout (config, zoomLevel)
|
|
168
|
-
{
|
|
169
|
-
const scaledLayouts = zoomLevel === null ? config.pageLayouts : getScaledPageLayouts(config, zoomLevel);
|
|
170
|
-
|
|
171
|
-
const documentSecondaryExtent = getExtentAlongSecondaryAxis(config, scaledLayouts);
|
|
172
|
-
|
|
173
|
-
// The current position in the document along the primary axis
|
|
174
|
-
let primaryDocPosition = config.verticallyOriented ?
|
|
175
|
-
config.padding.document.top :
|
|
176
|
-
config.padding.document.left;
|
|
177
|
-
|
|
178
|
-
const pageGroups = [];
|
|
179
|
-
|
|
180
|
-
// TODO: Use bottom, right as well
|
|
181
|
-
const pagePadding = {
|
|
182
|
-
top: config.padding.page.top,
|
|
183
|
-
left: config.padding.page.left
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
scaledLayouts.forEach((layout, index) => {
|
|
187
|
-
let top, left;
|
|
188
|
-
|
|
189
|
-
if (config.verticallyOriented)
|
|
190
|
-
{
|
|
191
|
-
top = primaryDocPosition;
|
|
192
|
-
left = (documentSecondaryExtent - layout.dimensions.width) / 2;
|
|
193
|
-
}
|
|
194
|
-
else
|
|
195
|
-
{
|
|
196
|
-
top = (documentSecondaryExtent - layout.dimensions.height) / 2;
|
|
197
|
-
left = primaryDocPosition;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const region = {
|
|
201
|
-
top: top,
|
|
202
|
-
bottom: top + pagePadding.top + layout.dimensions.height,
|
|
203
|
-
left: left,
|
|
204
|
-
right: left + pagePadding.left + layout.dimensions.width
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
pageGroups.push({
|
|
208
|
-
index: index,
|
|
209
|
-
dimensions: layout.dimensions,
|
|
210
|
-
pages: layout.pages,
|
|
211
|
-
region: region,
|
|
212
|
-
padding: pagePadding
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
primaryDocPosition = config.verticallyOriented ? region.bottom : region.right;
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
let height, width;
|
|
219
|
-
|
|
220
|
-
if (config.verticallyOriented)
|
|
221
|
-
{
|
|
222
|
-
height = primaryDocPosition + pagePadding.top;
|
|
223
|
-
width = documentSecondaryExtent;
|
|
224
|
-
}
|
|
225
|
-
else
|
|
226
|
-
{
|
|
227
|
-
height = documentSecondaryExtent;
|
|
228
|
-
width = primaryDocPosition + pagePadding.left;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
dimensions: {
|
|
233
|
-
height: height,
|
|
234
|
-
width: width
|
|
235
|
-
},
|
|
236
|
-
pageGroups: pageGroups
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function getScaledPageLayouts (config, zoomLevel)
|
|
241
|
-
{
|
|
242
|
-
const scaleRatio = Math.pow(2, zoomLevel - config.maxZoomLevel);
|
|
243
|
-
|
|
244
|
-
return config.pageLayouts.map(group => ({
|
|
245
|
-
dimensions: scaleDimensions(group.dimensions, scaleRatio),
|
|
246
|
-
|
|
247
|
-
pages: group.pages.map(page => ({
|
|
248
|
-
index: page.index,
|
|
249
|
-
|
|
250
|
-
groupOffset: {
|
|
251
|
-
top: Math.floor(page.groupOffset.top * scaleRatio),
|
|
252
|
-
left: Math.floor(page.groupOffset.left * scaleRatio)
|
|
253
|
-
},
|
|
254
|
-
|
|
255
|
-
dimensions: scaleDimensions(page.dimensions, scaleRatio)
|
|
256
|
-
}))
|
|
257
|
-
}));
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function scaleDimensions (dimensions, scaleRatio)
|
|
261
|
-
{
|
|
262
|
-
return {
|
|
263
|
-
height: Math.floor(dimensions.height * scaleRatio),
|
|
264
|
-
width: Math.floor(dimensions.width * scaleRatio)
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function getExtentAlongSecondaryAxis (config, scaledLayouts)
|
|
269
|
-
{
|
|
270
|
-
// Get the extent of the document along the secondary axis
|
|
271
|
-
let secondaryDim, secondaryPadding;
|
|
272
|
-
const docPadding = config.padding.document;
|
|
273
|
-
|
|
274
|
-
if (config.verticallyOriented)
|
|
275
|
-
{
|
|
276
|
-
secondaryDim = 'width';
|
|
277
|
-
secondaryPadding = docPadding.left + docPadding.right;
|
|
278
|
-
}
|
|
279
|
-
else
|
|
280
|
-
{
|
|
281
|
-
secondaryDim = 'height';
|
|
282
|
-
secondaryPadding = docPadding.top + docPadding.bottom;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return secondaryPadding + scaledLayouts.reduce((maxDim, layout) => Math.max(layout.dimensions[secondaryDim], maxDim), 0);
|
|
286
|
-
}
|
package/source/js/exceptions.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export function DivaParentElementNotFoundException (message)
|
|
2
|
-
{
|
|
3
|
-
this.name = "DivaParentElementNotFoundException";
|
|
4
|
-
this.message = message;
|
|
5
|
-
this.stack = (new Error()).stack;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
DivaParentElementNotFoundException.prototype = new Error();
|
|
9
|
-
|
|
10
|
-
export function NotAnIIIFManifestException (message)
|
|
11
|
-
{
|
|
12
|
-
this.name = "NotAnIIIFManifestException";
|
|
13
|
-
this.message = message;
|
|
14
|
-
this.stack = (new Error()).stack;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
NotAnIIIFManifestException.prototype = new Error();
|
|
18
|
-
|
|
19
|
-
export function ObjectDataNotSuppliedException (message)
|
|
20
|
-
{
|
|
21
|
-
this.name = "ObjectDataNotSuppliedException";
|
|
22
|
-
this.message = message;
|
|
23
|
-
this.stack = (new Error()).stack;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
ObjectDataNotSuppliedException.prototype = new Error();
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
onDoubleClick,
|
|
3
|
-
onPinch,
|
|
4
|
-
onDoubleTap
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
const DOUBLE_CLICK_TIMEOUT = 500;
|
|
8
|
-
const DOUBLE_TAP_DISTANCE_THRESHOLD = 50;
|
|
9
|
-
const DOUBLE_TAP_TIMEOUT = 250;
|
|
10
|
-
|
|
11
|
-
function onDoubleClick(elem, callback)
|
|
12
|
-
{
|
|
13
|
-
elem.addEventListener('dblclick', function (event)
|
|
14
|
-
{
|
|
15
|
-
if (!event.ctrlKey)
|
|
16
|
-
{
|
|
17
|
-
callback(event, getRelativeOffset(event.currentTarget, event));
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// Handle the control key for macs (in conjunction with double-clicking)
|
|
22
|
-
// FIXME: Does a click get handled with ctrl pressed on non-Macs?
|
|
23
|
-
const tracker = createDoubleEventTracker(DOUBLE_CLICK_TIMEOUT);
|
|
24
|
-
|
|
25
|
-
elem.addEventListener('contextmenu', function (event)
|
|
26
|
-
{
|
|
27
|
-
event.preventDefault();
|
|
28
|
-
|
|
29
|
-
if (event.ctrlKey)
|
|
30
|
-
{
|
|
31
|
-
if (tracker.isTriggered())
|
|
32
|
-
{
|
|
33
|
-
tracker.reset();
|
|
34
|
-
callback(event, getRelativeOffset(event.currentTarget, event));
|
|
35
|
-
}
|
|
36
|
-
else
|
|
37
|
-
{
|
|
38
|
-
tracker.trigger();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function onPinch(elem, callback)
|
|
45
|
-
{
|
|
46
|
-
let startDistance = 0;
|
|
47
|
-
|
|
48
|
-
elem.addEventListener('touchstart', function (event)
|
|
49
|
-
{
|
|
50
|
-
// Prevent mouse event from firing
|
|
51
|
-
event.preventDefault();
|
|
52
|
-
|
|
53
|
-
if (event.originalEvent.touches.length === 2)
|
|
54
|
-
{
|
|
55
|
-
startDistance = distance(
|
|
56
|
-
event.originalEvent.touches[0].clientX,
|
|
57
|
-
event.originalEvent.touches[0].clientY,
|
|
58
|
-
event.originalEvent.touches[1].clientX,
|
|
59
|
-
event.originalEvent.touches[1].clientY
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
elem.addEventListener('touchmove', function(event)
|
|
65
|
-
{
|
|
66
|
-
// Prevent mouse event from firing
|
|
67
|
-
event.preventDefault();
|
|
68
|
-
|
|
69
|
-
if (event.originalEvent.touches.length === 2)
|
|
70
|
-
{
|
|
71
|
-
const touches = event.originalEvent.touches;
|
|
72
|
-
|
|
73
|
-
const moveDistance = distance(
|
|
74
|
-
touches[0].clientX,
|
|
75
|
-
touches[0].clientY,
|
|
76
|
-
touches[1].clientX,
|
|
77
|
-
touches[1].clientY
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const zoomDelta = moveDistance - startDistance;
|
|
81
|
-
|
|
82
|
-
if (Math.abs(zoomDelta) > 0)
|
|
83
|
-
{
|
|
84
|
-
const touchCenter = {
|
|
85
|
-
pageX: (touches[0].clientX + touches[1].clientX) / 2,
|
|
86
|
-
pageY: (touches[0].clientY + touches[1].clientY) / 2
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
callback(event, getRelativeOffset(event.currentTarget, touchCenter), startDistance, moveDistance);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function onDoubleTap(elem, callback)
|
|
96
|
-
{
|
|
97
|
-
const tracker = createDoubleEventTracker(DOUBLE_TAP_TIMEOUT);
|
|
98
|
-
let firstTap = null;
|
|
99
|
-
|
|
100
|
-
elem.addEventListener('touchend', (event) =>
|
|
101
|
-
{
|
|
102
|
-
// Prevent mouse event from firing
|
|
103
|
-
event.preventDefault();
|
|
104
|
-
|
|
105
|
-
if (tracker.isTriggered())
|
|
106
|
-
{
|
|
107
|
-
tracker.reset();
|
|
108
|
-
|
|
109
|
-
// Doubletap has occurred
|
|
110
|
-
const secondTap = {
|
|
111
|
-
pageX: event.originalEvent.changedTouches[0].clientX,
|
|
112
|
-
pageY: event.originalEvent.changedTouches[0].clientY
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
// If first tap is close to second tap (prevents interference with scale event)
|
|
116
|
-
const tapDistance = distance(firstTap.pageX, firstTap.pageY, secondTap.pageX, secondTap.pageY);
|
|
117
|
-
|
|
118
|
-
// TODO: Could give something higher-level than secondTap to callback
|
|
119
|
-
if (tapDistance < DOUBLE_TAP_DISTANCE_THRESHOLD)
|
|
120
|
-
callback(event, getRelativeOffset(event.currentTarget, secondTap));
|
|
121
|
-
|
|
122
|
-
firstTap = null;
|
|
123
|
-
}
|
|
124
|
-
else
|
|
125
|
-
{
|
|
126
|
-
firstTap = {
|
|
127
|
-
pageX: event.originalEvent.changedTouches[0].clientX,
|
|
128
|
-
pageY: event.originalEvent.changedTouches[0].clientY
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
tracker.trigger();
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Pythagorean theorem to get the distance between two points (used for
|
|
137
|
-
// calculating finger distance for double-tap and pinch-zoom)
|
|
138
|
-
function distance(x1, y1, x2, y2)
|
|
139
|
-
{
|
|
140
|
-
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Utility to keep track of whether an event has been triggered twice
|
|
144
|
-
// during a a given duration
|
|
145
|
-
function createDoubleEventTracker(timeoutDuration)
|
|
146
|
-
{
|
|
147
|
-
let triggered = false;
|
|
148
|
-
let timeoutId = null;
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
trigger()
|
|
152
|
-
{
|
|
153
|
-
triggered = true;
|
|
154
|
-
resetTimeout();
|
|
155
|
-
timeoutId = setTimeout(function ()
|
|
156
|
-
{
|
|
157
|
-
triggered = false;
|
|
158
|
-
timeoutId = null;
|
|
159
|
-
}, timeoutDuration);
|
|
160
|
-
},
|
|
161
|
-
isTriggered()
|
|
162
|
-
{
|
|
163
|
-
return triggered;
|
|
164
|
-
},
|
|
165
|
-
reset()
|
|
166
|
-
{
|
|
167
|
-
triggered = false;
|
|
168
|
-
resetTimeout();
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
function resetTimeout()
|
|
173
|
-
{
|
|
174
|
-
if (timeoutId !== null)
|
|
175
|
-
{
|
|
176
|
-
clearTimeout(timeoutId);
|
|
177
|
-
timeoutId = null;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function getRelativeOffset(elem, pageCoords)
|
|
183
|
-
{
|
|
184
|
-
const bounds = elem.getBoundingClientRect();
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
left: pageCoords.pageX - bounds.left,
|
|
188
|
-
top: pageCoords.pageY - bounds.top
|
|
189
|
-
};
|
|
190
|
-
}
|