diff options
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 81 |
1 files changed, 47 insertions, 34 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b2fb5848e..079a5d977 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, makeObservable, observable, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; @@ -17,7 +17,7 @@ import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../ import { ImageField } from '../../../../fields/URLField'; import { TraceMobx } from '../../../../fields/util'; import { GestureUtils } from '../../../../pen-gestures/GestureUtils'; -import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, numberValue, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; import { Docs, DocUtils } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; @@ -76,7 +76,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @observable _paintedId = 'id' + Utils.GenerateGuid().replace(/-/g, ''); @computed get paintFunc() { - const field = this.layoutDoc[this.fieldKey]; + const field = this.dataDoc[this.fieldKey]; const paintFunc = StrCast(Field.toJavascriptString(Cast(field, RichTextField, null)?.Text as Field)).trim(); return !paintFunc ? '' @@ -169,17 +169,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @computed get nativeHeight() { return this._props.NativeHeight?.() || Doc.NativeHeight(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null)); } - @computed get cachedCenteringShiftX(): number { - const scaling = !this.nativeDimScaling ? 1 : this.nativeDimScaling; + @computed get centeringShiftX(): number { + const scaling = this.nativeDimScaling; return this._props.isAnnotationOverlay || this._props.originTopLeft ? 0 : this._props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections } - @computed get cachedCenteringShiftY(): number { + @computed get centeringShiftY(): number { + const panLocAtCenter = !(this._props.isAnnotationOverlay || this._props.originTopLeft); + if (!panLocAtCenter) return 0; const dv = this.DocumentView?.(); - const fitWidth = this._props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth; - const scaling = !this.nativeDimScaling ? 1 : this.nativeDimScaling; + const aspect = !(this._props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth) && dv?.nativeWidth && dv?.nativeHeight; + const scaling = this.nativeDimScaling; // if freeform has a native aspect, then the panel height needs to be adjusted to match it - const aspect = dv?.nativeWidth && dv?.nativeHeight && !fitWidth ? dv.nativeHeight / dv.nativeWidth : this._props.PanelHeight() / this._props.PanelWidth(); - return this._props.isAnnotationOverlay || this._props.originTopLeft ? 0 : (aspect * this._props.PanelWidth()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections + const height = aspect ? (dv.nativeHeight / dv.nativeWidth) * this._props.PanelWidth() : this._props.PanelHeight(); + return height / 2 / scaling; // shift so pan position is at center of window for non-overlay collections } @computed get panZoomXf() { return new Transform(this.panX(), this.panY(), 1 / this.zoomScaling()); @@ -187,7 +189,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @computed get screenToFreeformContentsXf() { return this._props .ScreenToLocalTransform() // - .translate(-this.cachedCenteringShiftX, -this.cachedCenteringShiftY) + .translate(-this.centeringShiftX, -this.centeringShiftY) .transform(this.panZoomXf); } @@ -250,8 +252,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panX, 1)); panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panY, 1)); zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], 1); //, NumCast(DocCast(this.Document.resolvedDataDoc)?.[this.scaleFieldKey], 1)); - PanZoomCenterXf = () => - this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; + PanZoomCenterXf = () => (this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.centeringShiftX}px, ${this.centeringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`); ScreenToContentsXf = () => this.screenToFreeformContentsXf.copy(); getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); isAnyChildContentActive = () => this._props.isAnyChildContentActive(); @@ -314,7 +315,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection // options.didMove = true; // } } - if (anchor.type !== DocumentType.CONFIG && !DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]).includes(anchor)) return; + if (anchor.type !== DocumentType.CONFIG && !DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]).includes(anchor) && !this.childLayoutPairs.map(pair => pair.layout).includes(anchor)) return; const xfToCollection = options?.docTransform ?? Transform.Identity(); 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.Document.isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc); @@ -335,6 +336,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> => new Promise<Opt<DocumentView>>(res => { if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false); + if (doc === this.Document) return res(this.DocumentView?.()); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); findDoc(dv => res(dv)); }); @@ -564,7 +566,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection clusterStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => { let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 if (doc && this.childDocList?.includes(doc)) - switch (property) { + switch (property.split(':')[0]) { case StyleProp.BackgroundColor: const cluster = NumCast(doc?.layout_cluster); if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) { @@ -589,7 +591,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; trySelectCluster = (addToSel: boolean) => { - if (this._hitCluster !== -1) { + if (addToSel && this._hitCluster !== -1) { !addToSel && SelectionManager.DeselectAll(); const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster); this.selectDocuments(eles); @@ -647,7 +649,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection x: B.x - inkWidth / 2, y: B.y - inkWidth / 2, _width: B.width + inkWidth, - _height: B.height + inkWidth }, // prettier-ignore + _height: B.height + inkWidth, + stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore inkWidth ); if (Doc.ActiveTool === InkTool.Write) { @@ -1112,9 +1115,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (scale !== undefined) { const maxZoom = 5; // sets the limit for how far we will zoom. this is useful for preventing small text boxes from filling the screen. So probably needs to be more sophisticated to consider more about the target and context const newScale = - scale === 0 - ? NumCast(this.layoutDoc[this.scaleFieldKey]) - : Math.min(maxZoom, (1 / (this.nativeDimScaling || 1)) * scale * Math.min(this._props.PanelWidth() / Math.abs(bounds.width), this._props.PanelHeight() / Math.abs(bounds.height))); + scale === 0 ? NumCast(this.layoutDoc[this.scaleFieldKey]) : Math.min(maxZoom, (1 / this.nativeDimScaling) * scale * Math.min(this._props.PanelWidth() / Math.abs(bounds.width), this._props.PanelHeight() / Math.abs(bounds.height))); return { panX: this._props.isAnnotationOverlay ? bounds.left - (Doc.NativeWidth(this.layoutDoc) / newScale - bounds.width) / 2 : (bounds.left + bounds.right) / 2, panY: this._props.isAnnotationOverlay ? bounds.top - (Doc.NativeHeight(this.layoutDoc) / newScale - bounds.height) / 2 : (bounds.top + bounds.bot) / 2, @@ -1261,7 +1262,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._lightboxDoc = doc; return true; } - if (this.childDocList?.includes(doc)) { + if (doc === this.Document || this.childDocList?.includes(doc) || this.childLayoutPairs.map(pair => pair.layout)?.includes(doc)) { if (doc.hidden) doc.hidden = false; return true; } @@ -1286,15 +1287,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const rotation = Cast(_rotation,'number', !this.layoutDoc._rotation_jitter ? null : NumCast(this.layoutDoc._rotation_jitter) * random(-1, 1, NumCast(x), NumCast(y)) ); + const childProps = { ...this._props, fieldKey: '', styleProvider: this.clusterStyleProvider }; return { x: Number.isNaN(NumCast(x)) ? 0 : NumCast(x), y: Number.isNaN(NumCast(y)) ? 0 : NumCast(y), z: Cast(z, 'number'), autoDim, rotation, - color: Cast(color, 'string') ? StrCast(color) : this._props.styleProvider?.(childDoc, this._props, StyleProp.Color), - backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.clusterStyleProvider(childDoc, this._props, StyleProp.BackgroundColor), - opacity: !_width ? 0 : this._keyframeEditing ? 1 : Cast(opacity, 'number') ?? this._props.styleProvider?.(childDoc, this._props, StyleProp.Opacity), + color: Cast(color, 'string') ? StrCast(color) : this.clusterStyleProvider(childDoc, childProps, StyleProp.Color), + backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.clusterStyleProvider(childDoc, childProps, StyleProp.BackgroundColor), + opacity: !_width ? 0 : this._keyframeEditing ? 1 : Cast(opacity, 'number') ?? this.clusterStyleProvider?.(childDoc, childProps, StyleProp.Opacity), zIndex: Cast(zIndex, 'number'), width: _width, height: _height, @@ -1404,8 +1406,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type) - const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.Document }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } }, this.Document); + const anchor = Docs.Create.ConfigDocument({ + title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), + layout_unrendered: true, + presentation_transition: 500, + annotationOn: this.Document, + }); + PresBox.pinDocView( + anchor, + { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ? { ...pinProps.pinData, poslayoutview: pinProps.pinData.dataview } : {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } }, + this.Document + ); if (addAsAnnotation) { if (Cast(this.dataDoc[this._props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) { @@ -1713,7 +1724,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection horizLines.push(topLeftInScreen[1], topLeftInScreen[1] + docSize[1] / 2, topLeftInScreen[1] + docSize[1]); // horiz center line vertLines.push(topLeftInScreen[0], topLeftInScreen[0] + docSize[0] / 2, topLeftInScreen[0] + docSize[0]); // right line }); - SnappingManager.addSnapLines(horizLines, vertLines); + this.layoutDoc._freeform_snapLines && SnappingManager.addSnapLines(horizLines, vertLines); }; incrementalRendering = () => this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])).length !== 0; @@ -1755,8 +1766,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection zoomScaling={this.zoomScaling} layoutDoc={this.layoutDoc} isAnnotationOverlay={this.isAnnotationOverlay} - cachedCenteringShiftX={this.cachedCenteringShiftX} - cachedCenteringShiftY={this.cachedCenteringShiftY} + centeringShiftX={this.centeringShiftX} + centeringShiftY={this.centeringShiftY} /> </div> ); @@ -1804,7 +1815,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } @computed get nativeDimScaling() { - if (this._firstRender || (this._props.isAnnotationOverlay && !this._props.annotationLayerHostsContent)) return 0; + if (this._firstRender || (this._props.isAnnotationOverlay && !this._props.annotationLayerHostsContent)) return 1; const nw = this.nativeWidth; const nh = this.nativeHeight; const hscale = nh ? this._props.PanelHeight() / nh : 1; @@ -1858,11 +1869,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection style={{ pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : (this._props.pointerEvents?.() as any), textAlign: this.isAnnotationOverlay ? 'initial' : undefined, - transform: `scale(${this.nativeDimScaling || 1})`, - width: `${100 / (this.nativeDimScaling || 1)}%`, - height: this._props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`, + transform: `scale(${this.nativeDimScaling})`, + width: `${100 / this.nativeDimScaling}%`, + height: this._props.getScrollHeight?.() ?? `${100 / this.nativeDimScaling}%`, }}> - {this.paintFunc ? null : this._lightboxDoc ? ( + {this.paintFunc ? ( + <FormattedTextBox {...this.props} /> // need this so that any live dashfieldviews will update the underlying text that the code eval reads + ) : this._lightboxDoc ? ( <div style={{ padding: 15, width: '100%', height: '100%' }}> <DocumentView {...this._props} |