diff options
author | yipstanley <stanley_yip@brown.edu> | 2019-06-11 19:02:00 -0400 |
---|---|---|
committer | yipstanley <stanley_yip@brown.edu> | 2019-06-11 19:02:00 -0400 |
commit | b96281d18a9c4ca0ea7f8360d7f69d12c325fada (patch) | |
tree | 9498fc9a61219585e798d35c80a5228d32716c64 /src | |
parent | 64f6a0d54656ded133af113746003d61eaa1d651 (diff) |
pin annotations
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 136 | ||||
-rw-r--r-- | src/client/views/pdf/Page.tsx | 4 |
3 files changed, 110 insertions, 31 deletions
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index de75c67cf..5b118185b 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -50,6 +50,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen trace(); // uses mozilla pdf as default const pdfUrl = Cast(this.props.Document.data, PdfField, new PdfField(window.origin + RouteStore.corsProxy + "/https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf")); + console.log(pdfUrl); let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); return ( <div onScroll={this.onScroll} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index bc773ebef..6823f640e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -1,6 +1,6 @@ import { observer } from "mobx-react"; import React = require("react"); -import { observable, action, runInAction, computed, IReactionDisposer, reaction } from "mobx"; +import { observable, action, runInAction, computed, IReactionDisposer, reaction, trace } from "mobx"; import * as Pdfjs from "pdfjs-dist"; import { Opt, HeightSym, WidthSym, Doc, DocListCast } from "../../../new_fields/Doc"; import "./PDFViewer.scss"; @@ -14,6 +14,10 @@ import { DocumentManager } from "../../util/DocumentManager"; import { SelectionManager } from "../../util/SelectionManager"; import { List } from "../../../new_fields/List"; import { DocumentContentsView } from "../nodes/DocumentContentsView"; +import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; +import { Transform } from "../../util/Transform"; +import { emptyFunction, returnTrue, returnFalse } from "../../../Utils"; +import { DocumentView } from "../nodes/DocumentView"; interface IPDFViewerProps { url: string; @@ -33,10 +37,14 @@ export class PDFViewer extends React.Component<IPDFViewerProps> { @action componentDidMount() { const pdfUrl = this.props.url; + console.log("pdf starting to load") let promise = Pdfjs.getDocument(pdfUrl).promise; promise.then((pdf: Pdfjs.PDFDocumentProxy) => { - runInAction(() => this._pdf = pdf); + runInAction(() => { + console.log("pdf url received"); + this._pdf = pdf; + }); }); } @@ -77,8 +85,16 @@ class Viewer extends React.Component<IViewerProps> { @observable private _annotations: Doc[] = []; private _pageBuffer: number = 1; + private _annotationLayer: React.RefObject<HTMLDivElement>; private _reactionDisposer?: IReactionDisposer; private _annotationReactionDisposer?: IReactionDisposer; + private _pagesLoaded: number = 0; + + constructor(props: IViewerProps) { + super(props); + + this._annotationLayer = React.createRef(); + } componentDidMount = () => { let wasSelected = this.props.parent.props.isSelected(); @@ -112,8 +128,9 @@ class Viewer extends React.Component<IViewerProps> { ); } - // On load, render pdf - setTimeout(() => this.renderPages(this.startIndex, this.endIndex, true), 1000); + setTimeout(() => { + this.renderPages(this.startIndex, this.endIndex, true); + }, 1000); } componentWillUnmount = () => { @@ -150,7 +167,7 @@ class Viewer extends React.Component<IViewerProps> { } @computed get endIndex(): number { - let width = this._pageSizes.map(i => i.width); + let width = this._pageSizes.map(i => i ? i.width : 0); return Math.min(this.props.pdf ? this.props.pdf.numPages - 1 : 0, this.getIndex(this.scrollY + Math.max(...width)) + this._pageBuffer); } @@ -185,6 +202,10 @@ class Viewer extends React.Component<IViewerProps> { return; } + if (this._pageSizes.length !== numPages) { + this._pageSizes = new Array(numPages).map(i => ({ width: 0, height: 0 })); + } + // this is only for an initial render to get all of the pages rendered if (this._visibleElements.length !== numPages) { let divs = Array.from(Array(numPages).keys()).map(i => ( @@ -248,14 +269,14 @@ class Viewer extends React.Component<IViewerProps> { return; } - createPinAnnotation = (x: number, y: number): void => { - let targetDoc = Docs.TextDocument({ title: "New Pin Annotation" }); + createPinAnnotation = (x: number, y: number, page: number): void => { + let targetDoc = Docs.TextDocument({ width: 100, height: 50, title: "New Pin Annotation" }); let pinAnno = new Doc(); pinAnno.x = x; pinAnno.y = y; pinAnno.width = pinAnno.height = PinRadius; - pinAnno.page = this.getIndex(y); + pinAnno.page = page; pinAnno.target = targetDoc; pinAnno.type = AnnotationTypes.Pin; // this._annotations.push(pinAnno); @@ -301,18 +322,18 @@ class Viewer extends React.Component<IViewerProps> { } 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._pageSizes[index - 1] = { width: page.width, height: page.height }; + this._pagesLoaded++; + if (this._pagesLoaded === 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); + // On load, render pdf + // setTimeout(() => { + this.renderPages(this.startIndex, this.endIndex, true); + // }, 1000); } } @@ -332,21 +353,38 @@ class Viewer extends React.Component<IViewerProps> { let type = NumCast(anno.type); switch (type) { case AnnotationTypes.Pin: - return <PinAnnotation document={anno} x={NumCast(anno.x)} y={NumCast(anno.y) + this.getPageHeight(NumCast(anno.page))} width={anno[WidthSym]()} height={anno[HeightSym]()} key={anno[Id]} />; + return <PinAnnotation parent={this} document={anno} x={NumCast(anno.x)} y={NumCast(anno.y) + this.getPageHeight(NumCast(anno.page))} width={anno[WidthSym]()} height={anno[HeightSym]()} key={anno[Id]} />; case AnnotationTypes.Region: - return <RegionAnnotation document={anno} x={NumCast(anno.x)} y={NumCast(anno.y) + this.getPageHeight(NumCast(anno.page))} width={anno[WidthSym]()} height={anno[HeightSym]()} key={anno[Id]} />; + return <RegionAnnotation parent={this} document={anno} x={NumCast(anno.x)} y={NumCast(anno.y) + this.getPageHeight(NumCast(anno.page))} width={anno[WidthSym]()} height={anno[HeightSym]()} key={anno[Id]} />; default: return <div></div>; } } + onDrop = (e: React.DragEvent) => { + console.log("Dropped!"); + } + + // ScreenToLocalTransform = (): Transform => { + // if (this._annotationLayer.current) { + // let boundingRect = this._annotationLayer.current.getBoundingClientRect(); + // let x = boundingRect.left; + // let y = boundingRect.top; + // let scale = NumCast(this.props.parent.Document.nativeWidth) / boundingRect.width; + // let t = new Transform(x, y, scale); + // return t; + // } + // return Transform.Identity(); + // } + render() { + trace(); return ( - <div> + <div onDrop={this.onDrop}> <div className="viewer"> {this._visibleElements} </div> - <div className="pdfViewer-annotationLayer" style={{ height: this.props.parent.Document.nativeHeight, width: `100%`, pointerEvents: "none" }}> + <div className="pdfViewer-annotationLayer" ref={this._annotationLayer} style={{ height: this.props.parent.Document.nativeHeight, width: `100%`, pointerEvents: "none" }}> <div className="pdfViewer-annotationLayer-subCont" style={{ transform: `translateY(${-this.scrollY}px)` }}> {this._annotations.map(anno => this.renderAnnotation(anno))} </div> @@ -365,25 +403,65 @@ interface IAnnotationProps { y: number; width: number; height: number; + parent: Viewer; document: Doc; } +@observer class PinAnnotation extends React.Component<IAnnotationProps> { - @observable private _backgroundColor: string = "red"; + @observable private _backgroundColor: string = "green"; + @observable private _display: string = "initial"; - pointerDown = (e: React.PointerEvent) => { + private _selected: boolean = true; + @action + pointerDown = (e: React.PointerEvent) => { + if (this._selected) { + this._backgroundColor = "red"; + this._display = "none"; + this._selected = false; + } + else { + this._backgroundColor = "green"; + this._display = "initial"; + this._selected = true; + } + e.preventDefault(); + e.stopPropagation(); } render() { - let targetDoc = Cast(this.props.document.targetDoc, Doc, Docs.TextDocument({ title: "New Pin Annotation" })); - return ( - <div className="pdfViewer-pinAnnotation" onPointerDown={this.pointerDown} - style={{ top: this.props.y - PinRadius / 2, left: this.props.x - PinRadius / 2, width: PinRadius, height: PinRadius, pointerEvents: "all", backgroundColor: this._backgroundColor }}> - {/* <DocumentContentsView Document={targetDoc} - isSelected={} /> */} - </div> - ); + let targetDoc = Cast(this.props.document.target, Doc); + if (targetDoc instanceof Doc) { + return ( + <div className="pdfViewer-pinAnnotation" onPointerDown={this.pointerDown} + style={{ + top: this.props.y - PinRadius / 2, left: this.props.x - PinRadius / 2, width: PinRadius, + height: PinRadius, pointerEvents: "all", backgroundColor: this._backgroundColor + }}> + <div style={{ + position: "absolute", top: "25px", left: "25px", transform: "scale(3)", transformOrigin: "top left", + display: this._display, width: targetDoc[WidthSym](), height: targetDoc[HeightSym]() + }}> + <DocumentView Document={targetDoc} + ContainingCollectionView={undefined} + ScreenToLocalTransform={this.props.parent.props.parent.props.ScreenToLocalTransform} + isTopMost={false} + ContentScaling={() => 1} + PanelWidth={() => NumCast(this.props.parent.props.parent.Document.nativeWidth)} + PanelHeight={() => NumCast(this.props.parent.props.parent.Document.nativeHeight)} + focus={emptyFunction} + selectOnLoad={false} + parentActive={this.props.parent.props.parent.props.active} + whenActiveChanged={this.props.parent.props.parent.props.whenActiveChanged} + bringToFront={emptyFunction} + addDocTab={this.props.parent.props.parent.props.addDocTab} + /> + </div> + </div > + ); + } + return null; } } diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index fe7369aeb..73a7a93a0 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -23,7 +23,7 @@ interface IPageProps { pageLoaded: (index: number, page: Pdfjs.PDFPageViewport) => void; parent: PDFBox; renderAnnotations: (annotations: Doc[], removeOld: boolean) => void; - makePin: (x: number, y: number) => void; + makePin: (x: number, y: number, page: number) => void; } @observer @@ -378,7 +378,7 @@ export default class Page extends React.Component<IPageProps> { let boundingRect = current.getBoundingClientRect(); let x = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width); let y = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height); - this.props.makePin(x, y); + this.props.makePin(x, y, this.props.page); } } |