From: Stephen Cameron Date: Thu, 30 Aug 2018 13:05:37 +0000 (+0200) Subject: Dynamic layout selection + code refactoring. WIP #2087 @5 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=3848f104c41253f343e112958a601fb36d1f07e1;p=fluidbook-html5.git Dynamic layout selection + code refactoring. WIP #2087 @5 --- diff --git a/js/libs/fluidbook/fluidbook.bookmarks.js b/js/libs/fluidbook/fluidbook.bookmarks.js index dc463594..7d65ddd2 100644 --- a/js/libs/fluidbook/fluidbook.bookmarks.js +++ b/js/libs/fluidbook/fluidbook.bookmarks.js @@ -24,7 +24,6 @@ function FluidbookBookmarks(fluidbook) { FluidbookBookmarks.prototype = { init: function () { var $this = this; - console.log('init'); $(document).on('click touchend', '.bookmark', function () { $this.toggleBookmark(parseInt($(this).attr('data-page'))); $this.fluidbook.tooltip.hideTooltip(); @@ -484,4 +483,4 @@ FluidbookBookmarks.prototype = { index += ''; return index; } -}; \ No newline at end of file +}; diff --git a/js/libs/fluidbook/fluidbook.links.js b/js/libs/fluidbook/fluidbook.links.js index 048621e0..5e9f64a1 100644 --- a/js/libs/fluidbook/fluidbook.links.js +++ b/js/libs/fluidbook/fluidbook.links.js @@ -189,30 +189,29 @@ FluidbookLinks.prototype = { zoomLink: function (link) { + var $this = this, + $link = $(link), + links = [], + zoomMargin = 50, + zoomZonesGap = 30, // Space between grouped zoom links + gapsTotal, + availableWidth = $(window).width() - (2 * zoomMargin), + availableHeight = $(window).height() - (2 * zoomMargin); + // If the interface is zoomed in, we must zoom out first if (this.fluidbook.zoom.zoom > 1) { - //currentScale = this.fluidbook.desktop.desktopScale; // Get current scale so the size of the popup can be calculated correctly + + // Zoom out + this.fluidbook.zoom.resetZoom(); // Wait for clickZoom out to finish before trying again to open zoom link $(this.fluidbook).one('fluidbook.zoom.out.end', function () { $this.zoomLink(link); }); - // Zoom out - this.fluidbook.zoom.resetZoom(); return false; } - - - var $this = this, - $link = $(link), - links = [], - zoomMargin = 50, - zoomZonesGap = 30, // Space between grouped zoom links - availableWidth = $(window).width() - (2 * zoomMargin), - availableHeight = $(window).height() - (2 * zoomMargin); - // Add clicked zoom link to the collection links.push($link); @@ -229,38 +228,55 @@ FluidbookLinks.prototype = { } } - // Sort links so topmost (lowest Y value) link is first. This allows it to be first/top when placed. - links.sort(function(a, b) { - return a.data('y') - b.data('y'); - }); + //=============== + // Calculate space taken by between blocks (always 1 less gap than total blocks) + gapsTotal = (links.length - 1) * zoomZonesGap; // Calculate positions and scaling for all zoomLink blocks - // First, get max height of all zoomLink blocks - var zoomGroupHeight = links.reduce(function(sum, zoomLink) { + // First, calculate stacked height of all zoomLink blocks + var stackedHeight = gapsTotal + links.reduce(function(sum, zoomLink) { return sum + (zoomLink.data('height') * zoomLink.data('maxzoom')); }, 0); + // Calculate side-by-side width of all zoomLink blocks + var sideBySideWidth = gapsTotal + links.reduce(function(sum, zoomLink) { + return sum + (zoomLink.data('width') * zoomLink.data('maxzoom')); + }, 0); + // Find widest element in collection - var zoomGroupMaxWidth = links.reduce(function(maxWidth, zoomLink) { + var widestLink = links.reduce(function(maxWidth, zoomLink) { var width = (zoomLink.data('width') * zoomLink.data('maxzoom')); return (width > maxWidth) ? width : maxWidth; }, 0); + // Find tallest element in collection + var tallestLink = links.reduce(function(maxHeight, zoomLink) { + var height = (zoomLink.data('height') * zoomLink.data('maxzoom')); + return (height > maxHeight) ? height : maxHeight; + }, 0); - // Todo: figure out which will offer best fit: stacked or side-by-side blocks - - // Count gaps between blocks (always 1 less gap than total blocks) - // For now we're assuming blocks are stacked, not side-by-side... - zoomGroupHeight += (links.length - 1) * zoomZonesGap; - - var zoomGroupScale = Math.min(availableHeight / zoomGroupHeight, availableWidth / zoomGroupMaxWidth, 1); + // Compare scaling required for each layout of blocks + var stackedScale = Math.min(availableHeight / stackedHeight, availableWidth / widestLink, 1), + sideBySideScale = Math.min(availableHeight / tallestLink, availableWidth / sideBySideWidth, 1), + groupScale = (stackedScale > sideBySideScale) ? stackedScale : sideBySideScale, + layout = (stackedScale > sideBySideScale) ? 'stacked' : 'side-by-side'; - zoomGroupHeight = zoomGroupHeight * zoomGroupScale; + // Apply scaling for the group so it is accounted for in later calculations + stackedHeight *= groupScale; + sideBySideWidth *= groupScale; + // Sort links so they are displayed in a natural order when zooming + // When stacked: highest link on page will come first + // When side-by-side: leftmost link on page will come first + links.sort(function(a, b) { + if (layout == 'stacked') { + return a.data('y') - b.data('y'); // Lowest Y co-ordinates first + } else { + return a.offset().left - b.offset().left; // Lowest X co-ordinates first + } + }); - // Y position of first block (so both blocks are vertically centred) - var zoomGroupY = Math.round((availableHeight - zoomGroupHeight) / 2); links.forEach(function(zoomLink, index) { // console.log(index, 'Found link with ID: ' + zoomLink.attr('id')); @@ -301,29 +317,52 @@ FluidbookLinks.prototype = { // link editor width (baseWidth) and comparing it to the actual link width. //maxZoom = maxZoom / (box.width / baseWidth); // Adjusted maxZoom level... - // Apply any necessary group scaling to the individual element - baseHeight = baseHeight * zoomGroupScale; - baseWidth = baseWidth * zoomGroupScale; + // Apply any necessary group scaling to the individual element... + baseHeight *= groupScale; + baseWidth *= groupScale; - // Calculate best scale factor to fit and also to honour the maxZoom level + // Then calculate best scale factor to fit and also to honour the maxZoom level zoomScale = Math.min((availableWidth / baseWidth), (availableHeight / baseHeight), maxZoom); // Dimensions of the final popup zoomWidth = baseWidth * zoomScale; zoomHeight = baseHeight * zoomScale; - // Calculate translate co-ordinates so image is centred correctly - // Values are rounded so we don't end up with image being positioned between pixels, which causes blurring - zoomX = Math.round((availableWidth / 2) - parent.offset().left - (zoomWidth / 2) + zoomMargin); - // zoomY = Math.round((availableHeight / 2) - parent.offset().top - (zoomHeight / 2) + zoomMargin); + //========= + // Position elements based on the layout + // There are two possible layouts: stacked or side-by-side + if (layout == 'stacked') { + // Calculate translate co-ordinates so image is centred correctly + // Values are rounded so we don't end up with image being positioned between pixels, which causes blurring + zoomX = Math.round((availableWidth / 2) - parent.offset().left - (zoomWidth / 2) + zoomMargin); + + // Y position of first block (so both blocks are vertically centred) + var groupY = Math.round((availableHeight - stackedHeight) / 2); - // If this is the first / only block, use calculated zoomGroupY position - if (index == 0) { - zoomY = zoomGroupY - parent.offset().top + zoomMargin; + // If this is the first / only block, use calculated groupY position + if (index == 0) { + zoomY = groupY - parent.offset().top + zoomMargin; - // Otherwise, calculateY position based on first element position + // Otherwise, calculate Y position based on first element position + } else { + zoomY = Math.round(groupY + links[0].data('height') * links[0].data('maxzoom') * groupScale + zoomZonesGap + zoomMargin - parent.offset().top); + } } else { - zoomY = Math.round(zoomGroupY + links[0].data('height') * links[0].data('maxzoom') * zoomGroupScale + zoomZonesGap + zoomMargin - parent.offset().top); + // Side-by-side layout + // Vertically centre each block + zoomY = Math.round((availableHeight / 2) - parent.offset().top - (zoomHeight / 2) + zoomMargin); + + // X position of first block (so both blocks are horizontally centred) + var groupX = Math.round((availableWidth - sideBySideWidth) / 2); + + // If this is the first / only block, use calculated groupX position + if (index == 0) { + zoomX = groupX - parent.offset().left + zoomMargin; + + // Otherwise, calculate X position based on first element position + } else { + zoomX = Math.round(groupX + (links[0].data('width') * links[0].data('maxzoom') * groupScale) + zoomZonesGap + zoomMargin - parent.offset().left); + } } // Keep starting scale with zoom element so it can be used when zooming back out @@ -332,42 +371,40 @@ FluidbookLinks.prototype = { // Initial position of the zoom box - should sit over the link and match // size and position so that the element appears to zoom from the link z.css({ - transform: 'translateX(0) translateY(0) scale(' + z.data('starting-scale') + ')', - width: zoomWidth, - height: zoomHeight, - left: Math.round(box.left), - top: Math.round(box.top) + transform: 'translateX(0) translateY(0) scale(' + z.data('starting-scale') + ')', + width: zoomWidth, + height: zoomHeight, + left: Math.round(box.left), + top: Math.round(box.top) }); - // z.find('img').remove(); // Load image before running zoom up animation this.fluidbook.displayLoader(); loadImage(zoomImage, function (img) { - //z.append(img); - - // Image is set as a background for better scaling / fitting via CSS - z.css('background-image', 'url(' + img.src + ')'); - this.fluidbook.hideLoader(); - z.show(); - $this.showOverlay(); - // Trigger zoom up animation just after showing zoom element - setTimeout(function () { - z.css({ - boxShadow: '0 0 100px rgba(0,0,0,0.3)', - transform: 'translateX(' + zoomX + 'px) translateY(' + zoomY + 'px) scale(1)' - }); - }, 50); - - // Hide close button initially so it only shows when zoom finishes. - $(".zoomPopupClose").css('opacity', 0); - - $this.fluidbook.stats.track(2, $this.fluidbook.currentPage); - - // Display close button after zoom animation has finished - setTimeout(function () { - $(".zoomPopupClose").css('opacity', 1); - }, 500); + // Image is set as a background for better scaling / fitting via CSS + z.css('background-image', 'url(' + img.src + ')'); + this.fluidbook.hideLoader(); + z.show(); + $this.showOverlay(); + + // Trigger zoom up animation just after showing zoom element + setTimeout(function () { + z.css({ + boxShadow: '0 0 100px rgba(0,0,0,0.3)', + transform: 'translateX(' + zoomX + 'px) translateY(' + zoomY + 'px) scale(1)' + }); + }, 50); + + // Hide close button initially so it only shows when zoom finishes. + $('.zoomPopupClose').css('opacity', 0); + + $this.fluidbook.stats.track(2, $this.fluidbook.currentPage); + + // Display close button after zoom animation has finished + setTimeout(function () { + $('.zoomPopupClose').css('opacity', 1); + }, 500); }); });