InlineDocument/src/web/view_page.ts
2024-04-21 14:39:49 +09:00

88 lines
2.3 KiB
TypeScript

import { PageInfo } from "../components/page_info";
import { Display } from "../display/display";
import { PromiseCapability } from "../utils/promise_capability";
import { RenderingState } from "./rendering_queue";
class ViewPage {
pageInfo: PageInfo;
display: Display;
div: HTMLDivElement;
canvas?: HTMLCanvasElement;
renderingState: RenderingState;
lastScale: number;
#drawPromise?: PromiseCapability;
constructor(
container: HTMLDivElement,
pageInfo: PageInfo,
display: Display
) {
this.pageInfo = pageInfo;
this.display = display;
this.div = document.createElement('div');
this.div.classList.add('page');
this.renderingState = "none";
this.lastScale = 0;
this.#drawPromise = undefined;
container.append(this.div);
}
reset() {
if (this.renderingState === "drawing") {
throw new Error(`ViewPage is currently drawing.`);
}
if (this.canvas) {
this.canvas.width = 0;
this.canvas.height = 0;
this.canvas.remove();
}
this.renderingState = "none";
}
async draw() {
if (this.renderingState === "drawed" || this.renderingState === "drawing") {
throw new Error(`Invalid rendering state.`);
}
this.renderingState = "drawing";
this.#drawPromise = new PromiseCapability();
try {
const canvas = this.canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
if (context === null) {
throw new RangeError('Out of memory');
}
const { bitmap } = await this.display.drawPageInfo(this.pageInfo);
canvas.width = bitmap.width;
canvas.height = bitmap.height;
canvas.style.width = `${Math.floor(this.pageInfo.width * this.display.scale)}px`;
canvas.style.height = `${Math.floor(this.pageInfo.height * this.display.scale)}px`;
context.drawImage(bitmap, 0, 0);
this.div.style.width = `${Math.floor(this.pageInfo.width * this.display.scale)}px`;
this.div.style.height = `${Math.floor(this.pageInfo.height * this.display.scale)}px`;
this.div.append(canvas);
} finally {
this.renderingState = "drawed";
this.#drawPromise.resolve(null);
}
}
async dispose() {
if (this.renderingState === "drawing") {
await this.#drawPromise?.promise;
}
this.reset();
this.div.remove();
}
}
export {
ViewPage,
}