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.
Files changed (131) hide show
  1. package/.clang-format +7 -0
  2. package/.github/workflows/npm-publish.yml +45 -0
  3. package/LICENSE +55 -0
  4. package/Makefile +75 -0
  5. package/README.md +15 -114
  6. package/elm.json +32 -0
  7. package/package.json +12 -59
  8. package/review/elm.json +52 -0
  9. package/review/src/ReviewConfig.elm +87 -0
  10. package/scripts/elm-esm.sh +40 -0
  11. package/scripts/minify-css.mjs +31 -0
  12. package/src/Filters.elm +1044 -0
  13. package/src/Main.elm +1217 -0
  14. package/src/Model.elm +213 -0
  15. package/src/Msg.elm +59 -0
  16. package/src/Utilities.elm +46 -0
  17. package/src/View/CollectionExplorer.elm +172 -0
  18. package/src/View/Helpers.elm +86 -0
  19. package/src/View/HtmlRenderer.elm +136 -0
  20. package/src/View/Icons.elm +159 -0
  21. package/src/View/ManifestInfoModal.elm +363 -0
  22. package/src/View/PageViewModal.elm +1046 -0
  23. package/src/View/Sidebar.elm +786 -0
  24. package/src/View/Toolbar.elm +189 -0
  25. package/src/View.elm +244 -0
  26. package/src/diva.ts +802 -0
  27. package/src/filters.ts +1843 -0
  28. package/src/styles/app.css +328 -0
  29. package/src/styles/collection.css +75 -0
  30. package/src/styles/modal.css +388 -0
  31. package/src/styles/sidebar.css +215 -0
  32. package/src/styles/theme.css +39 -0
  33. package/src/styles/toolbar.css +154 -0
  34. package/src/viewer-element.ts +1307 -0
  35. package/testing/index.html +52 -0
  36. package/testing/testing.html +231 -0
  37. package/tsconfig.json +12 -0
  38. package/AUTHORS +0 -22
  39. package/build/diva.css +0 -554
  40. package/build/diva.css.map +0 -1
  41. package/build/diva.js +0 -9
  42. package/build/diva.js.map +0 -1
  43. package/build/plugins/download.js +0 -2
  44. package/build/plugins/download.js.map +0 -1
  45. package/build/plugins/manipulation.js +0 -2
  46. package/build/plugins/manipulation.js.map +0 -1
  47. package/build/plugins/metadata.js +0 -2
  48. package/build/plugins/metadata.js.map +0 -1
  49. package/index.html +0 -28
  50. package/karma.conf.js +0 -87
  51. package/source/css/_mixins.scss +0 -43
  52. package/source/css/_variables.scss +0 -50
  53. package/source/css/_viewer.scss +0 -462
  54. package/source/css/diva.scss +0 -15
  55. package/source/css/plugins/_manipulation.scss +0 -228
  56. package/source/css/plugins/_metadata.scss +0 -31
  57. package/source/img/adjust.svg +0 -11
  58. package/source/img/book-view.svg +0 -6
  59. package/source/img/close.svg +0 -6
  60. package/source/img/download.svg +0 -6
  61. package/source/img/from-fullscreen.svg +0 -8
  62. package/source/img/grid-fewer.svg +0 -6
  63. package/source/img/grid-more.svg +0 -6
  64. package/source/img/grid-view.svg +0 -6
  65. package/source/img/link.svg +0 -6
  66. package/source/img/metadata.svg +0 -9
  67. package/source/img/page-view.svg +0 -6
  68. package/source/img/to-fullscreen.svg +0 -11
  69. package/source/img/zoom-in.svg +0 -6
  70. package/source/img/zoom-out.svg +0 -7
  71. package/source/js/composite-image.js +0 -174
  72. package/source/js/diva-global.js +0 -7
  73. package/source/js/diva.js +0 -1543
  74. package/source/js/document-handler.js +0 -180
  75. package/source/js/document-layout.js +0 -286
  76. package/source/js/exceptions.js +0 -26
  77. package/source/js/gesture-events.js +0 -190
  78. package/source/js/grid-handler.js +0 -122
  79. package/source/js/iiif-source-adapter.js +0 -63
  80. package/source/js/image-cache.js +0 -113
  81. package/source/js/image-manifest.js +0 -157
  82. package/source/js/image-request-handler.js +0 -76
  83. package/source/js/interpolate-animation.js +0 -122
  84. package/source/js/page-layouts/book-layout.js +0 -161
  85. package/source/js/page-layouts/grid-layout.js +0 -97
  86. package/source/js/page-layouts/index.js +0 -38
  87. package/source/js/page-layouts/page-dimensions.js +0 -9
  88. package/source/js/page-layouts/singles-layout.js +0 -27
  89. package/source/js/page-overlay-manager.js +0 -102
  90. package/source/js/page-tools-overlay.js +0 -95
  91. package/source/js/parse-iiif-manifest.js +0 -302
  92. package/source/js/plugins/_filters.js +0 -679
  93. package/source/js/plugins/download.js +0 -83
  94. package/source/js/plugins/manipulation.js +0 -837
  95. package/source/js/plugins/metadata.js +0 -190
  96. package/source/js/renderer.js +0 -584
  97. package/source/js/settings-view.js +0 -30
  98. package/source/js/tile-coverage-map.js +0 -25
  99. package/source/js/toolbar.js +0 -573
  100. package/source/js/utils/dragscroll.js +0 -106
  101. package/source/js/utils/elt.js +0 -94
  102. package/source/js/utils/events.js +0 -190
  103. package/source/js/utils/get-scrollbar-width.js +0 -29
  104. package/source/js/utils/hash-params.js +0 -86
  105. package/source/js/utils/parse-label-value.js +0 -34
  106. package/source/js/utils/vanilla.kinetic.js +0 -527
  107. package/source/js/validation-runner.js +0 -177
  108. package/source/js/viewer-core.js +0 -1514
  109. package/source/js/viewport.js +0 -143
  110. package/test/_setup.js +0 -13
  111. package/test/composite-image_test.js +0 -94
  112. package/test/diva_test.js +0 -43
  113. package/test/hash-params_test.js +0 -221
  114. package/test/image-cache_test.js +0 -106
  115. package/test/main.js +0 -6
  116. package/test/manifests/beromunsterManifest.json +0 -15514
  117. package/test/manifests/iiifv2.json +0 -11032
  118. package/test/manifests/iiifv2pages.json +0 -30437
  119. package/test/manifests/iiifv3.json +0 -10965
  120. package/test/navigation_test.js +0 -355
  121. package/test/parse-iiif-manifest_test.js +0 -68
  122. package/test/public_test.js +0 -881
  123. package/test/settings_test.js +0 -487
  124. package/test/utils/book-layout_test.js +0 -148
  125. package/test/utils/elt_test.js +0 -102
  126. package/test/utils/events_test.js +0 -245
  127. package/test/utils/hash-params_test.js +0 -79
  128. package/test/utils/parse-label-value_test.js +0 -45
  129. package/test/z_plugins_test.js +0 -180
  130. package/webpack.config.js +0 -58
  131. package/webpack.config.test.js +0 -45
@@ -1,837 +0,0 @@
1
- import {
2
- grayscale,
3
- saturation,
4
- vibrance,
5
- brightness,
6
- contrast,
7
- hue,
8
- gamma,
9
- ccRed,
10
- ccGreen,
11
- ccBlue,
12
- invert,
13
- threshold,
14
- sharpen,
15
- resetFilters
16
- } from "./_filters";
17
- import gestureEvents from '../gesture-events';
18
-
19
- /**
20
- * Returns a function, that, as long as it continues to be invoked, will not
21
- be triggered. The function will be called after it stops being called for
22
- N milliseconds. If `immediate` is passed, trigger the function on the
23
- leading edge, instead of the trailing.
24
- */
25
- function debounce (func, wait, immediate)
26
- {
27
- let timeout;
28
- return function ()
29
- {
30
- let context = this, args = arguments;
31
- let later = function ()
32
- {
33
- timeout = null;
34
- if (!immediate)
35
- {
36
- func.apply(context, args);
37
- }
38
- };
39
- let callNow = immediate && !timeout;
40
- clearTimeout(timeout);
41
- timeout = setTimeout(later, wait);
42
- if (callNow)
43
- {
44
- func.apply(context, args);
45
- }
46
- };
47
- }
48
-
49
- /**
50
- * A Diva.js plugin that allows users to manipulate images by adjusting their
51
- * brightness, contrast, and other parameters.
52
- **/
53
- export default class ManipulationPlugin
54
- {
55
- constructor (core)
56
- {
57
- this._core = core;
58
- this.pageToolsIcon = this.createIcon();
59
- this._backdrop = null;
60
- this._page = null;
61
- this._mainImage = null;
62
- this._canvas = null;
63
-
64
- // store the data for the original main image so that we
65
- // do the processing on that, not on a previously-processed image.
66
- this._originalData = null;
67
-
68
- // zoom stuff
69
- this.maxZoom = 4;
70
- this.minZoom = 1;
71
- this.zoom = 1;
72
-
73
- this.rotate = 0;
74
-
75
- // mirror stuff, 1 for not mirrored, -1 for mirrored
76
- this.mirrorHorizontal = 1;
77
- this.mirrorVertical = 1;
78
-
79
- this.boundEscapeListener = this.escapeListener.bind(this);
80
-
81
- // url of currently loaded image
82
- this.currentImageURL = null;
83
- }
84
-
85
- handleClick (event, settings, publicInstance, pageIndex)
86
- {
87
- document.body.style.overflow = 'hidden';
88
- this._backdrop = document.createElement('div');
89
- this._backdrop.classList.add('manipulation-fullscreen');
90
-
91
- this._sidebar = document.createElement('div');
92
- this._sidebar.classList.add('manipulation-sidebar');
93
-
94
- this._mainArea = document.createElement('div');
95
- this._mainArea.classList.add('manipulation-main-area');
96
-
97
- // enable scroll by dragging
98
- this._mainArea.classList.add('dragscroll');
99
- this._mainArea.addEventListener('mousedown', () => { this._mainArea.classList.add('grabbing'); });
100
- this._mainArea.addEventListener('mouseup', () => { this._mainArea.classList.remove('grabbing'); });
101
-
102
- // add double click zoom handler
103
- gestureEvents.onDoubleClick(this._mainArea, this.handleDblClick.bind(this));
104
-
105
- this._tools = document.createElement('div');
106
- this._tools.classList.add('manipulation-tools');
107
-
108
- this._backdrop.appendChild(this._sidebar);
109
- this._backdrop.appendChild(this._mainArea);
110
- this._backdrop.appendChild(this._tools);
111
-
112
- this._core.parentObject.appendChild(this._backdrop);
113
- document.addEventListener('keyup', this.boundEscapeListener);
114
-
115
- this._page = settings.manifest.pages[pageIndex];
116
-
117
- this._canvas = document.createElement('canvas');
118
- this._ctx = this._canvas.getContext('2d');
119
- this._mainArea.appendChild(this._canvas);
120
-
121
- this._initializeSidebar();
122
- this._initializeTools();
123
-
124
- window.resetDragscroll();
125
- this._loadImageInMainArea(event, this._page.url);
126
-
127
- // hide toolbar if fullscreen
128
- if (settings.inFullscreen)
129
- {
130
- document.getElementById(settings.selector + 'tools').style.display = 'none';
131
- }
132
-
133
- // handle smaller viewport
134
- if (window.innerWidth <= 1000)
135
- {
136
- this._mainArea.classList.remove('manipulation-main-area');
137
- this._mainArea.classList.add('manipulation-main-area-mobile');
138
- this._sidebar.classList.remove('manipulation-sidebar');
139
- this._sidebar.classList.add('manipulation-sidebar-mobile');
140
- this._tools.classList.remove('manipulation-tools');
141
- this._tools.classList.add('manipulation-tools-mobile');
142
-
143
- // add hamburger menus
144
- let burger = document.createElement('div');
145
- burger.classList.add('burger-menu');
146
- let s1 = document.createElement('div');
147
- let s2 = document.createElement('div');
148
- let s3 = document.createElement('div');
149
- s1.classList.add('stripe');
150
- s2.classList.add('stripe');
151
- s3.classList.add('stripe');
152
-
153
- burger.appendChild(s1);
154
- burger.appendChild(s2);
155
- burger.appendChild(s3);
156
-
157
- this.burgerClicked = false;
158
-
159
- burger.onclick = () => {
160
- if (this.burgerClicked)
161
- {
162
- this._sidebar.style.display = 'none';
163
- this._tools.style.display = 'none';
164
- this._mainArea.style.display = 'block';
165
- }
166
- else
167
- {
168
- this._sidebar.style.display = 'block';
169
- this._tools.style.display = 'block';
170
- this._mainArea.style.display = 'none';
171
- }
172
- this.burgerClicked = !this.burgerClicked;
173
- };
174
-
175
- this._backdrop.appendChild(burger);
176
- }
177
- }
178
-
179
- handleDblClick (event)
180
- {
181
- let newZoom = event.ctrlKey ? this.zoom - 1 : this.zoom + 1;
182
- if (newZoom < this.minZoom || newZoom > this.maxZoom)
183
- return;
184
-
185
- // update slider
186
- let slider = document.getElementById('zoom-slider');
187
- slider.value = newZoom;
188
-
189
- this.handleZoom(event, newZoom, true);
190
- }
191
-
192
- /*
193
- * Returns an SVG object representing the icon for the project. Implemented in code
194
- * here so that the entire Diva object can be passed to the client with no external
195
- * dependencies.
196
- **/
197
- createIcon ()
198
- {
199
- const manipulationIcon = document.createElement('div');
200
- manipulationIcon.classList.add('diva-manipulation-icon');
201
-
202
- let root = document.createElementNS("http://www.w3.org/2000/svg", "svg");
203
- root.setAttribute("x", "0px");
204
- root.setAttribute("y", "0px");
205
- root.setAttribute("viewBox", "0 0 25 25");
206
- root.id = `${this._core.settings.selector}manipulation-icon`;
207
-
208
- let g = document.createElementNS("http://www.w3.org/2000/svg", "g");
209
- g.id = `${this._core.settings.selector}manipulation-icon-glyph`;
210
- g.setAttribute("transform", "matrix(1, 0, 0, 1, -11.5, -11.5)");
211
- g.setAttribute("class", "diva-pagetool-icon");
212
-
213
- let path1 = document.createElementNS("http://www.w3.org/2000/svg", "path");
214
- path1.setAttribute("d", "M27,21h-1v-9h-3v9h-1c-0.55,0-1,0.45-1,1v3c0,0.55,0.45,1,1,1h1h3h1c0.55,0,1-0.45,1-1v-3C28,21.45,27.55,21,27,21z M27,24h-5v-0.5h5V24z");
215
-
216
- let path2 = document.createElementNS("http://www.w3.org/2000/svg", "path");
217
- path2.setAttribute("d", "M35,16h-1v-4h-3v4h-1c-0.55,0-1,0.45-1,1v3c0,0.55,0.45,1,1,1h1h3h1c0.55,0,1-0.45,1-1v-3C36,16.45,35.55,16,35,16z M35,19h-5v-0.5h5V19z");
218
-
219
- let path3 = document.createElementNS("http://www.w3.org/2000/svg", "path");
220
- path3.setAttribute("d", "M19,26h-1V12h-3v14h-1c-0.55,0-1,0.45-1,1v3c0,0.55,0.45,1,1,1h1h3h1c0.55,0,1-0.45,1-1v-3C20,26.45,19.55,26,19,26zM19,29h-5v-0.5h5V29z");
221
-
222
- let rect1 = document.createElementNS("http://www.w3.org/2000/svg", "rect");
223
- rect1.setAttribute('x', '23');
224
- rect1.setAttribute('y', '27');
225
- rect1.setAttribute('width', '3');
226
- rect1.setAttribute('height', '9');
227
-
228
- let rect2 = document.createElementNS("http://www.w3.org/2000/svg", "rect");
229
- rect2.setAttribute('x', '31');
230
- rect2.setAttribute('y', '22');
231
- rect2.setAttribute('width', '3');
232
- rect2.setAttribute('height', '14');
233
-
234
- let rect3 = document.createElementNS("http://www.w3.org/2000/svg", "rect");
235
- rect3.setAttribute('x', '15');
236
- rect3.setAttribute('y', '32');
237
- rect3.setAttribute('width', '3');
238
- rect3.setAttribute('height', '4');
239
-
240
- g.appendChild(path1);
241
- g.appendChild(path2);
242
- g.appendChild(rect1);
243
- g.appendChild(path3);
244
- g.appendChild(rect2);
245
- g.appendChild(rect3);
246
- root.appendChild(g);
247
-
248
- manipulationIcon.appendChild(root);
249
-
250
- return manipulationIcon;
251
- }
252
-
253
- escapeListener (event)
254
- {
255
- if (event.keyCode === 27)
256
- {
257
- document.removeEventListener('keyup', this.boundEscapeListener);
258
- document.body.style.overflow = 'auto';
259
- this._core.parentObject.removeChild(this._backdrop);
260
-
261
- // show toolbar
262
- document.getElementById(`${this._core.settings.selector}tools`).style.display = 'block';
263
- }
264
- }
265
-
266
- _initializeSidebar ()
267
- {
268
- // 150px wide images for the sidebar.
269
- let thumbnailSize = "150";
270
- let mainPageSidebarImageURL = `${this._page.url}full/${thumbnailSize},/0/default.jpg`;
271
-
272
- let otherImageURLs = this._page.otherImages.map((img) =>
273
- {
274
- return `${img.url}full/${thumbnailSize},/0/default.jpg`;
275
- });
276
-
277
- let primaryImgDiv = document.createElement('div');
278
- primaryImgDiv.classList.add('manipulation-sidebar-primary-image');
279
-
280
- let primaryImg = document.createElement('img');
281
- primaryImg.setAttribute('src', mainPageSidebarImageURL);
282
-
283
- let primaryImgLabel = document.createElement('div');
284
- primaryImgLabel.textContent = this._page.il;
285
-
286
- primaryImgDiv.appendChild(primaryImg);
287
- primaryImgDiv.appendChild(primaryImgLabel);
288
-
289
- this._sidebar.appendChild(primaryImgDiv);
290
-
291
- primaryImgDiv.addEventListener('click', () =>
292
- {
293
- this._loadImageInMainArea.call(this, event, this._page.url);
294
- });
295
-
296
- otherImageURLs.map((url, idx) =>
297
- {
298
- let othDiv = document.createElement('div');
299
- othDiv.classList.add('manipulation-sidebar-secondary-image');
300
-
301
- let othImg = document.createElement('img');
302
- othImg.setAttribute('src', url);
303
-
304
- let othImgLabel = document.createElement('div');
305
- othImgLabel.textContent = this._page.otherImages[idx].il;
306
-
307
- othDiv.appendChild(othImg);
308
- othDiv.appendChild(othImgLabel);
309
-
310
- this._sidebar.appendChild(othDiv);
311
-
312
- othDiv.addEventListener('click', () => this._loadImageInMainArea.call(this, event, this._page.otherImages[idx].url));
313
- });
314
- }
315
-
316
- _initializeTools ()
317
- {
318
- // Close button
319
- let closeButton = document.createElement('button');
320
-
321
- closeButton.innerHTML = '&#10006';
322
- closeButton.classList.add('close-button');
323
- closeButton.setAttribute('style', 'display: absolute; top: 1em; right: 1em;');
324
-
325
- closeButton.onclick = () =>
326
- {
327
- document.body.style.overflow = 'auto';
328
- this._core.parentObject.removeChild(this._backdrop);
329
- document.getElementById(this._core.settings.selector + 'tools').style.display = 'block';
330
- };
331
-
332
- // Header title
333
- let header = document.createElement('h2');
334
-
335
- header.setAttribute('style', 'margin-bottom: 0.3em;');
336
- header.classList.add('manipulation-tools-text');
337
- header.innerText = 'Image tools';
338
-
339
- // Zoom tool
340
- let zoomDiv = document.createElement('div');
341
- let zoomAdjust = document.createElement('input');
342
- let zoomText = document.createTextNode('Zoom');
343
-
344
- zoomDiv.classList.add('manipulation-tools-text');
345
- zoomAdjust.setAttribute('type', 'range');
346
- zoomAdjust.setAttribute('max', this.maxZoom);
347
- zoomAdjust.setAttribute('min', this.minZoom);
348
- zoomAdjust.setAttribute('value', this.zoom);
349
- zoomAdjust.id = 'zoom-slider';
350
- zoomDiv.addEventListener('change', debounce((e) => this.handleZoom(e, e.target.value, true), 250));
351
- zoomDiv.appendChild(zoomAdjust);
352
- zoomDiv.appendChild(zoomText);
353
-
354
- // Rotation tool
355
- let rotateDiv = document.createElement('div');
356
- let rotateAdjust = document.createElement('input');
357
- let rotateText = document.createTextNode('Rotation');
358
-
359
- rotateDiv.classList.add('manipulation-tools-text');
360
- rotateAdjust.setAttribute('type', 'range');
361
- rotateAdjust.setAttribute('max', 359);
362
- rotateAdjust.setAttribute('min', 0);
363
- rotateAdjust.setAttribute('value', 0);
364
-
365
- rotateDiv.addEventListener('input', (e) => { this.handleTransform(e, null, e.target.value); });
366
- rotateDiv.appendChild(rotateAdjust);
367
- rotateDiv.appendChild(rotateText);
368
-
369
- // Mirror tool
370
- let mirrorDiv = document.createElement('div');
371
- let verticalMirrorButton = document.createElement('button');
372
- verticalMirrorButton.id = 'vertical-mirror-button';
373
- let horizontalMirrorButton = document.createElement('button');
374
- horizontalMirrorButton.id = 'horizontal-mirror-button';
375
-
376
- verticalMirrorButton.textContent = "Mirror Vertically";
377
- horizontalMirrorButton.textContent = "Mirror Horizontally";
378
- verticalMirrorButton.addEventListener('click', (e) => this.handleTransform(e, 'vertical', this.rotate));
379
- horizontalMirrorButton.addEventListener('click', (e) => this.handleTransform(e, 'horizontal', this.rotate));
380
- mirrorDiv.appendChild(verticalMirrorButton);
381
- mirrorDiv.appendChild(horizontalMirrorButton);
382
-
383
- // Filters title
384
- let filtersTitle = document.createElement('div');
385
- filtersTitle.setAttribute('style', 'margin: 1em 0;');
386
-
387
- let titleText = document.createElement('h3');
388
- titleText.setAttribute('style', 'margin: 0;');
389
- titleText.classList.add('manipulation-tools-text');
390
- titleText.innerText = 'Filters';
391
-
392
- // Selection options (color filters or threshold)
393
- let select = document.createElement('select');
394
- select.id = 'filter-select';
395
- select.style.backgroundColor = 'white';
396
-
397
- let colorFilters = document.createElement('option');
398
- colorFilters.value = 'colours';
399
- colorFilters.innerText = 'Color Filters';
400
-
401
- let otherFilters = document.createElement('option');
402
- otherFilters.value = 'threshold';
403
- otherFilters.innerText = 'Threshold';
404
-
405
- select.addEventListener('change', switchVisibleFilters);
406
- select.appendChild(colorFilters);
407
- select.appendChild(otherFilters);
408
- filtersTitle.appendChild(titleText);
409
- filtersTitle.appendChild(select);
410
-
411
- // Grayscale filter
412
- let bwDiv = document.createElement('div');
413
- bwDiv.classList.add('color-filters');
414
- let blackWhiteButton = document.createElement('button');
415
- blackWhiteButton.textContent = "Grayscale";
416
- blackWhiteButton.addEventListener('click', (e) => this._applyTransformationToImageData(e, grayscale));
417
- bwDiv.appendChild(blackWhiteButton);
418
-
419
- // Saturation filter
420
- let saturationDiv = document.createElement('div');
421
- saturationDiv.classList.add('color-filters');
422
- saturationDiv.classList.add('manipulation-tools-text');
423
- let saturationAdjust = document.createElement('input');
424
- let saturationText = document.createTextNode('Saturation');
425
- saturationAdjust.setAttribute('type', 'range');
426
- saturationAdjust.setAttribute('max', 100);
427
- saturationAdjust.setAttribute('min', -100);
428
- saturationAdjust.setAttribute('value', 0);
429
-
430
- saturationAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, saturation, e.target.value), 250));
431
- saturationDiv.appendChild(saturationAdjust);
432
- saturationDiv.appendChild(saturationText);
433
-
434
- // Vibrance filter
435
- let vibDiv = document.createElement('div');
436
- vibDiv.classList.add('color-filters');
437
- vibDiv.classList.add('manipulation-tools-text');
438
- let vibranceAdjust = document.createElement('input');
439
- let vibranceText = document.createTextNode('Vibrance');
440
- vibranceAdjust.setAttribute('type', 'range');
441
- vibranceAdjust.setAttribute('max', 100);
442
- vibranceAdjust.setAttribute('min', -100);
443
- vibranceAdjust.setAttribute('value', 0);
444
-
445
- vibranceAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, vibrance, e.target.value), 250));
446
- vibDiv.appendChild(vibranceAdjust);
447
- vibDiv.appendChild(vibranceText);
448
-
449
- // Brightness filter
450
- let brightDiv = document.createElement('div');
451
- brightDiv.classList.add('color-filters');
452
- brightDiv.classList.add('manipulation-tools-text');
453
- let brightnessAdjust = document.createElement('input');
454
- let brightnessText = document.createTextNode('Brightness');
455
- brightnessAdjust.setAttribute('type', 'range');
456
- brightnessAdjust.setAttribute('max', 100);
457
- brightnessAdjust.setAttribute('min', -100);
458
- brightnessAdjust.setAttribute('value', 0);
459
-
460
- brightnessAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, brightness, e.target.value), 250));
461
- brightDiv.appendChild(brightnessAdjust);
462
- brightDiv.appendChild(brightnessText);
463
-
464
- // Contrast filter
465
- let contrastDiv = document.createElement('div');
466
- contrastDiv.classList.add('color-filters');
467
- contrastDiv.classList.add('manipulation-tools-text');
468
- let contrastAdjust = document.createElement('input');
469
- let contrastText = document.createTextNode('Contrast');
470
- contrastAdjust.setAttribute('type', 'range');
471
- contrastAdjust.setAttribute('max', 100);
472
- contrastAdjust.setAttribute('min', -100);
473
- contrastAdjust.setAttribute('value', 0);
474
-
475
- contrastAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, contrast, e.target.value), 250));
476
- contrastDiv.appendChild(contrastAdjust);
477
- contrastDiv.appendChild(contrastText);
478
-
479
- // Invert colours filter
480
- let invDiv = document.createElement('div');
481
- invDiv.classList.add('color-filters');
482
- let invertButton = document.createElement('button');
483
- invertButton.textContent = "Invert Colours";
484
- invertButton.addEventListener('click', (e) => this._applyTransformationToImageData(e, invert));
485
- invDiv.appendChild(invertButton);
486
-
487
- // Sharpness filter
488
- let sharpDiv = document.createElement('div');
489
- sharpDiv.classList.add('color-filters');
490
- sharpDiv.classList.add('manipulation-tools-text');
491
- let sharpenAdjust = document.createElement('input');
492
- let sharpenText = document.createTextNode('Sharpness');
493
- sharpenAdjust.setAttribute('type', 'range');
494
- sharpenAdjust.setAttribute('max', 100);
495
- sharpenAdjust.setAttribute('min', 0);
496
- sharpenAdjust.setAttribute('value', 0);
497
-
498
- sharpenAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, sharpen, e.target.value), 250));
499
- sharpDiv.appendChild(sharpenAdjust);
500
- sharpDiv.appendChild(sharpenText);
501
-
502
- // Hue filter
503
- let hueDiv = document.createElement('div');
504
- hueDiv.classList.add('color-filters');
505
- hueDiv.classList.add('manipulation-tools-text');
506
- let hueAdjust = document.createElement('input');
507
- let hueText = document.createTextNode('Hue');
508
- hueAdjust.setAttribute('type', 'range');
509
- hueAdjust.setAttribute('max', 100);
510
- hueAdjust.setAttribute('min', 0);
511
- hueAdjust.setAttribute('value', 0);
512
-
513
- hueAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, hue, e.target.value), 250));
514
- hueDiv.appendChild(hueAdjust);
515
- hueDiv.appendChild(hueText);
516
-
517
- // Gamma filter
518
- let gammaDiv = document.createElement('div');
519
- gammaDiv.classList.add('color-filters');
520
- gammaDiv.classList.add('manipulation-tools-text');
521
- let gammaAdjust = document.createElement('input');
522
- let gammaText = document.createTextNode('Gamma');
523
- gammaAdjust.setAttribute('type', 'range');
524
- gammaAdjust.setAttribute('max', 300);
525
- gammaAdjust.setAttribute('min', -100);
526
- gammaAdjust.setAttribute('value', 0);
527
-
528
- gammaAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, gamma, e.target.value), 250));
529
- gammaDiv.appendChild(gammaAdjust);
530
- gammaDiv.appendChild(gammaText);
531
-
532
- // Colour channel RGB slides
533
- let ccRedDiv = document.createElement('div');
534
- ccRedDiv.classList.add('color-filters');
535
- ccRedDiv.classList.add('manipulation-tools-text');
536
- let ccRedAdjust = document.createElement('input');
537
- let ccRedText = document.createTextNode('CC Red');
538
- ccRedAdjust.setAttribute('type', 'range');
539
- ccRedAdjust.setAttribute('max', 100);
540
- ccRedAdjust.setAttribute('min', -100);
541
- ccRedAdjust.setAttribute('value', 0);
542
-
543
- let ccGreenDiv = document.createElement('div');
544
- ccGreenDiv.classList.add('color-filters');
545
- ccGreenDiv.classList.add('manipulation-tools-text');
546
- let ccGreenAdjust = document.createElement('input');
547
- let ccGreenText = document.createTextNode('CC Green');
548
- ccGreenAdjust.setAttribute('type', 'range');
549
- ccGreenAdjust.setAttribute('max', 100);
550
- ccGreenAdjust.setAttribute('min', -100);
551
- ccGreenAdjust.setAttribute('value', 0);
552
-
553
- let ccBlueDiv = document.createElement('div');
554
- ccBlueDiv.classList.add('color-filters');
555
- ccBlueDiv.classList.add('manipulation-tools-text');
556
- let ccBlueAdjust = document.createElement('input');
557
- let ccBlueText = document.createTextNode('CC Blue');
558
- ccBlueAdjust.setAttribute('type', 'range');
559
- ccBlueAdjust.setAttribute('max', 100);
560
- ccBlueAdjust.setAttribute('min', -100);
561
- ccBlueAdjust.setAttribute('value', 0);
562
-
563
- ccRedAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, ccRed, e.target.value), 250));
564
- ccGreenAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, ccGreen, e.target.value), 250));
565
- ccBlueAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, ccBlue, e.target.value), 250));
566
-
567
- ccRedDiv.appendChild(ccRedAdjust);
568
- ccRedDiv.appendChild(ccRedText);
569
- ccGreenDiv.appendChild(ccGreenAdjust);
570
- ccGreenDiv.appendChild(ccGreenText);
571
- ccBlueDiv.appendChild(ccBlueAdjust);
572
- ccBlueDiv.appendChild(ccBlueText);
573
-
574
- // Threshold filter
575
- let threshDiv = document.createElement('div');
576
- threshDiv.style.display = 'none';
577
- let thresholdAdjust = document.createElement('input');
578
- let thresholdText = document.createTextNode('Threshold');
579
- threshDiv.classList.add('manipulation-tools-text');
580
- thresholdAdjust.setAttribute('type', 'range');
581
- thresholdAdjust.setAttribute('max', 255);
582
- thresholdAdjust.setAttribute('min', 64);
583
- thresholdAdjust.setAttribute('value', 0);
584
-
585
- thresholdAdjust.addEventListener('change', debounce((e) => this._applyTransformationToImageData(e, threshold, e.target.value), 250));
586
- threshDiv.appendChild(thresholdAdjust);
587
- threshDiv.appendChild(thresholdText);
588
-
589
- // Reset button
590
- let resetButton = document.createElement('button');
591
- resetButton.setAttribute('style', 'margin-top: 1em;');
592
- let buttonText = document.createTextNode('Reset');
593
- resetButton.appendChild(buttonText);
594
- resetButton.onclick = (e) => { this._loadImageInMainArea(e, this.currentImageURL); };
595
-
596
- // Log to keep track of the order of filter application
597
- let filterLog = document.createElement('div');
598
- filterLog.classList.add('manipulation-tools-text');
599
- filterLog.innerHTML = "<h3> Filter Application Order <h3>";
600
- filterLog.id = 'filter-log';
601
-
602
- this._tools.appendChild(closeButton);
603
- this._tools.appendChild(header);
604
- this._tools.appendChild(zoomDiv);
605
- this._tools.appendChild(rotateDiv);
606
- this._tools.appendChild(mirrorDiv);
607
- this._tools.appendChild(filtersTitle);
608
- this._tools.appendChild(bwDiv);
609
- this._tools.appendChild(invDiv);
610
- this._tools.appendChild(saturationDiv);
611
- this._tools.appendChild(vibDiv);
612
- this._tools.appendChild(brightDiv);
613
- this._tools.appendChild(contrastDiv);
614
- this._tools.appendChild(sharpDiv);
615
- this._tools.appendChild(hueDiv);
616
- this._tools.appendChild(gammaDiv);
617
- this._tools.appendChild(ccRedDiv);
618
- this._tools.appendChild(ccGreenDiv);
619
- this._tools.appendChild(ccBlueDiv);
620
- this._tools.appendChild(threshDiv);
621
- this._tools.appendChild(resetButton);
622
- this._tools.appendChild(filterLog);
623
-
624
- this._tools.setAttribute('style', 'padding: 0 1em;');
625
-
626
- function switchVisibleFilters ()
627
- {
628
- let filters = document.getElementsByClassName('color-filters');
629
-
630
- if (this.value === 'threshold')
631
- {
632
- for (let i = 0, len = filters.length; i < len; i++)
633
- {
634
- filters[i].style.display = 'none';
635
- }
636
-
637
- threshDiv.style.display = 'block';
638
- }
639
- else
640
- {
641
- for (let i = 0, len = filters.length; i < len; i++)
642
- {
643
- filters[i].style.display = 'block';
644
- }
645
-
646
- threshDiv.style.display = 'none';
647
- }
648
- }
649
- }
650
-
651
- _resetSliders ()
652
- {
653
- // check if element is a slider, if so then reset
654
- for (let i = 0, len = this._tools.children.length; i < len; i++)
655
- {
656
- let tool = this._tools.children[i].children[0];
657
- if (tool && tool.type === 'range')
658
- tool.value = 0;
659
- }
660
-
661
- document.getElementById('filter-log').innerHTML = "<h3> Filter Application Order <h3>";
662
-
663
- // reset counters
664
- this.zoom = 1;
665
- this.rotate = 0;
666
-
667
- // reset mirror
668
- this.mirrorHorizontal = 1;
669
- this.mirrorVertical = 1;
670
- this.handleTransform(null, null, this.rotate);
671
-
672
- resetFilters();
673
- }
674
-
675
- _loadImageInMainArea (event, imageURL)
676
- {
677
- this.currentImageURL = imageURL; // for resetting
678
-
679
- let url = `${imageURL}full/full/0/default.jpg`;
680
-
681
- this._mainImage = new Image();
682
- this._mainImage.crossOrigin = "anonymous";
683
-
684
- this._mainImage.addEventListener('load', () =>
685
- {
686
- // Determine the size of the (square) canvas based on the hypoteneuse
687
- this._canvas.size = Math.sqrt(this._mainImage.width * this._mainImage.width + this._mainImage.height * this._mainImage.height);
688
- this._canvas.width = this._canvas.size;
689
- this._canvas.height = this._canvas.size;
690
- this._canvas.cornerX = (this._canvas.size - this._mainImage.width) / 2;
691
- this._canvas.cornerY = (this._canvas.size - this._mainImage.height) / 2;
692
-
693
- this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
694
- this._ctx.drawImage(this._mainImage, this._canvas.cornerX, this._canvas.cornerY, this._mainImage.width, this._mainImage.height);
695
- this._originalData = this._ctx.getImageData(this._canvas.cornerX, this._canvas.cornerY, this._mainImage.width, this._mainImage.height);
696
- this._alteredData = this._originalData;
697
-
698
- // to preserve pre-zoom dimensions
699
- this.dims = {
700
- w: this._canvas.width,
701
- h: this._canvas.height
702
- };
703
-
704
- // clean up the image data since it's been painted to the canvas
705
- this._mainImage = null;
706
-
707
- // center the viewport
708
- this.centerView();
709
- });
710
-
711
- this._mainImage.src = url;
712
-
713
- this._resetSliders();
714
- }
715
-
716
- _applyTransformationToImageData (event, func, value)
717
- {
718
- let cw = this._canvas.width;
719
- let ch = this._canvas.height;
720
- let adjustment;
721
-
722
- if (value)
723
- {
724
- adjustment = parseInt(value, 10);
725
- }
726
-
727
- let newData = func(this._originalData, adjustment);
728
- this._alteredData = newData;
729
-
730
- this._ctx.clearRect(0, 0, cw, ch);
731
- this._ctx.putImageData(newData, this._canvas.cornerX, this._canvas.cornerY);
732
-
733
- // necessary to reset the current zoom level (since ImageData gets altered at zoom 1)
734
- this.handleZoom(event, this.zoom, false);
735
- }
736
-
737
- handleZoom (event, value, recenter)
738
- {
739
- let scale = value * 0.5 + 0.5;
740
-
741
- let w = this.dims.w;
742
- let h = this.dims.h;
743
-
744
- // temp canvas for drawing at original zoom level
745
- let tempCanvas = document.createElement('canvas');
746
- let tempCtx = tempCanvas.getContext('2d');
747
- tempCanvas.width = w;
748
- tempCanvas.height = h;
749
- tempCtx.putImageData(this._alteredData, this._canvas.cornerX, this._canvas.cornerY);
750
-
751
- this._canvas.width = w * scale;
752
- this._canvas.height = h * scale;
753
- this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
754
- this._ctx.scale(scale, scale);
755
- this._ctx.drawImage(tempCanvas, 0, 0);
756
-
757
- // determine if zooming in or not
758
- let zoomingIn = value > this.zoom ? true : false;
759
-
760
- this.zoom = parseInt(value, 10);
761
-
762
- if (recenter)
763
- {
764
- let rect = event.target.getBoundingClientRect();
765
- let x = event.clientX - rect.left;
766
- let y = event.clientY - rect.top;
767
-
768
- if (!zoomingIn)
769
- {
770
- // x & y are in terms of pre-zoom-out dimensions, so scale down accordingly
771
- let scaleOut = (this.zoom * 0.5 + 0.5) / ((this.zoom + 1) * 0.5 + 0.5);
772
- x *= scaleOut;
773
- y *= scaleOut;
774
- }
775
-
776
- this.centerView(x, y, zoomingIn);
777
- }
778
- }
779
-
780
- centerView (x, y, zoomingIn)
781
- {
782
- let view = document.getElementsByClassName('manipulation-main-area')[0];
783
- if (!view)
784
- view = document.getElementsByClassName('manipulation-main-area-mobile')[0];
785
-
786
- if (zoomingIn)
787
- {
788
- // x & y are in terms of pre-zoom-in dimensions, so scale up accordingly
789
- let scaleIn = (this.zoom * 0.5 + 0.5) / ((this.zoom - 1) * 0.5 + 0.5);
790
- x *= scaleIn;
791
- y *= scaleIn;
792
- }
793
-
794
- // distance from center
795
- let center = this._canvas.height / 2;
796
- let distY = y - center;
797
- let distX = x - center;
798
-
799
- let h = this._canvas.height;
800
- let w = this._canvas.width;
801
-
802
- let topCentered = (h - view.clientHeight) / 2;
803
- let leftCentered = (w - view.clientWidth) / 2;
804
-
805
- let top = y ? topCentered + distY : topCentered;
806
- let left = x ? leftCentered + distX : leftCentered;
807
-
808
- view.scrollTop = top;
809
- view.scrollLeft = left;
810
- }
811
-
812
- handleTransform (event, type, value)
813
- {
814
- let canvas = document.getElementsByClassName('manipulation-main-area')[0].children[0];
815
-
816
- if (type === 'vertical')
817
- this.mirrorVertical *= -1;
818
- else if (type === 'horizontal')
819
- this.mirrorHorizontal *= -1;
820
-
821
- canvas.style.transform = "scale("+this.mirrorHorizontal+","+this.mirrorVertical+") rotate("+value+"deg)";
822
-
823
- this.rotate = value;
824
- }
825
- }
826
-
827
- ManipulationPlugin.prototype.pluginName = "manipulation";
828
- ManipulationPlugin.prototype.isPageTool = true;
829
-
830
- /**
831
- * Make this plugin available in the global context
832
- * as part of the 'Diva' namespace.
833
- **/
834
- (function (global)
835
- {
836
- global.Diva.ManipulationPlugin = ManipulationPlugin;
837
- })(window);