aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf/PDFViewer.tsx
diff options
context:
space:
mode:
authorsrichman333 <sarah_n_richman@brown.edu>2023-11-24 17:59:13 -0500
committersrichman333 <sarah_n_richman@brown.edu>2023-11-24 17:59:13 -0500
commit0b38b0629496973d6c4571208710096deb91b7d7 (patch)
treef797da626587c198535c0ea54aee9d467226262a /src/client/views/pdf/PDFViewer.tsx
parent1b412d402c77a2aae82cf86b1f6a23f8a4f82caf (diff)
merge
Diffstat (limited to 'src/client/views/pdf/PDFViewer.tsx')
-rw-r--r--src/client/views/pdf/PDFViewer.tsx63
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}