diff options
author | bobzel <zzzman@gmail.com> | 2025-01-07 01:24:55 -0500 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2025-01-07 01:24:55 -0500 |
commit | 93ee735e435de5949a0eec54c07537c4de2eedf4 (patch) | |
tree | 2a9aaea1a4deaea5500e45ab890536b593f74ca0 /src | |
parent | 68af8fffb3111870dd84d4280fdd73b05832dfd2 (diff) |
fixed pdfs/marqueeAnnotator so that you can add rectangle annotations.
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/MarqueeAnnotator.tsx | 5 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DataVizBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.scss | 11 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 34 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 25 |
8 files changed, 48 insertions, 36 deletions
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index fa1123a2d..02516264c 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -15,18 +15,19 @@ import './MarqueeAnnotator.scss'; import { DocumentView } from './nodes/DocumentView'; import { ObservableReactComponent } from './ObservableReactComponent'; import { AnchorMenu } from './pdf/AnchorMenu'; +import { Transform } from '../util/Transform'; export interface MarqueeAnnotatorProps { Document: Doc; down?: number[]; scrollTop: number; - isNativeScaled?: boolean; scaling?: () => number; annotationLayerScaling?: () => number; annotationLayerScrollTop: number; containerOffset?: () => number[]; marqueeContainer: HTMLDivElement; docView: () => DocumentView; + screenTransform: () => Transform; savedAnnotations: () => ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean })[]>; selectionText: () => string; annotationLayer: HTMLDivElement; @@ -157,7 +158,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP // 4) reattach the vector to the center of the bounding box getTransformedScreenPt = (down: number[]) => { const { marqueeContainer } = this.props; - const containerXf = this.props.isNativeScaled ? this.props.docView().screenToContentsTransform() : this.props.docView().screenToViewTransform(); + const containerXf = this.props.screenTransform(); const boundingRect = marqueeContainer.getBoundingClientRect(); const center = { x: boundingRect.x + boundingRect.width / 2, y: boundingRect.y + boundingRect.height / 2 }; const downVec = Utils.rotPt(down[0] - center.x, diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 7026c3b01..b874d077b 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -832,6 +832,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { annotationLayerScrollTop={NumCast(this.Document._layout_scrollTop)} scaling={returnOne} docView={this.DocumentView} + screenTransform={this.DocumentView().screenToViewTransform} addDocument={this.sidebarAddDocument} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 423a73f44..de8a9ad21 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -39,7 +39,6 @@ import { FocusViewOptions } from './FocusViewOptions'; import './ImageBox.scss'; import { OpenWhere } from './OpenWhere'; import { Upload } from '../../../server/SharedMediaTypes'; -import { ImageUtils } from '../../util/Import & Export/ImageUtils'; export class ImageEditorData { // eslint-disable-next-line no-use-before-define @@ -268,7 +267,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const anchy = NumCast(cropping.y); const anchw = NumCast(cropping._width); const anchh = NumCast(cropping._height); - const viewScale = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) / anchw; + const viewScale = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) / anchh; cropping.title = 'crop: ' + this.Document.title; cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width); cropping.y = NumCast(this.Document.y); @@ -286,9 +285,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { croppingProto.data_nativeWidth = anchw; croppingProto.data_nativeHeight = anchh; croppingProto.freeform_scale = viewScale; - croppingProto.freeform_scale_min = viewScale; croppingProto.freeform_panX = anchx / viewScale; croppingProto.freeform_panY = anchy / viewScale; + croppingProto.freeform_scale_min = viewScale; croppingProto.freeform_panX_min = anchx / viewScale; croppingProto.freeform_panX_max = anchw / viewScale; croppingProto.freeform_panY_min = anchy / viewScale; @@ -593,6 +592,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { annotationLayerScrollTop={0} scaling={returnOne} annotationLayerScaling={this._props.NativeDimScaling} + screenTransform={this.DocumentView().screenToViewTransform} docView={this.DocumentView} addDocument={this.addDocument} finishMarquee={this.finishMarquee} diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 7bca1230f..f6908d5fd 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -250,6 +250,17 @@ cursor: ew-resize; background: lightGray; } +.pdfBox-container { + position: absolute; + transform-origin: top left; + top: 0; +} +.pdfBox-sidebarContainer { + position: absolute; + height: 100%; + right: 0; + top: 0; +} .pdfBox-interactive { width: 100%; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 1de4d2512..06b75e243 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; @@ -40,8 +40,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } + static pdfcache = new Map<string, Pdfjs.PDFDocumentProxy>(); + static pdfpromise = new Map<string, Promise<Pdfjs.PDFDocumentProxy>>(); public static openSidebarWidth = 250; public static sidebarResizerWidth = 5; + private _searchString: string = ''; private _initialScrollTarget: Opt<Doc>; private _pdfViewer: PDFViewer | undefined; @@ -63,11 +66,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const nh = Doc.NativeHeight(this.Document, this.dataDoc) || 1200; !this.Document._layout_fitWidth && (this.Document._height = NumCast(this.Document._width) * (nh / nw)); if (this.pdfUrl) { - if (PDFBox.pdfcache.get(this.pdfUrl.url.href)) - runInAction(() => { - this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href); - }); - else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) + this._pdf = PDFBox.pdfcache.get(this.pdfUrl.url.href); + !this._pdf && PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then( action(pdf => { this._pdf = pdf; @@ -265,12 +265,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }; @action - loaded = (nw: number, nh: number, np: number) => { - this.dataDoc[this._props.fieldKey + '_numPages'] = np; - Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), nw)); - Doc.SetNativeHeight(this.dataDoc, nh); + loaded = (p: { width: number; height: number }, pages: number) => { + this.dataDoc[this._props.fieldKey + '_numPages'] = pages; + Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), p.width)); + Doc.SetNativeHeight(this.dataDoc, p.height); this.layoutDoc._height = NumCast(this.layoutDoc._width) / (Doc.NativeAspect(this.dataDoc) || 1); - !this.Document._layout_fitWidth && (this.Document._height = NumCast(this.Document._width) * (nh / nw)); + !this.Document._layout_fitWidth && (this.Document._height = NumCast(this.Document._width) * (p.height / p.width)); }; override search = action((searchString: string, bwd?: boolean, clear: boolean = false) => { @@ -596,13 +596,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }}> <div className="pdfBox-background" onPointerDown={e => this.sidebarBtnDown(e, false)} /> <div + className="pdfBox-container" style={{ width: `calc(${100 / viewScale}% - ${(this.sidebarWidth() / viewScale) * (this._previewWidth ? viewScale : 1)}px)`, height: `${100 / viewScale}%`, transform: `scale(${viewScale})`, - position: 'absolute', - transformOrigin: 'top left', - top: 0, }}> <PDFViewer {...this._props} @@ -615,7 +613,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { focus={this.focus} url={this.pdfUrl!.url.pathname} anchorMenuClick={this.anchorMenuClick} - loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined} + loaded={Doc.NativeAspect(this.dataDoc) ? emptyFunction : this.loaded} setPdfViewer={this.setPdfViewer} addDocument={this.addDocument} moveDocument={this.moveDocument} @@ -624,14 +622,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { crop={this.crop} /> </div> - <div style={{ position: 'absolute', height: '100%', right: 0, top: 0, width: `calc(100 * ${this.sidebarWidth() / this._props.PanelWidth()}%` }}>{this.sidebarCollection}</div> + <div className="pdfBox-sidebarContainer" style={{ width: `calc(100 * ${this.sidebarWidth() / this._props.PanelWidth()}%` }}> + {this.sidebarCollection} + </div> {this.settingsPanel()} </div> ); } - static pdfcache = new Map<string, Pdfjs.PDFDocumentProxy>(); - static pdfpromise = new Map<string, Promise<Pdfjs.PDFDocumentProxy>>(); render() { TraceMobx(); const pdfView = !this._pdf ? null : this.renderPdfView; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 3bf7de2fe..9adee53e8 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1023,6 +1023,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { scaling={returnOne} annotationLayerScaling={this._props.NativeDimScaling} docView={this.DocumentView} + screenTransform={this.DocumentView().screenToViewTransform} containerOffset={this.marqueeOffset} addDocument={this.addDocWithTimecode} finishMarquee={this.finishMarquee} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index ffeb574e9..6026d9ca7 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1196,6 +1196,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { scaling={this._props.NativeDimScaling} addDocument={this.addDocumentWrapper} docView={this.DocumentView} + screenTransform={this.DocumentView().screenToViewTransform} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotationsCreator} selectionText={this.selectionText} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 722492e8d..ca7f72811 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -30,6 +30,7 @@ import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT'; import ReactLoading from 'react-loading'; +import { Transform } from '../../util/Transform'; interface IViewerProps extends FieldViewProps { pdfBox: PDFBox; @@ -40,7 +41,7 @@ interface IViewerProps extends FieldViewProps { pdf: Pdfjs.PDFDocumentProxy; url: string; sidebarAddDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean; - loaded?: (nw: number, nh: number, np: number) => void; + loaded: (p: { width: number; height: number }, pages: number) => void; // eslint-disable-next-line no-use-before-define setPdfViewer: (view: PDFViewer) => void; anchorMenuClick?: () => undefined | ((anchor: Doc) => void); @@ -151,24 +152,21 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { } initialLoad = () => { + const page0or180 = (page: { rotate: number }) => page.rotate === 0 || page.rotate === 180; if (this._pageSizes.length === 0) { const devicePixelRatio = window.devicePixelRatio; document.documentElement?.style.setProperty('--devicePixelRatio', window.devicePixelRatio.toString()); // set so that css can use this to adjust various PDFJs divs Promise.all( numberRange(this._props.pdf.numPages).map(i => - this._props.pdf.getPage(i + 1).then(page => { - const page0or180 = page.rotate === 0 || page.rotate === 180; - return { - width: page.view[page0or180 ? 2 : 3] * devicePixelRatio - page.view[page0or180 ? 0 : 1] * devicePixelRatio, - height: page.view[page0or180 ? 3 : 2] * devicePixelRatio - page.view[page0or180 ? 1 : 0] * devicePixelRatio, - }; - }) + this._props.pdf.getPage(i + 1).then(page => ({ + width: (page.view[page0or180(page) ? 2 : 3] - page.view[page0or180(page) ? 0 : 1]) * devicePixelRatio, + height: (page.view[page0or180(page) ? 3 : 2] - page.view[page0or180(page) ? 1 : 0]) * devicePixelRatio, + })) ) ).then( action(pages => { this._pageSizes = pages; - const lastPage = pages.lastElement(); - this._props.loaded?.(lastPage.width, lastPage.height, this._props.pdf.numPages); + this._props.loaded(pages.lastElement(), this._props.pdf.numPages); this.createPdfViewer(); }) ); @@ -599,6 +597,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { } savedAnnotations = () => this._savedAnnotations; addDocumentWrapper = (doc: Doc | Doc[]) => this._props.addDocument!(doc); + screenToMarqueeXf = () => this.props.pdfBox.DocumentView?.()?.screenToContentsTransform().scale(Pdfjs.PixelsPerInch.PDF_TO_CSS_UNITS) ?? Transform.Identity(); render() { TraceMobx(); return ( @@ -618,17 +617,17 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { {this.annotationLayer} {this.overlayLayer} {this._showWaiting ? <img alt="" className="pdfViewerDash-waiting" src="/assets/loading.gif" /> : null} - {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this._annotationLayer.current || !this.props.pdfBox.DocumentView ? null : ( <MarqueeAnnotator ref={this._marqueeref} Document={this._props.Document} getPageFromScroll={this.getPageFromScroll} anchorMenuClick={this._props.anchorMenuClick} scrollTop={0} - isNativeScaled annotationLayerScrollTop={NumCast(this._props.Document._layout_scrollTop)} addDocument={this.addDocumentWrapper} - docView={this._props.pdfBox.DocumentView!} + docView={this.props.pdfBox.DocumentView} + screenTransform={this.screenToMarqueeXf} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} selectionText={this.selectionText} |