diff options
Diffstat (limited to 'src')
4 files changed, 218 insertions, 80 deletions
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 14e0a8e66..311a0ad65 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -32,11 +32,12 @@ import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FocusViewOptions } from '../FocusViewOptions'; import './DataVizBox.scss'; -import { Col, DataVizTemplateInfo, DocCreatorMenu, LayoutType, TemplateFieldSize, TemplateFieldType } from './DocCreatorMenu/DocCreatorMenu'; +import { Col, DataVizTemplateInfo, DocCreatorMenu, LayoutType} from './DocCreatorMenu/DocCreatorMenu'; import { Histogram } from './components/Histogram'; import { LineChart } from './components/LineChart'; import { PieChart } from './components/PieChart'; import { TableBox } from './components/TableBox'; +import { TemplateFieldSize, TemplateFieldType } from './DocCreatorMenu/TemplateBackend'; export enum DataVizView { TABLE = 'table', diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx index c34403e79..c86264716 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx @@ -379,8 +379,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { this._selectedTemplate = template; MakeTemplate(template); const templateInfo: DataVizTemplateInfo = { doc: template, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount }; - // this._fullyRenderedDocs = this._dataViz?.createDocsFromTemplate(templateInfo, true) ?? []; - // this.updateRenderedDocCollection(); + this._fullyRenderedDocs = this._dataViz?.createDocsFromTemplate(templateInfo, true) ?? []; + this.updateRenderedDocCollection(); } }; @@ -724,7 +724,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { col.desc; const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT); - console.log(sysPrompt, prompt); + //console.log(sysPrompt, prompt); return createGeneratedImage(fieldNum, col, prompt); }) @@ -781,7 +781,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }); template.decorations.forEach(dec => { - const doc = FieldUtils.FreeformField( + console.log(dec); + const doc = FieldUtils.TextField( { tl: dec.tl, br: dec.br, @@ -1814,4 +1815,4 @@ export class FieldUtils { return doc; }; -}
\ No newline at end of file +} diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx index 119de88d0..f30183ed3 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx @@ -1,8 +1,9 @@ import { Doc } from "../../../../../fields/Doc"; import { FieldType } from "../../../../../fields/ObjectField"; import { Docs, DocumentOptions } from "../../../../documents/Documents"; +import { Col } from "./DocCreatorMenu"; import { Template } from "./Template"; -import { TemplateFieldSize, TemplateFieldType } from "./TemplateBackend"; +import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType } from "./TemplateBackend"; export enum FieldContentType { STRING = 'string', @@ -14,6 +15,12 @@ export enum ViewType { FREEFORM = 'freeform', } +export type FieldDimensions = { + width: number; + height: number; + coord: {x: number, y: number}; +} + export interface FieldOpts { backgroundColor?: string; color?: string; @@ -41,25 +48,37 @@ export type FieldSettings = { description?: string; }; -export class Field { +export interface Field { + getContent: () => string; + setContent: (content: string) => void; + getDimensions: FieldDimensions; + getSubfields: Field[]; + getAllSubfields: Field[]; + setupSubfields: () => Field[]; + renderedDoc: (content: string) => Doc; + matches: () => number[][]; +} + +export class StaticField { private content: string; private contentType: FieldContentType | undefined; - private subfields: Field[] | undefined; + private subfields: Field[] = []; private settings: FieldSettings; - private parent: Field | Template; - private dimensions: { width: number; height: number; coord: { x: number; y: number }}; + private parent: Field; + private dimensions: FieldDimensions; - constructor(settings: FieldSettings, parent: Field | Template) { + constructor(settings: FieldSettings, parent: Field, autoSetupFields: boolean = true) { this.settings = settings; this.parent = parent; - this.dimensions = this.parent.getChildDimensions({tl: settings.tl, br: settings.br}); + this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions); this.content = ''; - this.setupSubfields(); - } + if (autoSetupFields) { this.subfields = this.setupSubfields(); } + }; get getSubfields(): Field[] { return this.subfields ?? []; }; + get getAllSubfields(): Field[] { const fields: Field[] = []; this.subfields?.forEach(field => { @@ -67,22 +86,33 @@ export class Field { fields.concat(field.getAllSubfields) }); return fields; - } + }; + + get getDimensions() { return this.dimensions }; setContent = (newContent: string) => { this.content = newContent }; getContent() { return this.content }; - setupSubfields = () => { + setupSubfields = (): Field[] => { + const fields: Field[] = []; this.settings.subfields?.forEach(fieldSettings => { let field: Field; const dynamicType = fieldSettings.dynamicType; - if (dynamicType) { field = new DynamicField(fieldSettings, this, dynamicType); } + if (dynamicType) { + field = new DynamicField(fieldSettings, this, dynamicType); + } else { + field = new StaticField(fieldSettings, this); + } - field = new Field(fieldSettings, this); - this.subfields?.push(field); + fields.push(field); }); - } + return fields; + }; + + matches = (): number[][] => { + return []; + }; renderedDoc = (content: string): Doc => { const opts = this.settings.opts; @@ -97,21 +127,72 @@ export class Field { contentBold: opts.fontBold, textTransform: opts.fontTransform, color: opts.color, - _text_fontSize: `${this.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}` + _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}` }); - this.applyBasicOpts(textDoc); + FieldUtils.applyBasicOpts(textDoc, this.dimensions, this.settings); return textDoc; case FieldContentType.IMAGE: const url = String(content); const imgDoc = Docs.Create.ImageDocument(url, { _layout_fitWidth: false, }); - this.applyBasicOpts(imgDoc); + FieldUtils.applyBasicOpts(imgDoc, this.dimensions, this.settings); return imgDoc; } + }; + +} + +class DynamicField implements Field { + private type: ViewType; + private subfields: Field[] = []; + + private settings: FieldSettings; + + private parent: Field; + private dimensions: FieldDimensions; + + constructor(settings: FieldSettings, parent: Field, type: ViewType) { + this.type = type; + this.settings = settings; + this.parent = parent; + this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions); + this.subfields = this.setupSubfields(); + } + + setContent = (content: string) => { return }; + getContent = () => { return '' }; + + get getSubfields() { return this.subfields }; + get getAllSubfields() { + const fields: Field[] = []; + this.subfields?.forEach(field => { + fields.push(field); + fields.concat(field.getAllSubfields) + }); + return fields; + }; + + get getDimensions() { return this.dimensions }; + + matches = () => { + return []; } - getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): { width: number; height: number; coord: { x: number; y: number } } => { + setupSubfields = (): Field[] => { + this.settings.subfields?.forEach(fieldSettings => { + let field: Field; + const dynamicType = fieldSettings.dynamicType; + + if (dynamicType) { field = new DynamicField(fieldSettings, this, dynamicType); } + + field = new StaticField(fieldSettings, this); + this.subfields?.push(field); + }); + return []; + } + + getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => { const l = (coords.tl[0] * this.dimensions.height) / 2; const t = coords.tl[1] * this.dimensions.width / 2; //prettier-ignore const r = (coords.br[0] * this.dimensions.height) / 2; @@ -122,13 +203,113 @@ export class Field { return { width, height, coord }; }; - applyBasicOpts = (doc: Doc) => { - const opts = this.settings.opts; + renderedDoc = (): Doc => { + switch (this.type) { + case ViewType.CAROUSEL3D: + const carouselDoc = Docs.Create.Carousel3DDocument([], { + }); + FieldUtils.applyBasicOpts(carouselDoc, this.dimensions, this.settings); + case ViewType.FREEFORM: + const freeformDoc = Docs.Create.FreeformDocument([], { + }); + FieldUtils.applyBasicOpts(freeformDoc, this.dimensions, this.settings); + default: + return new Doc(); + } + } + +} + +export class TemplateMatcher { + + static matchesForTemplate = (field: FieldSettings, cols: Col[]): number[][] => { + const colMatchesField = (col: Col, field: FieldSettings) => { + return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type); + }; + + const matches: number[][] = Array(field.subfields?.length) + .fill([]) + .map(() => []); + + field.subfields?.forEach((field, i) => { + cols.forEach((col, v) => { + if (colMatchesField(col, field)) { + matches[i].push(v); + } + }); + }); + + return matches; + }; + + static 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) { + used.fill(false); + augmentingPath(v); + } + + let count: number = 0; + + for (let i = 0; i < fieldsCt; ++i) { + if (mt[i] !== -1) ++count; + } + + return count; + }; + + findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => { + let validTemplates: any[] = []; + templates.forEach(template => { + const numFields = template.fields.length; + if (!(numFields === cols.length)) return; + const matches = this.matchesForTemplate(template, cols); + if (this.maxMatches(numFields, matches) === numFields) { + validTemplates.push(template.title); + } + }); + + validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title)); + + return validTemplates; + }; + +} + + +export class FieldUtils { + public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => { + const l = (coords.tl[0] * parentDimensions.height) / 2; + const t = coords.tl[1] * parentDimensions.width / 2; //prettier-ignore + const r = (coords.br[0] * parentDimensions.height) / 2; + const b = coords.br[1] * parentDimensions.width / 2; //prettier-ignore + const width = r - l; + const height = b - t; + const coord = { x: l, y: t }; + return { width, height, coord }; + }; + + public static applyBasicOpts = (doc: Doc, parentDimensions: FieldDimensions, settings: FieldSettings) => { + const opts = settings.opts; doc.isDefaultTemplateDoc = true, - doc.x = this.dimensions.coord.x; - doc.y = this.dimensions.coord.y; - doc._height = this.dimensions.height; - doc._width = this.dimensions.width; + doc.x = parentDimensions.coord.x; + doc.y = parentDimensions.coord.y; + doc._height = parentDimensions.height; + doc._width = parentDimensions.width; doc.backgroundColor = opts.backgroundColor ?? ''; doc._layout_borderRounding = `${opts.cornerRounding ?? 0}px`; doc.borderColor = opts.borderColor; @@ -136,9 +317,9 @@ export class Field { doc.opacity = opts.opacity; doc._rotation = opts.rotation; doc.hCentering = opts.contentXCentering; - } + }; - calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => { + public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => { const words: string[] = text.split(/\s+/).filter(Boolean); let currFontSize = 1; @@ -178,41 +359,4 @@ export class Field { return currFontSize - 1; }; - -} - -class DynamicField extends Field { - type: ViewType; - - constructor(settings: FieldSettings, parent: Field | Template, type: ViewType) { - super(settings, parent); - this.type = type; - } - - renderedDoc = (): Doc => { - switch (this.type) { - case ViewType.CAROUSEL3D: - const carouselDoc = Docs.Create.Carousel3DDocument([], { - }); - this.applyBasicOpts(carouselDoc); - case ViewType.FREEFORM: - const freeformDoc = Docs.Create.FreeformDocument([], { - }); - this.applyBasicOpts(freeformDoc); - default: - return new Doc(); - } - } - - - -} - - -type DecorationField = FieldSettings; - -type InkDecoration = {}; - -type TemplateDecorations = FieldSettings | InkDecoration; - -interface TemplateOpts extends FieldOpts {} +}
\ No newline at end of file diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx index f9bf22047..57565906b 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx @@ -6,23 +6,15 @@ import { TemplateDocInfos } from "./TemplateBackend"; export class Template { + mainField: Field; width: number = 0; height: number = 0; fields: Field[] = []; - mainDoc: Doc; constructor(templateInfo: TemplateDocInfos) { this.width = templateInfo.width; this.height = templateInfo.height; this.fields = templateInfo.fields.map(settings => new Field(settings, this)); - this.mainDoc = this.setupMainDoc(); - } - - setupMainDoc = (): Doc => { - Docs.Create.FreeformDocument(, ){ - - } - return new Doc; } get childFields(): Field[] { |