diff options
Diffstat (limited to 'src/client/views/nodes/PDFBox.tsx')
| -rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 133 |
1 files changed, 95 insertions, 38 deletions
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 14fe2df80..855c744e6 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,26 +1,29 @@ import * as htmlToImage from "html-to-image"; -import { action, computed, IReactionDisposer, observable, reaction, Reaction, trace, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; import { observer } from "mobx-react"; import 'react-image-lightbox/style.css'; import Measure from "react-measure"; //@ts-ignore import { Document, Page } from "react-pdf"; import 'react-pdf/dist/Page/AnnotationLayer.css'; +import { Id } from "../../../new_fields/FieldSymbols"; +import { makeInterface } from "../../../new_fields/Schema"; +import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { ImageField, PdfField } from "../../../new_fields/URLField"; import { RouteStore } from "../../../server/RouteStore"; import { Utils } from '../../../Utils'; +import { DocServer } from "../../DocServer"; +import { DocComponent } from "../DocComponent"; +import { InkingControl } from "../InkingControl"; +import { SearchBox } from "../SearchBox"; import { Annotation } from './Annotation'; +import { positionSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; +import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; +var path = require('path'); import React = require("react"); -import { SelectionManager } from "../../util/SelectionManager"; -import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; -import { Opt } from "../../../new_fields/Doc"; -import { DocComponent } from "../DocComponent"; -import { makeInterface } from "../../../new_fields/Schema"; -import { positionSchema } from "./DocumentView"; -import { pageSchema } from "./ImageBox"; -import { ImageField, PdfField } from "../../../new_fields/URLField"; -import { InkingControl } from "../InkingControl"; +import { ContextMenu } from "../ContextMenu"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, @@ -65,19 +68,21 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen @observable private _currAnno: any = []; @observable private _interactive: boolean = false; - @observable private _loaded: boolean = false; @computed private get curPage() { return NumCast(this.Document.curPage, 1); } @computed private get thumbnailPage() { return NumCast(this.props.Document.thumbnailPage, -1); } componentDidMount() { + let wasSelected = this.props.active(); this._reactionDisposer = reaction( - () => [SelectionManager.SelectedDocuments().slice()], + () => [this.props.active(), this.curPage], () => { - if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage !== this.thumbnailPage && !this.props.isSelected()) { - this.saveThumbnail(); - this._interactive = true; - } + setTimeout(action(() => { // this forces the active() check to happen after all changes in a transaction have occurred. + if (this.curPage > 0 && !this.props.isTopMost && this.curPage !== this.thumbnailPage && wasSelected && !this.props.active()) { + this.saveThumbnail(); + } + wasSelected = this._interactive = this.props.active(); + }), 0); }, { fireImmediately: true }); @@ -243,20 +248,26 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen @action saveThumbnail = () => { + this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1); this._renderAsSvg = false; setTimeout(() => { + runInAction(() => this._smallRetryCount = this._mediumRetryCount = this._largeRetryCount = 0); let nwidth = FieldValue(this.Document.nativeWidth, 0); let nheight = FieldValue(this.Document.nativeHeight, 0); - htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 1 }) + htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 0.8 }) .then(action((dataUrl: string) => { - this.props.Document.thumbnail = new ImageField(new URL(dataUrl)); - this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1); - this._renderAsSvg = true; + SearchBox.convertDataUri(dataUrl, "icon" + this.Document[Id] + "_" + this.curPage).then((returnedFilename) => { + if (returnedFilename) { + let url = DocServer.prepend(returnedFilename); + this.props.Document.thumbnail = new ImageField(new URL(url)); + } + runInAction(() => this._renderAsSvg = true); + }) })) .catch(function (error: any) { console.error('oops, something went wrong!', error); }); - }, 250); + }, 1250); } @action @@ -266,7 +277,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen if (this._perPageInfo.length === 0) { //Makes sure it only runs once this._perPageInfo = [...Array(page._transport.numPages)]; } - this._loaded = true; } @action @@ -283,7 +293,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen } @computed get pdfPage() { - return <Page height={this.renderHeight} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} />; + return <Page height={this.renderHeight} renderTextLayer={false} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} />; } @computed get pdfContent() { @@ -291,18 +301,19 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen if (!pdfUrl) { return <p>No pdf url to render</p>; } - let body = NumCast(this.props.Document.nativeHeight) ? - this.pdfPage : + let pdfpage = this.pdfPage; + let body = this.Document.nativeHeight ? + pdfpage : <Measure offset onResize={this.setScaling}> {({ measureRef }) => <div className="pdfBox-page" ref={measureRef}> - {this.pdfPage} + {pdfpage} </div> } </Measure>; - let xf = NumCast(this.Document.nativeHeight) / this.renderHeight; + let xf = (this.Document.nativeHeight || 0) / this.renderHeight; return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}> - <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl.url}`} renderMode={this._renderAsSvg ? "svg" : "canvas"}> + <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl.url}`} renderMode={this._renderAsSvg || this.props.isTopMost ? "svg" : "canvas"}> {body} </Document> </div >; @@ -310,35 +321,81 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen @computed get pdfRenderer() { - let proxy = this._loaded ? (null) : this.imageProxyRenderer; let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField); - if ((!this._interactive && proxy) || !pdfUrl) { + let proxy = this.imageProxyRenderer; + if ((!this._interactive && proxy && (!this.props.ContainingCollectionView || !this.props.ContainingCollectionView.props.isTopMost)) || !pdfUrl) { return proxy; } return [ + proxy, this._pageInfo.area.filter(() => this._pageInfo.area).map((element: any) => element), this._currAnno.map((element: any) => element), - this.pdfContent, - proxy + this.pdfContent ]; } + choosePath(url: URL) { + if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1) + return url.href; + let ext = path.extname(url.href); + return url.href.replace(ext, this._curSuffix + ext); + } + @observable _smallRetryCount = 1; + @observable _mediumRetryCount = 1; + @observable _largeRetryCount = 1; + @action retryPath = () => { + if (this._curSuffix === "_s") this._smallRetryCount++; + if (this._curSuffix === "_m") this._mediumRetryCount++; + if (this._curSuffix === "_l") this._largeRetryCount++; + } + @action onError = () => { + let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount; + if (timeout < 10) + setTimeout(this.retryPath, Math.min(10000, timeout * 5)); + } + _curSuffix = "_m"; + @computed get imageProxyRenderer() { let thumbField = this.props.Document.thumbnail; - if (thumbField) { - let path = this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" : - thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; - return <img src={path} width="100%" />; + if (thumbField && this._renderAsSvg && NumCast(this.props.Document.thumbnailPage, 0) === this.Document.curPage) { + + // let transform = this.props.ScreenToLocalTransform().inverse(); + let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; + // var [sptX, sptY] = transform.transformPoint(0, 0); + // let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); + // let w = bptX - sptX; + + let path = thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; + // this._curSuffix = ""; + // if (w > 20) { + let field = thumbField; + // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; + // else if (w < 400 && this._mediumRetryCount < 10) this._curSuffix = "_m"; + // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; + if (field instanceof ImageField) path = this.choosePath(field.url); + // } + return <img className="pdfBox-thumbnail" key={path + (this._mediumRetryCount).toString()} src={path} onError={this.onError} />; } return (null); } @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true); @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false); + onContextMenu = (e: React.MouseEvent): void => { + let field = Cast(this.Document[this.props.fieldKey], PdfField); + if (field) { + let url = field.url.href; + ContextMenu.Instance.addItem({ + description: "Copy path", event: () => { + Utils.CopyText(url); + }, icon: "expand-arrows-alt" + }); + } + } render() { - let classname = "pdfBox-cont"; // + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); + 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} > + <div className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} onContextMenu={this.onContextMenu} > {this.pdfRenderer} </div > ); |
