From c3d9b102c5f8681c9cdb42fdd73537be14e66b65 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Thu, 8 Jan 2015 13:22:23 -0800 Subject: [PATCH 01/25] First version of m2 POC --- test/demo/m2/index.html | 55 +++++++++ test/demo/m2/js/main.js | 239 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 test/demo/m2/index.html create mode 100644 test/demo/m2/js/main.js diff --git a/test/demo/m2/index.html b/test/demo/m2/index.html new file mode 100644 index 00000000..ce9100ac --- /dev/null +++ b/test/demo/m2/index.html @@ -0,0 +1,55 @@ + + + + Mirador POC + + + + + + +
+ + + + + +
+
+ + diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js new file mode 100644 index 00000000..d9aa6386 --- /dev/null +++ b/test/demo/m2/js/main.js @@ -0,0 +1,239 @@ +/* globals $, App */ + +(function() { + // ---------- + window.App = { + // ---------- + init: function() { + var self = this; + + var count = 50; + + this.mode = 'none'; + this.pageBuffer = 0.05; + this.page = 0; + this.modeNames = [ + 'thumbs', + 'scroll', + 'book', + 'page' + ]; + + var tileSource = { + Image: { + xmlns: "http://schemas.microsoft.com/deepzoom/2008", + Url: "http://openseadragon.github.io/example-images/highsmith/highsmith_files/", + Format: "jpg", + Overlap: "2", + TileSize: "256", + Size: { + Height: "9221", + Width: "7026" + } + } + }; + + var tileSources = []; + for (var i = 0; i < count; i++) { + tileSources.push(tileSource); + } + + this.viewer = OpenSeadragon({ + id: "contentDiv", + prefixUrl: "../../../build/openseadragon/images/", + tileSources: tileSources + }); + + this.viewer.addHandler('open', function() { + self.setMode('thumbs'); + }); + + $.each(this.modeNames, function(i, v) { + $('.' + v).click(function() { + self.setMode(v); + }); + }); + + $('.next').click(function() { + var page = self.page + (self.mode === 'book' ? 2 : 1); + if (self.mode === 'book' && page % 2 === 0 && page !== 0) { + page --; + } + + self.goToPage(page); + }); + + $('.previous').click(function() { + var page = self.page - (self.mode === 'book' ? 2 : 1); + if (self.mode === 'book' && page % 2 === 0 && page !== 0) { + page --; + } + + self.goToPage(page); + }); + + this.update(); + }, + + // ---------- + update: function() { + var self = this; + + $('.nav').toggle(this.mode === 'book' || this.mode === 'page'); + $('.previous').toggleClass('hidden', this.page <= 0); + $('.next').toggleClass('hidden', this.page >= this.viewer.world.getItemCount() - 1); + + $.each(this.modeNames, function(i, v) { + $('.' + v).toggleClass('active', v === self.mode); + }); + }, + + // ---------- + setMode: function(mode) { + if (this.mode === mode) { + return; + } + + this.mode = mode; + + if (this.mode === 'thumbs') { + this.doThumbnails(); + } + + if (this.mode === 'scroll') { + this.doScroll(); + } + + if (this.mode === 'book') { + this.doBook(); + } + + if (this.mode === 'page') { + this.doPage(); + } + + this.update(); + }, + + // ---------- + goToPage: function(page) { + if (page < 0 || page >= this.viewer.world.getItemCount()) { + return; + } + + this.page = page; + + var bounds = this.viewer.world.getItemAt(this.page).getBounds(); + var x = bounds.x; + var y = bounds.y; + var width = bounds.width; + var height = bounds.height; + + if (this.mode === 'book') { + var item; + if (this.page % 2) { // First in a pair + item = this.viewer.world.getItemAt(this.page + 1); + if (item) { + width += item.getBounds().width; + } + } else { + item = this.viewer.world.getItemAt(this.page - 1); + if (item) { + var box = item.getBounds(); + x -= width; + width += box.width; + } + } + } + + x -= this.pageBuffer; + y -= this.pageBuffer; + width += (this.pageBuffer * 2); + height += (this.pageBuffer * 2); + this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(x, y, width, height)); + + this.update(); + }, + + // ---------- + doLayout: function(config) { + var count = this.viewer.world.getItemCount(); + var x = 0; + var y = 0; + + var item; + for (var i = 0; i < count; i++) { + item = this.viewer.world.getItemAt(i); + item.setPosition(new OpenSeadragon.Point(x, y)); + if (config.columns && i % config.columns === config.columns - 1) { + x = 0; + y += item.getBounds().height + config.buffer; + } else { + if (!config.book || i % 2 === 0) { + x += config.buffer; + } + + x += 1; + } + } + }, + + // ---------- + doThumbnails: function() { + var viewerWidth = $(this.viewer.element).width(); + var viewerHeight = $(this.viewer.element).height(); + var columns = Math.floor(viewerWidth / 150); + var buffer = 0.2; + this.doLayout({ + columns: columns, + buffer: buffer + }); + + var width = columns + (buffer * (columns + 1)); + var height = width * (viewerHeight / viewerWidth); + + this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(-buffer, -buffer, width, height)); + }, + + // ---------- + doScroll: function() { + var viewerWidth = $(this.viewer.element).width(); + var viewerHeight = $(this.viewer.element).height(); + var buffer = 0.05; + + this.doLayout({ + buffer: buffer + }); + + var height = this.viewer.world.getItemAt(0).getBounds().height; + height += buffer * 2; + var width = height * (viewerWidth / viewerHeight); + + this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(-buffer, -buffer, width, height)); + }, + + // ---------- + doBook: function() { + this.doLayout({ + buffer: 0.2, + book: true + }); + + this.goToPage(this.page); + }, + + // ---------- + doPage: function() { + this.doLayout({ + buffer: 2 + }); + + this.goToPage(this.page); + } + }; + + // ---------- + $(document).ready(function() { + App.init(); + }); +})(); From 3956e6013aeaa95eef28550e92f97ee3aecd7753 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Thu, 8 Jan 2015 14:04:31 -0800 Subject: [PATCH 02/25] Clicking into thumbnails (m2) --- test/demo/m2/js/main.js | 45 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js index d9aa6386..5d429681 100644 --- a/test/demo/m2/js/main.js +++ b/test/demo/m2/js/main.js @@ -41,6 +41,7 @@ this.viewer = OpenSeadragon({ id: "contentDiv", prefixUrl: "../../../build/openseadragon/images/", + // zoomPerClick: 1, tileSources: tileSources }); @@ -48,6 +49,26 @@ self.setMode('thumbs'); }); + this.viewer.addHandler('canvas-click', function(event) { + if (self.mode !== 'thumbs') { + return; + } + + var pos = self.viewer.viewport.pointFromPixel(event.position); + var count = self.viewer.world.getItemCount(); + var item, box; + + for (var i = 0; i < count; i++) { + item = self.viewer.world.getItemAt(i); + box = item.getBounds(); + if (pos.x > box.x && pos.y > box.y && pos.x < box.x + box.width && + pos.y < box.y + box.height) { + self.setMode('page', i); + break; + } + } + }); + $.each(this.modeNames, function(i, v) { $('.' + v).click(function() { self.setMode(v); @@ -89,13 +110,21 @@ }, // ---------- - setMode: function(mode) { + setMode: function(mode, page) { if (this.mode === mode) { + if (page !== undefined) { + this.goToPage(page); + } + return; } this.mode = mode; + if (page !== undefined) { + this.page = page; // Need to do this before layout + } + if (this.mode === 'thumbs') { this.doThumbnails(); } @@ -112,6 +141,10 @@ this.doPage(); } + if (page !== undefined) { + this.goToPage(page); // Need to do this after layout; does the zoom/pan + } + this.update(); }, @@ -160,11 +193,12 @@ var count = this.viewer.world.getItemCount(); var x = 0; var y = 0; + var points = []; var item; for (var i = 0; i < count; i++) { item = this.viewer.world.getItemAt(i); - item.setPosition(new OpenSeadragon.Point(x, y)); + points.push(new OpenSeadragon.Point(x, y)); if (config.columns && i % config.columns === config.columns - 1) { x = 0; y += item.getBounds().height + config.buffer; @@ -176,6 +210,13 @@ x += 1; } } + + var tl = this.viewer.world.getItemAt(this.page).getBounds().getTopLeft(); + var offset = tl.minus(points[this.page]); + for (i = 0; i < count; i++) { + item = this.viewer.world.getItemAt(i); + item.setPosition(points[i].plus(offset)); + } }, // ---------- From 4fa6fea850e7dc9ec1bb5d5ab5d54ee5fd433381 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 9 Jan 2015 11:45:53 -0800 Subject: [PATCH 03/25] Scrollwheel for thumbs (m2) --- changelog.txt | 1 + src/viewer.js | 7 +++-- test/demo/m2/README.md | 12 ++++++++ test/demo/m2/index.html | 16 ++++++++++- test/demo/m2/js/main.js | 61 +++++++++++++++++++++++++++++++++++++---- 5 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 test/demo/m2/README.md diff --git a/changelog.txt b/changelog.txt index 98a94fd0..6f707cbb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -39,6 +39,7 @@ OPENSEADRAGON CHANGELOG * Rect and Point toString() functions are now consistent: rounding values to nearest hundredth * Overlays appear in the DOM immediately on open or addOverlay (#507) * imageLoaderLimit now works (#544) +* Turning off scrollToZoom in gestureSettings now allows scroll events to propagate 1.2.0: (in progress) diff --git a/src/viewer.js b/src/viewer.js index 781af981..b3350306 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2534,8 +2534,11 @@ function onCanvasScroll( event ) { shift: event.shift, originalEvent: event.originalEvent }); - //cancels event - return false; + + if (gestureSettings && gestureSettings.scrollToZoom) { + //cancels event + return false; + } } function onContainerExit( event ) { diff --git a/test/demo/m2/README.md b/test/demo/m2/README.md new file mode 100644 index 00000000..c6afeccd --- /dev/null +++ b/test/demo/m2/README.md @@ -0,0 +1,12 @@ +# To Do + +* Correct page height for thumbs +* Scroll view: go to current page when entering mode; clamp at first and last + +* Constraints + * Thumbs: no zoom, no pan + * Scroll: can't zoom out much, can't pan up and down + * Book, Page: just the shown item +* Resize on window resize +* When going to thumbs, scroll to the proper part of the page +* Show/hide pages? diff --git a/test/demo/m2/index.html b/test/demo/m2/index.html index ce9100ac..c9b924ba 100644 --- a/test/demo/m2/index.html +++ b/test/demo/m2/index.html @@ -12,7 +12,15 @@ width: 100%; height: 100%; margin: 0; + } + + body { background: #eee; + overflow: scroll; + } + + .header { + height: 30px; } .nav { @@ -29,12 +37,18 @@ } .openseadragon1 { + background: white; + } + + .openseadragon1.full { position: absolute; left: 0; top: 30px; right: 0; bottom: 0; - background: white; + } + + .openseadragon1.thumbs { } diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js index 5d429681..7ed3fd4d 100644 --- a/test/demo/m2/js/main.js +++ b/test/demo/m2/js/main.js @@ -41,16 +41,19 @@ this.viewer = OpenSeadragon({ id: "contentDiv", prefixUrl: "../../../build/openseadragon/images/", - // zoomPerClick: 1, + autoResize: false, + // animationTime: 10, + // springStiffness: 2, tileSources: tileSources }); this.viewer.addHandler('open', function() { + self.$el = $(self.viewer.element); self.setMode('thumbs'); }); this.viewer.addHandler('canvas-click', function(event) { - if (self.mode !== 'thumbs') { + if (self.mode !== 'thumbs' || !event.quick) { return; } @@ -111,6 +114,8 @@ // ---------- setMode: function(mode, page) { + var self = this; + if (this.mode === mode) { if (page !== undefined) { this.goToPage(page); @@ -125,6 +130,45 @@ this.page = page; // Need to do this before layout } + var oldSize = new OpenSeadragon.Point(this.$el.width(), this.$el.height()); + var oldBounds = this.viewer.viewport.getBounds(); + var scrollTop = $(window).scrollTop(); + var scrollMax = $(document).height() - $(window).height(); + var scrollFactor = (scrollMax > 0 ? scrollTop / scrollMax : 0); + + if (this.mode === 'thumbs') { + this.viewer.gestureSettingsMouse.scrollToZoom = false; + this.viewer.zoomPerClick = 1; + $('.openseadragon1') + .addClass('thumbs') + .removeClass('full') + .css({ + height: 2000 + }); + } else { + this.viewer.gestureSettingsMouse.scrollToZoom = true; + this.viewer.zoomPerClick = 2; + $('.openseadragon1') + .addClass('full') + .removeClass('thumbs') + .css({ + height: 'auto' + }); + } + + var newSize = new OpenSeadragon.Point(this.$el.width(), this.$el.height()); + if (oldSize.x !== newSize.x || oldSize.y !== newSize.y) { + this.viewer.viewport.resize(newSize, false); + var newBounds = this.viewer.viewport.getBounds(); + var box = oldBounds.clone(); + box.height = box.width * (newBounds.height / newBounds.width); + + var boxMax = oldBounds.height - box.height; + box.y += boxMax * scrollFactor; + this.viewer.viewport.fitBounds(box, true); + this.viewer.viewport.update(); + } + if (this.mode === 'thumbs') { this.doThumbnails(); } @@ -230,10 +274,13 @@ buffer: buffer }); + var bounds = this.viewer.world.getItemAt(0).getBounds(); + var x = bounds.x - buffer; + var y = bounds.y - buffer; var width = columns + (buffer * (columns + 1)); var height = width * (viewerHeight / viewerWidth); - this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(-buffer, -buffer, width, height)); + this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(x, y, width, height)); }, // ---------- @@ -246,11 +293,13 @@ buffer: buffer }); - var height = this.viewer.world.getItemAt(0).getBounds().height; - height += buffer * 2; + var bounds = this.viewer.world.getItemAt(0).getBounds(); + var x = bounds.x - buffer; + var y = bounds.y - buffer; + var height = bounds.height + (buffer * 2); var width = height * (viewerWidth / viewerHeight); - this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(-buffer, -buffer, width, height)); + this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(x, y, width, height)); }, // ---------- From 70e461c21458b92a401704b40036b0678f5f8fa7 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 9 Jan 2015 13:53:48 -0800 Subject: [PATCH 04/25] * Correct page height for thumbs (m2) --- test/demo/m2/README.md | 1 - test/demo/m2/js/main.js | 167 +++++++++++++++++++++++----------------- 2 files changed, 97 insertions(+), 71 deletions(-) diff --git a/test/demo/m2/README.md b/test/demo/m2/README.md index c6afeccd..ceffed8f 100644 --- a/test/demo/m2/README.md +++ b/test/demo/m2/README.md @@ -1,6 +1,5 @@ # To Do -* Correct page height for thumbs * Scroll view: go to current page when entering mode; clamp at first and last * Constraints diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js index 7ed3fd4d..2a9e50af 100644 --- a/test/demo/m2/js/main.js +++ b/test/demo/m2/js/main.js @@ -11,6 +11,7 @@ this.mode = 'none'; this.pageBuffer = 0.05; + this.bigBuffer = 0.2; this.page = 0; this.modeNames = [ 'thumbs', @@ -130,6 +131,8 @@ this.page = page; // Need to do this before layout } + var layout = this.createLayout(); + var oldSize = new OpenSeadragon.Point(this.$el.width(), this.$el.height()); var oldBounds = this.viewer.viewport.getBounds(); var scrollTop = $(window).scrollTop(); @@ -139,16 +142,20 @@ if (this.mode === 'thumbs') { this.viewer.gestureSettingsMouse.scrollToZoom = false; this.viewer.zoomPerClick = 1; - $('.openseadragon1') + var viewerWidth = this.$el.width(); + var width = layout.bounds.width + (this.bigBuffer * 2); + var height = layout.bounds.height + (this.bigBuffer * 2); + var newHeight = viewerWidth * (height / width); + this.$el .addClass('thumbs') .removeClass('full') .css({ - height: 2000 + height: newHeight }); } else { this.viewer.gestureSettingsMouse.scrollToZoom = true; this.viewer.zoomPerClick = 2; - $('.openseadragon1') + this.$el .addClass('full') .removeClass('thumbs') .css({ @@ -169,24 +176,12 @@ this.viewer.viewport.update(); } - if (this.mode === 'thumbs') { - this.doThumbnails(); - } - - if (this.mode === 'scroll') { - this.doScroll(); - } - - if (this.mode === 'book') { - this.doBook(); - } - - if (this.mode === 'page') { - this.doPage(); - } + this.setLayout(layout); if (page !== undefined) { this.goToPage(page); // Need to do this after layout; does the zoom/pan + } else { + this.goHome(); } this.update(); @@ -233,7 +228,28 @@ }, // ---------- - doLayout: function(config) { + createLayout: function() { + var viewerWidth = this.$el.width(); + var viewerHeight = this.$el.height(); + var layoutConfig = {}; + + if (this.mode === 'thumbs') { + layoutConfig.columns = Math.floor(viewerWidth / 150); + layoutConfig.buffer = this.bigBuffer; + } else if (this.mode === 'scroll') { + layoutConfig.buffer = this.pageBuffer; + } else if (this.mode === 'book') { + layoutConfig.book = true; + layoutConfig.buffer = this.bigBuffer; + } else if (this.mode === 'page') { + layoutConfig.buffer = 2; + } + + var layout = { + bounds: null, + specs: [] + }; + var count = this.viewer.world.getItemCount(); var x = 0; var y = 0; @@ -243,12 +259,12 @@ for (var i = 0; i < count; i++) { item = this.viewer.world.getItemAt(i); points.push(new OpenSeadragon.Point(x, y)); - if (config.columns && i % config.columns === config.columns - 1) { + if (layoutConfig.columns && i % layoutConfig.columns === layoutConfig.columns - 1) { x = 0; - y += item.getBounds().height + config.buffer; + y += item.getBounds().height + layoutConfig.buffer; } else { - if (!config.book || i % 2 === 0) { - x += config.buffer; + if (!layoutConfig.book || i % 2 === 0) { + x += layoutConfig.buffer; } x += 1; @@ -257,68 +273,79 @@ var tl = this.viewer.world.getItemAt(this.page).getBounds().getTopLeft(); var offset = tl.minus(points[this.page]); + var box, pos; + for (i = 0; i < count; i++) { item = this.viewer.world.getItemAt(i); - item.setPosition(points[i].plus(offset)); + box = item.getBounds(); + pos = points[i].plus(offset); + box.x = pos.x; + box.y = pos.y; + layout.specs.push({ + item: item, + bounds: box + }); + + if (layout.bounds) { + layout.bounds = this.union(layout.bounds, box); + } else { + layout.bounds = box.clone(); + } + } + + return layout; + }, + + // ---------- + setLayout: function(layout) { + var spec; + + for (var i = 0; i < layout.specs.length; i++) { + spec = layout.specs[i]; + spec.item.setPosition(spec.bounds.getTopLeft()); } }, // ---------- - doThumbnails: function() { - var viewerWidth = $(this.viewer.element).width(); - var viewerHeight = $(this.viewer.element).height(); - var columns = Math.floor(viewerWidth / 150); - var buffer = 0.2; - this.doLayout({ - columns: columns, - buffer: buffer - }); + goHome: function() { + var viewerWidth = this.$el.width(); + var viewerHeight = this.$el.height(); + var layoutConfig = {}; - var bounds = this.viewer.world.getItemAt(0).getBounds(); - var x = bounds.x - buffer; - var y = bounds.y - buffer; - var width = columns + (buffer * (columns + 1)); - var height = width * (viewerHeight / viewerWidth); - - this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(x, y, width, height)); + var box; + if (this.mode === 'thumbs') { + box = this.viewer.world.getHomeBounds(); + box.x -= this.bigBuffer; + box.y -= this.bigBuffer; + box.width += (this.bigBuffer * 2); + box.height = box.width * (viewerHeight / viewerWidth); + this.viewer.viewport.fitBounds(box); + } else if (this.mode === 'scroll') { + this.goToPage(this.page); + } else if (this.mode === 'book') { + this.goToPage(this.page); + } else if (this.mode === 'page') { + this.goToPage(this.page); + } }, // ---------- doScroll: function() { - var viewerWidth = $(this.viewer.element).width(); - var viewerHeight = $(this.viewer.element).height(); - var buffer = 0.05; - - this.doLayout({ - buffer: buffer - }); - - var bounds = this.viewer.world.getItemAt(0).getBounds(); - var x = bounds.x - buffer; - var y = bounds.y - buffer; - var height = bounds.height + (buffer * 2); - var width = height * (viewerWidth / viewerHeight); - - this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(x, y, width, height)); + // var bounds = this.viewer.world.getItemAt(0).getBounds(); + // var x = bounds.x - buffer; + // var y = bounds.y - buffer; + // var height = bounds.height + (buffer * 2); + // var width = height * (viewerWidth / viewerHeight); }, // ---------- - doBook: function() { - this.doLayout({ - buffer: 0.2, - book: true - }); + union: function(box1, box2) { + var left = Math.min(box1.x, box2.x); + var top = Math.min(box1.y, box2.y); + var right = Math.max(box1.x + box1.width, box2.x + box2.width); + var bottom = Math.max(box1.y + box1.height, box2.y + box2.height); - this.goToPage(this.page); - }, - - // ---------- - doPage: function() { - this.doLayout({ - buffer: 2 - }); - - this.goToPage(this.page); + return new OpenSeadragon.Rect(left, top, right - left, bottom - top); } }; From a470d10f4d9a7587b76196849b2e7ccfd8f87978 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 9 Jan 2015 14:04:45 -0800 Subject: [PATCH 05/25] * Scroll view: go to current page when entering mode; clamp at first and last (m2) --- test/demo/m2/README.md | 5 +++-- test/demo/m2/js/main.js | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/test/demo/m2/README.md b/test/demo/m2/README.md index ceffed8f..f76745b3 100644 --- a/test/demo/m2/README.md +++ b/test/demo/m2/README.md @@ -1,7 +1,7 @@ # To Do -* Scroll view: go to current page when entering mode; clamp at first and last - +* Next/previous in scroll mode +* Detect which page you're on in scroll mode (when switching to other modes) * Constraints * Thumbs: no zoom, no pan * Scroll: can't zoom out much, can't pan up and down @@ -9,3 +9,4 @@ * Resize on window resize * When going to thumbs, scroll to the proper part of the page * Show/hide pages? +* Arrow keys diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js index 2a9e50af..43499dc1 100644 --- a/test/demo/m2/js/main.js +++ b/test/demo/m2/js/main.js @@ -195,6 +195,8 @@ this.page = page; + var viewerWidth = this.$el.width(); + var viewerHeight = this.$el.height(); var bounds = this.viewer.world.getItemAt(this.page).getBounds(); var x = bounds.x; var y = bounds.y; @@ -222,6 +224,17 @@ y -= this.pageBuffer; width += (this.pageBuffer * 2); height += (this.pageBuffer * 2); + + if (this.mode === 'scroll') { + if (this.page === 0) { + x = -this.pageBuffer; + width = height * (viewerWidth / viewerHeight); + } else if (this.page === this.viewer.world.getItemCount() - 1) { + width = height * (viewerWidth / viewerHeight); + x = (bounds.x + bounds.width + this.pageBuffer) - width; + } + } + this.viewer.viewport.fitBounds(new OpenSeadragon.Rect(x, y, width, height)); this.update(); From c1d93acb27e30476baa9f84138605880f73ff660 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 9 Jan 2015 15:11:11 -0800 Subject: [PATCH 06/25] Better next/previous support (m2) --- test/demo/m2/README.md | 6 +-- test/demo/m2/js/main.js | 89 +++++++++++++++++++++++++++++++---------- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/test/demo/m2/README.md b/test/demo/m2/README.md index f76745b3..392c1fd4 100644 --- a/test/demo/m2/README.md +++ b/test/demo/m2/README.md @@ -1,7 +1,8 @@ # To Do -* Next/previous in scroll mode -* Detect which page you're on in scroll mode (when switching to other modes) +* Real book +* Make sure adjacent pages aren't visible +* Thumbs hover and active state (SVG overlay?) * Constraints * Thumbs: no zoom, no pan * Scroll: can't zoom out much, can't pan up and down @@ -9,4 +10,3 @@ * Resize on window resize * When going to thumbs, scroll to the proper part of the page * Show/hide pages? -* Arrow keys diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js index 43499dc1..59885886 100644 --- a/test/demo/m2/js/main.js +++ b/test/demo/m2/js/main.js @@ -59,17 +59,20 @@ } var pos = self.viewer.viewport.pointFromPixel(event.position); - var count = self.viewer.world.getItemCount(); - var item, box; + var result = self.hitTest(pos); + if (result) { + self.setMode('page', result.index); + } + }); - for (var i = 0; i < count; i++) { - item = self.viewer.world.getItemAt(i); - box = item.getBounds(); - if (pos.x > box.x && pos.y > box.y && pos.x < box.x + box.width && - pos.y < box.y + box.height) { - self.setMode('page', i); - break; - } + this.viewer.addHandler('pan', function(event) { + if (self.mode !== 'scroll') { + return; + } + + var result = self.hitTest(event.center); + if (result) { + self.page = result.index; } }); @@ -80,31 +83,73 @@ }); $('.next').click(function() { - var page = self.page + (self.mode === 'book' ? 2 : 1); - if (self.mode === 'book' && page % 2 === 0 && page !== 0) { - page --; - } - - self.goToPage(page); + self.next(); }); $('.previous').click(function() { - var page = self.page - (self.mode === 'book' ? 2 : 1); - if (self.mode === 'book' && page % 2 === 0 && page !== 0) { - page --; + self.previous(); + }); + + $(window).keyup(function(event) { + if (self.mode === 'thumbs') { + return; } - self.goToPage(page); + if (event.which === 39) { // Right arrow + self.next(); + } else if (event.which === 37) { // Left arrow + self.previous(); + } }); this.update(); }, + // ---------- + next: function() { + var page = this.page + (this.mode === 'book' ? 2 : 1); + if (this.mode === 'book' && page % 2 === 0 && page !== 0) { + page --; + } + + this.goToPage(page); + }, + + // ---------- + previous: function() { + var page = this.page - (this.mode === 'book' ? 2 : 1); + if (this.mode === 'book' && page % 2 === 0 && page !== 0) { + page --; + } + + this.goToPage(page); + }, + + // ---------- + hitTest: function(pos) { + var count = this.viewer.world.getItemCount(); + var item, box; + + for (var i = 0; i < count; i++) { + item = this.viewer.world.getItemAt(i); + box = item.getBounds(); + if (pos.x > box.x && pos.y > box.y && pos.x < box.x + box.width && + pos.y < box.y + box.height) { + return { + item: item, + index: i + }; + } + } + + return null; + }, + // ---------- update: function() { var self = this; - $('.nav').toggle(this.mode === 'book' || this.mode === 'page'); + $('.nav').toggle(this.mode === 'scroll' || this.mode === 'book' || this.mode === 'page'); $('.previous').toggleClass('hidden', this.page <= 0); $('.next').toggleClass('hidden', this.page >= this.viewer.world.getItemCount() - 1); @@ -227,7 +272,7 @@ if (this.mode === 'scroll') { if (this.page === 0) { - x = -this.pageBuffer; + x = bounds.x - this.pageBuffer; width = height * (viewerWidth / viewerHeight); } else if (this.page === this.viewer.world.getItemCount() - 1) { width = height * (viewerWidth / viewerHeight); From 0429d8fe7fedaec8eb3171fe79b44543e779f8ad Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 9 Jan 2015 15:46:57 -0800 Subject: [PATCH 07/25] Using real book images (m2) --- test/demo/m2/README.md | 7 +- test/demo/m2/index.html | 1 + test/demo/m2/js/main.js | 27 +- test/demo/m2/js/tilesources.js | 482 +++++++++++++++++++++++++++++++++ 4 files changed, 491 insertions(+), 26 deletions(-) create mode 100644 test/demo/m2/js/tilesources.js diff --git a/test/demo/m2/README.md b/test/demo/m2/README.md index 392c1fd4..7885efec 100644 --- a/test/demo/m2/README.md +++ b/test/demo/m2/README.md @@ -1,12 +1,13 @@ # To Do -* Real book -* Make sure adjacent pages aren't visible -* Thumbs hover and active state (SVG overlay?) * Constraints * Thumbs: no zoom, no pan * Scroll: can't zoom out much, can't pan up and down * Book, Page: just the shown item +* Consistent height for all pages (rather than width) +* Make sure adjacent pages aren't visible +* Thumbs hover and active state (SVG overlay?) * Resize on window resize * When going to thumbs, scroll to the proper part of the page * Show/hide pages? +* Support 400+ page collections diff --git a/test/demo/m2/index.html b/test/demo/m2/index.html index c9b924ba..6cc52a42 100644 --- a/test/demo/m2/index.html +++ b/test/demo/m2/index.html @@ -5,6 +5,7 @@ + @@ -67,6 +70,9 @@ -
+
+
+
+
diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js index d7628d46..5b6cdcee 100644 --- a/test/demo/m2/js/main.js +++ b/test/demo/m2/js/main.js @@ -20,6 +20,25 @@ 'page' ]; + var highsmith = { + Image: { + xmlns: "http://schemas.microsoft.com/deepzoom/2008", + Url: "http://openseadragon.github.io/example-images/highsmith/highsmith_files/", + Format: "jpg", + Overlap: "2", + TileSize: "256", + Size: { + Height: "9221", + Width: "7026" + } + } + }; + + // this.tileSources = []; + // for (var i = 0; i < count; i++) { + // this.tileSources.push(highsmith); + // } + this.viewer = OpenSeadragon({ id: "contentDiv", prefixUrl: "../../../build/openseadragon/images/", @@ -37,21 +56,6 @@ }); }); - this.viewer.addHandler('canvas-click', function(event) { - if (self.mode !== 'thumbs' || !event.quick) { - return; - } - - var pos = self.viewer.viewport.pointFromPixel(event.position); - var result = self.hitTest(pos); - if (result) { - self.setMode({ - mode: 'page', - page: result.index - }); - } - }); - this.viewer.addHandler('canvas-drag', function() { if (this.mode === 'scroll') { var result = this.hitTest(this.viewer.viewport.getCenter()); @@ -65,18 +69,6 @@ self.applyConstraints(); }); - var tracker = new OpenSeadragon.MouseTracker({ - element: this.viewer.container, - moveHandler: function(event) { - if (self.mode === 'thumbs') { - var result = self.hitTest(self.viewer.viewport.pointFromPixel(event.position)); - self.updateHover(result ? result.index : -1); - } - } - }); - - tracker.setTracking(true); - $.each(this.modeNames, function(i, v) { $('.' + v).click(function() { self.setMode({ @@ -105,6 +97,37 @@ } }); + this.$scrollInner = $('.scroll-inner'); + + this.$scrollCover = $('.scroll-cover') + .scroll(function(event) { + var info = self.getScrollInfo(); + if (!info || self.ignoreScroll) { + return; + } + + var pos = new OpenSeadragon.Point(info.thumbBounds.getCenter().x, + info.thumbBounds.y + (info.viewportHeight / 2) + + (info.viewportMax * info.scrollFactor)); + + self.viewer.viewport.panTo(pos, true); + }) + .mousemove(function(event) { + var pixel = new OpenSeadragon.Point(event.clientX, event.clientY); + var result = self.hitTest(self.viewer.viewport.pointFromPixel(pixel)); + self.updateHover(result ? result.index : -1); + }) + .click(function(event) { + var pixel = new OpenSeadragon.Point(event.clientX, event.clientY); + var result = self.hitTest(self.viewer.viewport.pointFromPixel(pixel)); + if (result) { + self.setMode({ + mode: 'page', + page: result.index + }); + } + }); + var svgNode = this.viewer.svgOverlay(); this.highlight = d3.select(svgNode).append("rect") @@ -179,6 +202,26 @@ return null; }, + // ---------- + getScrollInfo: function() { + if (!this.thumbBounds) { + return null; + } + + var output = {}; + + var viewerWidth = this.$el.width(); + var viewerHeight = this.$el.height(); + var scrollTop = this.$scrollCover.scrollTop(); + output.scrollMax = this.$scrollInner.height() - this.$scrollCover.height(); + output.scrollFactor = (output.scrollMax > 0 ? scrollTop / output.scrollMax : 0); + + output.thumbBounds = this.thumbBounds; + output.viewportHeight = output.thumbBounds.width * (viewerHeight / viewerWidth); + output.viewportMax = Math.max(0, output.thumbBounds.height - output.viewportHeight); + return output; + }, + // ---------- update: function() { var self = this; @@ -237,13 +280,10 @@ this.page = config.page; // Need to do this before layout } - var layout = this.createLayout(); + this.ignoreScroll = true; + this.thumbBounds = null; - var oldSize = new OpenSeadragon.Point(this.$el.width(), this.$el.height()); - var oldBounds = this.viewer.viewport.getBounds(); - var scrollTop = $(window).scrollTop(); - var scrollMax = $(document).height() - $(window).height(); - var scrollFactor = (scrollMax > 0 ? scrollTop / scrollMax : 0); + var layout = this.createLayout(); if (this.mode === 'thumbs') { this.viewer.gestureSettingsMouse.scrollToZoom = false; @@ -254,9 +294,8 @@ var width = layout.bounds.width + (this.bigBuffer * 2); var height = layout.bounds.height + (this.bigBuffer * 2); var newHeight = viewerWidth * (height / width); - this.$el - .addClass('thumbs') - .removeClass('full') + this.$scrollCover.show(); + this.$scrollInner .css({ height: newHeight }); @@ -265,25 +304,7 @@ this.viewer.zoomPerClick = 2; this.viewer.panHorizontal = true; this.viewer.panVertical = true; - this.$el - .addClass('full') - .removeClass('thumbs') - .css({ - height: 'auto' - }); - } - - var newSize = new OpenSeadragon.Point(this.$el.width(), this.$el.height()); - if (oldSize.x !== newSize.x || oldSize.y !== newSize.y) { - this.viewer.viewport.resize(newSize, false); - var newBounds = this.viewer.viewport.getBounds(); - var box = oldBounds.clone(); - box.height = box.width * (newBounds.height / newBounds.width); - - var boxMax = oldBounds.height - box.height; - box.y += boxMax * scrollFactor; - this.viewer.viewport.fitBounds(box, true); - this.viewer.viewport.update(); + this.$scrollCover.hide(); } this.setLayout({ @@ -291,6 +312,38 @@ immediately: config.immediately }); + if (this.mode === 'thumbs') { + // Set up thumbBounds + this.thumbBounds = this.viewer.world.getHomeBounds(); + this.thumbBounds.x -= this.bigBuffer; + this.thumbBounds.y -= this.bigBuffer; + this.thumbBounds.width += (this.bigBuffer * 2); + this.thumbBounds.height += (this.bigBuffer * 2); + + // Scroll to the appropriate location + var info = this.getScrollInfo(); + + var viewportBounds = this.thumbBounds.clone(); + viewportBounds.y += info.viewportMax * info.scrollFactor; + viewportBounds.height = info.viewportHeight; + + var itemBounds = this.viewer.world.getItemAt(this.page).getBounds(); + var top = itemBounds.y - this.bigBuffer; + var bottom = top + itemBounds.height + (this.bigBuffer * 2); + + var normalY; + if (top < viewportBounds.y) { + normalY = top - this.thumbBounds.y; + } else if (bottom > viewportBounds.y + viewportBounds.height) { + normalY = (bottom - info.viewportHeight) - this.thumbBounds.y; + } + + if (normalY !== undefined) { + var viewportFactor = normalY / info.viewportMax; + this.$scrollCover.scrollTop(info.scrollMax * viewportFactor); + } + } + this.goHome({ immediately: config.immediately }); @@ -300,6 +353,10 @@ this.update(); this.updateHighlight(); this.updateHover(-1); + + setTimeout(function() { + self.ignoreScroll = false; + }, this.viewer.animationTime * 1000); }, // ---------- @@ -324,14 +381,14 @@ updateHover: function(page) { if (page === -1 || this.mode !== 'thumbs') { this.hover.style('opacity', 0); - this.$el.css({ + this.$scrollCover.css({ 'cursor': 'default' }); return; } - this.$el.css({ + this.$scrollCover.css({ 'cursor': 'pointer' }); @@ -527,13 +584,11 @@ var viewerHeight = this.$el.height(); var layoutConfig = {}; - var box; if (this.mode === 'thumbs') { - box = this.viewer.world.getHomeBounds(); - box.x -= this.bigBuffer; - box.y -= this.bigBuffer; - box.width += (this.bigBuffer * 2); + var info = this.getScrollInfo(); + var box = this.thumbBounds.clone(); box.height = box.width * (viewerHeight / viewerWidth); + box.y += info.viewportMax * info.scrollFactor; this.viewer.viewport.fitBounds(box, config.immediately); } else { this.goToPage({ From 2172da6aaaed78ce878977b4fbc3f28131aa65ff Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Tue, 20 Jan 2015 17:19:13 -0800 Subject: [PATCH 20/25] * Fixed an error in fitBounds that occurred sometimes with immediately = true --- changelog.txt | 1 + src/viewport.js | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index d3a20e31..6456733f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -46,6 +46,7 @@ OPENSEADRAGON CHANGELOG * Added ajaxWithCredentials option (#543) * Added viewport-change event for after the viewport changes but before it's drawn * A spring's current value is now updated immediately on reset (#524) +* Fixed an error in fitBounds that occurred sometimes with immediately = true 1.2.1: (in progress) diff --git a/src/viewport.js b/src/viewport.js index d6fd8606..b6b57e27 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -588,11 +588,17 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ } newBounds = this._applyBoundaryConstraints( newBounds, immediately ); + center = newBounds.getCenter(); + } + + if (immediately) { + this.panTo( center, true ); + return this.zoomTo(newZoom, null, true); } if (Math.abs(newZoom - oldZoom) < 0.00000000001 || Math.abs(newBounds.width - oldBounds.width) < 0.00000000001) { - return this.panTo( constraints ? newBounds.getCenter() : center, immediately ); + return this.panTo( center, immediately ); } referencePoint = oldBounds.getTopLeft().times( From 54be2b4b48122d4bf63e2c044118022b087247ac Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Tue, 20 Jan 2015 17:19:20 -0800 Subject: [PATCH 21/25] Fixed issues with window resizing (m2) --- test/demo/m2/js/main.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js index 5b6cdcee..76448fe0 100644 --- a/test/demo/m2/js/main.js +++ b/test/demo/m2/js/main.js @@ -152,6 +152,8 @@ immediately: true }); + self.viewer.forceRedraw(); + self.viewer.svgOverlay('resize'); }); @@ -354,7 +356,8 @@ this.updateHighlight(); this.updateHover(-1); - setTimeout(function() { + clearTimeout(this.scrollTimeout); + this.scrollTimeout = setTimeout(function() { self.ignoreScroll = false; }, this.viewer.animationTime * 1000); }, From a923c3f09c323a3fbf1d5192c5c4e3c44927f6ca Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Thu, 22 Jan 2015 11:52:08 -0800 Subject: [PATCH 22/25] Fixed issues with panning in scroll view (m2) --- test/demo/m2/README.md | 3 +++ test/demo/m2/js/main.js | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/demo/m2/README.md b/test/demo/m2/README.md index ef92c45c..0d16eac8 100644 --- a/test/demo/m2/README.md +++ b/test/demo/m2/README.md @@ -1,4 +1,7 @@ # To Do * Support 400+ page collections +* Choosing between multiple versions of a page +* Detail images overlaid on the page +* Cropped images * Show/hide pages? diff --git a/test/demo/m2/js/main.js b/test/demo/m2/js/main.js index 76448fe0..85bbae3d 100644 --- a/test/demo/m2/js/main.js +++ b/test/demo/m2/js/main.js @@ -57,10 +57,10 @@ }); this.viewer.addHandler('canvas-drag', function() { - if (this.mode === 'scroll') { - var result = this.hitTest(this.viewer.viewport.getCenter()); + if (self.mode === 'scroll') { + var result = self.hitTest(self.viewer.viewport.getCenter()); if (result) { - this.page = result.index; + self.page = result.index; } } }); @@ -267,7 +267,8 @@ } if (x !== center.x || y !== center.y) { - this.viewer.viewport.panTo(new OpenSeadragon.Point(x, y), true); + this.viewer.viewport.centerSpringX.current.value = x; + this.viewer.viewport.centerSpringY.current.value = y; } } }, From 408a8f6fd369f70c4b582bba790e59bda51f81a4 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 23 Jan 2015 16:00:58 -0800 Subject: [PATCH 23/25] 400+ collection; repeated nexts (m2) --- test/demo/m2/README.md | 5 +- test/demo/m2/index.html | 2 +- test/demo/m2/js/main.js | 12 +- test/demo/m2/js/tilesources2.js | 483 ++++++++++++++++++++++++++++++++ 4 files changed, 496 insertions(+), 6 deletions(-) create mode 100644 test/demo/m2/js/tilesources2.js diff --git a/test/demo/m2/README.md b/test/demo/m2/README.md index 0d16eac8..70789a3b 100644 --- a/test/demo/m2/README.md +++ b/test/demo/m2/README.md @@ -1,7 +1,10 @@ # To Do -* Support 400+ page collections * Choosing between multiple versions of a page * Detail images overlaid on the page * Cropped images + +# Maybe + * Show/hide pages? +* Lazyloading tilesources? diff --git a/test/demo/m2/index.html b/test/demo/m2/index.html index 7c6ef773..f3f42755 100644 --- a/test/demo/m2/index.html +++ b/test/demo/m2/index.html @@ -6,7 +6,7 @@ - +