Skip to content

Commit

Permalink
Initial PDF Navigator
Browse files Browse the repository at this point in the history
  • Loading branch information
aferditamuriqi committed Oct 9, 2022
1 parent 619a454 commit 8e772ac
Show file tree
Hide file tree
Showing 8 changed files with 982 additions and 366 deletions.
4 changes: 4 additions & 0 deletions examples/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ async function start() {
title: "API Example",
getUrl: (url) => `/viewer/index_api.html?url=${url}`,
},
{
title: "Static Placeholder PDF Example",
getUrl: (url) => `/viewer/index_pdf.html?url=${url}`,
},
],
});

Expand Down
348 changes: 224 additions & 124 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
},
"dependencies": {
"@types/sass": "^1.43.1",
"@types/pdfjs-dist": "^2.7.4",
"browserslist-useragent": "^3.0.3",
"cssesc": "^3.0.0",
"detect-browser": "^5.2.0",
Expand All @@ -34,6 +35,7 @@
"lodash.clonedeep": "^4.5.0",
"loglevel": "^1.8.0",
"mark.js": "^8.11.1",
"pdfjs-dist": "2.16.105",
"promise-polyfill": "^8.2.0",
"r2-shared-js": "^1.0.51",
"recursive-readdir": "^2.2.2",
Expand Down
71 changes: 70 additions & 1 deletion src/navigator/Navigator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,75 @@
* Licensed to: Bokbasen AS and CAST under one or more contributor license agreements.
*/

interface Navigator {}
import { Locator } from "../model/Locator";
import { IFrameAttributes } from "./IFrameNavigator";

interface Navigator {
publication: any;
rights?: any;
hasMediaOverlays?: any;

addListener?(argument: any, argument2: any): void;

startReadAloud?(): void;

stopReadAloud?(): void;

pauseReadAloud?(): void;

resumeReadAloud?(): void;

startReadAlong?(): void;

stopReadAlong?(): void;

pauseReadAlong?(): void;

resumeReadAlong?(): void;

hideLayer?(layer): any;

showLayer?(layer): any;

activateMarker?(id: string, position: string): any;

deactivateMarker?(): any;

tableOfContents(): any;

readingOrder(): any;

currentResource(): any;

mostRecentNavigatedTocItem?(): any;

totalResources(): any;

currentLocator(): any;

positions(): any;

goTo(locator: Locator): void;

goToPosition(value: number);

nextResource(): void;

previousResource(): void;

nextPage(): void;

previousPage(): void;

atStart?(): any;

atEnd?(): any;

snapToSelector?(selector): void;

applyAttributes?(value: IFrameAttributes): void;

stop(): void;
}

export default Navigator;
197 changes: 197 additions & 0 deletions src/navigator/PDFNavigator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import EventEmitter from "eventemitter3";
import Navigator from "./Navigator";
import { UserSettings } from "../model/user-settings/UserSettings";
import { Publication } from "../model/Publication";
import { Locator } from "../model/Locator";
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
import { findRequiredElement } from "../utils/HTMLUtilities";

export interface PDFNavigatorConfig {
mainElement: HTMLElement;
headerMenu?: HTMLElement | null;
footerMenu?: HTMLElement | null;
publication: Publication;
settings: UserSettings;
}

export class PDFNavigator extends EventEmitter implements Navigator {
settings: UserSettings;
publication: Publication;

headerMenu?: HTMLElement | null;
footerMenu?: HTMLElement | null;
mainElement: HTMLElement;

pdfDoc: any = null;
pageNum = 1;
pageRendering = false;
pageNumPending: any = null;
scale = 1.0;
canvas: HTMLCanvasElement;
ctx: CanvasRenderingContext2D | null;
resourceIndex = 0;
resource: any;

public static async create(
config: PDFNavigatorConfig
): Promise<PDFNavigator> {
const navigator = new this(config.settings, config.publication);

await navigator.start(
config.mainElement,
config.headerMenu,
config.footerMenu
);
return new Promise((resolve) => resolve(navigator));
}
protected constructor(settings: UserSettings, publication: Publication) {
super();
this.settings = settings;
this.publication = publication;
}

protected async start(
mainElement: HTMLElement,
headerMenu?: HTMLElement | null,
footerMenu?: HTMLElement | null
): Promise<void> {
this.headerMenu = headerMenu;
this.footerMenu = footerMenu;
this.mainElement = mainElement;

this.resourceIndex = 0;
this.resource = this.publication.readingOrder[this.resourceIndex];

console.log(this.resource);
console.log(this.resource.Href1);

GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.js`;

this.canvas = document.getElementById("the-canvas") as HTMLCanvasElement;
this.ctx = this.canvas.getContext("2d");

const self = this;

getDocument(this.resource.Href1).promise.then(function (pdfDoc_) {
self.pdfDoc = pdfDoc_;
self.renderPage(self.pageNum);
});
}

renderPage(num) {
const self = this;
const main = findRequiredElement(this.mainElement, "main");
self.pageRendering = true;

self.pdfDoc.getPage(num).then(function (page) {
let viewport = page.getViewport({ scale: self.scale });

const sc = main.clientHeight / viewport.height;
viewport = page.getViewport({ scale: sc });

self.canvas.height = viewport.height;
self.canvas.width = viewport.width;

// Render PDF page into canvas context
const renderContext = {
canvasContext: self.ctx,
viewport: viewport,
};
const renderTask = page.render(renderContext);

// Wait for rendering to finish
renderTask.promise.then(function () {
self.pageRendering = false;
if (self.pageNumPending !== null) {
// New page rendering is pending
self.renderPage(self.pageNumPending);
self.pageNumPending = null;
}
});
});
}

queueRenderPage(num) {
const self = this;
if (self.pageRendering) {
self.pageNumPending = num;
} else {
self.renderPage(num);
}
}

readingOrder(): any {}

tableOfContents(): any {}

currentResource(): any {}

totalResources(): any {}

currentLocator(): any {}

positions(): any {}

nextPage(): void {
const self = this;
if (self.pageNum >= self.pdfDoc.numPages) {
this.nextResource();
return;
}
this.pageNum++;
this.queueRenderPage(self.pageNum);
}

previousPage(): void {
const self = this;
if (self.pageNum <= 1) {
this.previousResource();
return;
}
self.pageNum--;
self.queueRenderPage(self.pageNum);
}

nextResource(): void {
const self = this;
console.log(self.resourceIndex, this.publication.readingOrder.length - 1);
if (this.resourceIndex >= this.publication.readingOrder.length - 1) {
return;
}
self.pageNum = 1;
self.resourceIndex++;
self.resource = this.publication.readingOrder[self.resourceIndex];
console.log(this.resource.Href1);
getDocument(this.resource.Href1).promise.then(function (pdfDoc_) {
self.pdfDoc = pdfDoc_;
self.renderPage(self.pageNum);
});
}

previousResource(): void {
const self = this;
console.log(self.resourceIndex, this.publication.readingOrder.length - 1);
if (this.resourceIndex === 0) {
return;
}
// TODO: how to know last page of previous resource
self.pageNum = 1;
self.resourceIndex--;
self.resource = this.publication.readingOrder[self.resourceIndex];
console.log(this.resource.Href1);
getDocument(this.resource.Href1).promise.then(function (pdfDoc_) {
self.pdfDoc = pdfDoc_;
self.renderPage(self.pageNum);
});
}

goTo(locator: Locator): void {
console.log(locator);
}

goToPosition(value: number): void {
console.log(value);
}

stop(): void {}
}
Loading

0 comments on commit 8e772ac

Please sign in to comment.