diff options
Diffstat (limited to 'src')
6 files changed, 96 insertions, 57 deletions
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 3c66faf0c..3bdc427d6 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -28,7 +28,7 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume componentWillUnmount() { this._dropDisposer?.(); } - protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view this._dropDisposer?.(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 6c2c27e8e..733c07031 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -23,7 +23,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) componentWillUnmount() { this._dropDisposer?.(); } - protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view this._dropDisposer?.(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3443f33e1..3d664e146 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,5 +1,5 @@ import { Bezier } from "bezier-js"; -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"; @@ -95,6 +95,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P private _clusterDistance: number = 75; private _hitCluster: number = -1; private _disposers: { [name: string]: IReactionDisposer } = {}; + private _renderCutoffData = observable.map<string, boolean>(); private _layoutPoolData = observable.map<string, PoolData>(); private _layoutSizeData = observable.map<string, { width?: number, height?: number }>(); private _cachedPool: Map<string, PoolData> = new Map(); @@ -1155,7 +1156,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P renderDepth={this.props.renderDepth + 1} replica={entry.replica} renderIndex={renderIndex} - renderCutoff={this.NumLoaded} + renderCutoffProvider={this.renderCutoffProvider} ContainingCollectionView={this.props.CollectionView} ContainingCollectionDoc={this.props.Document} CollectionFreeFormView={this} @@ -1259,6 +1260,12 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } } + + renderCutoffProvider = computedFn(function renderCutoffProvider(this: any, doc: Doc) { + return !this._renderCutoffData.get(doc[Id] + ""); + }.bind(this)); + + childPositionProviderUnmemoized = (doc: Doc, replica: string) => { return this._layoutPoolData.get(doc[Id] + (replica || "")); } @@ -1304,7 +1311,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } @observable _numLoaded = 1; - NumLoaded = () => this._numLoaded; get doLayoutComputation() { const { newPool, computedElementData } = this.doInternalLayoutComputation; const array = Array.from(newPool.entries()); @@ -1567,9 +1573,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P incrementalRender = action(() => { if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())) { - this._numLoaded++; + const unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); + const loadIncrement = 5; + for (var i = 0; i < Math.min(unrendered.length, loadIncrement); i++) { + this._renderCutoffData.set(unrendered[i][Id] + "", true); + } } - this._numLoaded < this.views.length && setTimeout(this.incrementalRender, 1); + this.childDocs.some(doc => !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); }); children = () => { @@ -1582,46 +1592,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P ]; } - chooseGridSpace = (gridSpace: number): number => { - if (!this.zoomScaling()) return 50; - const divisions = this.props.PanelWidth() / this.zoomScaling() / gridSpace + 3; - return divisions < 60 ? gridSpace : this.chooseGridSpace(gridSpace * 10); - } - - @computed get backgroundGrid() { - const gridSpace = this.chooseGridSpace(NumCast(this.layoutDoc["_backgroundGrid-spacing"], 50)); - const shiftX = (this.props.isAnnotationOverlay ? 0 : -this.panX() % gridSpace - gridSpace) * this.zoomScaling(); - const shiftY = (this.props.isAnnotationOverlay ? 0 : -this.panY() % gridSpace - gridSpace) * this.zoomScaling(); - const renderGridSpace = gridSpace * this.zoomScaling(); - const w = this.props.PanelWidth() + 2 * renderGridSpace; - const h = this.props.PanelHeight() + 2 * renderGridSpace; - const strokeStyle = CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark ? "rgba(255,255,255,0.5)" : "rgba(0, 0,0,0.5)"; - return <canvas className="collectionFreeFormView-grid" width={w} height={h} style={{ transform: `translate(${shiftX}px, ${shiftY}px)` }} - ref={(el) => { - const ctx = el?.getContext('2d'); - if (ctx) { - const Cx = this.cachedCenteringShiftX % renderGridSpace; - const Cy = this.cachedCenteringShiftY % renderGridSpace; - ctx.lineWidth = Math.min(1, Math.max(0.5, this.zoomScaling())); - ctx.setLineDash(gridSpace > 50 ? [3, 3] : [1, 5]); - ctx.clearRect(0, 0, w, h); - if (ctx) { - ctx.strokeStyle = strokeStyle; - ctx.beginPath(); - for (let x = Cx - renderGridSpace; x <= w - Cx; x += renderGridSpace) { - ctx.moveTo(x, Cy - h); - ctx.lineTo(x, Cy + h); - } - for (let y = Cy - renderGridSpace; y <= h - Cy; y += renderGridSpace) { - ctx.moveTo(Cx - w, y); - ctx.lineTo(Cx + w, y); - } - ctx.stroke(); - } - } - }} />; - } - @computed get placeholder() { return <div className="collectionfreeformview-placeholder" style={{ background: this.Document.backgroundColor }}> <span className="collectionfreeformview-placeholderSpan">{this.props.Document.title?.toString()}</span> @@ -1629,6 +1599,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } @computed get marqueeView() { + TraceMobx(); return <MarqueeView {...this.props} ungroup={this.props.Document._isGroup ? this.promoteCollection : undefined} @@ -1643,7 +1614,18 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P getTransform={this.getTransform} isAnnotationOverlay={this.isAnnotationOverlay}> <div className="marqueeView-div" ref={this._marqueeRef} style={{ opacity: this.props.dontRenderDocuments ? 0 : undefined }}> - {this.layoutDoc._backgroundGridShow ? this.backgroundGrid : (null)} + {this.layoutDoc._backgroundGridShow ? + <CollectionFreeFormBackgroundGrid + PanelWidth={this.props.PanelWidth} + PanelHeight={this.props.PanelHeight} + panX={this.panX} + panY={this.panY} + zoomScaling={this.zoomScaling} + layoutDoc={this.layoutDoc} + isAnnotationOverlay={this.isAnnotationOverlay} + cachedCenteringShiftX={this.cachedCenteringShiftX} + cachedCenteringShiftY={this.cachedCenteringShiftY} + /> : (null)} <CollectionFreeFormViewPannableContents isAnnotationOverlay={this.isAnnotationOverlay} isAnnotationOverlayScrollable={this.props.isAnnotationOverlayScrollable} @@ -1874,4 +1856,59 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF {this.zoomProgressivize} </div>; } +} + +interface CollectionFreeFormViewBackgroundGridProps { + panX: () => number; + panY: () => number; + PanelWidth: () => number; + PanelHeight: () => number; + isAnnotationOverlay?: boolean; + zoomScaling: () => number; + layoutDoc: Doc; + cachedCenteringShiftX: number; + cachedCenteringShiftY: number; +} +@observer +class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFormViewBackgroundGridProps> { + + + chooseGridSpace = (gridSpace: number): number => { + if (!this.props.zoomScaling()) return 50; + const divisions = this.props.PanelWidth() / this.props.zoomScaling() / gridSpace + 3; + return divisions < 60 ? gridSpace : this.chooseGridSpace(gridSpace * 10); + } + render() { + const gridSpace = this.chooseGridSpace(NumCast(this.props.layoutDoc["_backgroundGrid-spacing"], 50)); + const shiftX = (this.props.isAnnotationOverlay ? 0 : -this.props.panX() % gridSpace - gridSpace) * this.props.zoomScaling(); + const shiftY = (this.props.isAnnotationOverlay ? 0 : -this.props.panY() % gridSpace - gridSpace) * this.props.zoomScaling(); + const renderGridSpace = gridSpace * this.props.zoomScaling(); + const w = this.props.PanelWidth() + 2 * renderGridSpace; + const h = this.props.PanelHeight() + 2 * renderGridSpace; + const strokeStyle = CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark ? "rgba(255,255,255,0.5)" : "rgba(0, 0,0,0.5)"; + return <canvas className="collectionFreeFormView-grid" width={w} height={h} style={{ transform: `translate(${shiftX}px, ${shiftY}px)` }} + ref={(el) => { + const ctx = el?.getContext('2d'); + if (ctx) { + const Cx = this.props.cachedCenteringShiftX % renderGridSpace; + const Cy = this.props.cachedCenteringShiftY % renderGridSpace; + ctx.lineWidth = Math.min(1, Math.max(0.5, this.props.zoomScaling())); + ctx.setLineDash(gridSpace > 50 ? [3, 3] : [1, 5]); + ctx.clearRect(0, 0, w, h); + if (ctx) { + ctx.strokeStyle = strokeStyle; + ctx.beginPath(); + for (let x = Cx - renderGridSpace; x <= w - Cx; x += renderGridSpace) { + ctx.moveTo(x, Cy - h); + ctx.lineTo(x, Cy + h); + } + for (let y = Cy - renderGridSpace; y <= h - Cy; y += renderGridSpace) { + ctx.moveTo(Cx - w, y); + ctx.lineTo(Cx + w, y); + } + ctx.stroke(); + } + } + }} />; + } }
\ No newline at end of file diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index d67122eff..9466d8753 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -74,7 +74,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { { fireImmediately: true } ); } - protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view this._dropDisposer && this._dropDisposer(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 460982c8a..235c8accb 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -18,17 +18,18 @@ import { StyleProp } from "../StyleProvider"; import "./CollectionFreeFormDocumentView.scss"; import { DocumentView, DocumentViewProps } from "./DocumentView"; import React = require("react"); +import { Id } from "../../../fields/FieldSymbols"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; sizeProvider?: (doc: Doc, replica: string) => { width: number, height: number } | undefined; layerProvider: ((doc: Doc, assign?: boolean) => boolean) | undefined; + renderCutoffProvider: (doc: Doc) => boolean; zIndex?: number; highlight?: boolean; jitterRotation: number; dataTransition?: string; replica: string; - renderCutoff: () => number; renderIndex: number; CollectionFreeFormView: CollectionFreeFormView; } @@ -178,10 +179,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF mixBlendMode, display: this.ZInd === -99 ? "none" : undefined }} > - {this.props.renderCutoff() >= this.props.renderIndex ? - <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} /> + {this.props.renderCutoffProvider(this.props.Document) ? + <div style={{ position: "absolute", width: this.panelWidth(), height: this.panelHeight(), background: "lightGreen" }} /> : - <div style={{ position: "absolute", width: this.panelWidth(), height: this.panelHeight(), background: "lightGreen" }}></div>} + <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} /> + } </div>; } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 91f2359af..6468913fb 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -986,7 +986,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ":caption"); @computed get innards() { TraceMobx(); - const ffscale = (this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1); + const ffscale = () => (this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1); const showTitle = this.ShowTitle?.split(":")[0]; const showTitleHover = this.ShowTitle?.includes(":hover"); const showCaption = !this.props.hideCaptions && this.Document._viewType !== CollectionViewType.Carousel ? StrCast(this.layoutDoc._showCaption) : undefined; @@ -994,14 +994,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps <div className="documentView-captionWrapper" style={{ pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : this.isContentActive() || this.props.isDocumentActive?.() ? "all" : undefined, - minWidth: 50 * ffscale, - maxHeight: `max(100%, ${20 * ffscale}px)` + minWidth: 50 * ffscale(), + maxHeight: `max(100%, ${20 * ffscale()}px)` }}> <FormattedTextBox {...OmitKeys(this.props, ['children']).omit} yPadding={10} xPadding={10} fieldKey={showCaption} - fontSize={12 * Math.max(1, 2 * ffscale / 3)} + fontSize={12 * Math.max(1, 2 * ffscale() / 3)} styleProvider={this.captionStyleProvider} dontRegisterView={true} noSidebar={true} |