diff options
| author | Jenny Yu <jennyyu212@outlook.com> | 2022-04-28 16:17:25 -0400 |
|---|---|---|
| committer | Jenny Yu <jennyyu212@outlook.com> | 2022-04-28 16:17:25 -0400 |
| commit | 83c615b1b9706818894ee74481afd4c2bf34fe61 (patch) | |
| tree | 6e6a242fdbe1d5c164fce9d0c1ae84b4423ed40c /src/client/views/collections/collectionFreeForm | |
| parent | 9f62b6d1c9848439671065dac9ed79bc393c83fa (diff) | |
| parent | 15bc17cbbe3816ab78ce653105ddff06bce18c59 (diff) | |
Merge branch 'master' into recording-jenny
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
4 files changed, 88 insertions, 39 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 9fed82dae..16c7df311 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -111,23 +111,25 @@ export function computerStarburstLayout( viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any ) { + const mustFit = pivotDoc[WidthSym]() !== panelDim[0]; // if a panel size is set that's not the same as the pivot doc's size, then assume this is in a panel for a content fitting view (like a grid) in which case everything must be scaled to stay within the panel const docMap = new Map<string, PoolData>(); - const burstRadius = [NumCast(pivotDoc._starburstRadius, panelDim[0]), NumCast(pivotDoc._starburstRadius, panelDim[1])]; - const docScale = NumCast(pivotDoc._starburstDocScale); - const docSize = docScale * 100; // assume a icon sized at 100 - const scaleDim = [burstRadius[0] + docSize, burstRadius[1] + docSize]; + const docSize = mustFit ? panelDim[0] * .33 : 75; // assume an icon sized at 75 + const burstRadius = mustFit ? panelDim : [NumCast(pivotDoc._starburstRadius, panelDim[0]) - docSize, NumCast(pivotDoc._starburstRadius, panelDim[1]) - docSize]; + const scaleDim = [burstRadius[0] * 2 + docSize, burstRadius[1] * 2 + docSize]; childPairs.forEach(({ layout, data }, i) => { + const docSize = layout.layoutKey === "layout_icon" ? (mustFit ? panelDim[0] * .33 : 75) : 400; // assume a icon sized at 75 const deg = i / childPairs.length * Math.PI * 2; docMap.set(layout[Id], { - x: Math.cos(deg) * (burstRadius[0] / 3) - docScale * layout[WidthSym]() / 2, - y: Math.sin(deg) * (burstRadius[1] / 3) - docScale * layout[HeightSym]() / 2, - width: docScale * layout[WidthSym](), - height: docScale * layout[HeightSym](), + x: Math.cos(deg) * burstRadius[0] - docSize / 2, + y: Math.sin(deg) * burstRadius[1] - docSize * layout[HeightSym]() / layout[WidthSym]() / 2, + width: docSize,//layout[WidthSym](), + height: docSize * layout[HeightSym]() / layout[WidthSym](), + zIndex: NumCast(layout.zIndex), pair: { layout, data }, replica: "" }); }); - const divider = { type: "div", color: "transparent", x: -burstRadius[0] / 3, y: 0, width: 15, height: 15, payload: undefined }; + const divider = { type: "div", color: "transparent", x: -burstRadius[0], y: 0, width: 15, height: 15, payload: undefined }; return normalizeResults(scaleDim, 12, docMap, poolData, viewDefsToJSX, [], 0, [divider]); } @@ -265,7 +267,13 @@ export function computePivotLayout( }); const dividers = sortedPivotKeys.map((key, i) => - ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters })); + ({ + type: "div", color: "lightGray", + x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, + y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, + height: maxColHeight, + payload: pivotColumnGroups.get(key)!.filters + })); groupNames.push(...dividers); return normalizeResults(panelDim, max_text, docMap, poolData, viewDefsToJSX, groupNames, 0, []); } @@ -402,7 +410,7 @@ function normalizeResults( const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds); const docEles = Array.from(docMap.entries()).map(ele => ele[1]); const aggBounds = aggregateBounds(extras.concat(grpEles.concat(docEles.map(de => ({ ...de, type: "doc", payload: "" })))).filter(e => e.zIndex !== -99), 0, 0); - aggBounds.r = Math.max(minWidth, aggBounds.r - aggBounds.x); + aggBounds.r = aggBounds.x + Math.max(minWidth, aggBounds.r - aggBounds.x); const wscale = panelDim[0] / (aggBounds.r - aggBounds.x); let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? (panelDim[1]) / (aggBounds.b - aggBounds.y) : wscale; if (Number.isNaN(scale)) scale = 1; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6db2269c4..edc872a40 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -9,6 +9,7 @@ import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fiel import { List } from "../../../../fields/List"; import { ObjectField } from "../../../../fields/ObjectField"; import { RichTextField } from "../../../../fields/RichTextField"; +import { ImageField } from "../../../../fields/URLField"; import { createSchema, listSpec } from "../../../../fields/Schema"; import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; @@ -41,6 +42,8 @@ import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDo import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView"; import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; import { PresBox } from "../../nodes/trails/PresBox"; +import { VideoBox } from "../../nodes/VideoBox"; +import { CreateImage } from "../../nodes/WebBoxRenderer"; import { StyleLayers, StyleProp } from "../../StyleProvider"; import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; @@ -278,7 +281,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (!linkDragData.linkDragView.props.CollectionFreeFormDocumentView?.() || linkDragData.dragDocument.context !== this.props.Document) { // if the source doc view's context isn't this same freeformcollectionlinkDragData.dragDocument.context === this.props.Document const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" }); this.props.addDocument?.(source); - de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceGetAnchor() }, "doc annotation", ""); // TODODO this is where in text links get passed + de.complete.linkDocument = DocUtils.MakeLink({ doc: linkDragData.linkSourceGetAnchor() }, { doc: source }, "annotated by:annotation of", ""); // TODODO this is where in text links get passed } e.stopPropagation(); // do nothing if link is dropped into any freeform view parent of dragged document return true; @@ -454,9 +457,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection e.preventDefault(); break; case InkTool.None: - this._hitCluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)); - document.addEventListener("pointermove", this.onPointerMove); - document.addEventListener("pointerup", this.onPointerUp); + if (!(this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) { + this._hitCluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)); + document.addEventListener("pointermove", this.onPointerMove); + document.addEventListener("pointerup", this.onPointerUp); + } break; } } @@ -934,8 +939,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (deltaScale * invTransform.Scale > 20) { deltaScale = 20 / invTransform.Scale; } - if (deltaScale * invTransform.Scale < 1 && this.isAnnotationOverlay) { - deltaScale = 1 / invTransform.Scale; + if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) { + deltaScale = NumCast(this.rootDoc._viewScaleMin, 1) / invTransform.Scale; } const localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y); @@ -1017,8 +1022,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || CurrentUserUtils.OverlayDocs.includes(this.Document)) { this._viewTransition = panTime; const scale = this.getLocalTransform().inverse().Scale; - const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); - const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.Document.scrollHeight) : (1 - 1 / scale) * this.nativeHeight), Math.max(0, panY)); + const minScale = NumCast(this.rootDoc._viewScaleMin, 1); + const minPanX = NumCast(this.rootDoc._panXMin, 0); + const minPanY = NumCast(this.rootDoc._panYMin, 0); + const newPanX = Math.min( + minPanX + (1 - minScale / scale) * NumCast(this.rootDoc._panXMax, this.nativeWidth), Math.max(minPanX, panX)); + const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.Document.scrollHeight) : + minPanY + (1 - minScale / scale) * NumCast(this.rootDoc._panYMax, this.nativeHeight)), Math.max(minPanY, panY)); !this.Document._verticalScroll && (this.Document._panX = this.isAnnotationOverlay ? newPanX : panX); !this.Document._horizontalScroll && (this.Document._panY = this.isAnnotationOverlay ? newPanY : panY); } @@ -1044,8 +1054,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } else if (doc.isInkMask) { doc.zIndex = 5000; } else { - const docs = this.childLayoutPairs.map(pair => pair.layout); - docs.slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); + const docs = this.childLayoutPairs.map(pair => 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; @@ -1084,18 +1094,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection HistoryUtil.pushState(state); } } - if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) { - SelectionManager.DeselectAll(); - } + // if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) { + // SelectionManager.DeselectAll(); + // } if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined) { this.props.focus(doc, options); } else { const xfToCollection = options?.docTransform ?? Transform.Identity(); - const layoutdoc = Doc.Layout(doc); const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: this.Document[this.scaleFieldKey] }; const newState = HistoryUtil.getState(); const cantTransform = this.props.isAnnotationOverlay || ((this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc); - const { panX, panY, scale } = cantTransform ? savedState : this.calculatePanIntoView(layoutdoc, xfToCollection, options?.willZoom ? options?.scale || .75 : undefined); + const { panX, panY, scale } = cantTransform ? savedState : this.calculatePanIntoView(doc, xfToCollection, options?.willZoom ? options?.scale || .75 : undefined); if (!cantTransform) { // only pan and zoom to focus on a document if the document is not an annotation in an annotation overlay collection newState.initializers![this.Document[Id]] = { panX: panX, panY: panY }; HistoryUtil.pushState(newState); @@ -1142,10 +1151,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } calculatePanIntoView = (doc: Doc, xf: Transform, scale?: number) => { + const layoutdoc = Doc.Layout(doc); const pw = this.props.PanelWidth() / NumCast(this.layoutDoc._viewScale, 1); const ph = this.props.PanelHeight() / NumCast(this.layoutDoc._viewScale, 1); const pt = xf.transformPoint(NumCast(doc.x), NumCast(doc.y)); - const pt2 = xf.transformPoint(NumCast(doc.x) + doc[WidthSym](), NumCast(doc.y) + doc[HeightSym]()); + const pt2 = xf.transformPoint(NumCast(doc.x) + layoutdoc[WidthSym](), NumCast(doc.y) + layoutdoc[HeightSym]()); const bounds = { left: pt[0], right: pt2[0], top: pt[1], bot: pt2[1] }; const cx = NumCast(this.layoutDoc._panX); const cy = NumCast(this.layoutDoc._panY); @@ -1175,7 +1185,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection isContentActive = () => this.props.isSelected() || this.props.isContentActive(); - getChildDocView(entry: PoolData, renderIndex: number) { + getChildDocView(entry: PoolData) { const childLayout = entry.pair.layout; const childData = entry.pair.data; const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); @@ -1184,8 +1194,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection Document={childLayout} renderDepth={this.props.renderDepth + 1} replica={entry.replica} - renderIndex={renderIndex} dataTransition={entry.transition} + suppressSetHeight={this.layoutEngine ? true : false} renderCutoffProvider={this.renderCutoffProvider} ContainingCollectionView={this.props.CollectionView} ContainingCollectionDoc={this.props.Document} @@ -1328,10 +1338,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return [] as ViewDefResult[]; } + @computed get layoutEngine() { return this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine); } @computed get doInternalLayoutComputation() { TraceMobx(); const newPool = new Map<string, PoolData>(); - switch (this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine)) { + switch (this.layoutEngine) { case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) }; case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; case "pivot": return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; @@ -1361,7 +1372,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const elements = computedElementData.slice(); Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach((entry, i) => elements.push({ - ele: this.getChildDocView(entry[1], i), + ele: this.getChildDocView(entry[1]), bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica) })); @@ -1444,6 +1455,37 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection })); } + updateIcon = () => { + this.props.docViewPath().lastElement().ContentDiv!.style.width = (this.layoutDoc[WidthSym]()).toString(); + this.props.docViewPath().lastElement().ContentDiv!.style.height = (this.layoutDoc[HeightSym]()).toString(); + const htmlString = this._mainCont && new XMLSerializer().serializeToString(this.props.docViewPath().lastElement().ContentDiv!); + this.props.docViewPath().lastElement().ContentDiv!.style.width = ""; + this.props.docViewPath().lastElement().ContentDiv!.style.height = ""; + const nativeWidth = this.layoutDoc[WidthSym](); + const nativeHeight = this.layoutDoc[HeightSym](); + + CreateImage( + "", + document.styleSheets, + htmlString?.replace(/docView-hack/g, 'documentView-hack'), + nativeWidth, + nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(), + NumCast(this.layoutDoc._scrollTop) + ).then + ((data_url: any) => { + VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then( + returnedfilename => setTimeout(action(() => { + + this.dataDoc.icon = new ImageField(returnedfilename); + this.dataDoc["icon-nativeWidth"] = nativeWidth; + this.dataDoc["icon-nativeHeight"] = nativeHeight; + }), 500)); + }) + .catch(function (error: any) { + console.error('oops, something went wrong!', error); + }); + } + componentWillUnmount() { Object.values(this._disposers).forEach(disposer => disposer?.()); this._marqueeRef.current?.removeEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); @@ -1509,6 +1551,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection appearanceItems.push({ description: "Reset View", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); !Doc.UserDoc().noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); appearanceItems.push({ description: `${this.fitToContent ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); + appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" }); this.props.ContainingCollectionView && appearanceItems.push({ description: "Ungroup collection", event: this.promoteCollection, icon: "table" }); !Doc.UserDoc().noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss index 62510ce9d..41e4d6b6a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss @@ -10,6 +10,7 @@ user-select: none; } + .marqueeView:focus-within { overflow: hidden; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b8f687489..5f303b428 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -519,15 +519,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque d.y = NumCast(d.y) - this.Bounds.top; return d; }); - const summary = Docs.Create.TextDocument("", { x: this.Bounds.left, y: this.Bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" }); - const portal = Doc.MakeAlias(summary); - Doc.GetProto(summary)[Doc.LayoutFieldKey(summary) + "-annotations"] = new List<Doc>(selected); - Doc.GetProto(summary).layout_portal = CollectionView.LayoutString(Doc.LayoutFieldKey(summary) + "-annotations"); - summary._backgroundColor = "#e2ad32"; - portal.layoutKey = "layout_portal"; - portal.title = "document collection"; - DocUtils.MakeLink({ doc: summary }, { doc: portal }, "summarizing", ""); + const summary = Docs.Create.TextDocument("", { _backgroundColor: "#e2ad32", x: this.Bounds.left, y: this.Bounds.top, isPushpin: true, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" }); + const portal = Docs.Create.FreeformDocument(selected, { x: this.Bounds.left + 200, y: this.Bounds.top, isGroup: true, backgroundColor: "transparent" }); + DocUtils.MakeLink({ doc: summary }, { doc: portal }, "summary of:summarized by", ""); + portal.hidden = true; + this.props.addDocument?.(portal); this.props.addLiveTextDocument(summary); MarqueeOptionsMenu.Instance.fadeOut(true); } |
