diff options
author | yipstanley <stanley_yip@brown.edu> | 2019-09-24 18:30:18 -0400 |
---|---|---|
committer | yipstanley <stanley_yip@brown.edu> | 2019-09-24 18:30:18 -0400 |
commit | 1a12483b52c27259f0f2762d4369a79e1397af9c (patch) | |
tree | 9fca82bd3268912e60a6bf2e233f56622f53a4bb | |
parent | c3e5b50ed59f474cddace89ad4ca25f2ef0c2f74 (diff) |
ahhhh
-rw-r--r-- | src/client/util/DocumentManager.ts | 4 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.scss | 148 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 12 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.scss | 28 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 165 | ||||
-rw-r--r-- | src/client/views/pdf/Page.scss | 36 | ||||
-rw-r--r-- | src/client/views/pdf/Page.tsx | 293 | ||||
-rw-r--r-- | src/debug/Test.tsx | 99 |
8 files changed, 134 insertions, 651 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a3c7429b9..eaed82918 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -132,9 +132,7 @@ export class DocumentManager { let doc = Doc.GetProto(docDelegate); const contextDoc = await Cast(doc.annotationOn, Doc); if (contextDoc) { - const page = NumCast(doc.page, linkPage || 0); - const curPage = NumCast(contextDoc.curPage, page); - if (page !== curPage) contextDoc.curPage = page; + contextDoc.panY = doc.y; } let docView: DocumentView | null; diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index c88a94c28..b55ca8ba5 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -5,23 +5,15 @@ height: 100%; overflow-y: scroll; overflow-x: hidden; - .pdfBox-scrollHack { - pointer-events: none; - } } .pdfBox-cont { pointer-events: none; - .pdfPage-textlayer { - span { - pointer-events: none !important; - user-select: none; - } - } } .pdfBox-cont-interactive { pointer-events: all; + .pdfPage-textlayer { span { pointer-events: all !important; @@ -30,82 +22,90 @@ } } -.react-pdf__Page { - transform-origin: left top; - position: absolute; - top: 0; - left: 0; -} +.pdfViewer-text { + .textLayer { + span { + user-select: text; + } + } -.react-pdf__Page__textContent span { - user-select: text; -} + .react-pdf__Page { + transform-origin: left top; + position: absolute; + top: 0; + left: 0; + } -.react-pdf__Document { - position: absolute; -} + .react-pdf__Page__textContent span { + user-select: text; + } + .react-pdf__Document { + position: absolute; + } -.pdfBox-settingsCont { - position: absolute; - right: 0; - top: 0; - - .pdfBox-settingsButton { - border-bottom-left-radius: 50%; - display: flex; - justify-content: space-evenly; - align-items: center; - height: 70px; - background: none; - padding: 0; - - .pdfBox-settingsButton-arrow { - width: 0; - height: 0; - border-top: 25px solid transparent; - border-bottom: 25px solid transparent; - border-right: 25px solid #121721; - transition: all 0.5s; - } - .pdfBox-settingsButton-iconCont { - background: #121721; - height: 50px; - width: 70px; + .pdfBox-settingsCont { + position: absolute; + right: 0; + top: 0; + + .pdfBox-settingsButton { + border-bottom-left-radius: 50%; display: flex; - justify-content: center; + justify-content: space-evenly; align-items: center; - margin-left: -2px; - border-radius: 3px; - } - } + height: 70px; + background: none; + padding: 0; - .pdfBox-settingsButton:hover { - background: none; - } + .pdfBox-settingsButton-arrow { + width: 0; + height: 0; + border-top: 25px solid transparent; + border-bottom: 25px solid transparent; + border-right: 25px solid #121721; + transition: all 0.5s; + } - .pdfBox-settingsFlyout { - width: 600px; - position: absolute; - background: #323232; - box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25); - left: -400px; - border-radius: 7px; - padding: 20px; - display: flex; - flex-direction: column; - font-size: 30px; - transition: all 0.5s; - - .pdfBox-settingsFlyout-title { - color: white; + .pdfBox-settingsButton-iconCont { + background: #121721; + height: 50px; + width: 70px; + display: flex; + justify-content: center; + align-items: center; + margin-left: -2px; + border-radius: 3px; + } + } + + .pdfBox-settingsButton:hover { + background: none; } - .pdfBox-settingsFlyout-kvpInput { - margin-top: 20px; - display: grid; - grid-template-columns: 47.5% 5% 47.5%; + .pdfBox-settingsFlyout { + width: 600px; + position: absolute; + background: #323232; + box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25); + left: -400px; + border-radius: 7px; + padding: 20px; + display: flex; + flex-direction: column; + font-size: 30px; + transition: all 0.5s; + + .pdfBox-settingsFlyout-title { + color: white; + } + + .pdfBox-settingsFlyout-kvpInput { + margin-top: 20px; + display: grid; + grid-template-columns: 47.5% 5% 47.5%; + } } } }
\ No newline at end of file diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 764051d62..8471aefe0 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -52,10 +52,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen if (pdfUrl instanceof PdfField) { Pdfjs.getDocument(pdfUrl.url.pathname).promise.then(pdf => runInAction(() => this._pdf = pdf)); } - this._reactionDisposer = reaction( - () => this.Document.panY, - () => this._mainCont.current && this._mainCont.current.scrollTo({ top: this.Document.panY || 0, behavior: "auto" }) - ); } componentWillUnmount() { @@ -167,16 +163,11 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen this.Document.nativeWidth = nw; this.Document.nativeHeight = this.Document.nativeHeight ? nw * oldaspect : nh; this.Document.height = this.Document[WidthSym]() * (nh / nw); - this.Document.scrollHeight = np * this.Document.nativeHeight; } } - @action onScroll = (e: React.UIEvent<HTMLDivElement>) => { - if (e.currentTarget && this.props.ContainingCollectionDoc) { - this.props.Document.panTransformType = "None"; - this.Document.panY = e.currentTarget.scrollTop; - } + e.stopPropagation(); } @@ -189,7 +180,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen onScroll={this.onScroll} style={{ marginTop: `${(this.Document.panY || 0)}px` }} ref={this._mainCont}> - <div className="pdfBox-scrollHack" style={{ height: NumCast(this.props.Document.scrollHeight) + ((this.Document.nativeHeight || 0) - (this.Document.nativeHeight || 0) / (this.Document.scale || 1)) }} /> <PDFViewer pdf={this._pdf} url={pdfUrl.url.pathname} active={this.props.active} scrollTo={this.scrollTo} loaded={this.loaded} panY={this.Document.panY || 0} Document={this.props.Document} DataDoc={this.dataDoc} addDocTab={this.props.addDocTab} setPanY={this.setPanY} GoToPage={this.GotoPage} diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss index 8290a0ee3..247df4e90 100644 --- a/src/client/views/pdf/PDFViewer.scss +++ b/src/client/views/pdf/PDFViewer.scss @@ -1,33 +1,17 @@ .pdfViewer-viewer { pointer-events: inherit; width: 100%; + height: 100%; + position: absolute; + overflow-y: scroll; + overflow-x: hidden; - .pdfViewer-visibleElements { - .pdfPage-cont { - .pdfPage-textLayer { - div { - user-select: text; - } - - span { - color: transparent; - position: absolute; - white-space: pre; - cursor: text; - -webkit-transform-origin: 0% 0%; - transform-origin: 0% 0%; - } - } - } + .page { + position: relative; } .pdfViewer-text { - transform: scale(1.5); transform-origin: top left; - - .page .textLayer { - user-select: text; - } } .pdfViewer-annotationLayer { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 108d649a1..c16cb7eb5 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -16,7 +16,6 @@ import { Docs, DocUtils } from "../../documents/Documents"; import { KeyCodes } from "../../northstar/utils/KeyCodes"; import { CompileScript, CompiledScript } from "../../util/Scripting"; import Annotation from "./Annotation"; -import Page from "./Page"; import "./PDFViewer.scss"; import React = require("react"); import requestPromise = require("request-promise"); @@ -24,8 +23,6 @@ import PDFMenu from "./PDFMenu"; import { DragManager } from "../../util/DragManager"; const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer"); -export const scale = 2; - interface IViewerProps { pdf: Pdfjs.PDFDocumentProxy; url: string; @@ -134,6 +131,10 @@ export class PDFViewer extends React.Component<IViewerProps> { }), { fireImmediately: true } ); + this._reactionDisposer = reaction( + () => this.props.Document.panY, + () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.props.Document.panY) || 0, behavior: "auto" }) + ); document.removeEventListener("copy", this.copy); document.addEventListener("copy", this.copy); @@ -175,53 +176,31 @@ export class PDFViewer extends React.Component<IViewerProps> { initialLoad = async () => { this._pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages); if (this._mainCont.current) { + await Promise.all(this._pageSizes.map<Pdfjs.PDFPromise<any>>((val, i) => + this.props.pdf.getPage(i + 1).then((page: Pdfjs.PDFPageProxy) => { + runInAction(() => { + this._pageSizes.splice(i, 1, { + width: (page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]), + height: (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]) + }); + }); + }) + )); + this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages); this._simpleLinkService = new SimpleLinkService(this); + document.addEventListener("pagesinit", () => this._pdfViewer.currentScaleValue = (this.props.Document[WidthSym]() / this._pageSizes[0].width)); + document.addEventListener("pagerendered", () => console.log("rendered")); this._pdfViewer = new PDFJSViewer.PDFViewer({ container: this._mainCont.current, viewer: this._viewer.current, - linkService: this._simpleLinkService + linkService: this._simpleLinkService, + renderer: "svg" }); this._simpleLinkService.setPDFJSview(this._pdfViewer); - this._mainCont.current.addEventListener("pagesinit", () => { - this._pdfViewer.currentScaleValue = 1; - }); - this._mainCont.current.addEventListener("pagerendered", () => console.log("rendered")); this._pdfViewer.setDocument(this.props.pdf); this._pdfFindController = new PDFJSViewer.PDFFindController(this._pdfViewer); this._pdfViewer.findController = this._pdfFindController; - await Promise.all(this._pageSizes.map<Pdfjs.PDFPromise<any>>((val, i) => - this.props.pdf.getPage(i + 1).then((page: Pdfjs.PDFPageProxy) => { - this._pageSizes.splice(i, 1, { - width: (page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]) * scale, - height: (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]) * scale - }); - } - ))); - this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages); } - // if (this._pageSizes.length === 0) { - // this._isPage = Array<string>(this.props.pdf.numPages); - // this._pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages); - // this._visibleElements = Array<JSX.Element>(this.props.pdf.numPages); - // await Promise.all(this._pageSizes.map<Pdfjs.PDFPromise<any>>((val, i) => - // this.props.pdf.getPage(i + 1).then(action((page: Pdfjs.PDFPageProxy) => { - // this._pageSizes.splice(i, 1, { - // width: (page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]) * scale, - // height: (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]) * scale - // }); - // this._visibleElements.splice(i, 1, - // <div key={`${this.props.url}-placeholder-${i + 1}`} className="pdfviewer-placeholder" - // style={{ width: this._pageSizes[i].width, height: this._pageSizes[i].height }}> - // "PAGE IS LOADING... " - // </div>); - // this.getPlaceholderPage(i); - // })))); - // this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages); - - // let startY = NumCast(this.props.Document.startY, NumCast(this.props.Document.panY)); - // this.props.setPanY && this.props.setPanY(startY); - // this.props.scrollTo(startY); - // } } @action @@ -246,6 +225,7 @@ export class PDFViewer extends React.Component<IViewerProps> { anno.remove(); this.props.addDocument && this.props.addDocument(annoDoc, false); mainAnnoDoc = annoDoc; + mainAnnoDocProto.y = annoDoc.y; mainAnnoDocProto = Doc.GetProto(annoDoc); } else { this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => value.map(anno => { @@ -277,61 +257,6 @@ export class PDFViewer extends React.Component<IViewerProps> { } @action - getPlaceholderPage = (page: number) => { - if (this._isPage[page] !== "none") { - this._isPage[page] = "none"; - this._visibleElements[page] = ( - <div key={`${this.props.url}-placeholder-${page + 1}`} className="pdfviewer-placeholder" - style={{ width: this._pageSizes[page].width, height: this._pageSizes[page].height }}> - "PAGE IS LOADING... " - </div>); - } - } - - @action - getRenderedPage = (page: number) => { - if (this._isPage[page] !== "page") { - this._isPage[page] = "page"; - this._visibleElements[page] = (<Page {...this.props} - size={this._pageSizes[page]} - numPages={this.props.pdf.numPages} - setSelectionText={this.setSelectionText} - page={page} - key={`${this.props.url}-rendered-${page + 1}`} - name={`${this.props.pdf.fingerprint + `-page${page + 1}`}`} - pageLoaded={this.pageLoaded} - renderAnnotations={this.renderAnnotations} - createAnnotation={this.createAnnotation} - sendAnnotations={this.receiveAnnotations} - makeAnnotationDocuments={this.makeAnnotationDocument} - getScrollFromPage={this.getScrollFromPage} />); - } - } - - // change the address to be the file address of the PNG version of each page - // file address of the pdf - @action - getPageImage = async (page: number) => { - if (this._isPage[page] !== "image") { - this._isPage[page] = "image"; - try { - let res = JSON.parse(await rp.get(Utils.prepend(`/thumbnail${this.props.url.substring("files/".length, this.props.url.length - ".pdf".length)}-${page + 1}.PNG`))); - runInAction(() => this._visibleElements[page] = - <img key={res.path} src={res.path} onError={() => this.getRenderedPage(page)} - style={{ width: `${parseInt(res.width) * scale}px`, height: `${parseInt(res.height) * scale}px` }} />); - } catch (e) { - console.log(e); - } - } - } - - renderPages = () => { - numberRange(this.props.pdf.numPages).filter(p => this._isPage[p] !== undefined).map(i => - (i < this.startIndex || i > this.endIndex) ? this.getPlaceholderPage(i) : // pages outside of the pdf use empty stand-in divs - this.props.active() ? this.getRenderedPage(i) : this.getPageImage(i)); - } - - @action renderAnnotations = (annotations: Doc[], removeOldAnnotations: boolean): void => { if (removeOldAnnotations) { this._annotations = annotations; @@ -394,7 +319,7 @@ export class PDFViewer extends React.Component<IViewerProps> { createAnnotation = (div: HTMLDivElement, page: number) => { if (this._annotationLayer.current) { if (div.style.top) { - div.style.top = (parseInt(div.style.top) + this.getScrollFromPage(page)).toString(); + div.style.top = (parseInt(div.style.top)/*+ this.getScrollFromPage(page)*/).toString(); } this._annotationLayer.current.append(div); let savedPage = this._savedAnnotations.getValue(page); @@ -428,7 +353,7 @@ export class PDFViewer extends React.Component<IViewerProps> { phraseSearch: true, query: searchString }); - } + }; this._mainCont.current.addEventListener("pagesloaded", executeFind); this._mainCont.current.addEventListener("pagerendered", executeFind); } @@ -447,10 +372,10 @@ export class PDFViewer extends React.Component<IViewerProps> { container: this._mainCont.current, viewer: this._viewer.current, linkService: simpleLinkService - }) + }); simpleLinkService.setPDFJSview(this._pdfViewer); - this._mainCont.current.addEventListener("pagesinit", () => this._pdfViewer.currentScaleValue = 1); - this._mainCont.current.addEventListener("pagerendered", () => console.log("rendered")); + document.addEventListener("pagesinit", () => this._pdfViewer.currentScaleValue = this.props.Document[WidthSym]() / this._pageSizes[0].width); + document.addEventListener("pagerendered", () => console.log("rendered")); this._pdfViewer.setDocument(this.props.pdf); this._pdfFindController = new PDFJSViewer.PDFFindController(this._pdfViewer); this._pdfViewer.findController = this._pdfFindController; @@ -483,7 +408,7 @@ export class PDFViewer extends React.Component<IViewerProps> { if (this._mainCont.current) { let boundingRect = this._mainCont.current.getBoundingClientRect(); this._startX = this._marqueeX = (e.clientX - boundingRect.left) * (this._mainCont.current.offsetWidth / boundingRect.width); - this._startY = this._marqueeY = (e.clientY - boundingRect.top) * (this._mainCont.current.offsetHeight / boundingRect.height); + this._startY = this._marqueeY = (e.clientY - boundingRect.top) * (this._mainCont.current.offsetHeight / boundingRect.height) + this._mainCont.current.scrollTop; } this._marqueeing = true; this._marquee.current && (this._marquee.current.style.opacity = "0.2"); @@ -502,7 +427,7 @@ export class PDFViewer extends React.Component<IViewerProps> { // transform positions and find the width and height to set the marquee to let boundingRect = this._mainCont.current.getBoundingClientRect(); this._marqueeWidth = ((e.clientX - boundingRect.left) * (this._mainCont.current.offsetWidth / boundingRect.width)) - this._startX; - this._marqueeHeight = ((e.clientY - boundingRect.top) * (this._mainCont.current.offsetHeight / boundingRect.height)) - this._startY; + this._marqueeHeight = ((e.clientY - boundingRect.top) * (this._mainCont.current.offsetHeight / boundingRect.height)) - this._startY + this._mainCont.current.scrollTop; this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth); this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight); this._marqueeWidth = Math.abs(this._marqueeWidth); @@ -521,15 +446,20 @@ export class PDFViewer extends React.Component<IViewerProps> { let clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { let rect = clientRects.item(i); - if (rect && rect.width !== this._mainCont.current.getBoundingClientRect().width && rect.height !== this._mainCont.current.getBoundingClientRect().height) { - let annoBox = document.createElement("div"); - annoBox.className = "pdfPage-annotationBox"; - // transforms the positions from screen onto the pdf div - annoBox.style.top = ((rect.top - boundingRect.top) * (this._mainCont.current.offsetHeight / boundingRect.height)).toString(); - annoBox.style.left = ((rect.left - boundingRect.left) * (this._mainCont.current.offsetWidth / boundingRect.width)).toString(); - annoBox.style.width = (rect.width * this._mainCont.current.offsetWidth / boundingRect.width).toString(); - annoBox.style.height = (rect.height * this._mainCont.current.offsetHeight / boundingRect.height).toString(); - this.createAnnotation(annoBox, this.getPageFromScroll(rect.height)); + if (rect/* && rect.width !== this._mainCont.current.getBoundingClientRect().width && rect.height !== this._mainCont.current.getBoundingClientRect().height / this.props.pdf.numPages*/) { + let page = this.getPageFromScroll(rect.top); + let scaleY = this._mainCont.current.offsetHeight / boundingRect.height; + let scaleX = this._mainCont.current.offsetWidth / boundingRect.width; + if (rect.width !== this._mainCont.current.clientWidth) { + let annoBox = document.createElement("div"); + annoBox.className = "pdfPage-annotationBox"; + // transforms the positions from screen onto the pdf div + annoBox.style.top = ((rect.top - boundingRect.top) * scaleY + this._mainCont.current.scrollTop).toString(); + annoBox.style.left = ((rect.left - boundingRect.left) * scaleX).toString(); + annoBox.style.width = (rect.width * this._mainCont.current.offsetWidth / boundingRect.width).toString(); + annoBox.style.height = (rect.height * this._mainCont.current.offsetHeight / boundingRect.height).toString(); + this.createAnnotation(annoBox, this.getPageFromScroll(rect.top)); + } } } } @@ -641,8 +571,17 @@ export class PDFViewer extends React.Component<IViewerProps> { } render() { - return (<div className="pdfViewer-viewer" ref={this._mainCont} onPointerDown={this.onPointerDown}> - <div className="pdfViewer-text" ref={this._viewer} /> + let scaling = this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width / this.props.Document[WidthSym]() : 1; + return (<div className="pdfViewer-viewer" ref={this._mainCont} onPointerDown={this.onPointerDown} onWheel={(e) => { + runInAction(() => { + if (e.currentTarget) { + this.props.Document.panTransformType = "None"; + this.props.Document.panY = e.currentTarget.scrollTop; + } + e.stopPropagation(); + }); + }}> + <div className="pdfViewer-text" ref={this._viewer} style={{ transform: `scale(${scaling})` }} /> <div className="pdfPage-dragAnnotationBox" ref={this._marquee} style={{ left: `${this._marqueeX}px`, top: `${this._marqueeY}px`, diff --git a/src/client/views/pdf/Page.scss b/src/client/views/pdf/Page.scss deleted file mode 100644 index d8034b4b4..000000000 --- a/src/client/views/pdf/Page.scss +++ /dev/null @@ -1,36 +0,0 @@ - -.pdfViewer-text { - .page { - position: relative; - } -} -.pdfPage-cont { - position: relative; - - .pdfPage-canvasContainer { - position: absolute; - } - - .pdfPage-dragAnnotationBox { - position: absolute; - background-color: transparent; - opacity: 0.1; - } - - .pdfPage-textLayer { - position: absolute; - width: 100%; - height: 100%; - div { - user-select: text; - } - span { - color: transparent; - position: absolute; - white-space: pre; - cursor: text; - -webkit-transform-origin: 0% 0%; - transform-origin: 0% 0%; - } - } -}
\ No newline at end of file diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx deleted file mode 100644 index 533247170..000000000 --- a/src/client/views/pdf/Page.tsx +++ /dev/null @@ -1,293 +0,0 @@ -import { action, IReactionDisposer, observable } from "mobx"; -import { observer } from "mobx-react"; -import * as Pdfjs from "pdfjs-dist"; -import "pdfjs-dist/web/pdf_viewer.css"; -import { Doc, DocListCastAsync, Opt, WidthSym } from "../../../new_fields/Doc"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { Docs, DocUtils } from "../../documents/Documents"; -import { DragManager } from "../../util/DragManager"; -import PDFMenu from "./PDFMenu"; -import { scale } from "./PDFViewer"; -import "./Page.scss"; -import React = require("react"); - - -interface IPageProps { - size: { width: number, height: number }; - pdf: Pdfjs.PDFDocumentProxy; - name: string; - numPages: number; - page: number; - pageLoaded: (page: Pdfjs.PDFPageViewport) => void; - fieldExtensionDoc: Doc; - Document: Doc; - renderAnnotations: (annotations: Doc[], removeOld: boolean) => void; - sendAnnotations: (annotations: HTMLDivElement[], page: number) => void; - createAnnotation: (div: HTMLDivElement, page: number) => void; - makeAnnotationDocuments: (doc: Doc | undefined, color: string, linkTo: boolean) => Doc; - getScrollFromPage: (page: number) => number; - setSelectionText: (text: string) => void; -} - -@observer -export default class Page extends React.Component<IPageProps> { - @observable private _state: "N/A" | "rendering" = "N/A"; - @observable private _width: number = this.props.size.width; - @observable private _height: number = this.props.size.height; - @observable private _page: Opt<Pdfjs.PDFPageProxy>; - @observable private _currPage: number = this.props.page + 1; - @observable private _marqueeX: number = 0; - @observable private _marqueeY: number = 0; - @observable private _marqueeWidth: number = 0; - @observable private _marqueeHeight: number = 0; - - private _canvas: React.RefObject<HTMLCanvasElement> = React.createRef(); - private _textLayer: React.RefObject<HTMLDivElement> = React.createRef(); - private _marquee: React.RefObject<HTMLDivElement> = React.createRef(); - private _marqueeing: boolean = false; - private _reactionDisposer?: IReactionDisposer; - private _startY: number = 0; - private _startX: number = 0; - - componentDidMount = (): void => this.loadPage(this.props.pdf); - - componentDidUpdate = (): void => this.loadPage(this.props.pdf); - - componentWillUnmount = (): void => this._reactionDisposer && this._reactionDisposer(); - - loadPage = (pdf: Pdfjs.PDFDocumentProxy): void => { - pdf.getPage(this._currPage).then(page => this.renderPage(page)); - } - - @action - renderPage = (page: Pdfjs.PDFPageProxy): void => { - // lower scale = easier to read at small sizes, higher scale = easier to read at large sizes - if (this._state !== "rendering" && !this._page && this._canvas.current && this._textLayer.current) { - this._state = "rendering"; - let viewport = page.getViewport(scale); - this._canvas.current.width = this._width = viewport.width; - this._canvas.current.height = this._height = viewport.height; - this.props.pageLoaded(viewport); - let ctx = this._canvas.current.getContext("2d"); - if (ctx) { - //@ts-ignore - page.render({ canvasContext: ctx, viewport: viewport, enableWebGL: true }); // renders the page onto the canvas context - page.getTextContent().then(res => // renders text onto the text container - //@ts-ignore - Pdfjs.renderTextLayer({ - textContent: res, - container: this._textLayer.current, - viewport: viewport - })); - - this._page = page; - } - } - } - - @action - highlight = (targetDoc: Doc | undefined, color: string) => { - // creates annotation documents for current highlights - let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, color, false); - Doc.AddDocToList(this.props.fieldExtensionDoc, "annotations", annotationDoc); - return annotationDoc; - } - - /** - * This is temporary for creating annotations from highlights. It will - * start a drag event and create or put the necessary info into the drag event. - */ - @action - startDrag = (e: PointerEvent, ele: HTMLElement): void => { - e.preventDefault(); - e.stopPropagation(); - if (this._textLayer.current) { - let targetDoc = Docs.Create.TextDocument({ width: 200, height: 200, title: "New Annotation" }); - targetDoc.targetPage = this.props.page; - let annotationDoc = this.highlight(undefined, "red"); - annotationDoc.linkedToDoc = false; - let dragData = new DragManager.AnnotationDragData(this.props.Document, annotationDoc, targetDoc); - DragManager.StartAnnotationDrag([ele], dragData, e.pageX, e.pageY, { - handlers: { - dragComplete: async () => { - if (!BoolCast(annotationDoc.linkedToDoc)) { - let annotations = await DocListCastAsync(annotationDoc.annotations); - annotations && annotations.forEach(anno => anno.target = targetDoc); - DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(this.props.Document.title)}`); - } - } - }, - hideSource: false - }); - } - } - - // cleans up events and boolean - endDrag = (e: PointerEvent): void => { - e.stopPropagation(); - } - - createSnippet = (marquee: { left: number, top: number, width: number, height: number }): void => { - let view = Doc.MakeAlias(this.props.Document); - let data = Doc.MakeDelegate(Doc.GetProto(this.props.Document)); - data.title = StrCast(data.title) + "_snippet"; - view.proto = data; - view.nativeHeight = marquee.height; - view.height = (this.props.Document[WidthSym]() / NumCast(this.props.Document.nativeWidth)) * marquee.height; - view.nativeWidth = this.props.Document.nativeWidth; - view.startY = marquee.top + this.props.getScrollFromPage(this.props.page); - view.width = this.props.Document[WidthSym](); - DragManager.StartDocumentDrag([], new DragManager.DocumentDragData([view]), 0, 0); - } - - @action - onPointerDown = (e: React.PointerEvent): void => { - // if alt+left click, drag and annotate - if (NumCast(this.props.Document.scale, 1) !== 1) return; - if (!e.altKey && e.button === 0) { - PDFMenu.Instance.StartDrag = this.startDrag; - PDFMenu.Instance.Highlight = this.highlight; - PDFMenu.Instance.Snippet = this.createSnippet; - PDFMenu.Instance.Status = "pdf"; - PDFMenu.Instance.fadeOut(true); - if (e.target && (e.target as any).parentElement === this._textLayer.current) { - e.stopPropagation(); - if (!e.ctrlKey) { - this.props.sendAnnotations([], -1); - } - } - else { - // set marquee x and y positions to the spatially transformed position - if (this._textLayer.current) { - let boundingRect = this._textLayer.current.getBoundingClientRect(); - this._startX = this._marqueeX = (e.clientX - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width); - this._startY = this._marqueeY = (e.clientY - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height); - } - this._marqueeing = true; - this._marquee.current && (this._marquee.current.style.opacity = "0.2"); - this.props.sendAnnotations([], -1); - } - document.removeEventListener("pointermove", this.onSelectStart); - document.addEventListener("pointermove", this.onSelectStart); - document.removeEventListener("pointerup", this.onSelectEnd); - document.addEventListener("pointerup", this.onSelectEnd); - } - } - - @action - onSelectStart = (e: PointerEvent): void => { - if (this._marqueeing && this._textLayer.current) { - // transform positions and find the width and height to set the marquee to - let boundingRect = this._textLayer.current.getBoundingClientRect(); - this._marqueeWidth = ((e.clientX - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)) - this._startX; - this._marqueeHeight = ((e.clientY - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)) - this._startY; - this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth); - this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight); - this._marqueeWidth = Math.abs(this._marqueeWidth); - e.stopPropagation(); - e.preventDefault(); - } - else if (e.target && (e.target as any).parentElement === this._textLayer.current) { - e.stopPropagation(); - } - } - - @action - onSelectEnd = (e: PointerEvent): void => { - if (this._marqueeing) { - this._marqueeing = false; - if (this._marqueeWidth > 10 || this._marqueeHeight > 10) { - if (this._marquee.current) { // make a copy of the marquee - let copy = document.createElement("div"); - let style = this._marquee.current.style; - copy.style.left = style.left; - copy.style.top = style.top; - copy.style.width = style.width; - copy.style.height = style.height; - copy.style.border = style.border; - copy.style.opacity = style.opacity; - copy.className = "pdfPage-annotationBox"; - this.props.createAnnotation(copy, this.props.page); - this._marquee.current.style.opacity = "0"; - } - - if (!e.ctrlKey) { - PDFMenu.Instance.Status = "snippet"; - PDFMenu.Instance.Marquee = { left: this._marqueeX, top: this._marqueeY, width: this._marqueeWidth, height: this._marqueeHeight }; - } - PDFMenu.Instance.jumpTo(e.clientX, e.clientY); - } - - this._marqueeHeight = this._marqueeWidth = 0; - } - else { - let sel = window.getSelection(); - if (sel && sel.type === "Range") { - let selRange = sel.getRangeAt(0); - this.createTextAnnotation(sel, selRange); - PDFMenu.Instance.jumpTo(e.clientX, e.clientY); - } - } - - if (PDFMenu.Instance.Highlighting) { - this.highlight(undefined, "goldenrod"); - } - else { - PDFMenu.Instance.StartDrag = this.startDrag; - PDFMenu.Instance.Highlight = this.highlight; - } - document.removeEventListener("pointermove", this.onSelectStart); - document.removeEventListener("pointerup", this.onSelectEnd); - } - - @action - createTextAnnotation = (sel: Selection, selRange: Range) => { - if (this._textLayer.current) { - let boundingRect = this._textLayer.current.getBoundingClientRect(); - let clientRects = selRange.getClientRects(); - for (let i = 0; i < clientRects.length; i++) { - let rect = clientRects.item(i); - if (rect && rect.width !== this._textLayer.current.getBoundingClientRect().width && rect.height !== this._textLayer.current.getBoundingClientRect().height) { - let annoBox = document.createElement("div"); - annoBox.className = "pdfPage-annotationBox"; - // transforms the positions from screen onto the pdf div - annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString(); - annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString(); - annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString(); - annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString(); - this.props.createAnnotation(annoBox, this.props.page); - } - } - } - let text = selRange.cloneContents().textContent; - text && this.props.setSelectionText(text); - - // clear selection - if (sel.empty) { // Chrome - sel.empty(); - } else if (sel.removeAllRanges) { // Firefox - sel.removeAllRanges(); - } - } - - doubleClick = (e: React.MouseEvent) => { - if (e.target && (e.target as any).parentElement === this._textLayer.current) { - // do something to select the paragraph ideally - } - } - - render() { - return ( - <div className={"pdfPage-cont"} onPointerDown={this.onPointerDown} onDoubleClick={this.doubleClick} style={{ "width": this._width, "height": this._height }}> - <canvas className="PdfPage-canvasContainer" ref={this._canvas} /> - <div className="pdfPage-dragAnnotationBox" ref={this._marquee} - style={{ - left: `${this._marqueeX}px`, top: `${this._marqueeY}px`, - width: `${this._marqueeWidth}px`, height: `${this._marqueeHeight}px`, - border: `${this._marqueeWidth === 0 ? "" : "10px dashed black"}` - }}> - </div> - <div className="pdfPage-textlayer" ref={this._textLayer} /> - </div>); - } -}
\ No newline at end of file diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 20d02488e..3baedce4b 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -5,108 +5,9 @@ import { Doc } from '../new_fields/Doc'; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; import { Utils } from '../Utils'; -import { scale } from '../client/views/pdf/PDFViewer'; const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer"); const protoId = "protoDoc"; const delegateId = "delegateDoc"; class Test extends React.Component { - private _viewer: React.RefObject<HTMLDivElement> = React.createRef(); - private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); - private _pageSizes: Array<{ width: number, height: number }> = []; - _pdfViewer: PDFJSViewer.PDFViewer; - _pdfFindController: PDFJSViewer.PDFFindController; - _page: number = 0; - - componentDidMount = () => { - let pdfUrl = Utils.CorsProxy("https://www.hq.nasa.gov/alsj/a17/A17_FlightPlan.pdf"); - Pdfjs.getDocument(pdfUrl).promise.then(async pdf => { - if (this._mainCont.current) { - let simpleLinkService = new SimpleLinkService(this); - this._pdfViewer = new PDFJSViewer.PDFViewer({ - container: this._mainCont.current, - viewer: this._viewer.current, - linkService: simpleLinkService - }); - simpleLinkService.setPDFJSview(this._pdfViewer); - this._mainCont.current.addEventListener("pagesinit", () => { - this._pdfViewer.currentScaleValue = 1; - console.log(this._pdfViewer); - }); - this._mainCont.current.addEventListener("pagerendered", () => console.log("rendered")); - this._pdfViewer.setDocument(pdf); - this._pageSizes = Array<{ width: number, height: number }>(pdf.numPages); - this._pdfFindController = new PDFJSViewer.PDFFindController(this._pdfViewer); - this._pdfViewer.findController = this._pdfFindController; - await Promise.all(this._pageSizes.map<Pdfjs.PDFPromise<any>>((val, i) => - pdf.getPage(i + 1).then((page: Pdfjs.PDFPageProxy) => { - this._pageSizes.splice(i, 1, { - width: (page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]) * scale, - height: (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]) * scale - }); - } - ))); - } - }); - } - - goToPage = (page: number) => { - if (this._mainCont.current) { - // this._mainCont.current.scrollTo() - } - } - - render() { - return ( - <div ref={this._mainCont}> - <div ref={this._viewer} /> - </div> - ) - } -} - -class SimpleLinkService { - _viewer: Test; - _pdfjsView: any; - - constructor(viewer: Test) { - this._viewer = viewer; - } - setPDFJSview(v: any) { this._pdfjsView = v; } - - navigateTo() { } - - getDestinationHash() { return "#"; } - - getAnchorUrl() { return "#"; } - - setHash() { } - - isPageVisible(page: number) { return true; } - - executeNamedAction() { } - - cachePageRef() { } - - get pagesCount() { return this._viewer._pdfViewer.pagesCount; } - - get page() { return this._viewer._page; } - set page(p: number) { - this._pdfjsView._ensurePdfPageLoaded(this._pdfjsView._pages[p - 1]).then(() => { - this._pdfjsView.renderingQueue.renderView(this._pdfjsView._pages[p - 1]); - if (this._viewer.goToPage) { - this._viewer.goToPage(p); - } - }); - } - - - get rotation() { return 0; } - set rotation(value: any) { } } - -DocServer.init(window.location.protocol, window.location.hostname, 4321, "test"); -ReactDOM.render( - <Test />, - document.getElementById('root') -);
\ No newline at end of file |