From c31bb0d5d8c4d42fb5cd97b1582de0cae1b16ca0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 12 May 2022 12:17:12 -0400 Subject: fixed perfromance (flickering, speed) issues with having pointerEvents prop invalidate documents - switched to using a function to avoid flickering on PDFs of annotations in particular. --- src/Utils.ts | 4 +++ src/client/views/InkingStroke.tsx | 2 +- src/client/views/SidebarAnnos.tsx | 4 +-- src/client/views/StyleProvider.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 14 +++++---- src/client/views/nodes/ComparisonBox.tsx | 4 +-- src/client/views/nodes/DocumentView.tsx | 4 +-- src/client/views/nodes/FieldView.tsx | 4 +-- src/client/views/nodes/MapBox/MapBox.tsx | 10 +++++-- src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 4 +-- src/client/views/nodes/PDFBox.tsx | 1 - src/client/views/nodes/WebBox.tsx | 12 ++++---- src/client/views/pdf/Annotation.tsx | 6 ++-- src/client/views/pdf/PDFViewer.tsx | 34 ++++------------------ 14 files changed, 46 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/Utils.ts b/src/Utils.ts index 205f9379e..c3c13a555 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -440,6 +440,10 @@ export function returnTrue() { return true; } export function returnFalse() { return false; } +export function returnAll() { return "all"; } + +export function returnNone() { return "none"; } + export function returnVal(val1?: number, val2?: number) { return val1 !== undefined ? val1 : val2 !== undefined ? val2 : 0; } export function returnOne() { return 1; } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 5e9990444..3d9c048e5 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -332,7 +332,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkStrokeWidth, inkStrokeWidth + (highlightIndex && closed && fillColor && (new Color(fillColor)).alpha() < 1 ? 6 : 15), StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker, - markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, + markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, false, downHdlr); const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", "")); // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 04c0565ea..9e939aa19 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -4,7 +4,7 @@ import { Doc, DocListCast, StrListCast, Opt } from "../../fields/Doc"; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { NumCast, StrCast } from '../../fields/Types'; -import { emptyFunction, OmitKeys, returnOne, returnTrue, returnZero } from '../../Utils'; +import { emptyFunction, OmitKeys, returnAll, returnOne, returnTrue, returnZero } from '../../Utils'; import { Docs, DocUtils } from '../documents/Documents'; import { Transform } from '../util/Transform'; import { CollectionStackingView } from './collections/CollectionStackingView'; @@ -147,7 +147,7 @@ export class SidebarAnnos extends React.Component { renderDepth={this.props.renderDepth + 1} viewType={CollectionViewType.Stacking} fieldKey={this.sidebarKey} - pointerEvents={"all"} + pointerEvents={returnAll} /> ; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index ca9826ab9..5056dedaf 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -204,7 +204,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt this.props.isSelected() || this.props.isContentActive(); + pointerEvents = () => { + const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); + const pointerEvents = this.props.isContentActive() === false ? "none" : this.backgroundActive || this.props.childPointerEvents ? "all" : + (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : this.props.pointerEvents?.(); + return pointerEvents; + } getChildDocView(entry: PoolData) { const childLayout = entry.pair.layout; const childData = entry.pair.data; - const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); return ; @@ -1733,7 +1737,7 @@ export class CollectionFreeFormView extends CollectionSubView + pointerEvents={returnNone} /> {clearButton(which)} : // placeholder image if doc is missing
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 02ea87103..e117be0c2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -148,7 +148,7 @@ export interface DocumentViewSharedProps { ignoreAutoHeight?: boolean; forceAutoHeight?: boolean; disableDocBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. - pointerEvents?: string; + pointerEvents?: () => Opt; scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document createNewFilterDoc?: () => void; updateFilterDoc?: (doc: Doc) => void; @@ -870,7 +870,7 @@ export class DocumentViewInternal extends DocComponent {!this._retryThumb || !this.thumbShown() ? (null) : diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index ae9acfe3f..686b4308b 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { computed } from "mobx"; import { observer } from "mobx-react"; import { DateField } from "../../../fields/DateField"; -import { Doc, Field, FieldResult } from "../../../fields/Doc"; +import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc"; import { List } from "../../../fields/List"; import { WebField } from "../../../fields/URLField"; import { DocumentViewSharedProps } from "./DocumentView"; @@ -25,7 +25,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { setHeight?: (height: number) => void; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) - pointerEvents?: string; + pointerEvents?: () => Opt; fontSize?: number; height?: number; width?: number; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index e7fc38ecd..c0fd8d8a0 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -489,13 +489,17 @@ export class MapBox extends ViewBoxAnnotatableComponent { + return this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? + "all" : + SnappingManager.GetIsDragging() ? + undefined : "none"; + } @computed get annotationLayer() { - const pe = this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : - SnappingManager.GetIsDragging() ? undefined : "none"; return
{this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => )} + fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} />)}
; } diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx index 0d5fedb7b..db7dcb09d 100644 --- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx +++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react"; import * as React from "react"; import { Doc } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; -import { emptyFunction, OmitKeys, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents } from '../../../../Utils'; +import { emptyFunction, OmitKeys, returnAll, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; import { CollectionStackingView } from '../../collections/CollectionStackingView'; @@ -79,7 +79,7 @@ export class MapBoxInfoWindow extends React.Component (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, "data", d), true as boolean)} renderDepth={this.props.renderDepth + 1} viewType={CollectionViewType.Stacking} - pointerEvents="all" + pointerEvents={returnAll} />

diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index e6e723ef1..35b5e78a8 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -416,7 +416,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index f441e5d36..f01dba4d0 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -12,10 +12,9 @@ import { ComputedField } from "../../../fields/ScriptField"; import { Cast, ImageCast, NumCast, StrCast } from "../../../fields/Types"; import { ImageField, WebField } from "../../../fields/URLField"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from "../../../Utils"; +import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; -import { KeyCodes } from "../../util/KeyCodes"; import { ScriptingGlobals } from "../../util/ScriptingGlobals"; import { SnappingManager } from "../../util/SnappingManager"; import { undoBatch } from "../../util/UndoManager"; @@ -648,7 +647,7 @@ export class WebBox extends ViewBoxAnnotatableComponent e.stopPropagation()} style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]) || `100%` : "100%", }}> @@ -658,10 +657,9 @@ export class WebBox extends ViewBoxAnnotatableComponent {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => - )} + )} ; } @@ -703,9 +701,9 @@ export class WebBox extends ViewBoxAnnotatableComponent !this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none"; + pointerEvents = () => !this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none"; render() { - const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents ? this.props.pointerEvents as any : undefined; + const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents?.() as any; const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const scale = previewScale * (this.props.scaling?.() || 1); const renderAnnotations = (docFilters?: () => string[]) => diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index b1d1d8293..218f37f3d 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -16,7 +16,7 @@ interface IAnnotationProps extends FieldViewProps { dataDoc: Doc; fieldKey: string; showInfo: (anno: Opt) => void; - pointerEvents?: string; + pointerEvents?: () => Opt; } @observer export @@ -28,7 +28,7 @@ export interface IRegionAnnotationProps extends IAnnotationProps { document: Doc; - pointerEvents?: string; + pointerEvents?: () => Opt; } @observer class RegionAnnotation extends React.Component { @@ -98,7 +98,7 @@ class RegionAnnotation extends React.Component { width: NumCast(this.props.document._width), height: NumCast(this.props.document._height), opacity: this._brushed ? 0.5 : undefined, - pointerEvents: this.props.pointerEvents as any, + pointerEvents: this.props.pointerEvents?.() as any, backgroundColor: this._brushed ? "orange" : StrCast(this.props.document.backgroundColor), }} > ); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 7ad452e54..608ba07ff 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -8,7 +8,7 @@ import { InkTool } from "../../../fields/InkField"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { PdfField } from "../../../fields/URLField"; import { TraceMobx } from "../../../fields/util"; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils } from "../../../Utils"; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, returnFalse, smoothScroll, Utils } from "../../../Utils"; import { DocUtils } from "../../documents/Documents"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { SelectionManager } from "../../util/SelectionManager"; @@ -41,7 +41,6 @@ interface IViewerProps extends FieldViewProps { fieldKey: string; pdf: Pdfjs.PDFDocumentProxy; url: string; - startupLive: boolean; loaded?: (nw: number, nh: number, np: number) => void; setPdfViewer: (view: PDFViewer) => void; ContentScaling?: () => number; @@ -89,28 +88,8 @@ export class PDFViewer extends React.Component { @computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); } componentDidMount = async () => { - // change the address to be the file address of the PNG version of each page - // file address of the pdf - const { url: { href } } = Cast(this.props.dataDoc[this.props.fieldKey], PdfField)!; - const { url: relative } = this.props; - if (relative.includes("/pdfs/")) { - const pathComponents = relative.split("/pdfs/")[1].split("/"); - const coreFilename = pathComponents.pop()!.split(".")[0]; - const params: any = { - coreFilename, - pageNum: Math.min(this.props.pdf.numPages, Math.max(1, NumCast(this.props.Document._curPage, 1))), - }; - if (pathComponents.length) { - params.subtree = `${pathComponents.join("/")}/`; - } - } else { - const params: any = { - coreFilename: relative.split("/")[relative.split("/").length - 1], - pageNum: Math.min(this.props.pdf.numPages, Math.max(1, NumCast(this.props.Document._curPage, 1))), - }; - } runInAction(() => this._showWaiting = true); - this.props.startupLive && this.setupPdfJsViewer(); + this.setupPdfJsViewer(); this._mainCont.current?.addEventListener("scroll", e => (e.target as any).scrollLeft = 0); this._disposers.autoHeight = reaction(() => this.props.layoutDoc._autoHeight, @@ -456,12 +435,11 @@ export class PDFViewer extends React.Component { } } - pointerEvents = () => this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none"; + pointerEvents = () => this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none"; @computed get annotationLayer() { - const pe = this.pointerEvents(); return
{this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => - )} + )}
; } @@ -536,7 +514,7 @@ export class PDFViewer extends React.Component { ; } @computed get pdfViewerDiv() { - return
; + return
; } @computed get contentScaling() { return this.props.ContentScaling?.() || 1; } contentZoom = () => this._zoomed; @@ -544,7 +522,7 @@ export class PDFViewer extends React.Component { render() { TraceMobx(); return
-