aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-02-10 19:07:20 -0500
committerbobzel <zzzman@gmail.com>2025-02-10 19:07:20 -0500
commitc9686eaebffb3547b7e0f20aec64754627af76ce (patch)
tree7ebf1c38323a8d7af554ba564acf95cfe79b7709 /src/client/views/pdf
parentb72d018698ad1d2e713f0fcbef392d23bf1cf545 (diff)
parente93ca53af693fa1ec2186ca9417af122bb5e8e09 (diff)
updated from master
Diffstat (limited to 'src/client/views/pdf')
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx22
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx250
-rw-r--r--src/client/views/pdf/PDFViewer.scss12
-rw-r--r--src/client/views/pdf/PDFViewer.tsx66
4 files changed, 160 insertions, 190 deletions
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 5ab9b556c..11f2f7988 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -1,5 +1,5 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
+import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from '@dash/components';
import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -131,12 +131,15 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
/**
* Creates a GPT drawing based on selected text.
*/
- gptDraw = async (e: React.PointerEvent) => {
+ gptDraw = (e: React.PointerEvent) => {
try {
SmartDrawHandler.Instance.AddDrawing = this.createDrawingAnnotation;
runInAction(() => (this._isLoading = true));
- await SmartDrawHandler.Instance.drawWithGPT({ X: e.clientX, Y: e.clientY }, this._selectedText, 5, 100, true);
- runInAction(() => (this._isLoading = false));
+ SmartDrawHandler.Instance.drawWithGPT({ X: e.clientX, Y: e.clientY }, this._selectedText, 5, 100, true)?.then(
+ action(() => {
+ this._isLoading = false;
+ })
+ );
} catch (err) {
console.error(err);
}
@@ -150,11 +153,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
this.AddDrawingAnnotation(drawing);
const docData = drawing[DocData];
docData.title = opts.text.match(/^(.*?)~~~.*$/)?.[1] || opts.text;
- docData.drawingInput = opts.text;
- docData.drawingComplexity = opts.complexity;
- docData.drawingColored = opts.autoColor;
- docData.drawingSize = opts.size;
- docData.drawingData = gptRes;
+ docData.ai_drawing_input = opts.text;
+ docData.ai_drawing_complexity = opts.complexity;
+ docData.ai_drawing_colored = opts.autoColor;
+ docData.ai_drawing_size = opts.size;
+ docData.ai_drawing_data = gptRes;
+ docData.ai = 'gpt';
});
pointerDown = (e: React.PointerEvent) => {
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index d5f5f620c..f5a9f9e6a 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, IconButton, Type } from 'browndash-components';
-import { action, makeObservable, observable } from 'mobx';
+import { Button, IconButton, Toggle, ToggleType, Type } from '@dash/components';
+import { action, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { CgClose, CgCornerUpLeft } from 'react-icons/cg';
@@ -37,10 +37,8 @@ export enum GPTQuizType {
MULTIPLE = 2,
}
-interface GPTPopupProps {}
-
@observer
-export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
+export class GPTPopup extends ObservableReactComponent<object> {
// eslint-disable-next-line no-use-before-define
static Instance: GPTPopup;
private messagesEndRef: React.RefObject<HTMLDivElement>;
@@ -48,115 +46,84 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
@observable private chatMode: boolean = false;
private correlatedColumns: string[] = [];
- @observable
- public visible: boolean = false;
- @action
- public setVisible = (vis: boolean) => {
- this.visible = vis;
+ @observable public Visible: boolean = false;
+ @action public setVisible = (vis: boolean) => {
+ this.Visible = vis;
};
- @observable
- public loading: boolean = false;
- @action
- public setLoading = (loading: boolean) => {
+ @observable public loading: boolean = false;
+ @action public setLoading = (loading: boolean) => {
this.loading = loading;
};
- @observable
- public text: string = '';
- @action
- public setText = (text: string) => {
+ @observable public text: string = '';
+ @action public setText = (text: string) => {
this.text = text;
};
- @observable
- public selectedText: string = '';
- @action
- public setSelectedText = (text: string) => {
+ @observable public selectedText: string = '';
+ @action public setSelectedText = (text: string) => {
this.selectedText = text;
};
- @observable
- public dataJson: string = '';
+ @observable public dataJson: string = '';
public dataChatPrompt: string | undefined = undefined;
- @action
- public setDataJson = (text: string) => {
+ @action public setDataJson = (text: string) => {
if (text === '') this.dataChatPrompt = '';
this.dataJson = text;
};
- @observable
- public imgDesc: string = '';
- @action
- public setImgDesc = (text: string) => {
+ @observable public imgDesc: string = '';
+ @action public setImgDesc = (text: string) => {
this.imgDesc = text;
};
- @observable
- public imgUrls: string[][] = [];
- @action
- public setImgUrls = (imgs: string[][]) => {
+ @observable public imgUrls: string[][] = [];
+ @action public setImgUrls = (imgs: string[][]) => {
this.imgUrls = imgs;
};
- @observable
- public mode: GPTPopupMode = GPTPopupMode.SUMMARY;
- @action
- public setMode = (mode: GPTPopupMode) => {
+ @observable public mode: GPTPopupMode = GPTPopupMode.SUMMARY;
+ @action public setMode = (mode: GPTPopupMode) => {
this.mode = mode;
};
- @observable
- public highlightRange: number[] = [];
+ @observable public highlightRange: number[] = [];
@action callSummaryApi = () => {};
- @observable
- private done: boolean = false;
- @action
- public setDone = (done: boolean) => {
+ @observable private done: boolean = false;
+ @action public setDone = (done: boolean) => {
this.done = done;
this.chatMode = false;
};
- @observable
- private sortDone: boolean = false; // this is so redundant but the og done variable was causing weird unknown problems and im just a girl
-
- @action
- public setSortDone = (done: boolean) => {
- this.sortDone = done;
- };
-
// change what can be a ref into a ref
- @observable
- private sidebarId: string = '';
- @action
- public setSidebarId = (id: string) => {
+ @observable private sidebarId: string = '';
+ @action public setSidebarId = (id: string) => {
this.sidebarId = id;
};
- @observable
- private imgTargetDoc: Doc | undefined;
- @action
- public setImgTargetDoc = (anchor: Doc) => {
+ @observable private imgTargetDoc: Doc | undefined;
+ @action public setImgTargetDoc = (anchor: Doc) => {
this.imgTargetDoc = anchor;
};
- @observable
- private textAnchor: Doc | undefined;
- @action
- public setTextAnchor = (anchor: Doc) => {
+ @observable private textAnchor: Doc | undefined;
+ @action public setTextAnchor = (anchor: Doc) => {
this.textAnchor = anchor;
};
- @observable
- public sortDesc: string = '';
-
+ @observable public sortDesc: string = '';
@action public setSortDesc = (t: string) => {
this.sortDesc = t;
};
- @observable onSortComplete?: (sortResult: string, questionType: string, tag?: string) => void;
- @observable onQuizRandom?: () => void;
+ onSortComplete?: (sortResult: string, questionType: string, tag?: string) => void;
+ onQuizRandom?: () => void;
@observable cardsDoneLoading = false;
+ @observable collectionDoc: Doc | undefined = undefined;
+ @action setCollectionDoc(doc: Doc | undefined) {
+ this.collectionDoc = doc;
+ }
+
@action setCardsDoneLoading(done: boolean) {
- console.log(done + 'HI HIHI');
this.cardsDoneLoading = done;
}
@@ -186,39 +153,27 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
*/
generateQuiz = async () => {
this.setLoading(true);
- this.setSortDone(false);
- const quizType = this.quizMode;
+ await this.regenerateCallback?.();
const selected = DocumentView.SelectedDocs().lastElement();
-
- const questionText = 'Question: ' + StrCast(selected['gptInputText']);
-
- if (StrCast(selected['gptRubric']) === '') {
- const rubricText = 'Rubric: ' + (await this.generateRubric(StrCast(selected['gptInputText']), selected));
+ if (!StrCast(selected.gptRubric)) {
+ await this.generateRubric(StrCast(selected.gptInputText), selected);
}
- const rubricText = 'Rubric: ' + StrCast(selected['gptRubric']);
- const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + 'Rubric' + rubricText;
-
try {
- const res = await gptAPICall(queryText, GPTCallType.QUIZ);
- if (!res) {
- console.error('GPT call failed');
- return;
- }
- console.log(res);
- this.setQuizResp(res);
- this.conversationArray.push(res);
+ const res = await gptAPICall('Question: ' + StrCast(selected.gptInputText) + ' UserAnswer: ' + this.quizAnswer + '. Rubric: ' + StrCast(selected.gptRubric), GPTCallType.QUIZ);
+ if (res) {
+ this.setQuizResp(res);
+ this.conversationArray.push(res);
- this.setLoading(false);
- this.setSortDone(true);
+ this.setLoading(false);
+ this.onQuizRandom?.();
+ } else {
+ console.error('GPT provided no response');
+ }
} catch (err) {
- console.error('GPT call failed');
- }
-
- if (this.onQuizRandom) {
- this.onQuizRandom();
+ console.error('GPT call failed', err);
}
};
@@ -231,10 +186,10 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
generateRubric = async (inputText: string, doc: Doc) => {
try {
const res = await gptAPICall(inputText, GPTCallType.RUBRIC);
- doc['gptRubric'] = res;
+ doc.gptRubric = res;
return res;
} catch (err) {
- console.error('GPT call failed');
+ console.error('GPT call failed', err);
}
};
@@ -244,7 +199,8 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
* Callback function that causes the card view to update the childpair string list
* @param callback
*/
- @action public setRegenerateCallback(callback: () => Promise<void>) {
+ @action public setRegenerateCallback(collectionDoc: Doc | undefined, callback: null | (() => Promise<void>)) {
+ this.setCollectionDoc(collectionDoc);
this.regenerateCallback = callback;
}
@@ -262,37 +218,21 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
* Generates a response to the user's question depending on the type of their question
*/
generateCard = async () => {
- console.log(this.chatSortPrompt + 'USER PROMPT');
this.setLoading(true);
- this.setSortDone(false);
- if (this.regenerateCallback) {
- await this.regenerateCallback();
- }
+ await this.regenerateCallback?.();
try {
- // const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
const questionType = await gptAPICall(this.chatSortPrompt, GPTCallType.TYPE);
- const questionNumber = questionType.split(' ')[0];
- console.log(questionType);
- let res = '';
-
- switch (questionNumber) {
- case '1':
- case '2':
- case '4':
- res = await gptAPICall(this.sortDesc, GPTCallType.SUBSET, this.chatSortPrompt);
- break;
- case '6':
- res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
- break;
- default:
- const selected = DocumentView.SelectedDocs().lastElement();
- const questionText = StrCast(selected!['gptInputText']);
-
- res = await gptAPICall(questionText, GPTCallType.INFO, this.chatSortPrompt);
- break;
- }
+ const questionNumber = questionType.split(' ')[0][0];
+ const res = await (() => {
+ switch (questionNumber) {
+ case '1':
+ case '2':
+ case '4': return gptAPICall(this.sortDesc, GPTCallType.SUBSET, this.chatSortPrompt);
+ case '6': return gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ default: return gptAPICall(StrCast(DocumentView.SelectedDocs().lastElement()?.gptInputText), GPTCallType.INFO, this.chatSortPrompt);
+ }})(); // prettier-ignore
// Trigger the callback with the result
if (this.onSortComplete) {
@@ -308,7 +248,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
// Set the extracted explanation to sortRespText
this.setSortRespText(explanation);
- this.conversationArray.push(this.sortRespText);
+ runInAction(() => this.conversationArray.push(this.sortRespText));
this.scrollToBottom();
console.log(res);
@@ -318,7 +258,6 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
this.setLoading(false);
- this.setSortDone(true);
};
/**
@@ -448,7 +387,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
private getPreviewUrl = (source: string) => source.split('.').join('_m.');
- constructor(props: GPTPopupProps) {
+ constructor(props: object) {
super(props);
makeObservable(this);
GPTPopup.Instance = this;
@@ -498,9 +437,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
onClick={() => {
this.conversationArray = ['Define the selected card!'];
this.setMode(GPTPopupMode.QUIZ);
- if (this.onQuizRandom) {
- this.onQuizRandom();
- }
+ this.onQuizRandom?.();
}}
color={StrCast(Doc.UserDoc().userVariantColor)}
type={Type.TERT}
@@ -515,18 +452,25 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
</div>
);
- handleKeyPress = async (e: React.KeyboardEvent, isSort: boolean) => {
+ @action
+ handleKeyPress = (e: React.KeyboardEvent, isSort: boolean) => {
if (e.key === 'Enter') {
e.stopPropagation();
if (isSort) {
this.conversationArray.push(this.chatSortPrompt);
- await this.generateCard();
- this.chatSortPrompt = '';
+ this.generateCard().then(
+ action(() => {
+ this.chatSortPrompt = '';
+ })
+ );
} else {
this.conversationArray.push(this.quizAnswer);
- await this.generateQuiz();
- this.quizAnswer = '';
+ this.generateQuiz().then(
+ action(() => {
+ this.quizAnswer = '';
+ })
+ );
}
this.scrollToBottom();
@@ -569,21 +513,22 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
};
sortBox = () => (
- <div style={{ height: '80%' }}>
+ <div className="gptPopup-sortBox" style={{ height: '80%' }}>
{this.heading(this.mode === GPTPopupMode.SORT ? 'SORTING' : 'QUIZ')}
<>
- {!this.cardsDoneLoading ? (
- <div className="content-wrapper">
- <div className="loading-spinner">
- <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
- {this.loading ? <span>Loading...</span> : <span>Reading Cards...</span>}
+ {
+ !this.cardsDoneLoading ? (
+ <div className="content-wrapper">
+ <div className="loading-spinner">
+ <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
+ {this.loading ? <span>Loading...</span> : <span>Reading Cards...</span>}
+ </div>
</div>
- </div>
- ) : this.mode === GPTPopupMode.CARD ? (
- this.cardMenu()
- ) : (
- this.cardActual(this.mode)
- ) // Call the functions to render JSX
+ ) : this.mode === GPTPopupMode.CARD ? (
+ this.cardMenu()
+ ) : (
+ this.cardActual(this.mode)
+ ) // Call the functions to render JSX
}
</>
</div>
@@ -741,6 +686,15 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
{(this.mode === GPTPopupMode.SORT || this.mode === GPTPopupMode.QUIZ) && (
<IconButton color={StrCast(SettingsManager.userVariantColor)} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={() => (this.mode = GPTPopupMode.CARD)} style={{ right: '50px', position: 'absolute' }} />
)}
+ <Toggle
+ tooltip="Clear Chat filter"
+ toggleType={ToggleType.BUTTON}
+ type={Type.PRIM}
+ toggleStatus={Doc.hasDocFilter(this.collectionDoc, 'tags', '#chat')}
+ text={Doc.hasDocFilter(this.collectionDoc, 'tags', '#chat') ? 'filtered' : ''}
+ color="red"
+ onClick={() => this.collectionDoc && Doc.setDocFilter(this.collectionDoc, 'tags', '#chat', 'remove')}
+ />
<IconButton
color={StrCast(SettingsManager.userVariantColor)}
tooltip="close"
@@ -777,7 +731,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
return (
- <div className="summary-box" style={{ display: this.visible ? 'flex' : 'none' }}>
+ <div className="summary-box" style={{ display: this.Visible ? 'flex' : 'none' }}>
{content}
<div className="resize-handle" />
</div>
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index a225c4b59..030251762 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -7,6 +7,10 @@
left: 0;
}
+:root {
+ --devicePixelRatio: 1; // the actual value of this will be set in PDFViewer.tsx;
+}
+
.pdfViewerDash,
.pdfViewerDash-interactive {
position: absolute;
@@ -19,9 +23,16 @@
overflow-x: hidden;
transform-origin: top left;
+ .annotationLayer {
+ transform: scale(var(--devicePixelRatio));
+ }
.textLayer {
opacity: unset;
mix-blend-mode: multiply; // bcz: makes text fuzzy!
+ transform: scale(var(--devicePixelRatio));
+ }
+ [data-main-rotation='90'] {
+ transform: scale(var(--devicePixelRatio)) rotate(90deg) translateY(-100%);
}
.textLayer ::selection {
background: #accef76a;
@@ -39,6 +50,7 @@
.page {
position: relative;
border: unset;
+ height: 100% !important;
}
.pdfViewerDash-text-selected {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 358557ad7..8728ce99c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -11,7 +11,7 @@ import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { Cast, NumCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction } from '../../../Utils';
+import { emptyFunction, numberRange } from '../../../Utils';
import { DocUtils } from '../../documents/DocUtils';
import { SnappingManager } from '../../util/SnappingManager';
import { MarqueeOptionsMenu } from '../collections/collectionFreeForm';
@@ -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);
@@ -146,32 +147,30 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
}
};
- @observable _scrollHeight = 0;
+ @computed get _scrollHeight() {
+ return this._pageSizes.reduce((size, page) => size + page.height, 0);
+ }
- @action
- initialLoad = async () => {
+ initialLoad = () => {
+ const page0or180 = (page: { rotate: number }) => page.rotate === 0 || page.rotate === 180;
if (this._pageSizes.length === 0) {
- this._pageSizes = Array<{ width: number; height: number }>(this._props.pdf.numPages);
- await Promise.all(
- this._pageSizes.map((val, i) =>
- this._props.pdf.getPage(i + 1).then(
- action((page: Pdfjs.PDFPageProxy) => {
- const page0or180 = page.rotate === 0 || page.rotate === 180;
- this._pageSizes.splice(i, 1, {
- width: page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1],
- height: page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0],
- });
- if (i === this._props.pdf.numPages - 1) {
- this._props.loaded?.(page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1], page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0], this._props.pdf.numPages);
- }
- })
- )
+ 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 => ({
+ 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;
+ this._props.loaded(pages.lastElement(), this._props.pdf.numPages);
+ this.createPdfViewer();
+ })
);
}
- runInAction(() => {
- this._scrollHeight = (this._pageSizes.reduce((size, page) => size + page.height, 0) * 96) / 72;
- });
};
_scrollStopper: undefined | (() => void);
@@ -197,14 +196,12 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
crop = (region: Doc | undefined, addCrop?: boolean) => this._props.crop(region, addCrop);
@action
- setupPdfJsViewer = async () => {
+ setupPdfJsViewer = () => {
if (this._viewerIsSetup) return;
this._viewerIsSetup = true;
this._showWaiting = true;
this._props.setPdfViewer(this);
- await this.initialLoad();
-
- this.createPdfViewer();
+ this.initialLoad();
};
pagesinit = () => {
@@ -377,7 +374,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
if ((e.button !== 0 || e.altKey) && this._props.isContentActive()) {
this._setPreviewCursor?.(e.clientX, e.clientY, true, false, this._props.Document);
}
- if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this.isAnnotating = true;
@@ -533,7 +530,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
}
getScrollHeight = () => this._scrollHeight;
- scrollXf = () => this._props.ScreenToLocalTransform().translate(0, this._mainCont.current ? NumCast(this._props.layoutDoc._layout_scrollTop) : 0);
+ scrollXf = () => this._props.ScreenToLocalTransform().translate(0, this._mainCont.current ? NumCast(this._props.layoutDoc._layout_scrollTop) / 1.333 : 0);
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);
@@ -554,7 +551,8 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
className="pdfViewerDash-overlay"
style={{
mixBlendMode,
- display: display,
+ display,
+ transform: `scale(${Pdfjs.PixelsPerInch.PDF_TO_CSS_UNITS})`,
pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined,
}}>
<CollectionFreeFormView
@@ -600,6 +598,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 (
@@ -619,17 +618,18 @@ 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
+ annotationLayerScaling={() => Pdfjs.PixelsPerInch.PDF_TO_CSS_UNITS}
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}