From 58692ef043125ebd3113d81f3ca7161a7e6521cb Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Mon, 13 May 2024 18:44:23 -0400 Subject: equation parser works but occasional call stack error --- src/client/views/nodes/DocumentView.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8df28a770..32480447d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1025,6 +1025,7 @@ export class DocumentView extends DocComponent() { public static getViews = (doc?: Doc) => Array.from(doc?.[DocViews] ?? []) as DocumentView[]; public static getFirstDocumentView: (toFind: Doc) => DocumentView | undefined; public static getDocumentView: (target: Doc | undefined, preferredCollection?: DocumentView) => Opt; + public static getDocViewIndex: (target: Doc) => number; public static getContextPath: (doc: Opt, includeExistingViews?: boolean) => Doc[]; public static getLightboxDocumentView: (toFind: Doc) => Opt; public static showDocumentView: (targetDocView: DocumentView, options: FocusViewOptions) => Promise; -- cgit v1.2.3-70-g09d2 From f5c2f5bc8710a965a0b52e2e414f62a2a459a94f Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Sun, 25 Aug 2024 04:26:12 -0400 Subject: border work --- src/client/documents/Documents.ts | 2 + src/client/views/ContextMenu.scss | 35 ++++++++++ src/client/views/ContextMenu.tsx | 118 ++++++++++++++++++++++---------- src/client/views/ContextMenuItem.tsx | 12 +++- src/client/views/MainView.tsx | 6 +- src/client/views/PropertiesView.tsx | 10 +++ src/client/views/StyleProvider.tsx | 37 ++++++---- src/client/views/nodes/DocumentView.tsx | 37 ++++++---- 8 files changed, 191 insertions(+), 66 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 751fe6d91..aecc79189 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -256,6 +256,8 @@ export class DocumentOptions { layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown'); layout_borderRounding?: string; _layout_borderRounding?: STRt = new StrInfo('amount of rounding to document view corners'); + _layout_borderWidth?: NUMt = new NumInfo('Hey now', false); + _layout_borderColor?: STRt = new StrInfo('No no', false); _layout_modificationDate?: DATEt = new DateInfo('last modification date of doc layout', false); _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); _layout_reflowVertical?: BOOLt = new BoolInfo('permit vertical resizing with content "reflow"'); diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 232362c5c..ff6ad526e 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -165,3 +165,38 @@ border: solid black 1px; border-radius: 5px; } + +.contextMenu-borderMenu { + display: flex; + flex-direction: column; + align-items: flex-start; + width: 222px; + height: 300px; + background-color: white; + border: solid 1px black; + + .top-bar { + height: 20px; + width: 100%; + display: flex; + + .close-menu { + margin-top: 0; + margin-bottom: 0; + margin-right: 0; + padding: 0; + margin-left: auto; + z-index: 999999999; + width: 20px; + height: 20px; + color: black; + background-color: transparent; + } + } + + .bottom-box{ + .width-selector{ + + } + } +} diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index de985263d..9472fb95c 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -5,11 +5,17 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { DivHeight, DivWidth } from '../../ClientUtils'; +import { DivHeight, DivWidth, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { SnappingManager } from '../util/SnappingManager'; import './ContextMenu.scss'; import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { ColorResult, SketchPicker } from 'react-color'; +import { DocumentView } from './nodes/DocumentView'; +import { Doc } from '../../fields/Doc'; +import { undoable } from '../util/UndoManager'; +import { NumCast, StrCast } from '../../fields/Types'; +import { emptyFunction } from '../../Utils'; @observer export class ContextMenu extends ObservableReactComponent<{}> { @@ -38,6 +44,8 @@ export class ContextMenu extends ObservableReactComponent<{}> { @observable _mouseX: number = -1; @observable _mouseY: number = -1; @observable _shouldDisplay: boolean = false; + @observable _displayColorPicker: boolean = false; + @observable _selectorWidth: number = 0; constructor(props: any) { super(props); @@ -116,6 +124,10 @@ export class ContextMenu extends ObservableReactComponent<{}> { this._defaultItem = item; } + @action setColorPickerDisplay = (display: boolean) => { + this._displayColorPicker = display; + } + static readonly buffer = 20; get pageX() { return this._pageX + this._width > window.innerWidth - ContextMenu.buffer ? window.innerWidth - ContextMenu.buffer - this._width : Math.max(0, this._pageX); @@ -206,45 +218,79 @@ export class ContextMenu extends ObservableReactComponent<{}> { _searchRef = React.createRef(); // bcz: we shouldn't need this, since we set autoFocus on the tag, but for some reason we do... + get colorPicker() { + const doc = DocumentView.Selected().lastElement().Document; + const layoutDoc = doc ? Doc.Layout(doc) : doc; + + return ( +
+
+ +
+ layoutDoc._layout_borderColor = col.hex), + 'set stroke color property' + )} + presetColors={[]} + color={StrCast(layoutDoc._layout_borderColor)} + /> +
+ {layoutDoc._layout_borderWidth = e.target.value; this._selectorWidth = Number(e.target.value); console.log(layoutDoc._layout_borderWidth)}}/> +
+
+ ); + } + render() { this.itemsNeedSearch && setTimeout(() => this._searchRef.current?.focus()); return ( -
{ - if (r) { - this._width = DivWidth(r); - this._height = DivHeight(r); - } - this._searchRef.current?.focus(); - })} - style={{ - display: this._display ? '' : 'none', - left: this.pageX, - ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }), - background: SnappingManager.userBackgroundColor, - color: SnappingManager.userColor, - }}> - {!this.itemsNeedSearch ? null : ( - - - +
+ {this._displayColorPicker ? this.colorPicker : null} +
{ + if (r) { + this._width = DivWidth(r); + this._height = DivHeight(r); + } + this._searchRef.current?.focus(); + })} + style={{ + display: this._display ? '' : 'none', + left: this.pageX, + ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }), + background: SnappingManager.userBackgroundColor, + color: SnappingManager.userColor, + }}> + {!this.itemsNeedSearch ? null : ( + + + + + - - - )} - {this.menuItems} + )} + {this.menuItems} +
); } diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index eb1030eec..782077fd6 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -5,8 +5,14 @@ import { action, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { SnappingManager } from '../util/SnappingManager'; -import { UndoManager } from '../util/UndoManager'; +import { UndoManager, undoable } from '../util/UndoManager'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { ColorPicker, Type } from 'browndash-components'; +import { DocumentView } from './nodes/DocumentView'; +import { Doc } from '../../fields/Doc'; +import { StrCast } from '../../fields/Types'; +import { ColorResult, SketchPicker } from 'react-color'; +import color from 'color'; export interface OriginalMenuProps { description: string; @@ -14,6 +20,7 @@ export interface OriginalMenuProps { undoable?: boolean; icon: IconProp | JSX.Element; // maybe should be optional (icon?) closeMenu?: () => void; + colorPicker?: boolean; } export interface SubmenuProps { @@ -24,6 +31,7 @@ export interface SubmenuProps { addDivider?: boolean; icon: IconProp; // maybe should be optional (icon?) closeMenu?: () => void; + colorPicker?: boolean; } export type ContextMenuProps = OriginalMenuProps | SubmenuProps; @@ -101,7 +109,7 @@ export class ContextMenuItem extends ObservableReactComponent +
{this._props.icon ? {this.isJSXElement(this._props.icon) ? this._props.icon : } : null}
{this._props.description.replace(':', '')}
{ public static Live: boolean = false; private _docBtnRef = React.createRef(); + @observable private _keepContextMenuOpen: boolean = false; @observable private _windowWidth: number = 0; @observable private _windowHeight: number = 0; @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row) @@ -590,7 +591,10 @@ export class MainView extends ObservableReactComponent<{}> { if (typeof targets[i].className === 'object') targClass = targets[i + 1].className.toString(); else break; } - !targClass.includes('contextMenu') && ContextMenu.Instance.closeMenu(); + if (!targClass.includes('contextMenu')) { + console.log(targClass) + ContextMenu.Instance.closeMenu(); + } !['timeline-menu-desc', 'timeline-menu-item', 'timeline-menu-input'].includes(targClass) && TimelineMenu.Instance.closeMenu(); } }); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 024db82a4..775e15772 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -847,6 +847,12 @@ export class PropertiesView extends ObservableReactComponent void) { return ( @@ -898,6 +904,10 @@ export class PropertiesView extends ObservableReactComponent { this.colorStk = color; }); // prettier-ignore } + @computed get borderColorPicker() { + return this.colorPicker(this.colorStk, (color: string) => { this.colorStk = color; }); // prettier-ignore + } + @computed get strokeAndFill() { return (
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 8c100f238..3a48ec957 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -55,14 +55,25 @@ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: nu return style; } -export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { - return `M ${pw * 0.5} ${ph * inset} C ${pw * 0.6} ${ph * inset} ${pw * (1 - 2 * inset)} 0 ${pw * (1 - inset)} ${ph * inset} C ${pw} ${ph * (2 * inset)} ${pw * (1 - inset)} ${ph * 0.25} ${pw * (1 - inset)} ${ph * 0.3} C ${ - pw * (1 - inset) - } ${ph * 0.4} ${pw} ${ph * (1 - 2 * inset)} ${pw * (1 - inset)} ${ph * (1 - inset)} C ${pw * (1 - 2 * inset)} ${ph} ${pw * 0.6} ${ph * (1 - inset)} ${pw * 0.5} ${ph * (1 - inset)} C ${pw * 0.3} ${ph * (1 - inset)} ${pw * (2 * inset)} ${ph} ${ - pw * inset - } ${ph * (1 - inset)} C 0 ${ph * (1 - 2 * inset)} ${pw * inset} ${ph * 0.8} ${pw * inset} ${ph * 0.75} C ${pw * inset} ${ph * 0.7} 0 ${ph * (2 * inset)} ${pw * inset} ${ph * inset} C ${pw * (2 * inset)} 0 ${pw * 0.25} ${ph * inset} ${ - pw * 0.5 - } ${ph * inset}`; +export function wavyBorderPath(doc: Doc, pw: number, ph: number, inset: number = 0) { + const layoutDoc = doc ? Doc.Layout(doc) : doc; + const width = pw * inset; + const height = ph * inset; + + const radius = Math.min(Number(StrCast(layoutDoc._layout_borderRounding).replace('px', '')), (pw - 2 * width) / 2, (ph - 2 * height) / 2); + + return ` + M ${width + radius} ${height} + L ${pw - width - radius} ${height} + A ${radius} ${radius} 0 0 1 ${pw - width} ${height + radius} + L ${pw - width} ${ph - height - radius} + A ${radius} ${radius} 0 0 1 ${pw - width - radius} ${ph - height} + L ${width + radius} ${ph - height} + A ${radius} ${radius} 0 0 1 ${width} ${ph - height - radius} + L ${width} ${height + radius} + A ${radius} ${radius} 0 0 1 ${width + radius} ${height} + Z + `; } let _filterOpener: () => void; @@ -189,10 +200,12 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt - +
), diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8edb37acc..fe6d529ba 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -634,6 +634,7 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => { this.Document._chromeHidden = !this.Document._chromeHidden; }, icon: 'project-diagram' }); // prettier-ignore moreItems.push({ description: 'Copy ID', event: () => ClientUtils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' }); + moreItems.push({ description: 'Add border', event: () => ContextMenu.Instance.setColorPickerDisplay(true), icon: 'square', colorPicker: true }); } } @@ -944,22 +945,28 @@ export class DocumentViewInternal extends DocComponent + //
+ //
+ //
+ //
(!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} - onPointerOver={() => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} - onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} - style={{ - borderRadius: this.borderRounding, - pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) - }}> - {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} - {borderPath?.jsx} -
+ className={`${DocumentView.ROOT_DIV} docView-hack`} + ref={this._mainCont} + onContextMenu={this.onContextMenu} + onPointerDown={this.onPointerDown} + onClick={SnappingManager.ExploreMode ? this.onBrowseClick : this.onClick} + onPointerEnter={() => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} + onPointerOver={() => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} + onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} + style={{ + borderRadius: this.borderRounding, + pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) + }}> + {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} + {borderPath?.jsx} +
+ //
); } -- cgit v1.2.3-70-g09d2 From 143921c3ecee8dc0b7a91dfe725a3734d63a575e Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Sun, 25 Aug 2024 16:30:24 -0400 Subject: border --- src/client/views/ContextMenu.tsx | 3 ++- src/client/views/StyleProvider.tsx | 12 +++++------- src/client/views/nodes/DocumentView.tsx | 5 ++++- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 9472fb95c..dca00c2bf 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -223,7 +223,8 @@ export class ContextMenu extends ObservableReactComponent<{}> { const layoutDoc = doc ? Doc.Layout(doc) : doc; return ( -
+
), diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index fe6d529ba..3c898dea2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -547,6 +547,10 @@ export class DocumentViewInternal extends DocComponent ContextMenu.Instance.setColorPickerDisplay(true), icon: 'square', colorPicker: true }); + } + const customScripts = Cast(this.Document.contextMenuScripts, listSpec(ScriptField), []); StrListCast(this.Document.contextMenuLabels).forEach((label, i) => cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.Document, scriptContext: this._props.scriptContext }), icon: 'sticky-note' }) @@ -634,7 +638,6 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => { this.Document._chromeHidden = !this.Document._chromeHidden; }, icon: 'project-diagram' }); // prettier-ignore moreItems.push({ description: 'Copy ID', event: () => ClientUtils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' }); - moreItems.push({ description: 'Add border', event: () => ContextMenu.Instance.setColorPickerDisplay(true), icon: 'square', colorPicker: true }); } } -- cgit v1.2.3-70-g09d2 From f00a5326fa331859db131bb1d8988db93602830b Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Tue, 27 Aug 2024 19:16:28 -0400 Subject: maxmatching algorithm --- src/client/documents/Documents.ts | 5 +- src/client/views/ContextMenu.tsx | 9 +- src/client/views/StyleProvider.tsx | 4 +- .../views/nodes/DataVizBox/DocCreatorMenu.tsx | 190 ++++++++++++++------- src/client/views/nodes/DocumentView.tsx | 14 +- 5 files changed, 139 insertions(+), 83 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index aecc79189..a4ba2978c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -237,6 +237,9 @@ export class DocumentOptions { dataViz?: string; dataViz_savedTemplates?: LISTt; + borderWidth?: NUMt = new NumInfo('Width of user-added border', false); + borderColor?: STRt = new StrInfo('Color of user-added border', false); + layout?: string | Doc; // default layout string or template document layout_isSvg?: BOOLt = new BoolInfo('whether document decorations and other selections should handle pointerEvents for svg content or use doc bounding box'); layout_keyValue?: STRt = new StrInfo('layout definition for showing keyValue view of document', false); @@ -256,8 +259,6 @@ export class DocumentOptions { layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown'); layout_borderRounding?: string; _layout_borderRounding?: STRt = new StrInfo('amount of rounding to document view corners'); - _layout_borderWidth?: NUMt = new NumInfo('Hey now', false); - _layout_borderColor?: STRt = new StrInfo('No no', false); _layout_modificationDate?: DATEt = new DateInfo('last modification date of doc layout', false); _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); _layout_reflowVertical?: BOOLt = new BoolInfo('permit vertical resizing with content "reflow"'); diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index b80d97e81..f5654446d 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -2,7 +2,7 @@ /* eslint-disable react/jsx-props-no-spreading */ /* eslint-disable default-param-last */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, makeObservable, observable } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { DivHeight, DivWidth, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; @@ -222,7 +222,6 @@ export class ContextMenu extends ObservableReactComponent<{}> { get colorPicker() { const doc = DocumentView.Selected().lastElement().Document; - const layoutDoc = doc ? Doc.Layout(doc) : doc; return (
{
layoutDoc._layout_borderColor = col.hex), + action((col: ColorResult) => doc.borderColor = col.hex), 'set stroke color property' )} presetColors={[]} - color={StrCast(layoutDoc._layout_borderColor)} + color={StrCast(doc.borderColor)} />
this._widthMinMax.max = e.target.value}/> - {layoutDoc._layout_borderWidth = e.target.value; this._selectorWidth = Number(e.target.value); console.log(layoutDoc._layout_borderWidth)}}/> + runInAction(() => {doc.borderWidth = e.target.value; this._selectorWidth = Number(e.target.value)})}/> this._widthMinMax.max = e.target.value}/>
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index b7dbcf7a6..3ecb101f8 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -205,7 +205,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt - +
), diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx index 7df445b88..ffc4dd0b1 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx @@ -419,6 +419,8 @@ export class DocCreatorMenu extends ObservableReactComponent { + + } + + maxMatches = (fieldsCt: number, matches: number[][]) => { + const used: boolean[] = Array(fieldsCt).fill(false); + const mt: number[] = Array(fieldsCt).fill(-1); + + const augmentingPath = (v: number): boolean => { + if (used[v]) return false; + used[v] = true; + for (const to of matches[v]) { + if (mt[to] === -1 || augmentingPath(mt[to])) { + mt[to] = v; + return true; + } + } + return false; + } + + for (let v = 0; v < fieldsCt; ++v) { + console.log(v) + used.fill(false); + augmentingPath(v); + } + + let numMatches: number = 0; + + for (let i = 0; i < fieldsCt; ++i) { + if (mt[i] !== -1) ++numMatches; + } + + return numMatches; + } + get dashboardContents(){ return (
@@ -985,26 +1022,31 @@ enum FieldSize { HUGE = 'huge' } +type Field = { + tl: [number, number], + br: [number, number], + types: FieldType[], + sizes?: FieldSize[], + opts: FieldOpts; +}; + export interface TemplateDocInfos { height: number; width: number; - fields: {tl: [number, number], br: [number, number], types: FieldType[], sizes?: FieldSize[]}[]; -} - -export interface TemplateDocField { - coordinates: {tl: [number, number], br: [number, number]}; - getDoc: (parentWidth: number, parentHeight: number, title: string, content: string) => Doc; + fields: Field[]; } export interface FieldOpts { backgroundColor?: string; - roundedCorners?: boolean; - vertCenteredText?: boolean; - horizCenteredText?: boolean; - transparency?: number; + color?: string; + cornerRounding?: number; + borderWidth?: number; + borderColor?: string; + contentXCentering?: 'left' | 'center' | 'right'; + contentYCentering?: 'top' | 'center' | 'bottom'; + opacity?: number; rotation?: number; //animation?: boolean; - fontColor?: string; fontBold?: boolean; fontTransform?: 'toUpper' | 'toLower'; } @@ -1023,7 +1065,9 @@ export class FieldFuncs { public static TextField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => { const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight); - const doc = Docs.Create.TextDocument(content, { + const bool = true; + + const docWithBasicOpts = (Docs.Create.TextDocument)(content, { _height: height, _width: width, title: title, @@ -1031,11 +1075,15 @@ export class FieldFuncs { y: coord.y, _text_fontSize: `${height/2}` , backgroundColor: opts.backgroundColor ?? '', - - - }) + color: opts.color, + _layout_borderRounding: `${opts.cornerRounding}`, + borderWidth: opts.borderWidth, + borderColor: opts.borderColor, + opacity: opts.opacity, + _layout_centered: opts.contentXCentering === 'center' ? true : false, + }); - return doc; + return docWithBasicOpts; } public static ImageField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string) => { @@ -1071,70 +1119,82 @@ export class TemplateLayouts { tl: [-.6, -.9], br: [.6, -.8], types: [FieldType.TEXT], - sizes: [FieldSize.TINY] + sizes: [FieldSize.TINY], + opts: { + + } }, { tl: [-.9, -.7], br: [.9, .2], types: [FieldType.TEXT, FieldType.VISUAL], - sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE] + sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE], + opts: { + + } }, { tl: [-.6, .3], br: [.6, .4], types: [FieldType.TEXT], - sizes: [FieldSize.TINY] + sizes: [FieldSize.TINY], + opts: { + + } }, { tl: [-.9, .5], br: [.9, .9], types: [FieldType.TEXT, FieldType.VISUAL], - sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE] - }] - }; + sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE], + opts: { - public static FourField002: TemplateDocInfos = { - width: 450, - height: 600, - fields: [{ - tl: [-.6, -.9], - br: [.6, -.8], - types: [FieldType.TEXT], - sizes: [FieldSize.TINY] - }, { - tl: [-.9, -.7], - br: [.9, .2], - types: [FieldType.TEXT, FieldType.VISUAL], - sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE] - }, { - tl: [-.9, .3], - br: [-.05, .9], - types: [FieldType.TEXT], - sizes: [FieldSize.TINY] - }, { - tl: [.05, .3], - br: [.9, .9], - types: [FieldType.TEXT, FieldType.VISUAL], - sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE] + } }] }; - public static TwoFieldPlusCarousel: TemplateDocInfos = { - width: 500, - height: 600, - fields: [{ - tl: [-.9, -.99], - br: [.9, -.7], - types: [FieldType.TEXT], - sizes: [FieldSize.TINY] - }, { - tl: [-.9, -.65], - br: [.9, .35], - types: [], - sizes: [] - }, { - tl: [-.9, .4], - br: [.9, .95], - types: [FieldType.TEXT], - sizes: [FieldSize.TINY] - }] - }; +// public static FourField002: TemplateDocInfos = { +// width: 450, +// height: 600, +// fields: [{ +// tl: [-.6, -.9], +// br: [.6, -.8], +// types: [FieldType.TEXT], +// sizes: [FieldSize.TINY] +// }, { +// tl: [-.9, -.7], +// br: [.9, .2], +// types: [FieldType.TEXT, FieldType.VISUAL], +// sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE] +// }, { +// tl: [-.9, .3], +// br: [-.05, .9], +// types: [FieldType.TEXT], +// sizes: [FieldSize.TINY] +// }, { +// tl: [.05, .3], +// br: [.9, .9], +// types: [FieldType.TEXT, FieldType.VISUAL], +// sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE] +// }] +// }; + +// public static TwoFieldPlusCarousel: TemplateDocInfos = { +// width: 500, +// height: 600, +// fields: [{ +// tl: [-.9, -.99], +// br: [.9, -.7], +// types: [FieldType.TEXT], +// sizes: [FieldSize.TINY] +// }, { +// tl: [-.9, -.65], +// br: [.9, .35], +// types: [], +// sizes: [] +// }, { +// tl: [-.9, .4], +// br: [.9, .95], +// types: [FieldType.TEXT], +// sizes: [FieldSize.TINY] +// }] +// }; } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3c898dea2..5af6e65de 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -948,12 +948,7 @@ export class DocumentViewInternal extends DocComponent - //
- //
- //
- //
-
- //
); } @@ -1138,7 +1132,7 @@ export class DocumentView extends DocComponent() { return Math.max(minTextScale, this._props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled } @computed private get panelWidth() { - return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this._props.PanelWidth(); + return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling: this._props.PanelWidth(); } @computed private get panelHeight() { if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) { @@ -1449,6 +1443,8 @@ export class DocumentView extends DocComponent() { render() { TraceMobx(); + const borderWidth = 50/*Number(StrCast(this.layoutDoc.layout_borderWidth).replace('px', ''))*/; + console.log(this._props.PanelWidth(), borderWidth) const xshift = Math.abs(this.Xshift) <= 0.001 ? this._props.PanelWidth() : undefined; const yshift = Math.abs(this.Yshift) <= 0.001 ? this._props.PanelHeight() : undefined; @@ -1468,7 +1464,7 @@ export class DocumentView extends DocComponent() { style={{ transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`, - height: this._props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`), + height: this._props.forceAutoHeight ? '1000px' : yshift ?? (this.layout_fitWidth ? `${this.panelHeight + 500}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth() + 500}px`), }}> Date: Thu, 29 Aug 2024 04:06:15 -0400 Subject: Dataviz crash hopefully fixed; prototype func for generating templates; radius NaN bug handled --- src/client/documents/Documents.ts | 3 +- src/client/views/StyleProvider.tsx | 5 + src/client/views/nodes/DataVizBox/DataVizBox.tsx | 18 ++- .../views/nodes/DataVizBox/DocCreatorMenu.tsx | 149 +++++++++++++++------ .../views/nodes/DataVizBox/components/TableBox.tsx | 13 +- src/client/views/nodes/DocumentView.tsx | 1 - 6 files changed, 137 insertions(+), 52 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a4ba2978c..723f851c6 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -178,6 +178,7 @@ export class DocumentOptions { map_bearing?: NUMt = new NumInfo('bearing of a map view', false); map_style?: STRt = new StrInfo('mapbox style for a map view', false); identifier?: STRt = new StrInfo('documentIcon displayed for each doc as "d[x]"', false); + _rotation?: NUMt = new NumInfo('Amount of rotation on a document in degrees', false); date_range?: STRt = new StrInfo('date range for calendar', false); @@ -237,7 +238,7 @@ export class DocumentOptions { dataViz?: string; dataViz_savedTemplates?: LISTt; - borderWidth?: NUMt = new NumInfo('Width of user-added border', false); + borderWidth?: STRt = new StrInfo('Width of user-added border', false); borderColor?: STRt = new StrInfo('Color of user-added border', false); layout?: string | Doc; // default layout string or template document diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 3ecb101f8..bb0883cc0 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -56,11 +56,14 @@ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: nu } export function border(doc: Doc, pw: number, ph: number, rad: number = 0, inset: number = 0) { + if (!rad) rad = 0; const width = pw * inset; const height = ph * inset; const radius = Math.min(rad, (pw - 2 * width) / 2, (ph - 2 * height) / 2); + console.log(pw, ph, rad, inset) + return ` M ${width + radius} ${height} L ${pw - width - radius} ${height} @@ -206,8 +209,10 @@ export function DefaultStyleProvider(doc: Opt, props: Opt() { + private _urlError: boolean = false; private _mainCont: React.RefObject = React.createRef(); private _marqueeref = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); @@ -116,8 +117,17 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // all CSV records in the dataset (that aren't an empty row) @computed.struct get records() { - const records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); - return records?.filter(record => Object.keys(record).some(key => record[key])) ?? []; + try { + const records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); + this._urlError = false; + return records?.filter(record => Object.keys(record).some(key => record[key])) ?? []; + } catch (e){ + this._urlError = true; + const data: { [key: string]: string; }[] = [ + { error: "Data not found"}, + ]; + return data; + } } // currently chosen visualization type: line, pie, histogram, table @@ -133,8 +143,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } selectAxes = (axes: string[]) => { this.layoutDoc._dataViz_axes = new List(axes); - //axes.forEach(axis => console.log(axis)) - //DocCreatorMenu.Instance.generateTemplates(''); }; @computed.struct get titleCol() { return StrCast(this.layoutDoc._dataViz_titleCol); @@ -315,7 +323,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { componentDidMount() { this._props.setContentViewBox?.(this); - if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData(); + if (!this._urlError) { if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData() }; this._disposers.datavis = reaction( () => { if (this.layoutDoc.dataViz_schemaLive === undefined) this.layoutDoc.dataViz_schemaLive = true; diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx index 43cf57167..27ffc63ef 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx @@ -404,21 +404,21 @@ export class DocCreatorMenu extends ObservableReactComponent { testTemplate = () => { - // const temp = TemplateLayouts.TwoFieldPlusCarousel; - // const title = new TemplateDocTextField({tl: temp.fields[0].tl, br: temp.fields[0].br}); - // const title1 = new TemplateDocTextField({tl: temp.fields[0].tl, br: temp.fields[0].br}); - // const title2 = new TemplateDocTextField({tl: temp.fields[0].tl, br: temp.fields[0].br}); - // const title3 = new TemplateDocTextField({tl: temp.fields[0].tl, br: temp.fields[0].br}); - // const focus = new TemplateDocCarouselField({tl: temp.fields[1].tl, br: temp.fields[1].br}, temp.width, temp.height, '', [title1, title2, title3].map(field => field.getDoc(temp.width, temp.height, 'hey now', ''))); - // const caption = new TemplateDocTextField({tl: temp.fields[2].tl, br: temp.fields[2].br}); - // let fields = [title, caption].map(field => field.getDoc(temp.width, temp.height, 'hey now', '')); - // fields = fields.concat(focus.getDoc()); - // console.log(temp.height, temp.width) - // const doc = Docs.Create.StackingDocument(fields, { _height: temp.height, _width: temp.width, title: 'hey', x: 400, y: 400 }); - - // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; - // mainCollection.addDocument(doc); - //this._dataViz?.getRandomSample(); + const temp = TemplateLayouts.FourField001; + const title: Doc = FieldFuncs.TextField({tl: temp.fields[0].tl, br: temp.fields[0].br}, temp.height, temp.width, 'title', 'Title', {backgroundColor: 'transparent'}); + const image: Doc = FieldFuncs.ImageField({tl: temp.fields[1].tl, br: temp.fields[1].br}, temp.height, temp.width, 'title', '', {borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10, rotation: 40}); + const caption: Doc = FieldFuncs.TextField({tl: temp.fields[2].tl, br: temp.fields[2].br}, temp.height, temp.width, 'title', 'Caption', {backgroundColor: 'transparent'}); + const desc: Doc = FieldFuncs.TextField({tl: temp.fields[3].tl, br: temp.fields[3].br}, temp.height, temp.width, 'title', '', {backgroundColor: 'lightblue', borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10}); + + const doc = Docs.Create.FreeformDocument([title, image, caption, desc], { _height: temp.height, _width: temp.width, title: 'hey', x: 400, y: 400 }); + + const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; + mainCollection.addDocument(doc); + + // setTimeout(() => image.borderWidth = '10', 1000); + // setTimeout(() => desc.borderWidth = '10', 1000); + + // this._dataViz?.getRandomSample(); // public static FourField001: TemplateDocInfos = { @@ -450,12 +450,12 @@ export class DocCreatorMenu extends ObservableReactComponent { // opts: { - const field1: Col = {title: 'hey', type: TemplateFieldType.TEXT, size: FieldSize.HUGE, desc: ''} - const field2: Col = {title: 'heyo', type: TemplateFieldType.TEXT, size: FieldSize.TINY, desc: ''} - const field3: Col = {title: 'heya', type: TemplateFieldType.VISUAL, size: FieldSize.LARGE, desc: ''} - const field4: Col = {title: 'heyy', type: TemplateFieldType.TEXT, size: FieldSize.MEDIUM, desc: ''} + // const field1: Col = {title: 'hey', type: TemplateFieldType.TEXT, size: FieldSize.HUGE, desc: ''} + // const field2: Col = {title: 'heyo', type: TemplateFieldType.TEXT, size: FieldSize.TINY, desc: ''} + // const field3: Col = {title: 'heya', type: TemplateFieldType.VISUAL, size: FieldSize.LARGE, desc: ''} + // const field4: Col = {title: 'heyy', type: TemplateFieldType.TEXT, size: FieldSize.MEDIUM, desc: ''} - console.log(this.findValidTemplates([field1, field2, field3, field4], [TemplateLayouts.FourField001])); + // console.log(this.findValidTemplates([field1, field2, field3, field4], [TemplateLayouts.FourField001])); } get templatesPreviewContents(){ @@ -609,9 +609,9 @@ export class DocCreatorMenu extends ObservableReactComponent { } } - doc = () => { - return Docs.Create.FreeformDocument([], { _height: 200, _width: 200, title: 'title'}); - } + // doc = () => { + // return Docs.Create.FreeformDocument([], { _height: 200, _width: 200, title: 'title'}); + // } screenToLocalTransform = () => this._props @@ -802,7 +802,7 @@ export class DocCreatorMenu extends ObservableReactComponent { } @action addField = () => { - const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.TEXT, desc: '', size: FieldSize.MEDIUM}]) + const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.UNSET, desc: '', size: FieldSize.MEDIUM}]) this._columns = newFields; } @@ -822,9 +822,7 @@ export class DocCreatorMenu extends ObservableReactComponent { if (this._columns.length === 1) { this._columns = [] } else { - console.log(this._columns) this._columns.splice(this._columns.indexOf(toRemove[0]), 1); - console.log(this._columns) } } } @@ -899,7 +897,6 @@ export class DocCreatorMenu extends ObservableReactComponent { templates.forEach(template => { const numFields = template.fields.length; const matches = this.matchesForTemplate(template, cols); - console.log(matches) if (this.maxMatches(numFields, matches) === numFields) { validTemplates.push(template.title); } @@ -908,7 +905,32 @@ export class DocCreatorMenu extends ObservableReactComponent { return validTemplates; } + createEmptyTemplate = (template: TemplateDocInfos, assignments: {[field: number]: Col}) => { + const fields: Doc[] = []; + + Object.entries(assignments).forEach(([f, col]) => { + const field: Field = template.fields[Number(f)]; + const doc = (col.type === TemplateFieldType.VISUAL ? FieldFuncs.ImageField : FieldFuncs.TextField)({ + tl: field.tl, + br: field.br }, + template.height, + template.width, + col.title, + '', + field.opts + ); + + fields.push(doc); + }); + + const renderedTemplate = Docs.Create.FreeformDocument(fields, { _height: template.height, _width: template.width, title: template.title, x: 400, y: 400 }); + + const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; + mainCollection.addDocument(renderedTemplate); + } + get dashboardContents(){ + return (
@@ -919,10 +941,10 @@ export class DocCreatorMenu extends ObservableReactComponent { {this.fieldsInfos.map((field, index) =>
- +
- {field.type ? null : Select media type} - {field.type ? field.type === 'text' ? 'Text Field' : 'File Field' : ''} + {field.type === TemplateFieldType.UNSET ? Select media type : null} + {field.type === TemplateFieldType.TEXT ? 'Text Field' : field.type === TemplateFieldType.VISUAL ? 'File Field' : ''}
{this.setFieldType(field, TemplateFieldType.TEXT)}}/>
Text
@@ -930,15 +952,13 @@ export class DocCreatorMenu extends ObservableReactComponent {
File
+