aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-11-22 11:52:57 -0500
committerbobzel <zzzman@gmail.com>2023-11-22 11:52:57 -0500
commitcc75a03d89a4b553a53b55404464cd2ca93d9b48 (patch)
treed4c455549245a287656d7e03ff9e459231251829 /src/client/views/pdf
parent52241c5a42c0fa2d92eca8110523081ce9f353af (diff)
fixed more issues with rotation. restrutured how MarqueeAnnotator works to be simpler and more correct.
Diffstat (limited to 'src/client/views/pdf')
-rw-r--r--src/client/views/pdf/Annotation.tsx30
-rw-r--r--src/client/views/pdf/PDFViewer.tsx50
2 files changed, 38 insertions, 42 deletions
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 38e4f65b6..e1e87763c 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -12,12 +12,13 @@ import { FieldViewProps } from '../nodes/FieldView';
import { AnchorMenu } from './AnchorMenu';
import './Annotation.scss';
import { LinkManager } from '../../util/LinkManager';
+import { Rect } from 'react-measure';
interface IAnnotationProps extends FieldViewProps {
anno: Doc;
dataDoc: Doc;
fieldKey: string;
- showInfo: (anno: Opt<Doc>) => void;
+ showInfo?: (anno: Opt<Doc>) => void;
pointerEvents?: () => Opt<string>;
}
@observer
@@ -70,17 +71,23 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
};
@action
+ onContextMenu = (e: React.MouseEvent) => {
+ AnchorMenu.Instance.Status = 'annotation';
+ AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this);
+ AnchorMenu.Instance.Pinned = false;
+ AnchorMenu.Instance.PinToPres = this.pinToPres;
+ AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle;
+ AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
+ AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion);
+ AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
+ e.stopPropagation();
+ e.preventDefault();
+ };
+ @action
onPointerDown = (e: React.PointerEvent) => {
if (e.button === 2 || e.ctrlKey) {
- AnchorMenu.Instance.Status = 'annotation';
- AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this);
- AnchorMenu.Instance.Pinned = false;
- AnchorMenu.Instance.PinToPres = this.pinToPres;
- AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle;
- AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
- AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion);
- AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
e.stopPropagation();
+ e.preventDefault();
} else if (e.button === 0) {
e.stopPropagation();
LinkFollower.FollowLink(undefined, this.annoTextRegion, false);
@@ -102,13 +109,14 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
ref={this._mainCont}
onPointerEnter={action(() => {
Doc.BrushDoc(this.props.anno);
- this.props.showInfo(this.props.anno);
+ this.props.showInfo?.(this.props.anno);
})}
onPointerLeave={action(() => {
Doc.UnBrushDoc(this.props.anno);
- this.props.showInfo(undefined);
+ this.props.showInfo?.(undefined);
})}
onPointerDown={this.onPointerDown}
+ onContextMenu={this.onContextMenu}
style={{
left: NumCast(this.props.document.x),
top: NumCast(this.props.document.y),
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index a66e519c9..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();
@@ -368,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);
@@ -390,7 +385,7 @@ 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;
};
@@ -420,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 || '';
@@ -482,24 +480,13 @@ 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);
@@ -567,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 (
@@ -585,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}