spread-layout.js (4.0 KB)
1 import { SPREADS } from './constants.js'; 2 import { createEmptyPlaceholder } from './html-utils.js'; 3 import { initPageFlip, animatePageFlip, setSpreadImmediate, getIsAnimating } from './page-flip-animation.js'; 4 5 // Track whether flip mode is enabled 6 let flipModeEnabled = false; 7 let currentFlipSpread = 0; 8 9 // Enable/disable flip animation mode 10 export function setFlipMode(enabled) { 11 flipModeEnabled = enabled; 12 } 13 14 export function isFlipModeEnabled() { 15 return flipModeEnabled; 16 } 17 18 // Common logic for displaying a spread (used by both editor preview and standalone viewer) 19 export function setupSpreadLayout(container, spread, doc, useFlipAnimation = false) { 20 if (useFlipAnimation) { 21 // Initialize flip animation on first call 22 if (!container.querySelector('.zine-book')) { 23 initPageFlip(container, doc); 24 } 25 return; 26 } 27 28 // Original non-animated behavior 29 // Add empty placeholder before right page if no left page 30 if (!spread.left && spread.right) { 31 container.appendChild(createEmptyPlaceholder(doc)); 32 } 33 34 // Move visible pages into container 35 const visiblePages = [spread.left, spread.right].filter(Boolean); 36 visiblePages.forEach(id => { 37 const page = doc.getElementById(id); 38 if (page) container.appendChild(page); 39 }); 40 41 // Add empty placeholder after left page if no right page 42 if (spread.left && !spread.right) { 43 container.appendChild(createEmptyPlaceholder(doc)); 44 } 45 } 46 47 // Navigate to a spread with optional flip animation 48 export function navigateToSpread(container, spreadIndex, doc, useFlipAnimation = false, onComplete) { 49 if (useFlipAnimation && container.querySelector('.zine-book')) { 50 // Always call animatePageFlip - it now handles queueing internally 51 animatePageFlip(currentFlipSpread, spreadIndex, doc, onComplete); 52 currentFlipSpread = spreadIndex; 53 } else { 54 // Original non-animated behavior 55 const spread = SPREADS[spreadIndex]; 56 container.innerHTML = ''; 57 setupSpreadLayout(container, spread, doc, false); 58 if (onComplete) onComplete(); 59 } 60 } 61 62 // Scale spread container to fit viewport 63 export function scaleSpreadToFit(container, doc, bottomPadding = 0) { 64 // Find the book container if in flip mode 65 const bookContainer = container.querySelector('.zine-book') || container; 66 67 const vw = doc.documentElement.clientWidth; 68 const vh = doc.documentElement.clientHeight - bottomPadding; 69 const spreadWidthPx = bookContainer.offsetWidth; 70 const spreadHeightPx = bookContainer.offsetHeight; 71 if (spreadWidthPx === 0 || spreadHeightPx === 0) return; 72 const scaleX = (vw - 40) / spreadWidthPx; 73 const verticalPadding = vh <= 630 ? 40 : 130; 74 const scaleY = (vh - verticalPadding) / spreadHeightPx; 75 const scale = Math.min(scaleX, scaleY); 76 77 // Use CSS zoom for high-resolution rendering instead of transform scale 78 bookContainer.style.zoom = scale; 79 80 // Store the current zoom on the book container for use by updateBookPosition 81 bookContainer.dataset.currentZoom = scale; 82 83 // Notify parent of spread position and grid size for background grid 84 if (doc.defaultView?.parent && doc.defaultView.parent !== doc.defaultView) { 85 const rect = bookContainer.getBoundingClientRect(); 86 87 // Derive grid from height (always 1 page tall = 11 cells) 88 // Cell aspect ratio: (2.75/7) / (4.25/11) = 30.25/29.75 89 const gridHeight = rect.height / 11; 90 const gridWidth = gridHeight * (30.25 / 29.75); 91 92 // Remove the net visual shift so grid always anchors to the un-shifted book position 93 // margin-left is doubled to compensate for flex re-centering, so the net visual 94 // shift is half the margin value; getBoundingClientRect already reflects this 95 const marginLeft = bookContainer.style.marginLeft || '0in'; 96 const marginMatch = marginLeft.match(/([-.0-9]+)in/); 97 const netShiftPx = marginMatch ? (parseFloat(marginMatch[1]) / 2) * 96 * scale : 0; 98 99 doc.defaultView.parent.postMessage({ 100 type: 'scaleChange', 101 gridWidth, 102 gridHeight, 103 spreadLeft: rect.left - netShiftPx, 104 spreadTop: rect.top 105 }, '*'); 106 } 107 }