diff options
Diffstat (limited to 'src')
9 files changed, 80 insertions, 351 deletions
diff --git a/src/client/views/collections/CollectionPivotView.scss b/src/client/views/collections/CollectionPivotView.scss deleted file mode 100644 index 505091e98..000000000 --- a/src/client/views/collections/CollectionPivotView.scss +++ /dev/null @@ -1,88 +0,0 @@ -.collectionPivotView { - display: flex; - flex-direction: row; - position: absolute; - height: 100%; - width: 100%; - - .collectionPivotView-flyout { - width: 400px; - height: 300px; - display: inline-block; - - .collectionPivotView-flyout-item { - background-color: lightgray; - text-align: left; - display: inline-block; - position: relative; - width: 100%; - } - } - - .pivotKeyEntry { - position: absolute; - top: 5px; - right: 5px; - z-index: 10; - pointer-events: all; - padding: 5px; - border: 1px solid black; - } - - .collectionPivotView-treeView { - display: flex; - flex-direction: column; - width: 200px; - height: 100%; - - .collectionPivotView-addfacet { - display: inline-block; - width: 200px; - height: 30px; - background: darkGray; - text-align: center; - - .collectionPivotView-button { - align-items: center; - display: flex; - width: 100%; - height: 100%; - - .collectionPivotView-span { - margin: auto; - } - } - - >div, - >div>div { - width: 100%; - height: 100%; - text-align: center; - } - } - - .collectionPivotView-tree { - display: inline-block; - width: 100%; - height: calc(100% - 30px); - } - } - - .collectionPivotView-pivot { - display: inline-block; - width: calc(100% - 200px); - height: 100%; - } - - .collectionPivotView-dragger { - background-color: lightgray; - height: 40px; - width: 20px; - position: absolute; - border-radius: 10px; - top: 55%; - border: 1px black solid; - z-index: 2; - left: -10px; - } -}
\ No newline at end of file diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx deleted file mode 100644 index 992018a3f..000000000 --- a/src/client/views/collections/CollectionPivotView.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import { faEdit } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, observable } from "mobx"; -import { observer } from "mobx-react"; -import { Set } from "typescript-collections"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { List } from "../../../new_fields/List"; -import { listSpec } from "../../../new_fields/Schema"; -import { ComputedField, ScriptField } from "../../../new_fields/ScriptField"; -import { Cast, StrCast } from "../../../new_fields/Types"; -import { Docs } from "../../documents/Documents"; -import { EditableView } from "../EditableView"; -import { anchorPoints, Flyout } from "../TemplateMenu"; -import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; -import "./CollectionPivotView.scss"; -import { CollectionSubView } from "./CollectionSubView"; -import { CollectionTreeView } from "./CollectionTreeView"; -import React = require("react"); -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { RichTextField } from "../../../new_fields/RichTextField"; - -@observer -export class CollectionPivotView extends CollectionSubView(doc => doc) { - componentDidMount() { - this.props.Document._freeformLayoutEngine = "pivot"; - const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked; - if (!this.props.Document._facetCollection) { - const facetCollection = Docs.Create.TreeDocument([], { title: "facetFilters", _yMargin: 0, treeViewHideTitle: true }); - facetCollection.target = this.props.Document; - this.props.Document.excludeFields = new List<string>(["_facetCollection", "_docFilter"]); - - const scriptText = "setDocFilter(containingTreeView.target, heading, this.title, checked)"; - const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailed'); useRightSplit(alias); "; - facetCollection.onCheckedClick = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "boolean", checked: "boolean", containingTreeView: Doc.name }); - this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "boolean", containingCollection: Doc.name }); - this.props.Document._facetCollection = facetCollection; - this.props.Document._fitToBox = true; - } - } - bodyPanelWidth = () => this.props.PanelWidth() - this._facetWidth; - getTransform = () => this.props.ScreenToLocalTransform().translate(-this._facetWidth, 0); - - @computed get _allFacets() { - const facets = new Set<string>(); - this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key))); - return facets.toArray(); - } - - /** - * Responds to clicking the check box in the flyout menu - */ - facetClick = (facetHeader: string) => { - const facetCollection = this.props.Document._facetCollection; - if (facetCollection instanceof Doc) { - const found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facetHeader); - if (found !== -1) { - (facetCollection.data as List<Doc>).splice(found, 1); - const docFilter = Cast(this.props.Document._docFilter, listSpec("string")); - if (docFilter) { - let index: number; - while ((index = docFilter.findIndex(item => item === facetHeader)) !== -1) { - docFilter.splice(index, 3); - } - } - } else { - const newFacet = Docs.Create.TreeDocument([], { title: facetHeader, treeViewOpen: true, isFacetFilter: true }); - const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.dataDoc }; - const params = { layoutDoc: Doc.name, dataDoc: Doc.name, }; - newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, params, capturedVariables); - Doc.AddDocToList(facetCollection, "data", newFacet); - } - } - } - _canClick = false; - _facetWidthOnDown = 0; - @observable _facetWidth = 200; - onPointerDown = (e: React.PointerEvent) => { - this._canClick = true; - this._facetWidthOnDown = e.screenX; - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointermove", this.onPointerMove); - document.addEventListener("pointerup", this.onPointerUp); - e.stopPropagation(); - e.preventDefault(); - } - - - @action - onPointerMove = (e: PointerEvent) => { - this._facetWidth = Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0); - Math.abs(e.movementX) > 6 && (this._canClick = false); - } - @action - onPointerUp = (e: PointerEvent) => { - if (Math.abs(e.screenX - this._facetWidthOnDown) < 6 && this._canClick) { - this._facetWidth = this._facetWidth < 15 ? 200 : 0; - } - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - } - - menuCallback = (x: number, y: number) => { - ContextMenu.Instance.clearItems(); - const docItems: ContextMenuProps[] = []; - const keySet: Set<string> = new Set(); - - this.childLayoutPairs.map(pair => - Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof (pair.layout[fieldKey]) === "string").map(fieldKey => - keySet.add(fieldKey))); - keySet.toArray().map(fieldKey => - docItems.push({ description: ":" + fieldKey, event: () => this.props.Document.pivotField = fieldKey, icon: "compress-arrows-alt" })); - docItems.push({ description: ":(null)", event: () => this.props.Document.pivotField = undefined, icon: "compress-arrows-alt" }) - ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" }); - const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y); - ContextMenu.Instance.displayMenu(x, y, ":"); - } - - @observable private collapsed: boolean = false; - private toggleVisibility = action(() => this.collapsed = !this.collapsed); - - render() { - const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null); - const flyout = ( - <div className="collectionPivotView-flyout" style={{ width: `${this._facetWidth}` }}> - {this._allFacets.map(facet => <label className="collectionPivotView-flyout-item" key={`${facet}`} onClick={e => this.facetClick(facet)}> - <input type="checkbox" onChange={e => { }} checked={DocListCast((this.props.Document._facetCollection as Doc)?.data).some(d => d.title === facet)} /> - <span className="checkmark" /> - {facet} - </label>)} - </div> - ); - const newEditableViewProps = { - GetValue: () => "", - SetValue: (value: any) => { - if (value?.length) { - this.props.Document.pivotField = value; - return true; - } - return false; - }, - showMenuOnLoad: true, - contents: ":" + StrCast(this.props.Document.pivotField), - toggle: this.toggleVisibility, - color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; - }; - return !facetCollection ? (null) : - <div className="collectionPivotView" style={{ height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}> - <div className={"pivotKeyEntry"}> - <EditableView {...newEditableViewProps} menuCallback={this.menuCallback} /> - </div> - <div className="collectionPivotView-dragger" key="dragger" onPointerDown={this.onPointerDown} style={{ transform: `translate(${this._facetWidth}px, 0px)` }} > - <span title="library View Dragger" style={{ width: "5px", position: "absolute", top: "0" }} /> - </div> - <div className="collectionPivotView-treeView" style={{ width: `${this._facetWidth}px`, overflow: this._facetWidth < 15 ? "hidden" : undefined }}> - <div className="collectionPivotView-addFacet" style={{ width: `${this._facetWidth}px` }} onPointerDown={e => e.stopPropagation()}> - <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}> - <div className="collectionPivotView-button"> - <span className="collectionPivotView-span">Facet Filters</span> - <FontAwesomeIcon icon={faEdit} size={"lg"} /> - </div> - </Flyout> - </div> - <div className="collectionPivotView-tree" key="tree"> - <CollectionTreeView {...this.props} Document={facetCollection} /> - </div> - </div> - <div className="collectionPivotView-pivot" key="pivot" style={{ width: this.bodyPanelWidth() }}> - <CollectionFreeFormView {...this.props} ScreenToLocalTransform={this.getTransform} PanelWidth={this.bodyPanelWidth} /> - </div> - </div>; - } -}
\ No newline at end of file diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss index 805d06d3d..3aac2bc75 100644 --- a/src/client/views/collections/CollectionTimeView.scss +++ b/src/client/views/collections/CollectionTimeView.scss @@ -1,4 +1,4 @@ -.collectionTimeView { +.collectionTimeView, .collectionTimeView-pivot { display: flex; flex-direction: row; position: absolute; @@ -93,7 +93,7 @@ } } - .collectionTimeView-pivot { + .collectionTimeView-innards { display: inline-block; width: calc(100% - 200px); height: 100%; @@ -110,4 +110,9 @@ z-index: 2; left: -10px; } +} +.collectionTimeView-pivot { + .collectionFreeform-customText { + text-align: center; + } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index b4ab88f9a..253dfa890 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -107,8 +107,10 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { const keySet: Set<string> = new Set(); this.childLayoutPairs.map(pair => - Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof (pair.layout[fieldKey]) === "number" || typeof (pair.layout[fieldKey]) === "string").map(fieldKey => - keySet.add(fieldKey))); + Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => + pair.layout[fieldKey] instanceof RichTextField || + typeof (pair.layout[fieldKey]) === "number" || + typeof (pair.layout[fieldKey]) === "string").map(fieldKey => keySet.add(fieldKey))); keySet.toArray().map(fieldKey => docItems.push({ description: ":" + fieldKey, event: () => this.props.Document.pivotField = fieldKey, icon: "compress-arrows-alt" })); docItems.push({ description: ":(null)", event: () => this.props.Document.pivotField = undefined, icon: "compress-arrows-alt" }) @@ -189,11 +191,12 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { } @computed get contents() { - return <div className="collectionTimeView-pivot" key="pivot" style={{ width: this.bodyPanelWidth() }}> + return <div className="collectionTimeView-innards" key="timeline" style={{ width: this.bodyPanelWidth() }}> <CollectionFreeFormView {...this.props} ScreenToLocalTransform={this.getTransform} PanelWidth={this.bodyPanelWidth} /> </div>; } + _changing = false; render() { const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null); const flyout = ( @@ -219,8 +222,33 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { toggle: this.toggleVisibility, color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; }; + + let nonNumbers = 0; + this.childDocs.map(doc => { + const num = NumCast(doc[StrCast(this.props.Document.pivotField)], Number(StrCast(doc[StrCast(this.props.Document.pivotField)]))); + if (Number.isNaN(num)) { + nonNumbers++; + } + }); + const doTimeline = nonNumbers / this.childDocs.length < 0.1; + if (doTimeline !== (this.props.Document._freeformLayoutEngine === "timeline")) { + if (!this._changing) { + this._changing = true; + setTimeout(() => { + if (nonNumbers / this.childDocs.length > 0.1) { + this.childDocs.map(child => child.isMinimized = false); + this.props.Document._freeformLayoutEngine = "pivot"; + } else { + this.props.Document._freeformLayoutEngine = "timeline"; + } + this._changing = false; + }, 0); + } + return (null); + } + return !facetCollection ? (null) : - <div className="collectionTimeView" style={{ height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}> + <div className={"collectionTimeView" + (doTimeline ? "" : "-pivot")} style={{ height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}> <div className={"pivotKeyEntry"}> <EditableView {...newEditableViewProps} menuCallback={this.menuCallback} /> </div> @@ -243,7 +271,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { </div> </div> {this.contents} - {!this.props.isSelected() ? (null) : <> + {!this.props.isSelected() || !doTimeline ? (null) : <> <div className="collectionTimeView-thumb-min collectionTimeView-thumb" key="min" onPointerDown={this.onMinDown} /> <div className="collectionTimeView-thumb-max collectionTimeView-thumb" key="mid" onPointerDown={this.onMaxDown} /> <div className="collectionTimeView-thumb-mid collectionTimeView-thumb" key="max" onPointerDown={this.onMidDown} /> diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 3cb24f079..631870866 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -659,7 +659,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { Document.childLayout = cardLayout; Document.childDetailed = detailedLayout; - Document._viewType = CollectionViewType.Pivot; + Document._viewType = CollectionViewType.Time; Document.pivotField = "company"; } }); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5a7bdef61..d5d62159b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -29,7 +29,6 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionLinearView } from './CollectionLinearView'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; -import { CollectionPivotView } from './CollectionPivotView'; import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; import { CollectionStaffView } from './CollectionStaffView'; @@ -52,7 +51,6 @@ export enum CollectionViewType { Masonry, Multicolumn, Multirow, - Pivot, Time, Carousel, Linear, @@ -71,7 +69,6 @@ export namespace CollectionViewType { ["masonry", CollectionViewType.Masonry], ["multicolumn", CollectionViewType.Multicolumn], ["multirow", CollectionViewType.Multirow], - ["pivot", CollectionViewType.Pivot], ["time", CollectionViewType.Time], ["carousel", CollectionViewType.Carousel], ["linear", CollectionViewType.Linear], @@ -191,7 +188,6 @@ export class CollectionView extends Touchable<FieldViewProps> { case CollectionViewType.Carousel: { return (<CollectionCarouselView key="collview" {...props} />); } case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (<CollectionStackingView key="collview" {...props} />); } case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (<CollectionStackingView key="collview" {...props} />); } - case CollectionViewType.Pivot: { return (<CollectionPivotView key="collview" {...props} />); } case CollectionViewType.Time: { return (<CollectionTimeView key="collview" {...props} />); } case CollectionViewType.Freeform: default: { this.props.Document._freeformLayoutEngine = undefined; return (<CollectionFreeFormView key="collview" {...props} />); } @@ -234,8 +230,7 @@ export class CollectionView extends Touchable<FieldViewProps> { subItems.push({ description: "Multirow", event: () => this.props.Document._viewType = CollectionViewType.Multirow, icon: "columns" }); subItems.push({ description: "Masonry", event: () => this.props.Document._viewType = CollectionViewType.Masonry, icon: "columns" }); subItems.push({ description: "Carousel", event: () => this.props.Document._viewType = CollectionViewType.Carousel, icon: "columns" }); - subItems.push({ description: "Pivot", event: () => this.props.Document._viewType = CollectionViewType.Pivot, icon: "columns" }); - subItems.push({ description: "Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" }); + subItems.push({ description: "Pivot/Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" }); switch (this.props.Document._viewType) { case CollectionViewType.Freeform: { subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index c5db6f10f..f00af52cf 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -70,7 +70,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro case CollectionViewType.Stacking: return this._stacking_commands; case CollectionViewType.Masonry: return this._stacking_commands; case CollectionViewType.Freeform: return this._freeform_commands; - case CollectionViewType.Pivot: return this._freeform_commands; case CollectionViewType.Time: return this._freeform_commands; case CollectionViewType.Carousel: return this._freeform_commands; } @@ -271,32 +270,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro return this.props.CollectionView.props.Document; } - private get pivotKey() { - return StrCast(this.document.pivotField); - } - - private set pivotKey(value: string) { - this.document.pivotField = value; - } - - @observable private pivotKeyDisplay = this.pivotKey; - getPivotInput = () => { - if (StrCast(this.document._freeformLayoutEngine) !== "pivot") { - return (null); - } - return (<input className="collectionViewBaseChrome-viewSpecsInput" - placeholder="PIVOT ON..." - value={this.pivotKeyDisplay} - onChange={action((e: React.ChangeEvent<HTMLInputElement>) => this.pivotKeyDisplay = e.currentTarget.value)} - onKeyPress={action((e: React.KeyboardEvent<HTMLInputElement>) => { - const value = e.currentTarget.value; - if (e.which === 13) { - this.pivotKey = value; - this.pivotKeyDisplay = ""; - } - })} />); - } - @action.bound clearFilter = () => { this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction("true", { doc: Doc.name }); @@ -419,10 +392,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="6">Masonry</option> <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="7">MultiCol</option> <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="8">MultiRow</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="9">Pivot</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="10">Time</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="11">Carousel</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="12">Linear</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="9">Pivo/Time</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="10">Carousel</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="11">Linear</option> </select> <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: collapsed ? "none" : "grid" }}> <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.openViewSpecs} > diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index d2a2b42a0..6f84346df 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -46,10 +46,14 @@ export function computePivotLayout( poolData: ObservableMap<string, any>, pivotDoc: Doc, childDocs: Doc[], - childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: any) => ViewDefResult[] + childPairs: { layout: Doc, data?: Doc }[], + panelDim: number[], + viewDefsToJSX: (views: any) => ViewDefResult[] ) { - const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 200); + const fieldKey = "data"; + const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 1000); const pivotColumnGroups = new Map<FieldResult<Field>, Doc[]>(); + const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3)); const pivotFieldKey = toLabel(pivotDoc.pivotField); for (const doc of childDocs) { @@ -69,16 +73,20 @@ export function computePivotLayout( const expander = 1.05; const gap = .15; let x = 0; + let max_text = 60; pivotColumnGroups.forEach((val, key) => { let y = 0; let xCount = 0; + const text = toLabel(key); + max_text = Math.max(max_text, Math.min(500, text.length)); groupNames.push({ type: "text", - text: toLabel(key), + text, x, y: pivotAxisWidth, width: pivotAxisWidth * expander * numCols, - fontSize: NumCast(pivotDoc.pivotFontSize, 20) + height: max_text, + fontSize }); for (const doc of val) { const layoutDoc = Doc.Layout(doc); @@ -103,37 +111,7 @@ export function computePivotLayout( x += pivotAxisWidth * (numCols * expander + gap); }); - const grpEles = groupNames.map(gn => { return { x: gn.x, y: gn.y, width: gn.width, height: undefined } as PivotData; }); - const docEles = childPairs.map(pair => - docMap.get(pair.layout) || { x: NumCast(pair.layout.x), y: NumCast(pair.layout.y), width: NumCast(pair.layout._width), height: NumCast(pair.layout._height) } // new pos is computed pos, or pos written to the document's fields - ); - const minLabelHeight = 56; - const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0); - const wscale = panelDim[0] / (aggBounds.r - aggBounds.x); - const scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] - (2 * minLabelHeight) ? (panelDim[1] - (2 * minLabelHeight)) / (aggBounds.b - aggBounds.y) : wscale; - const centerY = ((panelDim[1] - 2 * minLabelHeight) - (aggBounds.b - aggBounds.y) * scale) / 2; - const centerX = (panelDim[0] - (aggBounds.r - aggBounds.x) * scale) / 2; - - childPairs.map(pair => { - const fallbackPos = { - x: NumCast(pair.layout.x), - y: NumCast(pair.layout.y), - z: NumCast(pair.layout.z), - width: NumCast(pair.layout._width), - height: NumCast(pair.layout._height) - }; - const newPosRaw = docMap.get(pair.layout) || fallbackPos; // new pos is computed pos, or pos written to the document's fields - const newPos = { x: newPosRaw.x * scale + centerX, y: (newPosRaw.y - aggBounds.y) * scale + centerY, z: newPosRaw.z, width: (newPosRaw.width || 0) * scale, height: newPosRaw.height! * scale }; - const lastPos = poolData.get(pair.layout[Id]); // last computed pos - if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.width !== lastPos.width || newPos.height !== lastPos.height) { - runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos })); - } - }); - return { - elements: viewDefsToJSX([{ type: "text", text: "", x: 0, y: -aggBounds.y * scale - minLabelHeight, width: panelDim[0], height: panelDim[1], fontSize: 1 }].concat(groupNames.map(gname => { - return { type: gname.type, text: gname.text, x: gname.x * scale + centerX, y: (gname.y - aggBounds.y) * scale + centerY, width: (gname.width || 0) * scale, height: Math.max(minLabelHeight, centerY), fontSize: gname.fontSize }; - }))) - }; + return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, []); } @@ -186,7 +164,7 @@ export function computeTimelineLayout( groupNames.push({ type: "text", text: prevKey.toString(), x: x, y: 0, height: fontHeight, fontSize }); } - const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, panelDim[1] / 2.5); + const pivotAxisWidth = NumCast(pivotDoc.pivotTimeWidth, panelDim[1] / 2.5); let stacking: number[] = []; sortedKeys.forEach(key => { const keyDocs = pivotDateGroups.get(key)!; @@ -212,12 +190,19 @@ export function computeTimelineLayout( groupNames.push({ type: "text", text: Math.ceil(maxTime).toString(), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize }); } - const grpEles = groupNames.map(gn => { return { x: gn.x, y: gn.y, height: gn.height } as PivotData; }); + const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1 } as any; + return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]); +} + +function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: any, + poolData: any, viewDefsToJSX: any, groupNames: PivotData[], minWidth: number, extras: any[]) { + + const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, height: gn.height }) as PivotData); const docEles = childPairs.filter(d => !d.layout.isMinimized).map(pair => docMap.get(pair.layout) || { x: NumCast(pair.layout.x), y: NumCast(pair.layout.y), width: pair.layout[WidthSym](), height: pair.layout[HeightSym]() } as PivotData // new pos is computed pos, or pos written to the document's fields ); const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0); - aggBounds.r = Math.max((maxTime - minTime) * scaling, aggBounds.r - aggBounds.x); + aggBounds.r = 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; @@ -237,12 +222,18 @@ export function computeTimelineLayout( runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos })); } }); + return { - elements: viewDefsToJSX([ - { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1 } as any - ].concat(groupNames.map(gname => { - return { type: gname.type, text: gname.text, x: gname.x * scale, y: gname.y * scale, width: gname.width === undefined ? gname.width : gname.width * scale, height: Math.max(fontHeight, gname.height! * scale), fontSize: gname.fontSize }; - }))) + elements: viewDefsToJSX(extras.concat(groupNames.map(gname => ({ + type: gname.type, + text: gname.text, + x: gname.x * scale, + y: gname.y * scale, + width: gname.width === undefined ? undefined : gname.width * scale, + height: Math.max(fontHeight, gname.height! * scale), + // height: gname.height === undefined ? undefined : gname.height * scale, + fontSize: gname.fontSize + })))) }; } diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss index fd9de90e0..8370af490 100644 --- a/src/client/views/presentationview/PresElementBox.scss +++ b/src/client/views/presentationview/PresElementBox.scss @@ -71,7 +71,7 @@ } .presElementBox-name { - font-size: 12px; + font-size: 12pxππ; position: absolute; display: inline-block; width: calc(100% - 45px); |