From 186d1cbadec563959adfeb343ac339be4f118285 Mon Sep 17 00:00:00 2001 From: Stephen Cameron Date: Mon, 27 Aug 2018 17:51:28 +0200 Subject: [PATCH] WIP #2087 @4 --- js/libs/fluidbook/fluidbook.links.js | 164 ++++++++++++++++----------- js/libs/fluidbook/fluidbook.nav.js | 2 +- style/fluidbook.less | 7 +- 3 files changed, 105 insertions(+), 68 deletions(-) diff --git a/js/libs/fluidbook/fluidbook.links.js b/js/libs/fluidbook/fluidbook.links.js index 7225536b..b2f28317 100644 --- a/js/libs/fluidbook/fluidbook.links.js +++ b/js/libs/fluidbook/fluidbook.links.js @@ -21,7 +21,7 @@ FluidbookLinks.prototype = { }); // ToDo: consider re-using existing popinOverlay div? - $('body').append('
' + getSpriteIcon('interface-close') + '
'); + $('body').append('
'); $(document).on('click', '.zoomPopup', function (e) { e.preventDefault(); @@ -42,7 +42,7 @@ FluidbookLinks.prototype = { $this.resize(); }); - $(document).on('click', '#zoomPopupOverlay, #zoomPopupWrapper, #zoomPopupClose', function (e) { + $(document).on('click', '#zoomPopupOverlay, .zoomPopupWrapper, .zoomPopupClose', function (e) { $this.zoomLinkReset(); return false; }); @@ -188,7 +188,6 @@ FluidbookLinks.prototype = { }, zoomLink: function (link) { - var $this = this; // If the interface is zoomed in, we must zoom out first if (this.fluidbook.zoom.zoom > 1) { @@ -199,79 +198,104 @@ FluidbookLinks.prototype = { $this.zoomLink(link); }); - // Zoom out this.fluidbook.zoom.resetZoom(); return false; } - //this.zoomLinkReset(); - var z = $('#zoomPopupWrapper'), + + var $this = this, + $link = $(link), + links = [], zoomMargin = 50, availableWidth = $(window).width() - (2 * zoomMargin), - availableHeight = $(window).height() - (2 * zoomMargin), - $link = $(link), - box = $link[0].getBoundingClientRect(), // Should return full values without rounding - parent = $link.closest('.link'), - baseWidth = parseInt($link.data('width')), // Width of the original link from the editor - baseHeight = parseInt($link.data('height')), // Height of the original link from the editor - maxZoom = parseInt($link.data('maxzoom')) || 2, // The default value for this should match that of the compiler in zoomLink::generateImage() - x, - y, - zoomWidth, - zoomHeight, - zoomScale; - - if ($(parent).length == 0) { - return; + availableHeight = $(window).height() - (2 * zoomMargin); + + // Add clicked zoom link to the collection + links.push($link); + + // If there is a zoom group, we need to find the other zone it is linked to + // For now, only 2 zones maximum can be linked together so if we have more + // than one group (eg. for a shared zone), we should treat it as a standalone + // zone when clicked. + if ($link.data('group-count') == 1) { + // Find other zones in the same group + var $others = $('.zoom-group-' + $link.data('group')).not('#' + $link.attr('id')); + + if ($others.length >= 1) { + links.push($others.first()); // Take the first because we only support 1 linked zone currently + } } - var linkId = $(parent).attr('id').split('_', 2)[1]; - var zoomImage = 'data/links/zoom_' + linkId + '.jpg'; + links.forEach(function(zoomLink) { + // console.log('Found link with ID: ' + zoomLink.attr('id')); + + var zoomID = zoomLink.attr('id'); + // Add holder for each zoom zone + $('#zoomPopupGroupWrapper').append('
' + getSpriteIcon('interface-close') + '
'); - // TODO: In the compiler we should look at generating higher-res images to cater for hiDPI displays - // TODO: It should be clearer what the sizes in the link editor really mean - due to screen size and scaling, a 100x100 link could appear as 150x150 in the player so if it we set a max zoom level of 2, it will only appear at 200x200, which is not much bigger than the embedded size. It's hard to handle max zoom levels while also working with a player that always scales the content to fit the screen. The most pragmatic approach probably is to generate higher res images. + var z = $('#zoomPopup_' + zoomID), + box = zoomLink[0].getBoundingClientRect(), // Should return full values without rounding + parent = zoomLink.closest('.link'), + baseWidth = parseInt(zoomLink.data('width')), // Width of the original link from the editor + baseHeight = parseInt(zoomLink.data('height')), // Height of the original link from the editor + maxZoom = parseInt(zoomLink.data('maxzoom')) || 2, // The default value for this should match that of the compiler in zoomLink::generateImage() + x, + y, + zoomWidth, + zoomHeight, + zoomScale; + if ($(parent).length == 0) { + return; + } - // Due to the scaling done by the Fluidbook interface, the actual link size is likely to be different - // to the original link editor width and height. Since the zoom image is generated based on the link editor - // dimensions multiplied by the max zoom level, we need to be able to take that into account so we don't exceed - // the resolution of the image in the popup. We can't use the fluidbook.resize.bookScale variable because it - // measures the scaling of the high-res images. Instead, we work out the relative scaling by taking the - // link editor width (baseWidth) and comparing it to the actual link width. - //maxZoom = maxZoom / (box.width / baseWidth); // Adjusted maxZoom level... + var linkId = $(parent).attr('id').split('_', 2)[1]; + var zoomImage = 'data/links/zoom_' + linkId + '.jpg'; - // Calculate best scale factor to fit and also to honour the maxZoom level - zoomScale = Math.min((availableWidth / baseWidth), (availableHeight / baseHeight), maxZoom); + // TODO: In the compiler we should look at generating higher-res images to cater for hiDPI displays + // TODO: It should be clearer what the sizes in the link editor really mean - due to screen size and scaling, a 100x100 link could appear as 150x150 in the player so if it we set a max zoom level of 2, it will only appear at 200x200, which is not much bigger than the embedded size. It's hard to handle max zoom levels while also working with a player that always scales the content to fit the screen. The most pragmatic approach probably is to generate higher res images. - // 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 - x = Math.round((availableWidth / 2) - parent.offset().left - (zoomWidth / 2) + zoomMargin); - y = Math.round((availableHeight / 2) - parent.offset().top - (zoomHeight / 2) + zoomMargin); + // Due to the scaling done by the Fluidbook interface, the actual link size is likely to be different + // to the original link editor width and height. Since the zoom image is generated based on the link editor + // dimensions multiplied by the max zoom level, we need to be able to take that into account so we don't exceed + // the resolution of the image in the popup. We can't use the fluidbook.resize.bookScale variable because it + // measures the scaling of the high-res images. Instead, we work out the relative scaling by taking the + // link editor width (baseWidth) and comparing it to the actual link width. + //maxZoom = maxZoom / (box.width / baseWidth); // Adjusted maxZoom level... - // Keep starting scale with zoom element so it can be used when zooming back out - z.data('starting-scale', box.width / zoomWidth); + // Calculate best scale factor to fit and also to honour the maxZoom level + zoomScale = Math.min((availableWidth / baseWidth), (availableHeight / baseHeight), maxZoom); - // 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({ + // 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 + x = Math.round((availableWidth / 2) - parent.offset().left - (zoomWidth / 2) + zoomMargin); + y = Math.round((availableHeight / 2) - parent.offset().top - (zoomHeight / 2) + zoomMargin); + + // Keep starting scale with zoom element so it can be used when zooming back out + z.data('starting-scale', box.width / zoomWidth); + + // 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) - }); - // z.find('img').remove(); + }); + // z.find('img').remove(); - // Load image before running zoom up animation - this.fluidbook.displayLoader(); - loadImage(zoomImage, function (img) { + // 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 @@ -282,10 +306,10 @@ FluidbookLinks.prototype = { // 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(' + x + 'px) translateY(' + y + 'px) scale(1)' - }); + z.css({ + boxShadow: '0 0 100px rgba(0,0,0,0.3)', + transform: 'translateX(' + x + 'px) translateY(' + y + 'px) scale(1)' + }); }, 50); // Hide close button initially so it only shows when zoom finishes. @@ -295,8 +319,10 @@ FluidbookLinks.prototype = { // Display close button after zoom animation has finished setTimeout(function () { - $(".zoomPopupClose").css('opacity', 1); + $(".zoomPopupClose").css('opacity', 1); }, 500); + }); + }); }, @@ -305,7 +331,10 @@ FluidbookLinks.prototype = { }, zoomLinkReset: function (immediate) { - if ($('#zoomPopupWrapper:visible').length == 0) { + + var $this = this; + + if ($('.zoomPopupWrapper:visible').length == 0) { return; } @@ -313,26 +342,31 @@ FluidbookLinks.prototype = { immediate = false; } + var $wrapper = $('#zoomPopupGroupWrapper'); - var z = $('#zoomPopupWrapper'); + // Close each popup that is open + $wrapper.find('.zoomPopupWrapper').each(function() { + var z = $(this); + z.find('.zoomPopupClose').css('opacity', '0'); - $(".zoomPopupClose").css('opacity', '0'); + if (immediate) { + $('.zoomPopupWrapper').hide(); + $this.hideOverlay(1); + } - z.css({ + z.css({ transform: 'translate(0,0) scale(' + z.data('starting-scale') + ')', boxShadow: '0 0 0 rgba(0,0,0,0.3)', + }); }); - if (immediate) { - $('#zoomPopupWrapper').hide(); - this.hideOverlay(1); - } // Hide popup after transition completes // ToDo: use CSS transition end event to do this without needing a timeout value (or use Web Animation API) // ToDo: see https://davidwalsh.name/css-animation-callback this.hideOverlay(500); setTimeout(function () { - $('#zoomPopupWrapper').hide(); + $('.zoomPopupWrapper').hide(); + $wrapper.html(''); // Empty group wrapper }, 500); return false; diff --git a/js/libs/fluidbook/fluidbook.nav.js b/js/libs/fluidbook/fluidbook.nav.js index 41fef794..bf4500a2 100644 --- a/js/libs/fluidbook/fluidbook.nav.js +++ b/js/libs/fluidbook/fluidbook.nav.js @@ -347,7 +347,7 @@ FluidbookNav.prototype = { $_GET['home'] = decodeURIComponent($_GET['home']); } homeURL = $_GET['home']; - } else if (this.fluidbook.landingpage.hasLandingPage) { + } else if (this.fluidbook.landingpage !== undefined && this.fluidbook.landingpage.hasLandingPage) { homeURL = '#/landing'; homeRequireLoader = false; } diff --git a/style/fluidbook.less b/style/fluidbook.less index 67dec8f6..4bfa5a37 100644 --- a/style/fluidbook.less +++ b/style/fluidbook.less @@ -2533,7 +2533,11 @@ ul.chapters { .overlayBackground(); } -#zoomPopupWrapper { +.zoomPopupWrapper, .zoomPopupClose { + cursor: zoom-out !important; // Needed for close link, otherwise pointer cursor is used +} + +.zoomPopupWrapper { display: none; background-color: transparent; background-repeat: no-repeat; @@ -2542,7 +2546,6 @@ ul.chapters { transition: all 0.5s ease-in-out; transform-origin: 0 0; position: absolute; - cursor: pointer; z-index: 101; &:hover { -- 2.39.5