From d6d90d14f3fceb625601859d90c3a15fdd891984 Mon Sep 17 00:00:00 2001 From: Brandon McArthur Date: Tue, 13 Feb 2024 14:29:21 -0700 Subject: [PATCH] additional work for functions working in trelliscope panels (#1206) Co-authored-by: Brandon McArthur --- .../Life_expectancy/displayInfo.jsonp | 7 ++--- src/TrelliscopeApp.tsx | 5 ++-- src/components/Content/Content.tsx | 8 +++--- .../ContentContainer/ContentContainer.tsx | 16 ++++++----- src/components/DataProvider/index.tsx | 22 +++++++-------- .../PanelDialog/PanelDialog.module.scss | 3 ++- src/components/PanelDialog/PanelDialog.tsx | 22 ++++++++++----- src/index.tsx | 6 ++++- src/jsApi.ts | 27 ++++++++++++++++--- src/types/configs.d.ts | 7 ++--- src/types/global.d.ts | 13 ++++++++- 11 files changed, 91 insertions(+), 45 deletions(-) diff --git a/_examples/gapminder_testing/displays/Life_expectancy/displayInfo.jsonp b/_examples/gapminder_testing/displays/Life_expectancy/displayInfo.jsonp index 971fa168..37bcfa7c 100644 --- a/_examples/gapminder_testing/displays/Life_expectancy/displayInfo.jsonp +++ b/_examples/gapminder_testing/displays/Life_expectancy/displayInfo.jsonp @@ -99,7 +99,8 @@ __loadDisplayInfo__5ae49320({ { "source": { "isLocal": true, - "type": "file" + "type": "JS", + 'function': null }, "aspect": 1.5, "paneltype": "img", @@ -114,7 +115,7 @@ __loadDisplayInfo__5ae49320({ { "source": { "isLocal": true, - "type": "file" + "type": "JS" }, "aspect": 0.5, "paneltype": "iframe", @@ -129,7 +130,7 @@ __loadDisplayInfo__5ae49320({ { "source": { "isLocal": false, - "type": "file" + "type": "JS" }, "aspect": 1.50146627565982, "paneltype": "img", diff --git a/src/TrelliscopeApp.tsx b/src/TrelliscopeApp.tsx index 2a309a2f..2aa9378d 100644 --- a/src/TrelliscopeApp.tsx +++ b/src/TrelliscopeApp.tsx @@ -14,11 +14,10 @@ interface TrelliscopeAppProps { } // component for embedding a Trelliscope app in a React app -const TrelliscopeApp: React.FC = ({ data, width, height, options = {}}) => { +const TrelliscopeApp: React.FC = ({ data, width, height, options = {} }) => { const crossFilterClient = new CrossfilterClient(); const id = 'trelliscope_app'; - // TODO: need to get appDims from a ref of parent component - const appDims = { width, height } + const appDims = { width, height }; return (
diff --git a/src/components/Content/Content.tsx b/src/components/Content/Content.tsx index 210dcfab..f02958ca 100644 --- a/src/components/Content/Content.tsx +++ b/src/components/Content/Content.tsx @@ -206,9 +206,11 @@ const Content: React.FC = ({ table, tableWrapperRef, tableContentR { = ({ children, client }) => { setData(client.getData(numPerPage, page)); }, [numPerPage, page]); - const dataContextValue = useMemo(() => ({ - data, allData: client.allData, - filteredData: client.filteredData, - groupBy: client.groupBy - }), [data, client.allData, client.filteredData, client.groupBy]); - - return ( - - {children} - + const dataContextValue = useMemo( + () => ({ + data, + allData: client.allData, + filteredData: client.filteredData, + groupBy: client.groupBy, + }), + [data, client.allData, client.filteredData, client.groupBy], ); + + return {children}; }; export default DataProvider; diff --git a/src/components/PanelDialog/PanelDialog.module.scss b/src/components/PanelDialog/PanelDialog.module.scss index af2456d9..695f1c2d 100644 --- a/src/components/PanelDialog/PanelDialog.module.scss +++ b/src/components/PanelDialog/PanelDialog.module.scss @@ -13,7 +13,8 @@ iframe { border: none; - max-height: 500px; + // max-height: 500px; + height: auto; // max-width: 100%; // width: min(80vw, 80vh); // height: min(80vw, 80vh); diff --git a/src/components/PanelDialog/PanelDialog.tsx b/src/components/PanelDialog/PanelDialog.tsx index a5731e53..b404ddc7 100644 --- a/src/components/PanelDialog/PanelDialog.tsx +++ b/src/components/PanelDialog/PanelDialog.tsx @@ -59,7 +59,7 @@ const PanelDialog: React.FC = ({ data, filteredData, open, pan ({ ...variable, sourcePath: curMetaData?.[variable.varname], - } as PanelExtended), + }) as PanelExtended, ), ); }, [curMetaData, panel?.varname, selectedVariables]); @@ -179,6 +179,10 @@ const PanelDialog: React.FC = ({ data, filteredData, open, pan setSelectedVariables(value); }; + const getDataForPanel = (selectedPanel: IPanelMeta, selectedSource: string) => { + return data.find((datum) => datum[selectedPanel?.name] === selectedSource); + }; + return ( = ({ data, filteredData, open, pan = ({ data, filteredData, open, pan { + return `https://raw.githubusercontent.com/hafen/countryflags/master/png/512/${row.iso_alpha2}.png`; }); trelliscopeApp(example.id, appdat); }); diff --git a/src/jsApi.ts b/src/jsApi.ts index 378ab10e..0ef10e8f 100644 --- a/src/jsApi.ts +++ b/src/jsApi.ts @@ -2,6 +2,7 @@ /* eslint-disable @typescript-eslint/lines-between-class-members */ import { max } from 'd3-array'; import { metaIndex } from './slices/metaDataAPI'; +import { cloneDeep } from 'lodash'; export class Meta implements IMeta { name: string; // why?? @@ -697,6 +698,24 @@ class TrelliscopeClass implements ITrelliscopeAppSpec { return this; } + setPanelFunction(varname: string, func: PanelFunction): ITrelliscopeAppSpec { + const { name } = this.displayList[0]; + const { metas } = this.displays[name].displayInfo; + const meta = metas.find((m) => m.varname === varname) as IPanelMeta; + if (meta === undefined) { + throw new Error(`varname ${varname} not found in metas`); + } + if (meta.type !== 'panel') { + throw new Error(`varname ${varname} is not a panel`); + } + meta.source = { + ...meta.source, + type: 'JS', + function: func, + }; + return this; + } + setRangeFilter({ varname, min = null, @@ -812,7 +831,7 @@ export function Trelliscope({ } export function prepareTrelliscope(data: ITrelliscopeAppSpec, id: string): ITrelliscopeAppSpec { - const data2 = JSON.parse(JSON.stringify(data)); + const data2 = cloneDeep(data); data2.config.id = id; const di = data2.displays[data2.displayList[0].name].displayInfo; // make sure there is a primary panel specified @@ -827,13 +846,13 @@ export function prepareTrelliscope(data: ITrelliscopeAppSpec, id: string): ITrel const md = data2.displays[data2.displayList[0].name].metaData; // eslint-disable-next-line @typescript-eslint/no-explicit-any di.metas - .filter((d: { type: string }) => d.type === 'factor') - .forEach((d: { name: string | number; levels: string | any[] }) => { + .filter((d: IMeta) => d.type === 'factor') + .forEach((d: IMeta) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any md.forEach((row: { [x: string]: any }) => { if (row[d.name]) { // eslint-disable-next-line no-param-reassign - row[d.name] = d.levels.indexOf(row[d.name]) + 1; + row[d.name] = (d.levels ?? []).indexOf(row[d.name]) + 1; } }); }); diff --git a/src/types/configs.d.ts b/src/types/configs.d.ts index 2dcf9667..cfde386b 100644 --- a/src/types/configs.d.ts +++ b/src/types/configs.d.ts @@ -396,10 +396,10 @@ type PanelType = 'img' | 'iframe'; type PanelSourceType = 'file' | 'REST' | 'localWebSocket' | 'JS'; -type PanelFunction = (args: []) => string; +type PanelFunction = (args) => string; interface IJSPanelSource extends IPanelSource { - function: PanelFunction; + function?: PanelFunction; } interface IPanelSource { @@ -412,7 +412,7 @@ interface IPanelMeta extends IMeta { paneltype: PanelType; // format?: PanelFormat; aspect: number; - source: IPanelSource; + source: IJSPanelSource; } // interface IFilePanelSource extends IPanelSource { @@ -509,4 +509,5 @@ interface ITrelliscopeAppSpec { setVarLabels(labels: { [index: string]: string }): ITrelliscopeAppSpec; setPrimaryPanel(panel: string): ITrelliscopeAppSpec; setRangeFilter(arg0: { varname: string; min?: number | Date | null; max?: number | Date | null }): ITrelliscopeAppSpec; + setPanelFunction(arg0: string, arg1: PanelFunction): ITrelliscopeAppSpec; } diff --git a/src/types/global.d.ts b/src/types/global.d.ts index fa24a69b..d9e804e0 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -15,6 +15,16 @@ interface HTMLWidgetData { jsHooks: unknown[]; } +interface TrelliscopeFuncGlobalSpec { + data: Datum[]; + name: string; + description?: string; + tags?: string[]; + keycols: string[]; + primarypanel?: string; + infoOnLoad?: boolean; +} + type PanelData = string | HTMLWidgetData; declare global { interface Window { @@ -24,7 +34,8 @@ declare global { | ((data: IDisplay) => void) | ((data: Datum[]) => void) | ((data: IConfig) => void) - | ((data: IDisplay[]) => void); + | ((data: IDisplay[]) => void) + | ((data: TrelliscopeAppGlobalSpec) => void); metaData: Datum[] | null; } interface Document {