Add texture-space book pagination foundation
This commit is contained in:
@@ -7,8 +7,9 @@ import { BaseModule } from './base-module.js';
|
||||
class BookTextureRendererModule extends BaseModule {
|
||||
constructor() {
|
||||
super('book-texture-renderer', 'Book Texture Renderer');
|
||||
this.dependencies = ['book-page-format', 'localization'];
|
||||
this.dependencies = ['book-page-format', 'book-pagination', 'localization'];
|
||||
this.pageFormat = null;
|
||||
this.pagination = null;
|
||||
this.localization = null;
|
||||
this.metrics = null;
|
||||
this.canvases = {
|
||||
@@ -28,8 +29,10 @@ class BookTextureRendererModule extends BaseModule {
|
||||
'initialize',
|
||||
'createPageCanvases',
|
||||
'drawEmptySpread',
|
||||
'drawSpread',
|
||||
'drawPageBase',
|
||||
'drawDebugText',
|
||||
'drawPageLines',
|
||||
'drawLine',
|
||||
'publishSpread',
|
||||
'getPageCanvas',
|
||||
'getHitMap',
|
||||
@@ -39,11 +42,15 @@ class BookTextureRendererModule extends BaseModule {
|
||||
|
||||
async initialize() {
|
||||
this.pageFormat = this.getModule('book-page-format');
|
||||
this.pagination = this.getModule('book-pagination');
|
||||
this.localization = this.getModule('localization');
|
||||
this.reportProgress(20, 'Preparing page texture canvases');
|
||||
this.createPageCanvases();
|
||||
this.drawEmptySpread();
|
||||
this.addEventListener(document, 'webgl-book:scene-ready', this.handleSceneReady);
|
||||
this.addEventListener(document, 'book-pagination:spread-updated', (event) => {
|
||||
this.drawSpread(event.detail?.spread || this.pagination?.getCurrentSpread?.());
|
||||
});
|
||||
this.reportProgress(100, 'Book texture renderer ready');
|
||||
return true;
|
||||
}
|
||||
@@ -62,7 +69,14 @@ class BookTextureRendererModule extends BaseModule {
|
||||
drawEmptySpread() {
|
||||
this.drawPageBase('left');
|
||||
this.drawPageBase('right');
|
||||
this.drawDebugText('right', 'Book canvas renderer ready');
|
||||
this.publishSpread();
|
||||
}
|
||||
|
||||
drawSpread(spread = null) {
|
||||
this.drawPageBase('left');
|
||||
this.drawPageBase('right');
|
||||
this.drawPageLines('left', spread?.left || []);
|
||||
this.drawPageLines('right', spread?.right || []);
|
||||
this.publishSpread();
|
||||
}
|
||||
|
||||
@@ -91,19 +105,51 @@ class BookTextureRendererModule extends BaseModule {
|
||||
this.hitMaps[side] = [];
|
||||
}
|
||||
|
||||
drawDebugText(side, text) {
|
||||
drawPageLines(side, lines = []) {
|
||||
const ctx = this.contexts[side];
|
||||
const metrics = this.metrics;
|
||||
if (!ctx || !metrics) return;
|
||||
if (!ctx || !this.metrics || !Array.isArray(lines)) return;
|
||||
|
||||
ctx.save();
|
||||
ctx.fillStyle = 'rgba(31, 19, 10, 0.82)';
|
||||
ctx.font = `${Math.round(metrics.typography.bodyFontSizePt * 1.55)}px ${metrics.typography.fontFamily}`;
|
||||
ctx.fillStyle = 'rgba(31, 19, 10, 0.86)';
|
||||
ctx.textBaseline = 'alphabetic';
|
||||
ctx.fillText(String(text || ''), metrics.content.x, metrics.content.y + 44);
|
||||
lines.forEach(line => this.drawLine(ctx, line));
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
drawLine(ctx, lineRecord = {}) {
|
||||
const metrics = this.metrics;
|
||||
const fontPx = Math.max(1, Number(lineRecord.fontPx || 22));
|
||||
const lineHeightPx = Math.max(fontPx + 2, Number(lineRecord.lineHeightPx || metrics.typographyLineHeightPx || 30));
|
||||
const line = lineRecord.line || {};
|
||||
const nodes = Array.isArray(line.nodes) ? line.nodes : [];
|
||||
const baseY = metrics.content.y + (Number(lineRecord.pageLine || 0) * lineHeightPx) + fontPx;
|
||||
const ratio = line.isFinal || line.align === 'center' ? 0 : Number(line.ratio || 0);
|
||||
const naturalWidth = nodes.reduce((sum, node) => {
|
||||
if (node.type === 'box' || node.type === 'glue') return sum + Number(node.width || 0);
|
||||
return sum;
|
||||
}, 0);
|
||||
const centerOffset = line.align === 'center'
|
||||
? Math.max(0, (metrics.content.width - naturalWidth) / 2)
|
||||
: Number(line.offset || 0);
|
||||
let x = metrics.content.x + centerOffset;
|
||||
|
||||
ctx.font = `${fontPx}px ${metrics.typography.fontFamily}`;
|
||||
nodes.forEach((node, index) => {
|
||||
if (!node) return;
|
||||
if (node.type === 'box' && node.value) {
|
||||
const nextNode = nodes[index + 1];
|
||||
const value = `${node.value}${nextNode?.type === 'penalty' && nextNode.penalty === 100 ? '-' : ''}`;
|
||||
ctx.fillText(value, x, baseY);
|
||||
x += Number(node.width || ctx.measureText(value).width || 0);
|
||||
} else if (node.type === 'glue' && node.width !== 0) {
|
||||
let width = Number(node.width || 0);
|
||||
if (ratio > 0) width += Number(node.stretch || 0) * ratio;
|
||||
if (ratio < 0) width += Number(node.shrink || 0) * ratio;
|
||||
x += width;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
publishSpread() {
|
||||
document.dispatchEvent(new CustomEvent('webgl-book:page-canvases', {
|
||||
detail: {
|
||||
|
||||
Reference in New Issue
Block a user