diff options
| author | anika-ahluwalia <anika.ahluwalia@gmail.com> | 2020-04-29 17:21:06 -0500 |
|---|---|---|
| committer | anika-ahluwalia <anika.ahluwalia@gmail.com> | 2020-04-29 17:21:06 -0500 |
| commit | a3d0d5cb8d00eb6c360c95e0c5c03e37b218e49a (patch) | |
| tree | 734f941feef0c87e2c15cb0c323334de29cafcaf /src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | |
| parent | 7b8651a1a1f824e6c6a5135a4420766686f35175 (diff) | |
| parent | d66aaffc27405f4231a29cd6edda3477077ae946 (diff) | |
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into script_documents
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 125 |
1 files changed, 73 insertions, 52 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1f0bc89c5..d85233041 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -32,7 +32,7 @@ import { ContextMenuProps } from "../../ContextMenuItem"; import { InkingControl } from "../../InkingControl"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentViewProps, DocumentView } from "../../nodes/DocumentView"; -import { FormattedTextBox } from "../../nodes/FormattedTextBox"; +import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; import { pageSchema } from "../../nodes/ImageBox"; import PDFMenu from "../../pdf/PDFMenu"; import { CollectionDockingView } from "../CollectionDockingView"; @@ -44,6 +44,7 @@ import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { CollectionViewType } from "../CollectionView"; +import { Timeline } from "../../animationtimeline/Timeline"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); @@ -85,14 +86,16 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P private _clusterDistance: number = 75; private _hitCluster = false; private _layoutComputeReaction: IReactionDisposer | undefined; - private _layoutPoolData = new ObservableMap<string, any>(); - private _cachedPool: Map<string, any> = new Map(); + private _layoutPoolData = new ObservableMap<string, PoolData>(); + private _layoutSizeData = new ObservableMap<string, { width?: number, height?: number }>(); + private _cachedPool: Map<string, PoolData> = new Map(); @observable private _pullCoords: number[] = [0, 0]; @observable private _pullDirection: string = ""; public get displayName() { return "CollectionFreeFormView(" + this.props.Document.title?.toString() + ")"; } // this makes mobx trace() statements more descriptive @observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables @observable _clusterSets: (Doc[])[] = []; + @observable _timelineRef = React.createRef<Timeline>(); @computed get fitToContentScaling() { return this.fitToContent ? NumCast(this.layoutDoc.fitToContentScaling, 1) : 1; } @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; } @@ -508,7 +511,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P if (this.layoutDoc.targetScale && (Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) { if (Date.now() - this._lastTap < 300) { const docpt = this.getTransform().transformPoint(e.clientX, e.clientY); - this.scaleAtPt(docpt, NumCast(this.layoutDoc.targetScale, NumCast(this.layoutDoc.scale))); + this.scaleAtPt(docpt, 1); e.stopPropagation(); e.preventDefault(); } @@ -728,7 +731,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P if (!this.isAnnotationOverlay && clamp) { // this section wraps the pan position, horizontally and/or vertically whenever the content is panned out of the viewing bounds const docs = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout); - const measuredDocs = docs.filter(doc => doc && this.childDataProvider(doc)).map(doc => this.childDataProvider(doc)); + const measuredDocs = docs.filter(doc => doc && this.childDataProvider(doc, "")).map(doc => this.childDataProvider(doc, "")); if (measuredDocs.length) { const ranges = measuredDocs.reduce(({ xrange, yrange }, { x, y, width, height }) => // computes range of content ({ @@ -821,18 +824,18 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document.scale, pt: this.Document.panTransformType }; - if (!willZoom && DocumentView._focusHack.length) { - Doc.BrushDoc(this.props.Document); - !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1); - } else { - if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) { - if (!doc.z) this.setPan(newPanX, newPanY, "Ease", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow - } - Doc.BrushDoc(this.props.Document); - this.props.focus(this.props.Document); - willZoom && this.setScaleToZoom(layoutdoc, scale); + // if (!willZoom && DocumentView._focusHack.length) { + // Doc.BrushDoc(this.props.Document); + // !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1); + // } else { + if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) { + if (!doc.z) this.setPan(newPanX, newPanY, "Ease", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow } + Doc.BrushDoc(this.props.Document); + this.props.focus(this.props.Document); + willZoom && this.setScaleToZoom(layoutdoc, scale); Doc.linkFollowHighlight(doc); + //} afterFocus && setTimeout(() => { if (afterFocus?.()) { @@ -853,7 +856,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; } @computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); } backgroundHalo = () => BoolCast(this.Document.useClusters); - + @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); } + parentActive = () => this.props.active() || this.backgroundActive ? true : false; getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { return { ...this.props, @@ -879,7 +883,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P focus: this.focusDocument, backgroundColor: this.getClusterColor, backgroundHalo: this.backgroundHalo, - parentActive: this.props.active, + parentActive: this.parentActive, bringToFront: this.bringToFront, addDocTab: this.addDocTab, }; @@ -899,16 +903,16 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } return this.props.addDocTab(doc, where); }); - getCalculatedPositions(params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): PoolData { + getCalculatedPositions(params: { pair: { layout: Doc, data?: Doc }, index: number, collection: Doc, docs: Doc[], state: any }): PoolData { const result = this.Document.arrangeScript?.script.run(params, console.log); if (result?.success) { - return { ...result, transition: "transform 1s" }; + return { x: 0, y: 0, transition: "transform 1s", ...result, pair: params.pair, replica: "" }; } - const layoutDoc = Doc.Layout(params.doc); - const { x, y, z, color, zIndex } = params.doc; + const layoutDoc = Doc.Layout(params.pair.layout); + const { x, y, z, color, zIndex } = params.pair.layout; return { x: NumCast(x), y: NumCast(y), z: Cast(z, "number"), color: StrCast(color), zIndex: Cast(zIndex, "number"), - width: Cast(layoutDoc._width, "number"), height: Cast(layoutDoc._height, "number") + width: Cast(layoutDoc._width, "number"), height: Cast(layoutDoc._height, "number"), pair: params.pair, replica: "" }; } @@ -946,21 +950,22 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } } - childDataProvider = computedFn(function childDataProvider(this: any, doc: Doc) { - return this._layoutPoolData.get(doc[Id]); + childDataProvider = computedFn(function childDataProvider(this: any, doc: Doc, replica: string) { + return this._layoutPoolData.get(doc[Id] + (replica || "")); + }.bind(this)); + childSizeProvider = computedFn(function childSizeProvider(this: any, doc: Doc, replica: string) { + return this._layoutSizeData.get(doc[Id] + (replica || "")); }.bind(this)); doEngineLayout(poolData: Map<string, PoolData>, engine: ( poolData: Map<string, PoolData>, pivotDoc: Doc, - childDocs: Doc[], - filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], - viewDefsToJSX: ((views: ViewDefBounds[]) => ViewDefResult[])) => ViewDefResult[]) { - return engine(poolData, this.props.Document, this.childDocs, this.childDocs, - this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); + viewDefsToJSX: ((views: ViewDefBounds[]) => ViewDefResult[])) => ViewDefResult[] + ) { + return engine(poolData, this.props.Document, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); } doFreeformLayout(poolData: Map<string, PoolData>) { @@ -970,15 +975,18 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : []; this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { - const pos = this.getCalculatedPositions({ doc: pair.layout, index: i, collection: this.Document, docs: layoutDocs, state }); + const pos = this.getCalculatedPositions({ pair, index: i, collection: this.Document, docs: layoutDocs, state }); poolData.set(pair.layout[Id], pos); }); return elements; } @computed get doInternalLayoutComputation() { - const newPool = new Map<string, any>(); - const engine = StrCast(this.layoutDoc._layoutEngine) || this.props.layoutEngine?.(); + TraceMobx(); + + + const newPool = new Map<string, PoolData>(); + const engine = this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine); switch (engine) { case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) }; case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; @@ -992,30 +1000,39 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P get doLayoutComputation() { const { newPool, computedElementData } = this.doInternalLayoutComputation; runInAction(() => - Array.from(newPool.keys()).map(key => { - const lastPos = this._cachedPool.get(key); // last computed pos - const newPos = newPool.get(key); - if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex || newPos.width !== lastPos.width || newPos.height !== lastPos.height) { - this._layoutPoolData.set(key, newPos); + Array.from(newPool.entries()).map(entry => { + const lastPos = this._cachedPool.get(entry[0]); // last computed pos + const newPos = entry[1]; + if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex) { + this._layoutPoolData.set(entry[0], newPos); + } + if (!lastPos || newPos.height !== lastPos.height || newPos.width !== lastPos.width) { + this._layoutSizeData.set(entry[0], { width: newPos.width, height: newPos.height }); } })); this._cachedPool.clear(); - Array.from(newPool.keys()).forEach(k => this._cachedPool.set(k, newPool.get(k))); + Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1])); const elements: ViewDefResult[] = computedElementData.slice(); - const engine = this.props.layoutEngine?.() || this.props.Document._layoutEngine; - this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).forEach(pair => + const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); + Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach(entry => elements.push({ ele: <CollectionFreeFormDocumentView - key={pair.layout[Id]} - {...this.getChildDocumentViewProps(pair.layout, pair.data)} + key={entry[1].pair.layout[Id] + (entry[1].replica || "")} + {...this.getChildDocumentViewProps(entry[1].pair.layout, entry[1].pair.data)} + replica={entry[1].replica} dataProvider={this.childDataProvider} + sizeProvider={this.childSizeProvider} LayoutDoc={this.childLayoutDocFunc} - pointerEvents={engine && engine !== "starburst" ? false : undefined} - jitterRotation={NumCast(this.props.Document.jitterRotation)} - fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} + pointerEvents={ + this.backgroundActive ? + true : + (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? false : undefined} + jitterRotation={NumCast(this.props.Document._jitterRotation)} + //fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this + fitToBox={BoolCast(this.props.freezeChildDimensions)} // bcz: check this FreezeDimensions={BoolCast(this.props.freezeChildDimensions)} />, - bounds: this.childDataProvider(pair.layout) + bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica) })); return elements; @@ -1076,6 +1093,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const options = ContextMenu.Instance.findByDescription("Options..."); const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; + this._timelineRef.current!.timelineContextMenu(e); optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); @@ -1083,7 +1101,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" }); optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); - optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = (this.props.Document.jitterRotation ? 0 : 10)), icon: "paint-brush" }); + optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document._jitterRotation = (this.props.Document._jitterRotation ? 0 : 10)), icon: "paint-brush" }); optionItems.push({ description: "Import document", icon: "upload", event: ({ x, y }) => { const input = document.createElement("input"); @@ -1111,8 +1129,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P input.click(); } }); - - ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); + ContextMenu.Instance.addItem({ description: "Options ...", subitems: optionItems, icon: "eye" }); + this._timelineRef.current!.timelineContextMenu(e); } private childViews = () => { @@ -1150,9 +1168,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P return <MarqueeView {...this.props} nudge={this.nudge} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument} addLiveTextDocument={this.addLiveTextBox} getContainerTransform={this.getContainerTransform} getTransform={this.getTransform} isAnnotationOverlay={this.isAnnotationOverlay}> <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} shifted={!this.nativeHeight && !this.isAnnotationOverlay} - easing={this.easing} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}> + easing={this.easing} viewDefDivClick={this.props.viewDefDivClick} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}> {this.children} </CollectionFreeFormViewPannableContents> + <Timeline ref={this._timelineRef} {...this.props} /> </MarqueeView>; } @@ -1164,6 +1183,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const wscale = nw ? this.props.PanelWidth() / nw : 1; return wscale < hscale ? wscale : hscale; } + @computed get backgroundEvents() { return this.layoutDoc.isBackground && SelectionManager.GetIsDragging(); } render() { TraceMobx(); const clientRect = this._mainCont?.getBoundingClientRect(); @@ -1179,7 +1199,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P onWheel={this.onPointerWheel} onClick={this.onClick} //pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined, onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} style={{ - pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined, + pointerEvents: this.backgroundEvents ? "all" : undefined, transform: this.contentScaling ? `scale(${this.contentScaling})` : "", transformOrigin: this.contentScaling ? "left top" : "", width: this.contentScaling ? `${100 / this.contentScaling}%` : "", @@ -1223,6 +1243,7 @@ interface CollectionFreeFormViewPannableContentsProps { panY: () => number; zoomScaling: () => number; easing: () => boolean; + viewDefDivClick?: ScriptField; children: () => JSX.Element[]; shifted: boolean; } @@ -1230,7 +1251,7 @@ interface CollectionFreeFormViewPannableContentsProps { @observer class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{ render() { - const freeformclass = "collectionfreeformview" + (this.props.easing() ? "-ease" : "-none"); + const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : (this.props.easing() ? "-ease" : "-none")); const cenx = this.props.centeringShiftX(); const ceny = this.props.centeringShiftY(); const panx = -this.props.panX(); |
