From 2bf76070e1847313e931d291e675251cad31a9a8 Mon Sep 17 00:00:00 2001 From: ObservedObserver <270001151@qq.com> Date: Tue, 27 Jun 2023 16:51:12 +0800 Subject: [PATCH] refactor: adjust main view design --- packages/rath-client/src/interfaces.ts | 7 +- .../pages/megaAutomation/mainCanvas/index.tsx | 8 +- .../vizOperation/fieldContainer.tsx | 8 +- .../vizOperation/operationBar.tsx | 33 +++-- .../pages/semiAutomation/focusZone/index.tsx | 72 +++++----- .../pages/semiAutomation/narrative/index.tsx | 6 +- .../predictZone/featSegment.tsx | 1 + .../predictZone/pattSegment.tsx | 1 + .../semiEmbed/liteFocusZone.tsx | 42 +++--- .../rath-client/src/store/megaAutomation.ts | 76 ++++++----- .../src/store/semiAutomation/autoVis.ts | 43 ++++++ .../src/store/semiAutomation/mainStore.ts | 126 +++++++++--------- 12 files changed, 243 insertions(+), 180 deletions(-) create mode 100644 packages/rath-client/src/store/semiAutomation/autoVis.ts diff --git a/packages/rath-client/src/interfaces.ts b/packages/rath-client/src/interfaces.ts index 509b3ec2b..b3bf84fbb 100644 --- a/packages/rath-client/src/interfaces.ts +++ b/packages/rath-client/src/interfaces.ts @@ -1,7 +1,7 @@ // define new interfaces here, global.ts is no longer maintained. import { AnyMark } from "vega-lite/build/src/mark"; import { IAnalyticType, IFieldSummary, IInsightSpace, ISemanticType } from "visual-insights"; -import { IFilter } from '@kanaries/loa' +import { IFilter, IPattern } from '@kanaries/loa' import { Aggregator } from "./global"; import type { DateTimeInfoType } from "./dev/workers/engine/dateTimeExpand"; @@ -392,6 +392,11 @@ export type IDatasetData = { meta: IBackUpDataMeta; }; +export interface IVisView { + spec: IVegaSubset | null; + dataViewQuery: IPattern | null; +} + export interface ICreateDashboardPayload { datasourceId: string; workspaceName: string; diff --git a/packages/rath-client/src/pages/megaAutomation/mainCanvas/index.tsx b/packages/rath-client/src/pages/megaAutomation/mainCanvas/index.tsx index bdea1be6e..300c6f34b 100644 --- a/packages/rath-client/src/pages/megaAutomation/mainCanvas/index.tsx +++ b/packages/rath-client/src/pages/megaAutomation/mainCanvas/index.tsx @@ -10,10 +10,10 @@ import ResizeContainer from './resizeContainer'; const MainCanvas: FC<{ handler?: Ref }> = ({ handler }) => { const { megaAutoStore, ltsPipeLineStore, commonStore, editorStore } = useGlobalStore(); - const { mainViewSpec, dataSource, visualConfig, mainViewSpecSource } = megaAutoStore; + const { mainView, dataSource, visualConfig, mainViewSpecSource } = megaAutoStore; const { muteSpec } = editorStore; const { rendering } = ltsPipeLineStore; - const spec = mainViewSpecSource === 'custom' ? muteSpec : mainViewSpec; + const spec = mainViewSpecSource === 'custom' ? muteSpec : mainView.spec; return (
{rendering && ( @@ -21,9 +21,9 @@ const MainCanvas: FC<{ handler?: Ref }> = ({ handler }) => { )} - {mainViewSpec && ( + {mainView.spec && ( diff --git a/packages/rath-client/src/pages/megaAutomation/vizOperation/fieldContainer.tsx b/packages/rath-client/src/pages/megaAutomation/vizOperation/fieldContainer.tsx index 25fe8db9b..8ac24c506 100644 --- a/packages/rath-client/src/pages/megaAutomation/vizOperation/fieldContainer.tsx +++ b/packages/rath-client/src/pages/megaAutomation/vizOperation/fieldContainer.tsx @@ -13,7 +13,7 @@ const PillsContainer = styled.div` const FieldContainer: React.FC = (props) => { const { megaAutoStore } = useGlobalStore(); - const { mainViewPattern, fieldMetas } = megaAutoStore; + const { mainView, fieldMetas } = megaAutoStore; const appendFieldHandler = useCallback( (fid: string) => { @@ -22,13 +22,13 @@ const FieldContainer: React.FC = (props) => { [megaAutoStore] ); - if (mainViewPattern === null) { + if (mainView.dataViewQuery === null) { return
; } return (
- {mainViewPattern.fields + {mainView.dataViewQuery.fields .filter((f) => f.analyticType === 'dimension') .map((f) => { return ( @@ -44,7 +44,7 @@ const FieldContainer: React.FC = (props) => { })} - {mainViewPattern.fields + {mainView.dataViewQuery.fields .filter((f) => f.analyticType === 'measure') .map((f, fIndex) => { return ( diff --git a/packages/rath-client/src/pages/megaAutomation/vizOperation/operationBar.tsx b/packages/rath-client/src/pages/megaAutomation/vizOperation/operationBar.tsx index 1676a537d..968d6a930 100644 --- a/packages/rath-client/src/pages/megaAutomation/vizOperation/operationBar.tsx +++ b/packages/rath-client/src/pages/megaAutomation/vizOperation/operationBar.tsx @@ -13,25 +13,24 @@ interface OperationBarProps { } const OperationBar: React.FC = ({ handler }) => { const { megaAutoStore, commonStore, collectionStore, painterStore, editorStore, semiAutoStore } = useGlobalStore(); - const { mainViewSpec, mainViewPattern } = megaAutoStore; + const { mainView } = megaAutoStore; const customizeAnalysis = useCallback(() => { - if (mainViewSpec) { - commonStore.visualAnalysisInGraphicWalker(mainViewSpec) + if (mainView.spec) { + commonStore.visualAnalysisInGraphicWalker(mainView.spec) } - }, [mainViewSpec, commonStore]) + }, [mainView.spec, commonStore]) const analysisInPainter = useCallback(() => { - if (mainViewSpec && mainViewPattern) { - painterStore.analysisInPainter(mainViewSpec, mainViewPattern) + if (mainView.spec && mainView.dataViewQuery) { + painterStore.analysisInPainter(mainView.spec, mainView.dataViewQuery) } - }, [mainViewSpec, mainViewPattern, painterStore]) + }, [mainView.spec, mainView.dataViewQuery, painterStore]) - const viewExists = !(mainViewPattern === null || mainViewSpec === null); let starIconName = 'FavoriteStar'; - if (viewExists) { - const viewFields = toJS(mainViewPattern.fields); - const viewSpec = toJS(mainViewSpec); + if (mainView.dataViewQuery && mainView.spec) { + const viewFields = toJS(mainView.dataViewQuery.fields); + const viewSpec = toJS(mainView.spec); if (collectionStore.collectionContains(viewFields, viewSpec, IVisSpecType.vegaSubset)) { starIconName = 'FavoriteStarFill' } @@ -55,8 +54,8 @@ const OperationBar: React.FC = ({ handler }) => { text: intl.get('megaAuto.commandBar.editInEditor'), iconProps: { iconName: 'Edit' }, onClick: () => { - if (mainViewPattern && mainViewSpec) { - editorStore.syncSpec(IVisSpecType.vegaSubset, mainViewSpec) + if (mainView.dataViewQuery && mainView.spec) { + editorStore.syncSpec(IVisSpecType.vegaSubset, mainView.spec) megaAutoStore.changeMainViewSpecSource() } } @@ -84,8 +83,8 @@ const OperationBar: React.FC = ({ handler }) => { text: intl.get('megaAuto.commandBar.associate'), iconProps: { iconName: 'Lightbulb' }, onClick: () => { - if (mainViewPattern !== null) { - semiAutoStore.analysisInCopilot(toJS(mainViewPattern)) + if (mainView.dataViewQuery !== null) { + semiAutoStore.analysisInCopilot(toJS(mainView.dataViewQuery)) commonStore.setAppKey(PIVOT_KEYS.semiAuto); } } @@ -95,8 +94,8 @@ const OperationBar: React.FC = ({ handler }) => { text: intl.get('common.star'), iconProps: { iconName: starIconName }, onClick: () => { - if (mainViewPattern && mainViewSpec) { - collectionStore.toggleCollectState(toJS(mainViewPattern.fields), toJS(mainViewSpec), IVisSpecType.vegaSubset) + if (mainView.dataViewQuery && mainView.spec) { + collectionStore.toggleCollectState(toJS(mainView.dataViewQuery.fields), toJS(mainView.spec), IVisSpecType.vegaSubset) } } }, diff --git a/packages/rath-client/src/pages/semiAutomation/focusZone/index.tsx b/packages/rath-client/src/pages/semiAutomation/focusZone/index.tsx index 9fde56dc3..a3e13be17 100644 --- a/packages/rath-client/src/pages/semiAutomation/focusZone/index.tsx +++ b/packages/rath-client/src/pages/semiAutomation/focusZone/index.tsx @@ -8,7 +8,6 @@ import ViewField from '../../megaAutomation/vizOperation/viewField'; import FieldPlaceholder from '../../../components/fieldPill/fieldPlaceholder'; import { MainViewContainer } from '../components'; import FilterCreationPill from '../../../components/fieldPill/filterCreationPill'; -import Narrative from '../narrative'; import EncodeCreationPill from '../../../components/fieldPill/encodeCreationPill'; import EditorCore from '../../editor/core/index'; import type { IReactVegaHandler } from '../../../components/react-vega'; @@ -19,34 +18,34 @@ const BUTTON_STYLE = { marginRight: '1em', marginTop: '1em' }; const FocusZone: React.FC = () => { const { semiAutoStore, commonStore, collectionStore, painterStore, editorStore } = useGlobalStore(); - const { mainVizSetting, mainView, showMiniFloatView, mainViewSpec, fieldMetas, neighborKeys, mainViewSpecSource } = semiAutoStore; + const { mainView, showMiniFloatView, fieldMetas, neighborKeys, mainViewSpecSource } = semiAutoStore; const { muteSpec } = editorStore; const appendFieldHandler = useCallback( (fid: string) => { - if (mainView === null) { + if (mainView.dataViewQuery === null) { semiAutoStore.initMainViewWithSingleField(fid); } else { semiAutoStore.addMainViewField(fid); } }, - [semiAutoStore, mainView] + [semiAutoStore, mainView.dataViewQuery] ); const editChart = useCallback(() => { - if (mainViewSpec) { - commonStore.visualAnalysisInGraphicWalker(mainViewSpec); + if (mainView.spec) { + commonStore.visualAnalysisInGraphicWalker(mainView.spec); } - }, [mainViewSpec, commonStore]); + }, [mainView.spec, commonStore]); const paintChart = useCallback(() => { - if (mainViewSpec && mainView) { - painterStore.analysisInPainter(mainViewSpec, mainView); + if (mainView.spec && mainView.dataViewQuery) { + painterStore.analysisInPainter(mainView.spec, mainView.dataViewQuery); } - }, [mainViewSpec, painterStore, mainView]); + }, [mainView.spec, mainView.dataViewQuery, painterStore]); const viewSpec = useMemo(() => { - return mainViewSpecSource === 'custom' ? muteSpec : mainViewSpec; - }, [mainViewSpec, muteSpec, mainViewSpecSource]); + return mainViewSpecSource === 'custom' ? muteSpec : mainView.spec; + }, [mainView.spec, muteSpec, mainViewSpecSource]); const ChartEditButtonProps = useMemo(() => { return { @@ -62,21 +61,21 @@ const FocusZone: React.FC = () => { text: intl.get('megaAuto.commandBar.editInEditor'), iconProps: { iconName: 'Edit' }, onClick: () => { - if (mainViewSpec) { - editorStore.syncSpec(IVisSpecType.vegaSubset, mainViewSpec); + if (mainView.spec) { + editorStore.syncSpec(IVisSpecType.vegaSubset, mainView.spec); semiAutoStore.changeMainViewSpecSource(); } }, }, ], }; - }, [editChart, editorStore, mainViewSpec, semiAutoStore]); + }, [editChart, editorStore, mainView.spec, semiAutoStore]); const handler = useRef(null); return ( - {mainView && showMiniFloatView && } + {mainView.dataViewQuery && showMiniFloatView && }
{mainViewSpecSource === 'custom' && ( @@ -93,17 +92,12 @@ const FocusZone: React.FC = () => { /> )}
-
{mainView && mainViewSpec && }
- {mainVizSetting.nlg && ( -
- -
- )} +
{mainView.dataViewQuery && mainView.spec && }

- {mainView && - mainView.fields.map((f: IFieldMeta) => ( + {mainView.dataViewQuery && + mainView.dataViewQuery.fields.map((f: IFieldMeta) => ( { semiAutoStore.setNeighborKeys(neighborKeys.includes(f.fid) ? [] : [f.fid]); @@ -120,9 +114,9 @@ const FocusZone: React.FC = () => {
- {mainView && - mainView.filters && - mainView.filters.map((f) => { + {mainView.dataViewQuery && + mainView.dataViewQuery.filters && + mainView.dataViewQuery.filters.map((f) => { const targetField = fieldMetas.find((m) => m.fid === f.fid); if (!targetField) return null; let filterDesc = `${targetField.name || targetField.fid} ∈ `; @@ -146,9 +140,9 @@ const FocusZone: React.FC = () => { />
- {mainView && - mainView.encodes && - mainView.encodes.map((f) => { + {mainView.dataViewQuery && + mainView.dataViewQuery.encodes && + mainView.dataViewQuery.encodes.map((f) => { if (f.field === undefined) return ( { /> ); })} - {mainView && ( + {mainView.dataViewQuery && ( { semiAutoStore.addFieldEncode2MainViewPattern(encode); }} @@ -188,27 +182,29 @@ const FocusZone: React.FC = () => { style={BUTTON_STYLE} text={intl.get('megaAuto.commandBar.editing')} iconProps={{ iconName: 'BarChartVerticalEdit' }} - disabled={mainView === null} + disabled={mainView.dataViewQuery === null} menuProps={ChartEditButtonProps} /> - {mainView && mainViewSpec && ( + {mainView.dataViewQuery && mainView.spec && ( { - collectionStore.toggleCollectState(fieldMetas, mainViewSpec, IVisSpecType.vegaSubset, mainView.filters); + if (mainView.spec && mainView.dataViewQuery) { + collectionStore.toggleCollectState(fieldMetas, mainView.spec, IVisSpecType.vegaSubset, mainView.dataViewQuery.filters); + } }} /> )} @@ -228,7 +224,7 @@ const FocusZone: React.FC = () => { ariaLabel={intl.get('megaAuto.commandBar.download')} title={intl.get('megaAuto.commandBar.download')} text={intl.get('megaAuto.commandBar.download')} - disabled={mainView === null} + disabled={mainView.dataViewQuery === null} onClick={() => { handler.current?.exportImage(); }} diff --git a/packages/rath-client/src/pages/semiAutomation/narrative/index.tsx b/packages/rath-client/src/pages/semiAutomation/narrative/index.tsx index 9e455af1b..e29f90e4e 100644 --- a/packages/rath-client/src/pages/semiAutomation/narrative/index.tsx +++ b/packages/rath-client/src/pages/semiAutomation/narrative/index.tsx @@ -12,13 +12,13 @@ const Narrative: React.FC = () => { const [explainLoading, setExplainLoading] = useState(false); const requestId = useRef(0); const fieldsInViz = useMemo(() => { - return mainView?.fields || []; - }, [mainView]); + return mainView.dataViewQuery?.fields || []; + }, [mainView.dataViewQuery]); const [viewInfo, setViewInfo] = useState([]) useEffect(() => { setViewInfo([]) setExplainLoading(false); - }, [mainView]) + }, [mainView.dataViewQuery]) useEffect(() => { (() => getInsightExpl({ requestId, diff --git a/packages/rath-client/src/pages/semiAutomation/predictZone/featSegment.tsx b/packages/rath-client/src/pages/semiAutomation/predictZone/featSegment.tsx index 485f4d589..0db6ac266 100644 --- a/packages/rath-client/src/pages/semiAutomation/predictZone/featSegment.tsx +++ b/packages/rath-client/src/pages/semiAutomation/predictZone/featSegment.tsx @@ -61,6 +61,7 @@ const FeatSegment: React.FC = () => { }} /> +

{featViews.views[i].imp}

{ }} /> +

{pattViews.views[i].imp}

{ const { semiAutoStore, commonStore, collectionStore, painterStore } = useGlobalStore(); - const { mainVizSetting, mainView, showMiniFloatView, mainViewSpec, fieldMetas, neighborKeys } = semiAutoStore; + const { mainVizSetting, mainView, showMiniFloatView, fieldMetas, neighborKeys } = semiAutoStore; const [showActions, setShowActions] = useState(false); const appendFieldHandler = useCallback( (fid: string) => { @@ -27,47 +27,49 @@ const LiteFocusZone: React.FC = (props) => { ); const editChart = useCallback(() => { - if (mainViewSpec) { - commonStore.visualAnalysisInGraphicWalker(mainViewSpec); + if (mainView.spec) { + commonStore.visualAnalysisInGraphicWalker(mainView.spec); } - }, [mainViewSpec, commonStore]); + }, [mainView.spec, commonStore]); const paintChart = useCallback(() => { - if (mainViewSpec && mainView) { - painterStore.analysisInPainter(mainViewSpec, mainView); + if (mainView.spec && mainView.dataViewQuery) { + painterStore.analysisInPainter(mainView.spec, mainView.dataViewQuery); } - }, [mainViewSpec, painterStore, mainView]); + }, [mainView.spec, painterStore, mainView.dataViewQuery]); return ( - {mainView && showMiniFloatView && } + {mainView.dataViewQuery && showMiniFloatView && }
- {mainView && mainViewSpec && ( + {mainView.dataViewQuery && mainView.spec && ( { - collectionStore.toggleCollectState(fieldMetas, mainViewSpec, IVisSpecType.vegaSubset, mainView.filters); + if (mainView.dataViewQuery && mainView.spec) { + collectionStore.toggleCollectState(fieldMetas, mainView.spec, IVisSpecType.vegaSubset, mainView.dataViewQuery.filters); + } }} /> )} @@ -93,8 +95,8 @@ const LiteFocusZone: React.FC = (props) => { />
- {mainView && mainViewSpec && ( - + {mainView.dataViewQuery && mainView.spec && ( + )}
{mainVizSetting.nlg && ( @@ -106,8 +108,8 @@ const LiteFocusZone: React.FC = (props) => {
{showActions && (
- {mainView && - mainView.fields.map((f: IFieldMeta) => ( + {mainView.dataViewQuery && + mainView.dataViewQuery.fields.map((f: IFieldMeta) => ( { )} {showActions && (
- {mainView && - mainView.filters && - mainView.filters.map((f) => { + {mainView.dataViewQuery && + mainView.dataViewQuery.filters && + mainView.dataViewQuery.filters.map((f) => { const targetField = fieldMetas.find((m) => m.fid === f.fid); if (!targetField) return null; let filterDesc = `${targetField.name || targetField.fid} ∈ `; diff --git a/packages/rath-client/src/store/megaAutomation.ts b/packages/rath-client/src/store/megaAutomation.ts index acdbcccde..922a317c5 100644 --- a/packages/rath-client/src/store/megaAutomation.ts +++ b/packages/rath-client/src/store/megaAutomation.ts @@ -1,6 +1,7 @@ import { IFieldEncode, IPattern } from '@kanaries/loa'; import { computed, makeAutoObservable, observable, runInAction, toJS } from 'mobx'; import { Specification, IInsightSpace, ISpec } from 'visual-insights'; +import produce from 'immer'; import { STORAGE_FILE_SUFFIX } from '../constants'; import { IResizeMode, IRow, ISpecSourceType, ITaskTestMode, IVegaSubset, PreferencePanelConfig } from '../interfaces'; import { adviceVisSize } from '../pages/collection/utils'; @@ -41,8 +42,13 @@ export class MegaAutomationStore { public showSaveModal: boolean = false; public showSubinsights: boolean = false; public visualConfig!: PreferencePanelConfig; - public mainViewSpec: IVegaSubset | null = null; - public mainViewPattern: IPattern | null = null; + public mainView: { + spec: IVegaSubset | null, + dataViewQuery: IPattern | null + } = { + spec: null, + dataViewQuery: null + } public orderBy: string = EXPLORE_VIEW_ORDER.DEFAULT; public nlgThreshold: number = 0.2; public vizMode: 'lite' | 'strict' = 'strict'; @@ -61,7 +67,7 @@ export class MegaAutomationStore { assoListT1: observable.ref, assoListT2: observable.ref, insightSpaces: computed, - mainViewSpec: observable.ref, + mainView: observable.shallow, // @ts-expect-error private field ltsPipeLineStore: false }); @@ -81,8 +87,10 @@ export class MegaAutomationStore { this.showPreferencePannel = false; this.showSaveModal = false; this.showSubinsights = false; - this.mainViewSpec = null; - this.mainViewPattern = null; + this.mainView = { + dataViewQuery: null, + spec: null + } this.orderBy = EXPLORE_VIEW_ORDER.DEFAULT; this.nlgThreshold = 0.2; this.vizMode = 'strict'; @@ -197,8 +205,8 @@ export class MegaAutomationStore { public setVisualConig (updater: (config: PreferencePanelConfig) => void) { runInAction(() => { updater(this.visualConfig) - if (this.mainViewPattern) { - this.createMainViewSpec(this.mainViewPattern); + if (this.mainView.dataViewQuery) { + this.createMainViewSpec(this.mainView.dataViewQuery); } }); } @@ -264,17 +272,17 @@ export class MegaAutomationStore { } public createMainViewPattern (iSpace: IInsightSpace) { const viewFields = this.fieldMetas.filter(f => iSpace.dimensions.includes(f.fid) || iSpace.measures.includes(f.fid)); - this.mainViewPattern = { + this.mainView.dataViewQuery = { fields: viewFields, imp: iSpace.score || 0, encodes: [] } - return this.mainViewPattern; + return this.mainView.dataViewQuery; } public createMainViewSpec (pattern: IPattern) { const { visualConfig, vizMode, fieldMetas } = this; if (vizMode === 'lite') { - this.mainViewSpec = adviceVisSize(distVis({ + this.mainView.spec = adviceVisSize(distVis({ resizeMode: visualConfig.resize, pattern: toJS(pattern), width: visualConfig.resizeConfig.width, @@ -285,7 +293,7 @@ export class MegaAutomationStore { specifiedEncodes: pattern.encodes }), fieldMetas) } else if (vizMode === 'strict') { - this.mainViewSpec = adviceVisSize(labDistVis({ + this.mainView.spec = adviceVisSize(labDistVis({ resizeMode: visualConfig.resize, pattern: toJS(pattern), width: visualConfig.resizeConfig.width, @@ -299,39 +307,47 @@ export class MegaAutomationStore { } } public refreshMainViewSpec () { - if (this.mainViewPattern) { - this.createMainViewSpec(this.mainViewPattern) + if (this.mainView.dataViewQuery) { + this.createMainViewSpec(this.mainView.dataViewQuery) } } public addFieldEncode2MainViewPattern (encode: IFieldEncode) { - if (this.mainViewPattern) { - if (!this.mainViewPattern.encodes) { - this.mainViewPattern.encodes = []; - } - this.mainViewPattern.encodes.push(encode) + if (this.mainView.dataViewQuery) { + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { + if (!draft.encodes) { + draft.encodes = [] + } + draft.encodes.push(encode) + }) } } public removeFieldEncodeFromMainViewPattern (encode: IFieldEncode) { - if (this.mainViewPattern) { - if (!this.mainViewPattern.encodes) { - this.mainViewPattern.encodes = []; - } - this.mainViewPattern.encodes = this.mainViewPattern.encodes.filter(e => e.field !== encode.field) + if (this.mainView.dataViewQuery) { + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { + if (!draft.encodes) { + draft.encodes = [] + } + draft.encodes = draft.encodes.filter(e => e.field !== encode.field) + }) } } public addField2MainViewPattern (fid: string) { const targetField = this.fieldMetas.find(f => f.fid === fid); - if (targetField && this.mainViewPattern) { - this.mainViewPattern.fields.push(targetField); - this.createMainViewSpec(this.mainViewPattern) + if (targetField && this.mainView.dataViewQuery) { + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { + draft.fields.push(targetField); + }) + this.createMainViewSpec(this.mainView.dataViewQuery) } } public removeFieldInViewPattern (fid: string) { - if (this.mainViewPattern) { - const targetFieldIndex = this.mainViewPattern.fields.findIndex(f => f.fid === fid); + if (this.mainView.dataViewQuery) { + const targetFieldIndex = this.mainView.dataViewQuery.fields.findIndex(f => f.fid === fid); if (targetFieldIndex > -1) { - this.mainViewPattern.fields.splice(targetFieldIndex, 1) - this.createMainViewSpec(this.mainViewPattern) + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { + draft.fields.splice(targetFieldIndex, 1); + }) + this.createMainViewSpec(this.mainView.dataViewQuery) } } } diff --git a/packages/rath-client/src/store/semiAutomation/autoVis.ts b/packages/rath-client/src/store/semiAutomation/autoVis.ts new file mode 100644 index 000000000..323ccaa06 --- /dev/null +++ b/packages/rath-client/src/store/semiAutomation/autoVis.ts @@ -0,0 +1,43 @@ +import { IPattern } from "@kanaries/loa"; +import { toJS } from "mobx"; +import { IFieldMeta, IRow, IVegaSubset } from "../../interfaces"; +import { adviceVisSize } from "../../pages/collection/utils"; +import { distVis } from "../../queries/distVis"; +import { labDistVis } from "../../queries/labdistVis"; +import { IMainVizSetting } from "./localTypes"; + +interface AutoVisProps { + mainVizSetting: IMainVizSetting; + mainViewQuery: IPattern | null; + fieldMetas: IFieldMeta[]; + vizAlgo: 'lite' | 'strict'; + dataSource?: IRow[]; +} +export function autoVis (props: AutoVisProps): IVegaSubset | null { + const { mainVizSetting, mainViewQuery, fieldMetas, vizAlgo, dataSource = [] } = props; + if (mainViewQuery === null) return null + if (vizAlgo === 'lite') { + return adviceVisSize(distVis({ + resizeMode: mainVizSetting.resize.mode, + pattern: toJS(mainViewQuery), + width: mainVizSetting.resize.width, + height: mainVizSetting.resize.height, + interactive: mainVizSetting.interactive, + stepSize: 32, + excludeScaleZero: mainVizSetting.excludeScaleZero, + specifiedEncodes: mainViewQuery.encodes + }), fieldMetas, 800, 500) + } else { + return adviceVisSize(labDistVis({ + resizeMode: mainVizSetting.resize.mode, + pattern: toJS(mainViewQuery), + width: mainVizSetting.resize.width, + height: mainVizSetting.resize.height, + interactive: mainVizSetting.interactive, + stepSize: 32, + dataSource, + excludeScaleZero: mainVizSetting.excludeScaleZero, + specifiedEncodes: mainViewQuery.encodes + }), fieldMetas, 800, 500) + } +} \ No newline at end of file diff --git a/packages/rath-client/src/store/semiAutomation/mainStore.ts b/packages/rath-client/src/store/semiAutomation/mainStore.ts index dae78eca3..1b62d069c 100644 --- a/packages/rath-client/src/store/semiAutomation/mainStore.ts +++ b/packages/rath-client/src/store/semiAutomation/mainStore.ts @@ -2,13 +2,12 @@ import produce from "immer"; import { IReactionDisposer, makeAutoObservable, observable, reaction, runInAction, toJS } from "mobx"; import { IFieldEncode, IFilter, IPattern } from "@kanaries/loa"; import { Specification } from "visual-insights"; -import { IResizeMode, IRow, ISpecSourceType, IVegaSubset } from "../../interfaces"; +import { IResizeMode, IRow, ISpecSourceType, IVisView } from "../../interfaces"; import { distVis } from "../../queries/distVis"; -import { labDistVis } from "../../queries/labdistVis"; import { labDistVisService, loaEngineService } from "../../services/index"; import { DataSourceStore } from "../dataSourceStore"; -import { adviceVisSize } from "../../pages/collection/utils"; import { IAssoViews, IMainVizSetting, IRenderViewKey, ISetting, makeInitAssoViews } from "./localTypes"; +import { autoVis } from "./autoVis"; const RENDER_BATCH_SIZE = 5; @@ -42,7 +41,10 @@ export class SemiAutomationStore { public filterViews!: IAssoViews; public neighborViews!: IAssoViews; private dataSourceStore: DataSourceStore; - public mainView: IPattern | null = null; + public mainView: IVisView = { + spec: null, + dataViewQuery: null + }; public specForGraphicWalker: Specification = {}; public showMiniFloatView: boolean = false; public neighborKeys: string[] = []; @@ -59,7 +61,7 @@ export class SemiAutomationStore { featViews: observable.shallow, filterViews: observable.shallow, neighborViews: observable.shallow, - mainView: observable.ref, + mainView: observable.shallow, // @ts-expect-error private field dataSourceStore: false, reactions: false @@ -67,7 +69,10 @@ export class SemiAutomationStore { } public init () { this.mainViewSpecSource = 'default'; - this.mainView = null; + this.mainView = { + dataViewQuery: null, + spec: null + } this.autoAsso = { pattViews: true, featViews: true, @@ -94,7 +99,7 @@ export class SemiAutomationStore { this.neighborViews = makeInitAssoViews(RENDER_BATCH_SIZE); this.reactions.push(reaction(() => { return { - mainView: this.mainView, + mainViewQuery: this.mainView.dataViewQuery, dataSource: this.dataSource, fieldMetas: this.fieldMetas, autoFeat: this.autoAsso.featViews, @@ -102,8 +107,8 @@ export class SemiAutomationStore { autoFilter: this.autoAsso.filterViews, } }, (props) => { - const { mainView, autoFeat, autoFilter, autoPatt } = props; - if (mainView) { + const { mainViewQuery, autoFeat, autoFilter, autoPatt } = props; + if (mainViewQuery) { autoPatt && this.pattAssociate(); !autoPatt && this.initRenderViews('pattViews') autoFeat && this.featAssociate(); @@ -117,21 +122,41 @@ export class SemiAutomationStore { this.reactions.push(reaction(() => { return { - mainView: this.mainView, + mainViewQuery: this.mainView.dataViewQuery, dataSource: this.dataSource, fieldMetas: this.fieldMetas, autoNeighbor: this.autoAsso.neighborViews, neighborKeys: this.neighborKeys } }, (props) => { - const { mainView, autoNeighbor, neighborKeys } = props; - if (mainView && neighborKeys.length > 0) { + const { mainViewQuery, autoNeighbor, neighborKeys } = props; + if (mainViewQuery && neighborKeys.length > 0) { autoNeighbor && this.neighborAssociate(); !autoNeighbor && this.initRenderViews('neighborViews'); } else { this.initRenderViews('neighborViews'); } })) + + this.reactions.push(reaction(() => { + return { + dataViewQuery: this.mainView.dataViewQuery, + dataSource: this.dataSource, + mainVizSetting: this.mainVizSetting, + fieldMetas: this.fieldMetas, + vizAlgo: this.settings.vizAlgo + } + }, (props) => { + const { mainVizSetting, dataViewQuery, fieldMetas } = props; + if (dataViewQuery === null) return null + this.mainView.spec = autoVis({ + mainViewQuery: dataViewQuery, + mainVizSetting, + fieldMetas, + dataSource: this.dataSource, + vizAlgo: this.settings.vizAlgo + }) + })) } public setMainViewSpecSource (sourceType: ISpecSourceType) { this.mainViewSpecSource = sourceType; @@ -163,7 +188,10 @@ export class SemiAutomationStore { this[akey] = makeInitAssoViews(); } public clearMainView () { - this.mainView = null; + this.mainView = { + dataViewQuery: null, + spec: null + } } public initMainViewWithSingleField (fid: string) { const field = this.fieldMetas.find(f => f.fid === fid); @@ -235,15 +263,15 @@ export class SemiAutomationStore { const { fieldMetas, dataSource, mainView } = this; const neighborKeys = toJS(this.neighborKeys) try { - if (mainView === null) throw new Error('mainView is null'); - const viewFields = mainView.fields.filter(f => !neighborKeys.includes(f.fid)); + if (mainView.dataViewQuery === null) throw new Error('mainView is null'); + const viewFields = mainView.dataViewQuery.fields.filter(f => !neighborKeys.includes(f.fid)); const res = await loaEngineService({ dataSource, fields: fieldMetas, task: 'neighbors', props: { fields: [...viewFields, { fid: '*', neighbors: neighborKeys, includeNeighbor: false}], - filters: mainView.filters, + filters: mainView.dataViewQuery.filters, } }, 'local') this.updateAssoViews('neighborViews', res); @@ -261,7 +289,7 @@ export class SemiAutomationStore { dataSource, fields: fieldMetas, task: 'featureSelection', - props: mainView + props: mainView.dataViewQuery }, 'local') this.updateAssoViews('featViews', res) } catch (error) { @@ -277,7 +305,7 @@ export class SemiAutomationStore { dataSource, fields: fieldMetas, task: 'patterns', - props: mainView + props: mainView.dataViewQuery }, 'local') this.updateAssoViews('pattViews', res); } catch (error) { @@ -309,7 +337,7 @@ export class SemiAutomationStore { dataSource, fields: fieldMetas, task: 'filterSelection', - props: mainView + props: mainView.dataViewQuery }, 'local') this.updateAssoViews('filterViews', res); } catch (error) { @@ -317,37 +345,9 @@ export class SemiAutomationStore { this.endAssoViewComputing('filterViews'); } } - public get mainViewSpec (): IVegaSubset | null { - const { mainVizSetting, mainView, fieldMetas } = this; - if (mainView === null) return null - if (this.settings.vizAlgo === 'lite') { - return adviceVisSize(distVis({ - resizeMode: mainVizSetting.resize.mode, - pattern: toJS(mainView), - width: mainVizSetting.resize.width, - height: mainVizSetting.resize.height, - interactive: mainVizSetting.interactive, - stepSize: 32, - excludeScaleZero: mainVizSetting.excludeScaleZero, - specifiedEncodes: mainView.encodes - }), fieldMetas, 800, 500) - } else { - return adviceVisSize(labDistVis({ - resizeMode: mainVizSetting.resize.mode, - pattern: toJS(mainView), - width: mainVizSetting.resize.width, - height: mainVizSetting.resize.height, - interactive: mainVizSetting.interactive, - stepSize: 32, - dataSource: this.dataSource, - excludeScaleZero: mainVizSetting.excludeScaleZero, - specifiedEncodes: mainView.encodes - }), fieldMetas, 800, 500) - } - } public addFieldEncode2MainViewPattern (encode: IFieldEncode) { - if (this.mainView) { - this.mainView = produce(this.mainView, draft => { + if (this.mainView.dataViewQuery) { + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { if (!draft.encodes) { draft.encodes = []; } @@ -356,8 +356,8 @@ export class SemiAutomationStore { } } public removeFieldEncodeFromMainViewPattern (encode: IFieldEncode) { - if (this.mainView) { - this.mainView = produce(this.mainView, draft => { + if (this.mainView.dataViewQuery) { + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { if (!draft.encodes) { draft.encodes = []; } @@ -366,29 +366,29 @@ export class SemiAutomationStore { } } public addMainViewField (fieldId: string) { - if (this.mainView === null) return; + if (this.mainView.dataViewQuery === null) return; const targetFieldIndex = this.fieldMetas.findIndex(f => f.fid === fieldId); - this.mainView = produce(this.mainView, draft => { + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { draft.fields.push(this.fieldMetas[targetFieldIndex]) }) } public removeMainViewFilter (filterFieldId: string) { - if (!this.mainView?.filters) return; - this.mainView = produce(this.mainView, draft => { + if (!this.mainView.dataViewQuery?.filters) return; + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { draft.filters = draft.filters!.filter(f => f.fid !== filterFieldId) }) } public addMainViewFilter (filter: IFilter) { - if (!this.mainView) return; - if (typeof this.mainView.filters === 'undefined') this.mainView.filters = []; - this.mainView = produce(this.mainView, draft => { + if (!this.mainView.dataViewQuery) return; + if (typeof this.mainView.dataViewQuery.filters === 'undefined') this.mainView.dataViewQuery.filters = []; + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { draft.filters!.push(filter) }) } public removeMainViewField (fieldId: string) { - if (this.mainView === null) return; - const targetFieldIndex = this.mainView.fields.findIndex(f => f.fid === fieldId); - this.mainView = produce(this.mainView, draft => { + if (this.mainView.dataViewQuery === null) return; + const targetFieldIndex = this.mainView.dataViewQuery.fields.findIndex(f => f.fid === fieldId); + this.mainView.dataViewQuery = produce(this.mainView.dataViewQuery, draft => { draft.fields.splice(targetFieldIndex, 1) }) } @@ -405,12 +405,12 @@ export class SemiAutomationStore { this.neighborViews.amount = RENDER_BATCH_SIZE; } public updateMainView (view: IPattern) { - this.mainView = view; + this.mainView.dataViewQuery = view; // this.initAssociate() // this.clearViews(); } public analysisInCopilot(pattern: IPattern) { this.init(); - this.mainView = pattern; + this.mainView.dataViewQuery = pattern; } } \ No newline at end of file