From c5c2c309cd88bbeb2f1b668cb040cffaac9c8470 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 4 Apr 2023 20:12:16 -0400 Subject: fixed using freeformview in sidebar of pdfs. fixed issues with dragging items out of schema and with selecting the schema view by clicking on headers. Fixed a lot of errors caused by using OmitKeys which masks type checking. fixed some pointerevent problems with treeview and freeformview --- .../collectionFreeForm/CollectionFreeFormView.tsx | 139 ++++++++++++--------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 + 2 files changed, 80 insertions(+), 61 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index aed3683d4..d39668a5d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { DateField } from '../../../../fields/DateField'; @@ -53,10 +53,14 @@ import { MarqueeView } from './MarqueeView'; import React = require('react'); export type collectionFreeformViewProps = { + noPointerWheel?: () => boolean; // turn off pointerwheel interactions (see PDFViewer) + NativeWidth?: () => number; + NativeHeight?: () => number; + originTopLeft?: boolean; annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; childPointerEvents?: string; - scaleField?: string; + viewField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; getScrollHeight?: () => number | undefined; @@ -97,8 +101,14 @@ export class CollectionFreeFormView extends CollectionSubView (this.fitContentsToBox ? true : false); // panx, pany, zoomscale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document. // this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image - panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1)); - panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1)); + panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1)); + panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1)); zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1)); contentTransform = () => - !this.cachedCenteringShiftX && !this.cachedCenteringShiftY && this.zoomScaling() === 1 - ? '' - : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; + this.props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; getTransform = () => this.cachedGetTransform.copy(); getLocalTransform = () => this.cachedGetLocalTransform.copy(); getContainerTransform = () => this.cachedGetContainerTransform.copy(); @@ -293,7 +301,7 @@ export class CollectionFreeFormView extends CollectionSubView { - options.docTransform = new Transform(-NumCast(this.rootDoc.panX) + NumCast(anchor.x), -NumCast(this.rootDoc.panY) + NumCast(anchor.y), 1); + options.docTransform = new Transform(-NumCast(this.rootDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.rootDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); const res = this.props.focus(this.rootDoc, options); options.docTransform = undefined; return res; @@ -301,7 +309,7 @@ export class CollectionFreeFormView extends CollectionSubView { const xfToCollection = options?.docTransform ?? Transform.Identity(); - const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined }; + const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined }; const cantTransform = this.fitContentsToBox || ((this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc); const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? options?.zoomScale || 0.75 : undefined); @@ -772,7 +780,7 @@ export class CollectionFreeFormView extends CollectionSubView= 0.05 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20); this.props.Document[this.scaleFieldKey] = Math.abs(safeScale); - this.setPan(-localTransform.TranslateX / safeScale, NumCast(this.props.Document.scrollTop) * safeScale || -localTransform.TranslateY / safeScale); + this.setPan(-localTransform.TranslateX / safeScale, (this.props.originTopLeft ? undefined : NumCast(this.props.Document.scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); } }; @action onPointerWheel = (e: React.WheelEvent): void => { - if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom + if (this.props.noPointerWheel?.() || this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; e.stopPropagation(); @@ -995,7 +1003,7 @@ export class CollectionFreeFormView extends CollectionSubView= panX + panelDim[0] / 2) panX = ranges.xrange.max + panelDim[0] / 2; // snaps pan position of range of content goes out of bounds - else if (ranges.xrange.max <= panX - panelDim[0] / 2) panX = ranges.xrange.min - panelDim[0] / 2; - if (ranges.yrange.min >= panY + panelDim[1] / 2) panY = ranges.yrange.max + panelDim[1] / 2; - else if (ranges.yrange.max <= panY - panelDim[1] / 2) panY = ranges.yrange.min - panelDim[1] / 2; + const panelWidMax = (this.props.PanelWidth() / this.zoomScaling()) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1); + const panelWidMin = (this.props.PanelWidth() / this.zoomScaling()) * (this.props.originTopLeft ? 0 : 1); + const panelHgtMax = (this.props.PanelHeight() / this.zoomScaling()) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1); + const panelHgtMin = (this.props.PanelHeight() / this.zoomScaling()) * (this.props.originTopLeft ? 0 : 1); + if (ranges.xrange.min >= panX + panelWidMax / 2) panX = ranges.xrange.max + (this.props.originTopLeft ? 0 : panelWidMax / 2); + else if (ranges.xrange.max <= panX - panelWidMin / 2) panX = ranges.xrange.min - (this.props.originTopLeft ? panelWidMax / 2 : panelWidMin / 2); + if (ranges.yrange.min >= panY + panelHgtMax / 2) panY = ranges.yrange.max + (this.props.originTopLeft ? 0 : panelHgtMax / 2); + else if (ranges.yrange.max <= panY - panelHgtMin / 2) panY = ranges.yrange.min - (this.props.originTopLeft ? panelHgtMax / 2 : panelHgtMin / 2); } } if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(Doc.MyOverlayDocs?.data).includes(this.Document)) { @@ -1078,8 +1089,8 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) { this.setPan( - NumCast(this.layoutDoc._panX) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale - NumCast(this.layoutDoc._panY) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), + NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale + NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), nudgeTime, true ); @@ -1106,12 +1117,14 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).slice(); docs.sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); - let zlast = docs.length ? Math.max(docs.length, NumCast(docs[docs.length - 1].zIndex)) : 1; - if (zlast - docs.length > 100) { - for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1; - zlast = docs.length + 1; + let zlast = docs.length ? Math.max(docs.length, NumCast(docs.lastElement().zIndex)) : 1; + if (docs.lastElement() !== doc) { + if (zlast - docs.length > 100) { + for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1; + zlast = docs.length + 1; + } + doc.zIndex = zlast + 1; } - doc.zIndex = zlast + 1; } }; @@ -1134,8 +1147,8 @@ export class CollectionFreeFormView extends CollectionSubView { @@ -1158,8 +1171,8 @@ export class CollectionFreeFormView extends CollectionSubView screen.bot ? Math.min(ph / 10, maxYShift / 2) : 0; @@ -1171,8 +1184,8 @@ export class CollectionFreeFormView extends CollectionSubView { if (cbounds) { const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; - const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; + const p = [NumCast(this.layoutDoc[this.panXFieldKey]), NumCast(this.layoutDoc[this.panYFieldKey])]; const pbounds = { x: cbounds.x - p[0] + c[0], y: cbounds.y - p[1] + c[1], @@ -1511,8 +1524,8 @@ export class CollectionFreeFormView extends CollectionSubView NumCast(doc._height))) + 20; const dim = Math.ceil(Math.sqrt(docs.length)); docs.forEach((doc, i) => { - doc.x = NumCast(this.Document._panX) + (i % dim) * width - (width * dim) / 2; - doc.y = NumCast(this.Document._panY) + Math.floor(i / dim) * height - (height * dim) / 2; + doc.x = NumCast(this.Document[this.panXFieldKey]) + (i % dim) * width - (width * dim) / 2; + doc.y = NumCast(this.Document[this.panYFieldKey]) + Math.floor(i / dim) * height - (height * dim) / 2; }); }; @@ -1675,7 +1688,7 @@ export class CollectionFreeFormView extends CollectionSubView { - this.props.Document._panX = this.props.Document._panY = 0; + this.props.Document[this.panXFieldKey] = this.props.Document[this.panYFieldKey] = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: 'compress-arrows-alt', @@ -1795,11 +1808,11 @@ export class CollectionFreeFormView extends CollectionSubView !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); }); - children = () => { + get children() { this.incrementalRender(); - const children = typeof this.props.children === 'function' ? ((this.props.children as any)() as JSX.Element[]) : []; + const children = typeof this.props.children === 'function' ? ((this.props.children as any)() as JSX.Element[]) : this.props.children ? [this.props.children] : []; return [...children, ...this.views, ]; - }; + } @computed get placeholder() { return ( @@ -1843,6 +1856,7 @@ export class CollectionFreeFormView extends CollectionSubView this.nativeDimScaling; private groupDropDisposer?: DragManager.DragDropDisposer; protected createGroupEventsTarget = (ele: HTMLDivElement) => { @@ -1912,7 +1927,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.createDashEventsTarget(r); // prevent wheel events from passivly propagating up through containers - r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false }); + !this.props.isAnnotationOverlay && r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false }); }} onWheel={this.onPointerWheel} onClick={this.onClick} @@ -1985,7 +2000,8 @@ interface CollectionFreeFormViewPannableContentsProps { transform: () => string; zoomScaling: () => number; viewDefDivClick?: ScriptField; - children: () => JSX.Element[]; + children?: React.ReactNode | undefined; + //children: () => JSX.Element[]; transition?: string; presPaths: () => JSX.Element | null; presPinView?: boolean; @@ -2079,7 +2095,7 @@ class CollectionFreeFormViewPannableContents extends React.Component - {this.props.children()} + {this.props.children} {!this.props.brushView.width ? null : (
number; PanelHeight: () => number; isAnnotationOverlay?: boolean; + nativeDimScaling: () => number; zoomScaling: () => number; layoutDoc: Doc; cachedCenteringShiftX: number; @@ -2124,10 +2141,10 @@ class CollectionFreeFormBackgroundGrid extends React.Component { + // if (this.props.pointerEvents?.() === 'none') return; this._downX = this._lastX = e.clientX; this._downY = this._lastY = e.clientY; if (!(e.nativeEvent as any).marqueeHit) { @@ -345,6 +346,7 @@ export class MarqueeView extends React.Component { + if (this.props.pointerEvents?.() === 'none') return; if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { if (Doc.ActiveTool === InkTool.None) { if (!(e.nativeEvent as any).marqueeHit) { -- cgit v1.2.3-70-g09d2