diff options
| author | srichman333 <sarah_n_richman@brown.edu> | 2023-11-24 17:59:13 -0500 |
|---|---|---|
| committer | srichman333 <sarah_n_richman@brown.edu> | 2023-11-24 17:59:13 -0500 |
| commit | 0b38b0629496973d6c4571208710096deb91b7d7 (patch) | |
| tree | f797da626587c198535c0ea54aee9d467226262a /src/client/views/pdf/PDFViewer.tsx | |
| parent | 1b412d402c77a2aae82cf86b1f6a23f8a4f82caf (diff) | |
merge
Diffstat (limited to 'src/client/views/pdf/PDFViewer.tsx')
| -rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 63 |
1 files changed, 23 insertions, 40 deletions
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 43b662f0f..ca9bf7bd2 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -2,7 +2,7 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; -import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; +import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Height } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; @@ -11,7 +11,6 @@ import { TraceMobx } from '../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, returnAll, returnFalse, returnNone, returnZero, smoothScroll, Utils } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { SelectionManager } from '../../util/SelectionManager'; -import { SharingManager } from '../../util/SharingManager'; import { SnappingManager } from '../../util/SnappingManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; @@ -56,16 +55,15 @@ export class PDFViewer extends React.Component<IViewerProps> { static _annotationStyle: any = addStyleSheet(); @observable private _pageSizes: { width: number; height: number }[] = []; @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); - @observable private _marqueeing: number[] | undefined; @observable private _textSelecting = true; @observable private _showWaiting = true; - @observable private _overlayAnnoInfo: Opt<Doc>; @observable private Index: number = -1; private _pdfViewer: any; private _styleRule: any; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void); + private _marqueeref = React.createRef<MarqueeAnnotator>(); private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _viewer: React.RefObject<HTMLDivElement> = React.createRef(); @@ -110,13 +108,7 @@ export class PDFViewer extends React.Component<IViewerProps> { this._disposers.selected = reaction( () => this.props.isSelected(), - selected => { - // if (!selected) { - // Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove())); - // Array.from(this._savedAnnotations.keys()).forEach(k => this._savedAnnotations.set(k, [])); - // } - SelectionManager.Views().length === 1 && this.setupPdfJsViewer(); - }, + selected => SelectionManager.Views().length === 1 && this.setupPdfJsViewer(), { fireImmediately: true } ); this._disposers.curPage = reaction( @@ -374,17 +366,14 @@ export class PDFViewer extends React.Component<IViewerProps> { if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { this.props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeing = [e.clientX, e.clientY]; + this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]); this.isAnnotating = true; const target = e.target as any; if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.parentElement?.className !== 'textLayer'))) { this._textSelecting = false; } else { // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee. - setTimeout( - action(() => (this._marqueeing = undefined)), - 100 - ); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. + setTimeout(() => this._marqueeref.current?.onTerminateSelection(), 100); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, 'htmlAnnotation', { 'pointer-events': 'none' }); document.addEventListener('pointerup', this.onSelectEnd); @@ -396,12 +385,13 @@ export class PDFViewer extends React.Component<IViewerProps> { finishMarquee = (x?: number, y?: number) => { this._getAnchor = AnchorMenu.Instance?.GetAnchor; this.isAnnotating = false; - this._marqueeing = undefined; + this._marqueeref.current?.onTerminateSelection(); this._textSelecting = true; }; @action onSelectEnd = (e: PointerEvent): void => { + this._getAnchor = AnchorMenu.Instance?.GetAnchor; this.isAnnotating = false; clearStyleSheetRules(PDFViewer._annotationStyle); this.props.select(false); @@ -425,23 +415,26 @@ export class PDFViewer extends React.Component<IViewerProps> { @action createTextAnnotation = (sel: Selection, selRange: Range) => { if (this._mainCont.current) { + this._mainCont.current.style.transform = `rotate(${NumCast(this.props.DocumentView!().screenToLocalTransform().RotateDeg)}deg)`; const boundingRect = this._mainCont.current.getBoundingClientRect(); const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { const rect = clientRects.item(i); - if (rect?.width && rect.width < this._mainCont.current.clientWidth / this.props.ScreenToLocalTransform().Scale) { + if (rect && rect?.width && rect.width < this._mainCont.current.clientWidth / this.props.ScreenToLocalTransform().Scale) { const scaleX = this._mainCont.current.offsetWidth / boundingRect.width; + const scaleY = this._mainCont.current.offsetHeight / boundingRect.height; const pdfScale = NumCast(this.props.layoutDoc._freeform_scale, 1); const annoBox = document.createElement('div'); annoBox.className = 'marqueeAnnotator-annotationBox'; // transforms the positions from screen onto the pdf div - annoBox.style.top = (((rect.top - boundingRect.top) * scaleX) / pdfScale + this._mainCont.current.scrollTop).toString(); annoBox.style.left = (((rect.left - boundingRect.left) * scaleX) / pdfScale).toString(); - annoBox.style.width = ((rect.width * this._mainCont.current.offsetWidth) / boundingRect.width / pdfScale).toString(); - annoBox.style.height = ((rect.height * this._mainCont.current.offsetHeight) / boundingRect.height / pdfScale).toString(); + annoBox.style.top = (((rect.top - boundingRect.top) * scaleY) / pdfScale + this._mainCont.current.scrollTop).toString(); + annoBox.style.width = ((rect.width * scaleX) / pdfScale).toString(); + annoBox.style.height = ((rect.height * scaleY) / pdfScale).toString(); this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, this.getPageFromScroll(rect.top)); } } + this._mainCont.current!.style.transform = ''; } this._selectionContent = selRange.cloneContents(); this._selectionText = this._selectionContent?.textContent || ''; @@ -487,30 +480,19 @@ export class PDFViewer extends React.Component<IViewerProps> { return ( <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}> {inlineAnnos.map(anno => ( - <Annotation {...this.props} fieldKey={this.props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} /> + <Annotation {...this.props} fieldKey={this.props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} /> ))} </div> ); } - @computed get overlayInfo() { - return !this._overlayAnnoInfo ? null : ( - <div className="pdfViewerDash-overlayAnno" style={{ top: NumCast(this._overlayAnnoInfo.y), left: NumCast(this._overlayAnnoInfo.x) }}> - <div className="pdfViewerDash-overlayAnno" style={{ right: -50, background: SharingManager.Instance.users.find(users => users.user.email === this._overlayAnnoInfo!.author)?.userColor }}> - {this._overlayAnnoInfo.author + ' ' + Field.toString(this._overlayAnnoInfo.author_date as Field)} - </div> - </div> - ); - } - getScrollHeight = () => this._scrollHeight; - showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno)); scrollXf = () => (this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.layoutDoc._layout_scrollTop)) : this.props.ScreenToLocalTransform()); overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._freeform_scale, 1)); panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1); panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); - transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()]; - opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(SnappingManager.GetCanEmbed() && this.props.isContentActive() ? [] : [Utils.IsOpaqueFilter()])]; + transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter]; + opaqueFilter = () => [...this.props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.GetCanEmbed() && this.props.isContentActive() ? [] : [Utils.OpaqueBackgroundFilter])]; childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc) || this.props.isContentActive() === false) return 'none'; @@ -572,6 +554,7 @@ export class PDFViewer extends React.Component<IViewerProps> { return <div className={'pdfViewerDash-text' + (this.props.pointerEvents?.() !== 'none' && this._textSelecting && this.props.isContentActive() ? '-selected' : '')} ref={this._viewer} />; } savedAnnotations = () => this._savedAnnotations; + addDocumentWrapper = (doc: Doc | Doc[]) => this.props.addDocument!(doc); render() { TraceMobx(); return ( @@ -590,17 +573,17 @@ export class PDFViewer extends React.Component<IViewerProps> { {this.pdfViewerDiv} {this.annotationLayer} {this.overlayLayer} - {this.overlayInfo} {this._showWaiting ? <img className="pdfViewerDash-waiting" src={'/assets/loading.gif'} /> : null} - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this._annotationLayer.current ? null : ( <MarqueeAnnotator + ref={this._marqueeref} rootDoc={this.props.rootDoc} getPageFromScroll={this.getPageFromScroll} anchorMenuClick={this.props.anchorMenuClick} scrollTop={0} - down={this._marqueeing} - addDocument={(doc: Doc | Doc[]) => this.props.addDocument!(doc)} - docView={this.props.docViewPath().lastElement()} + annotationLayerScrollTop={NumCast(this.props.Document._layout_scrollTop)} + addDocument={this.addDocumentWrapper} + docView={this.props.DocumentView!} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} selectionText={this.selectionText} |
