diff options
author | yipstanley <stanley_yip@brown.edu> | 2019-05-20 04:02:23 -0400 |
---|---|---|
committer | yipstanley <stanley_yip@brown.edu> | 2019-05-20 04:02:23 -0400 |
commit | e815a45a50e215e1a5c3ada6404226326a8530a9 (patch) | |
tree | cf20d4107f6dc28e12161912f470881e915ba71f | |
parent | 3a9f1a40cb6bcd35783aa83e66c3e253812aa39d (diff) |
YES
-rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 21 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.scss | 4 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 165 |
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) => { |