From 139600ab7e8a82a31744cd3798247236cd5616fc Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 3 May 2024 22:08:56 -0400 Subject: fixed pdf rendering. fixed cropping images. fixed zooming out of an image that is fitWidth to set scroll bar properly. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 87 ++++++++-------------- src/client/views/nodes/ImageBox.tsx | 14 ++-- src/client/views/nodes/PDFBox.tsx | 8 +- src/client/views/nodes/WebBox.tsx | 1 - src/client/views/pdf/PDFViewer.tsx | 2 +- 5 files changed, 42 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a36c36261..21a069bd8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -22,7 +22,7 @@ import { ImageField } from '../../../../fields/URLField'; import { TraceMobx } from '../../../../fields/util'; import { Gestures, PointData } from '../../../../pen-gestures/GestureTypes'; import { GestureUtils } from '../../../../pen-gestures/GestureUtils'; -import { aggregateBounds, emptyFunction, intersectRect, Utils } from '../../../../Utils'; +import { aggregateBounds, clamp, emptyFunction, intersectRect, Utils } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { DocUtils } from '../../../documents/DocUtils'; @@ -377,7 +377,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout) .slice() @@ -411,8 +410,7 @@ export class CollectionFreeFormView extends CollectionSubView { const layoutDoc = Doc.Layout(d); const delta = Utils.rotPt(x - dropPos[0], y - dropPos[1], fromScreenXf.Rotate); if (this.Document._currentFrame !== undefined) { @@ -431,7 +429,7 @@ export class CollectionFreeFormView extends CollectionSubView { SnappingManager.TriggerUserPanned(); - this.setPan(NumCast(this.Document[this.panXFieldKey]) - e.deltaX, NumCast(this.Document[this.panYFieldKey]) - e.deltaY, 0, true); + this.setPan(NumCast(this.Document[this.panXFieldKey]) - e.deltaX, NumCast(this.Document[this.panYFieldKey]) - e.deltaY, 0); }; @action pan = (e: PointerEvent): void => { - const ctrlKey = e.ctrlKey && !e.shiftKey; - const shiftKey = e.shiftKey && !e.ctrlKey; + const [ctrlKey, shiftKey] = [e.ctrlKey && !e.shiftKey, e.shiftKey && !e.ctrlKey]; SnappingManager.TriggerUserPanned(); this.DocumentView?.().clearViewTransition(); const [dxi, dyi] = this.screenToFreeformContentsXf.transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); const { x: dx, y: dy } = Utils.rotPt(dxi, dyi, this.ScreenToLocalBoxXf().Rotate); - this.setPan(NumCast(this.Document[this.panXFieldKey]) - (ctrlKey ? 0 : dx), NumCast(this.Document[this.panYFieldKey]) - (shiftKey ? 0 : dy), 0, true); + this.setPan(NumCast(this.Document[this.panXFieldKey]) - (ctrlKey ? 0 : dx), NumCast(this.Document[this.panYFieldKey]) - (shiftKey ? 0 : dy), 0); this._lastX = e.clientX; this._lastY = e.clientY; }; @@ -795,18 +791,15 @@ export class CollectionFreeFormView extends CollectionSubView NumCast(this.Document[this.scaleFieldKey + '_max'], Number.MAX_VALUE)) { - deltaScale = NumCast(this.Document[this.scaleFieldKey + '_max'], 1) / invTransform.Scale; - } - if (deltaScale * invTransform.Scale < NumCast(this.Document[this.scaleFieldKey + '_min'], this.isAnnotationOverlay ? 1 : 0)) { - deltaScale = NumCast(this.Document[this.scaleFieldKey + '_min'], 1) / invTransform.Scale; - } - + const minScale = NumCast(this.Document[this.scaleFieldKey + '_min'], this.isAnnotationOverlay ? 1 : 0); + const maxScale = NumCast(this.Document[this.scaleFieldKey + '_max'], Number.MAX_VALUE); + deltaScale = clamp(deltaScale, minScale / invTransform.Scale, maxScale / invTransform.Scale); const localTransform = invTransform.scaleAbout(deltaScale, x, y); if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20); + const allowScroll = this.Document[this.scaleFieldKey] !== minScale && Math.abs(safeScale) === minScale; this.Document[this.scaleFieldKey] = Math.abs(safeScale); - this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); + this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale, undefined, allowScroll); } }; @@ -843,35 +836,18 @@ export class CollectionFreeFormView extends CollectionSubView will talk with Bob about using mobx to do this to remove this line of code. if (Doc.UserDoc()?.presentationMode === 'watching') ReplayMovements.Instance.pauseFromInteraction(); - if (!this.isAnnotationOverlay && clamp) { + if (!this.isAnnotationOverlay && this.childDocs.length) { // this section wraps the pan position, horizontally and/or vertically whenever the content is panned out of the viewing bounds - const docs = this.childLayoutPairs.map(pair => pair.layout).filter(doc => doc instanceof Doc && doc.type !== DocumentType.LINK); - const measuredDocs = docs.map(doc => ({ x: NumCast(doc.x), y: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) })); - if (measuredDocs.length) { - const { originTopLeft } = this._props; - // const xrangeMin = Math.min(...measuredDocs.map(doc => doc.x), originTopLeft ? 0 : Number.MAX_VALUE); - // const yrangeMin = Math.min(...measuredDocs.map(doc => doc.y), originTopLeft ? 0 : Number.MAX_VALUE); - // const xrangeMax = Math.max(...measuredDocs.map(doc => doc.x + doc.width)); - // const yrangeMax = Math.max(...measuredDocs.map(doc => doc.y + doc.height)); - const { bounds: { x: xrangeMin, y: yrangeMin, r: xrangeMax, b: yrangeMax } } = this.contentBounds(); // prettier-ignore - const nativeScaling = this._props.NativeDimScaling?.() || 1; - const scaling = this.zoomScaling() * nativeScaling; - const [widScaling, hgtScaling] = [this._props.PanelWidth() / scaling, this._props.PanelHeight() / scaling]; - const panelWidMax = widScaling * (originTopLeft ? 2 / nativeScaling : 1); - const panelHgtMax = hgtScaling * (originTopLeft ? 2 / nativeScaling : 1); - const panelWidMin = widScaling * (originTopLeft ? 0 : 1); - const panelHgtMin = hgtScaling * (originTopLeft ? 0 : 1); - if (xrangeMin >= panX + panelWidMax / 2) panX = xrangeMax + (originTopLeft ? 0 : panelWidMax / 2); - else if (xrangeMax <= panX - panelWidMin / 2) panX = xrangeMin - (originTopLeft ? panelWidMax / 2 : panelWidMin / 2); // prettier-ignore - if (yrangeMin >= panY + panelHgtMax / 2) panY = yrangeMax + (originTopLeft ? 0 : panelHgtMax / 2); - else if (yrangeMax <= panY - panelHgtMin / 2) panY = yrangeMin - (originTopLeft ? panelHgtMax / 2 : panelHgtMin / 2); // prettier-ignore - } + const { bounds: { x: xrangeMin, y: yrangeMin, r: xrangeMax, b: yrangeMax } } = this.contentBounds(); // prettier-ignore + const scaling = this.zoomScaling() * (this._props.NativeDimScaling?.() || 1); + const [widScaling, hgtScaling] = [this._props.PanelWidth() / scaling, this._props.PanelHeight() / scaling]; + panX = clamp(panX, xrangeMin - widScaling / 2, xrangeMax + widScaling / 2); + panY = clamp(panY, yrangeMin - hgtScaling / 2, yrangeMax + hgtScaling / 2); } if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc) { this.setPanZoomTransition(panTime); @@ -880,22 +856,22 @@ export class CollectionFreeFormView extends CollectionSubView 2 && this.layoutDoc.layout_scrollTop === undefined && NumCast(this.layoutDoc._freeform_scale, minScale) === minScale) { - const maxPanScrollY = minPanY + fitYscroll; - const relTop = (panY - minPanY) / (maxPanScrollY - minPanY); + const newPanY = clamp(panY, minPanY, maxPanY); + // this mess fixes a problem when zooming to the default on an image that is fit width and can scroll. + // Without this, the scroll always goes to the top, instead of matching the pan position. + if (fitYscroll > 2 && allowScroll && NumCast(this.layoutDoc._freeform_scale, minScale) === minScale) { setTimeout(() => { + const relTop = (clamp(panY, minPanY, fitYscroll) - minPanY) / fitYscroll; this.layoutDoc.layout_scrollTop = relTop * maxScrollTop; }, 10); - newPanY = minPanY; } !this.Document._verticalScroll && (this.Document[this.panXFieldKey] = this.isAnnotationOverlay ? newPanX : panX); !this.Document._horizontalScroll && (this.Document[this.panYFieldKey] = this.isAnnotationOverlay ? newPanY : panY); @@ -909,8 +885,7 @@ export class CollectionFreeFormView extends CollectionSubView boolean>) { ImageEditorData.set(this.imageData.open, this.imageData.rootDoc, this.imageData.source, addDoc); } // prettier-ignore } @observer -export class ImageBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { +export class ImageBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } @@ -191,12 +191,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent() impl const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw; this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw; - this.layoutDoc._freeform_panX = nw * NumCast(this.layoutDoc._freeform_panX); - this.layoutDoc._freeform_panY = nw * NumCast(this.layoutDoc._freeform_panY); - this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nw * NumCast(this.dataDoc._freeform_panXMax) : undefined; - this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nw * NumCast(this.dataDoc._freeform_panXMin) : undefined; - this.dataDoc._freeform_panYMax = this.dataDoc._freeform_panYMax ? nw * NumCast(this.dataDoc._freeform_panYMax) : undefined; - this.dataDoc._freeform_panYMin = this.dataDoc._freeform_panYMin ? nw * NumCast(this.dataDoc._freeform_panYMin) : undefined; + this.dataDoc._freeform_panX = nw * NumCast(this.dataDoc._freeform_panX); + this.dataDoc._freeform_panY = nw * NumCast(this.dataDoc._freeform_panY); + this.dataDoc._freeform_panX_max = this.dataDoc._freeform_panX_max ? nw * NumCast(this.dataDoc._freeform_panX_max) : undefined; + this.dataDoc._freeform_panX_min = this.dataDoc._freeform_panX_min ? nw * NumCast(this.dataDoc._freeform_panX_min) : undefined; + this.dataDoc._freeform_panY_max = this.dataDoc._freeform_panY_max ? nw * NumCast(this.dataDoc._freeform_panY_max) : undefined; + this.dataDoc._freeform_panY_min = this.dataDoc._freeform_panY_min ? nw * NumCast(this.dataDoc._freeform_panY_min) : undefined; }); @undoBatch rotate = action(() => { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index b8b9f63a9..1dc194c42 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -656,11 +656,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { ); else { if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise); - PDFBox.pdfpromise.get(href)?.then( - action((pdf: any) => { - PDFBox.pdfcache.set(href, (this._pdf = pdf)); - }) - ); + PDFBox.pdfpromise.get(href)?.then((pdf: any) => { + PDFBox.pdfcache.set(href, (this._pdf = pdf)); + }); } } return pdfView ?? this.renderTitleBox; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 198652310..b6ef36974 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1049,7 +1049,6 @@ export class WebBox extends ViewBoxAnnotatableComponent() { setContentViewBox={this.setInnerContent} NativeWidth={returnZero} NativeHeight={returnZero} - originTopLeft={false} isAnnotationOverlayScrollable renderDepth={this._props.renderDepth + 1} isAnnotationOverlay diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 45b1d727e..2327ee0d8 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -33,7 +33,7 @@ import './PDFViewer.scss'; // pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; // The workerSrc property shall be specified. -Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.1.392/build/pdf.worker.mjs'; +Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.2.67/build/pdf.worker.mjs'; interface IViewerProps extends FieldViewProps { pdfBox: PDFBox; -- cgit v1.2.3-70-g09d2