Refine line-based story scrolling
This commit is contained in:
@@ -79,15 +79,14 @@ class LayoutRendererModule extends BaseModule {
|
||||
layoutData.addTopSpace ? 'story-textblock-start' : '',
|
||||
layoutData.dropCap ? 'story-dropcap-paragraph' : ''
|
||||
].filter(Boolean).join(' ');
|
||||
paragraph.style.position = 'relative';
|
||||
paragraph.style.position = 'absolute';
|
||||
paragraph.style.margin = '0';
|
||||
paragraph.style.left = '0';
|
||||
const globalLineStart = Math.max(0, Number(layoutData.lineStart || 0));
|
||||
const windowOriginLine = Math.max(0, Number(layoutData.windowOriginLine || 0));
|
||||
paragraph.style.top = `${(globalLineStart - windowOriginLine) * Number(lineHeightPx || 0)}px`;
|
||||
if (fontSize) paragraph.style.fontSize = fontSize;
|
||||
if (fontFamily) paragraph.style.fontFamily = fontFamily;
|
||||
if (Array.isArray(measures) && measures.length > 0) {
|
||||
paragraph.style.width = `${Math.max(...measures)}px`;
|
||||
paragraph.style.maxWidth = '100%';
|
||||
}
|
||||
|
||||
// Calculate paragraph height
|
||||
const storyElement = document.getElementById('story');
|
||||
if (!storyElement) {
|
||||
@@ -95,30 +94,25 @@ class LayoutRendererModule extends BaseModule {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pageWidth = Number(layoutData.pageWidth || storyElement.clientWidth);
|
||||
paragraph.style.width = `${pageWidth}px`;
|
||||
paragraph.style.maxWidth = '100%';
|
||||
|
||||
if (!Number.isFinite(Number(lineHeightPx)) || Number(lineHeightPx) <= 0) {
|
||||
throw new Error('LayoutRenderer: Missing canonical lineHeightPx for story layout.');
|
||||
}
|
||||
const lineHeight = Number(lineHeightPx);
|
||||
let marginLines = 0;
|
||||
if (layoutData.role === 'chapter-heading') {
|
||||
paragraph.style.marginTop = `${lineHeight * 2}px`;
|
||||
paragraph.style.marginBottom = `${lineHeight}px`;
|
||||
marginLines = 3;
|
||||
} else if (layoutData.role === 'section-heading') {
|
||||
paragraph.style.marginTop = `${lineHeight}px`;
|
||||
paragraph.style.marginBottom = `${lineHeight}px`;
|
||||
marginLines = 2;
|
||||
} else if (layoutData.addTopSpace) {
|
||||
paragraph.style.marginTop = `${lineHeight}px`;
|
||||
marginLines = 1;
|
||||
}
|
||||
const contentTopLines = Math.max(0, Number(layoutData.contentTopLines || 0));
|
||||
const maxLineWidth = Array.isArray(measures) && measures.length > 0
|
||||
? Math.max(...measures)
|
||||
: storyElement.clientWidth;
|
||||
? Math.max(pageWidth, ...measures)
|
||||
: pageWidth;
|
||||
// Height should include all lines (breaks.length represents number of lines)
|
||||
const numLines = Math.max(1, breaks.length - 1);
|
||||
paragraph.style.height = `${lineHeight * numLines}px`;
|
||||
paragraph.dataset.heightLines = String(numLines + marginLines);
|
||||
const totalLines = Math.max(1, Number(layoutData.lineCount || (numLines + contentTopLines)));
|
||||
paragraph.style.height = `${lineHeight * totalLines}px`;
|
||||
paragraph.dataset.heightLines = String(totalLines);
|
||||
paragraph.dataset.lineStart = String(globalLineStart);
|
||||
paragraph.dataset.lineCount = String(totalLines);
|
||||
|
||||
console.log(`LayoutRenderer: Rendering paragraph ${id} - ${breaks.length} breaks (${numLines} lines), lineHeight: ${lineHeight}px, total height: ${lineHeight * numLines}px`);
|
||||
|
||||
@@ -139,6 +133,7 @@ class LayoutRendererModule extends BaseModule {
|
||||
const dropCap = document.createElement('span');
|
||||
dropCap.className = 'drop-cap story-drop-cap';
|
||||
dropCap.textContent = layoutData.dropCapText;
|
||||
dropCap.style.top = `${contentTopLines * lineHeight}px`;
|
||||
paragraph.appendChild(dropCap);
|
||||
}
|
||||
|
||||
@@ -195,7 +190,7 @@ class LayoutRendererModule extends BaseModule {
|
||||
word.dataset.lineWidth = String(lineWidth);
|
||||
|
||||
// Calculate position with proper line and justification
|
||||
const topPercent = (lineIndex * lineHeight * 100) / parseFloat(paragraph.style.height);
|
||||
const topPercent = ((contentTopLines + lineIndex) * lineHeight * 100) / parseFloat(paragraph.style.height);
|
||||
const leftPercent = ((lineOffset + currentLeft) * 100) / maxLineWidth;
|
||||
|
||||
word.style.top = `${topPercent}%`;
|
||||
@@ -266,7 +261,7 @@ class LayoutRendererModule extends BaseModule {
|
||||
word.dataset.line = String(lineIndex);
|
||||
word.dataset.lineStart = String(lineOffset);
|
||||
word.dataset.lineWidth = String(lineWidth);
|
||||
const topPercent = (lineIndex * lineHeight * 100) / parseFloat(paragraph.style.height);
|
||||
const topPercent = ((contentTopLines + lineIndex) * lineHeight * 100) / parseFloat(paragraph.style.height);
|
||||
const leftPercent = ((lineOffset + currentLeft) * 100) / maxLineWidth;
|
||||
word.style.top = `${topPercent}%`;
|
||||
word.style.left = `${leftPercent}%`;
|
||||
|
||||
Reference in New Issue
Block a user