aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryipstanley <stanley_yip@brown.edu>2019-05-20 04:02:23 -0400
committeryipstanley <stanley_yip@brown.edu>2019-05-20 04:02:23 -0400
commite815a45a50e215e1a5c3ada6404226326a8530a9 (patch)
treecf20d4107f6dc28e12161912f470881e915ba71f
parent3a9f1a40cb6bcd35783aa83e66c3e253812aa39d (diff)
YES
-rw-r--r--src/client/views/nodes/PDFBox.tsx21
-rw-r--r--src/client/views/pdf/PDFViewer.scss4
-rw-r--r--src/client/views/pdf/PDFViewer.tsx165
3 files changed, 176 insertions, 14 deletions
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index d74dc53c4..62c8e1c99 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -54,7 +54,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
public static LayoutString() { return FieldView.LayoutString(PDFBox); }
@observable private _alt = false;
- @observable private _interactive: boolean = false;
+ @observable private _scrollY: number = 0;
getHeight = (): number => {
if (this.props.Document) {
@@ -65,13 +65,28 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
return 0;
}
+ loaded = (nw: number, nh: number) => {
+ if (this.props.Document) {
+ let doc = this.props.Document.proto ? this.props.Document.proto : this.props.Document;
+ doc.nativeWidth = nw;
+ doc.nativeHeight = nh;
+ }
+ }
+
+ @action
+ onScroll = (e: React.UIEvent<HTMLDivElement>) => {
+ if (e.currentTarget) {
+ this._scrollY = e.currentTarget.scrollTop;
+ }
+ }
+
render() {
trace();
const pdfUrl = window.origin + RouteStore.corsProxy + "/https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf";
let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
return (
- <div style={{ overflow: "scroll", height: `${NumCast(this.props.Document.height)}px` }} onWheel={(e: React.WheelEvent) => e.stopPropagation()} className={classname}>
- <PDFViewer url={pdfUrl} />
+ <div onScroll={this.onScroll} style={{ overflow: "scroll", height: `${NumCast(this.props.Document.nativeWidth ? this.props.Document.nativeWidth : 300)}px` }} onWheel={(e: React.WheelEvent) => e.stopPropagation()} className={classname}>
+ <PDFViewer url={pdfUrl} loaded={this.loaded} scrollY={this._scrollY} />
</div>
);
}
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index d8ff06406..3a6045317 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -16,4 +16,8 @@
border-radius: 5px;
}
+.textLayer {
+ user-select: auto;
+}
+
.viewer {} \ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 26becebf1..6201f6330 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -1,14 +1,18 @@
import { observer } from "mobx-react";
import React = require("react");
-import { observable, action, runInAction } from "mobx";
+import { observable, action, runInAction, computed } from "mobx";
import { RouteStore } from "../../../server/RouteStore";
import * as Pdfjs from "pdfjs-dist";
import { Opt } from "../../../new_fields/Doc";
import "./PDFViewer.scss";
import "pdfjs-dist/web/pdf_viewer.css";
+import { number } from "prop-types";
+import { JSXElement } from "babel-types";
interface IPDFViewerProps {
url: string;
+ loaded: (nw: number, nh: number) => void;
+ scrollY: number;
}
@observer
@@ -27,11 +31,9 @@ export class PDFViewer extends React.Component<IPDFViewerProps> {
}
render() {
- console.log("PDFVIEWER");
- console.log(this._pdf);
return (
<div>
- <Viewer pdf={this._pdf} />
+ <Viewer pdf={this._pdf} loaded={this.props.loaded} scrollY={this.props.scrollY} />
</div>
);
}
@@ -39,25 +41,166 @@ export class PDFViewer extends React.Component<IPDFViewerProps> {
interface IViewerProps {
pdf: Opt<Pdfjs.PDFDocumentProxy>;
+ loaded: (nw: number, nh: number) => void;
+ scrollY: number;
}
+type PDFItem = React.Component<IPageProps> | HTMLDivElement;
+
+@observer
class Viewer extends React.Component<IViewerProps> {
+ @observable.shallow private _visibleElements: JSX.Element[] = [];
+ @observable private _isPage: boolean[] = [];
+ @observable private _pageSizes: { width: number, height: number }[] = [];
+ @observable private _startIndex: number = 0;
+ @observable private _endIndex: number = 1;
+ @observable private _loaded: boolean = false;
+ @observable private _pdf: Opt<Pdfjs.PDFDocumentProxy>;
+
+ private _pageBuffer: number = 1;
+
+ @computed get scrollY(): number {
+ return this.props.scrollY;
+ }
+
+ @computed get startIndex(): number {
+ return Math.max(0, this.getIndex(this.scrollY) - this._pageBuffer);
+ }
+
+ @computed get endIndex(): number {
+ let width = this._pageSizes.map(i => i.width);
+ return Math.min(this.props.pdf ? this.props.pdf.numPages - 1 : 0, this.getIndex(this.scrollY + Math.max(...width)) + this._pageBuffer);
+ }
+
+ componentDidMount = () => {
+ let numPages = this.props.pdf ? this.props.pdf.numPages : 0;
+ this.renderPages(0, numPages - 1, true);
+ }
+
+ componentDidUpdate = (prevProps: IViewerProps) => {
+ if (this.scrollY !== prevProps.scrollY || this._pdf !== this.props.pdf) {
+ this._pdf = this.props.pdf;
+ this.renderPages(this.startIndex, this.endIndex);
+ }
+ }
+
+ @action
+ renderPages = (startIndex: number, endIndex: number, forceRender: boolean = false) => {
+ let numPages = this.props.pdf ? this.props.pdf.numPages : 0;
+
+ if (this._visibleElements.length !== numPages) {
+ let divs = Array.from(Array(numPages).keys()).map(i => (
+ <Page
+ pdf={this.props.pdf}
+ page={i}
+ numPages={numPages}
+ key={`${this.props.pdf ? this.props.pdf.fingerprint + `-page${i + 1}` : "undefined"}`}
+ name={`${this.props.pdf ? this.props.pdf.fingerprint + `-page${i + 1}` : "undefined"}`}
+ pageLoaded={this.pageLoaded}
+ {...this.props} />
+ ));
+ let arr = Array.from(Array(numPages).keys()).map(i => false);
+ this._visibleElements.push(...divs);
+ this._isPage.push(...arr);
+ }
+
+ if (startIndex === this._startIndex && endIndex === this._endIndex && !forceRender) {
+ return;
+ }
+
+ for (let i = startIndex; i <= endIndex; i++) {
+ if (this._isPage[i] && forceRender) {
+ this._visibleElements[i] = (
+ <Page
+ pdf={this.props.pdf}
+ page={i}
+ numPages={numPages}
+ key={`${this.props.pdf ? this.props.pdf.fingerprint + `-page${i + 1}` : "undefined"}`}
+ name={`${this.props.pdf ? this.props.pdf.fingerprint + `-page${i + 1}` : "undefined"}`}
+ pageLoaded={this.pageLoaded}
+ {...this.props} />
+ );
+ this._isPage[i] = true;
+ }
+ else if (!this._isPage[i]) {
+ this._visibleElements[i] = (
+ <Page
+ pdf={this.props.pdf}
+ page={i}
+ numPages={numPages}
+ key={`${this.props.pdf ? this.props.pdf.fingerprint + `-page${i + 1}` : "undefined"}`}
+ name={`${this.props.pdf ? this.props.pdf.fingerprint + `-page${i + 1}` : "undefined"}`}
+ pageLoaded={this.pageLoaded}
+ {...this.props} />
+ );
+ this._isPage[i] = true;
+ }
+ }
+
+ for (let i = 0; i < numPages; i++) {
+ if (i < startIndex || i > endIndex) {
+ if (this._isPage[i]) {
+ this._visibleElements[i] = (
+ <div key={`pdfviewer-placeholder-${i}`} className="pdfviewer-placeholder" style={{ width: this._pageSizes[i] ? this._pageSizes[i].width : 0, height: this._pageSizes[i] ? this._pageSizes[i].height : 0 }} />
+ );
+ this._isPage[i] = false;
+ }
+ }
+ }
+
+ return;
+ }
+
+ getIndex = (vOffset: number) => {
+ if (this._loaded) {
+ let index = 0;
+ let currOffset = vOffset;
+ while (currOffset - this._pageSizes[index].height > 0) {
+ currOffset -= this._pageSizes[index].height;
+ index++;
+ }
+ return index;
+ }
+ return 0;
+ }
+
+ @action
+ pageLoaded = (index: number, page: Pdfjs.PDFPageViewport): void => {
+ let numPages = this.props.pdf ? this.props.pdf.numPages : 0;
+ this.props.loaded(page.width, page.height);
+ if (index > this._pageSizes.length) {
+ this._pageSizes.push({ width: page.width, height: page.height });
+ }
+ else {
+ this._pageSizes[index - 1] = { width: page.width, height: page.height };
+ }
+ if (index === numPages) {
+ this._loaded = true;
+ let divs = Array.from(Array(numPages).keys()).map(i => (
+ <div key={`pdfviewer-placeholder-${i}`} className="pdfviewer-placeholder" style={{ width: this._pageSizes[i] ? this._pageSizes[i].width : 0, height: this._pageSizes[i] ? this._pageSizes[i].height : 0 }} />
+ ));
+ this._visibleElements = new Array<JSX.Element>(...divs);
+ }
+ }
+
render() {
- console.log("VIEWER");
+ console.log(`START: ${this.startIndex}`);
+ console.log(`END: ${this.endIndex}`)
let numPages = this.props.pdf ? this.props.pdf.numPages : 0;
- console.log(numPages);
return (
<div className="viewer">
- {Array.from(Array(numPages).keys()).map((i) => (
+ {/* {Array.from(Array(numPages).keys()).map((i) => (
<Page
pdf={this.props.pdf}
page={i}
numPages={numPages}
key={`${this.props.pdf ? this.props.pdf.fingerprint + `-page${i + 1}` : "undefined"}`}
name={`${this.props.pdf ? this.props.pdf.fingerprint + `-page${i + 1}` : "undefined"}`}
+ pageLoaded={this.pageLoaded}
{...this.props}
/>
- ))} }
+ ))} */}
+ {this._visibleElements}
</div>
);
}
@@ -68,6 +211,7 @@ interface IPageProps {
name: string;
numPages: number;
page: number;
+ pageLoaded: (index: number, page: Pdfjs.PDFPageViewport) => void;
}
@observer
@@ -113,12 +257,10 @@ class Page extends React.Component<IPageProps> {
pdf.getPage(this._currPage).then(
(page: Pdfjs.PDFPageProxy) => {
- console.log("PAGE");
- console.log(page);
this._state = "rendering";
this.renderPage(page);
}
- )
+ );
}
@action
@@ -132,6 +274,7 @@ class Page extends React.Component<IPageProps> {
this._width = viewport.width;
canvas.height = viewport.height;
this._height = viewport.height;
+ this.props.pageLoaded(this._currPage, viewport);
if (context) {
page.render({ canvasContext: context, viewport: viewport });
page.getTextContent().then((res: Pdfjs.TextContent) => {