diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 6 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 4 | ||||
-rw-r--r-- | src/client/views/pdf/PDFBox2.tsx | 28 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.scss | 19 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 186 |
6 files changed, 242 insertions, 2 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 9d2f4d3cd..5752bb096 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -33,8 +33,12 @@ import { DocServer } from "../DocServer"; import { StrokeData, InkField } from "../../new_fields/InkField"; import { dropActionType } from "../util/DragManager"; import { DateField } from "../../new_fields/DateField"; +<<<<<<< HEAD +import { PDFBox2 } from "../views/pdf/PDFBox2"; +======= import { schema } from "prosemirror-schema-basic"; import { UndoManager } from "../util/UndoManager"; +>>>>>>> 01a223f2e6685506cc1e5db69e9062d5ff0d3246 export interface DocumentOptions { x?: number; @@ -170,7 +174,7 @@ export namespace Docs { } function CreatePdfPrototype(): Doc { let pdfProto = setupPrototypeOptions(pdfProtoId, "PDF_PROTO", CollectionPDFView.LayoutString("annotations"), - { x: 0, y: 0, nativeWidth: 1200, width: 300, backgroundLayout: PDFBox.LayoutString(), curPage: 1 }); + { x: 0, y: 0, nativeWidth: 1200, width: 300, height: 300, backgroundLayout: PDFBox.LayoutString(), curPage: 1 }); return pdfProto; } function CreateWebPrototype(): Doc { diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index d2cb11586..8e08385a4 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -23,6 +23,7 @@ import { FieldViewProps } from "./FieldView"; import { Without, OmitKeys } from "../../../Utils"; import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; +import { PDFBox2 } from "../pdf/PDFBox2"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? type BindingProps = Without<FieldViewProps, 'fieldKey'>; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index e71ac4924..9b0207d0c 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -21,6 +21,7 @@ import { positionSchema } from "./DocumentView"; import { pageSchema } from "./ImageBox"; import { ImageField, PdfField } from "../../../new_fields/URLField"; import { InkingControl } from "../InkingControl"; +import { PDFViewer } from "../pdf/PDFViewer"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, @@ -340,10 +341,11 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false); 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 className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} > - {this.pdfRenderer} + <PDFViewer url={pdfUrl} /> </div > ); } diff --git a/src/client/views/pdf/PDFBox2.tsx b/src/client/views/pdf/PDFBox2.tsx new file mode 100644 index 000000000..71825c260 --- /dev/null +++ b/src/client/views/pdf/PDFBox2.tsx @@ -0,0 +1,28 @@ +import React = require("react"); +import { FieldViewProps, FieldView } from "../nodes/FieldView"; +import { DocComponent } from "../DocComponent"; +import { makeInterface } from "../../../new_fields/Schema"; +import { positionSchema } from "../nodes/DocumentView"; +import { pageSchema } from "../nodes/ImageBox"; +import { PDFViewer } from "./PDFViewer"; +import { RouteStore } from "../../../server/RouteStore"; +import { InkingControl } from "../InkingControl"; +import { observer } from "mobx-react"; +import { trace } from "mobx"; + +type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; +const PdfDocument = makeInterface(positionSchema, pageSchema); + +@observer +export class PDFBox2 extends DocComponent<FieldViewProps, PdfDocument>(PdfDocument) { + public static LayoutString() { return FieldView.LayoutString(PDFBox2); } + + render() { + trace(); + const pdfUrl = "https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf"; + let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool); + return ( + <PDFViewer url={pdfUrl} /> + ) + } +}
\ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss new file mode 100644 index 000000000..d8ff06406 --- /dev/null +++ b/src/client/views/pdf/PDFViewer.scss @@ -0,0 +1,19 @@ +.canvasContainer {} + +.viewer-button-cont { + position: absolute; + display: flex; + justify-content: space-evenly; + align-items: center; +} + +.viewer-previousPage, +.viewer-nextPage { + background: grey; + font-weight: bold; + opacity: 0.5; + padding: 0 10px; + border-radius: 5px; +} + +.viewer {}
\ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx new file mode 100644 index 000000000..1b445eae4 --- /dev/null +++ b/src/client/views/pdf/PDFViewer.tsx @@ -0,0 +1,186 @@ +import { observer } from "mobx-react"; +import React = require("react"); +import { observable, action, runInAction } from "mobx"; +import { RouteStore } from "../../../server/RouteStore"; +import * as Pdfjs from "pdfjs-dist"; +import { Opt } from "../../../new_fields/Doc"; +import "./PDFViewer.scss"; + +interface IPDFViewerProps { + url: string; +} + +@observer +export class PDFViewer extends React.Component<IPDFViewerProps> { + @observable _pdf: Opt<Pdfjs.PDFDocumentProxy>; + + @action + componentDidMount() { + // const pdfUrl = window.origin + RouteStore.corsProxy + "/https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf"; + const pdfUrl = this.props.url; + let promise = Pdfjs.getDocument(pdfUrl).promise; + + promise.then((pdf: Pdfjs.PDFDocumentProxy) => { + runInAction(() => this._pdf = pdf); + }); + } + + render() { + console.log("PDFVIEWER"); + console.log(this._pdf); + return ( + <div> + <Viewer pdf={this._pdf} /> + </div> + ); + } +} + +interface IViewerProps { + pdf: Opt<Pdfjs.PDFDocumentProxy>; +} + +class Viewer extends React.Component<IViewerProps> { + render() { + console.log("VIEWER"); + let numPages = this.props.pdf ? this.props.pdf.numPages : 0; + console.log(numPages); + return ( + <div className="viewer"> + {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"}`} + {...this.props} + /> + ))} } + </div> + ); + } +} + +interface IPageProps { + pdf: Opt<Pdfjs.PDFDocumentProxy>; + name: string; + numPages: number; + page: number; +} + +@observer +class Page extends React.Component<IPageProps> { + @observable _state: string = "N/A"; + @observable _width: number = 0; + @observable _height: number = 0; + @observable _page: Opt<Pdfjs.PDFPageProxy>; + canvas: React.RefObject<HTMLCanvasElement>; + textLayer: React.RefObject<HTMLDivElement>; + @observable _currPage: number = this.props.page + 1; + + constructor(props: IPageProps) { + super(props); + this.canvas = React.createRef(); + this.textLayer = React.createRef(); + } + + componentDidMount() { + console.log(this.props.pdf); + if (this.props.pdf) { + this.update(this.props.pdf); + } + } + + componentDidUpdate() { + if (this.props.pdf) { + this.update(this.props.pdf); + } + } + + private update = (pdf: Pdfjs.PDFDocumentProxy) => { + if (pdf) { + this.loadPage(pdf); + } + else { + this._state = "loading"; + } + } + + private loadPage = (pdf: Pdfjs.PDFDocumentProxy) => { + if (this._state === "rendering" || this._page) return; + + pdf.getPage(this._currPage).then( + (page: Pdfjs.PDFPageProxy) => { + console.log("PAGE"); + console.log(page); + this._state = "rendering"; + this.renderPage(page); + } + ) + } + + @action + private renderPage = (page: Pdfjs.PDFPageProxy) => { + let scale = 1; + let viewport = page.getViewport(scale); + let canvas = this.canvas.current; + if (canvas) { + let context = canvas.getContext("2d"); + canvas.width = viewport.width; + this._width = viewport.width; + canvas.height = viewport.height; + this._height = viewport.height; + if (context) { + page.render({ canvasContext: context, viewport: viewport }); + page.getTextContent().then((res: Pdfjs.TextContent) => { + //@ts-ignore + let textLayer = Pdfjs.renderTextLayer({ + textContent: res, + container: this.textLayer.current, + viewport: viewport + }); + // textLayer._render(); + this._state = "rendered"; + }); + + this._page = page; + } + } + } + + @action + prevPage = (e: React.MouseEvent) => { + if (this._currPage > 2 && this._state !== "rendering") { + this._currPage = Math.max(this._currPage - 1, 1); + this._page = undefined; + this.loadPage(this.props.pdf!); + this._state = "rendering"; + } + } + + @action + nextPage = (e: React.MouseEvent) => { + if (this._currPage < this.props.numPages - 1 && this._state !== "rendering") { + this._currPage = Math.min(this._currPage + 1, this.props.numPages) + this._page = undefined; + this.loadPage(this.props.pdf!); + this._state = "rendering"; + } + } + + render() { + return ( + <div className={this.props.name} style={{ "width": this._width, "height": this._height }}> + <div className="canvasContainer"> + <canvas ref={this.canvas} /> + </div> + <div className="textlayer" ref={this.textLayer} style={{ "position": "relative", "top": `-${this._height}px`, "height": `${this._height}px` }} /> + {/* <div className="viewer-button-cont" style={{ "width": this._width / 10, "height": this._height / 20, "left": this._width * .9, "top": this._height * .95 }}> + <div className="viewer-previousPage" onClick={this.prevPage}><</div> + <div className="viewer-nextPage" onClick={this.nextPage}>></div> + </div> */} + </div> + ); + } +}
\ No newline at end of file |