diff --git a/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts b/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts index ef1965be27..3f130163b6 100644 --- a/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts +++ b/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts @@ -1,22 +1,18 @@ import { debounce } from "@mendix/widget-plugin-platform/utils/debounce"; -import { useEffect, useMemo, useRef, useState, type RefObject } from "react"; +import { useEffect, useMemo, useRef, useState, type RefObject, CSSProperties } from "react"; import { CustomChartContainerProps } from "../../typings/CustomChartProps"; import { PlotlyChart, ChartProps } from "../components/PlotlyChart"; -import { ChartDataProcessor } from "../utils/ChartDataProcessor"; +import { parseData, parseLayout, parseConfig } from "../utils/utils"; interface UseCustomChartReturn { chartRef: RefObject; - containerStyle: { - width?: string; - height?: string; - }; + containerStyle: CSSProperties; } export function useCustomChart(props: CustomChartContainerProps): UseCustomChartReturn { const chartRef = useRef(null); const [chart, setChart] = useState(null); const [containerDimensions, setContainerDimensions] = useState<{ width?: number; height?: number }>({}); - const dataProcessor = useRef(new ChartDataProcessor()); const [setContainerDimensionsDebounced, abortDimensionsDebounce] = useMemo( () => @@ -63,74 +59,65 @@ export function useCustomChart(props: CustomChartContainerProps): UseCustomChart return; } - const data = dataProcessor.current.parseData(props.dataStatic, props.dataAttribute?.value, props.sampleData); - - const layout = dataProcessor.current.parseLayout( - props.layoutStatic, - props.layoutAttribute?.value, - props.sampleLayout - ); + const data = parseData(props.dataStatic, props.dataAttribute?.value, props.sampleData); - const dimensions = dataProcessor.current.calculateDimensions( - props.widthUnit, - props.width, - props.heightUnit, - props.height, - containerDimensions.width, - containerDimensions.height - ); + const layout = parseLayout(props.layoutStatic, props.layoutAttribute?.value, props.sampleLayout); - const { width, height } = dimensions; + const dimensions = { + width: containerDimensions.width ?? 0, + height: containerDimensions.height ?? 0 + }; const updateData: ChartProps = { data, layout: { ...layout, - width, - height, + width: dimensions.width, + height: dimensions.height, autosize: true, font: { family: "Open Sans, sans-serif", - size: Math.max(12 * (width / 1000), 8) + size: Math.max(12 * (dimensions.width / 1000), 8) }, legend: { ...layout.legend, font: { ...layout.legend?.font, - size: Math.max(10 * (width / 1000), 7) + size: Math.max(10 * (dimensions.width / 1000), 7) }, - itemwidth: Math.max(10 * (width / 1000), 3) + itemwidth: Math.max(10 * (dimensions.width / 1000), 3), + itemsizing: "constant" }, xaxis: { ...layout.xaxis, tickfont: { ...layout.xaxis?.tickfont, - size: Math.max(10 * (width / 1000), 7) + size: Math.max(10 * (dimensions.width / 1000), 7) } }, yaxis: { ...layout.yaxis, tickfont: { ...layout.yaxis?.tickfont, - size: Math.max(10 * (width / 1000), 7) + size: Math.max(10 * (dimensions.width / 1000), 7) } }, margin: { ...layout.margin, - l: Math.max(50 * (width / 1000), 30), - r: Math.max(50 * (width / 1000), 30), - t: Math.max(50 * (width / 1000), 30), - b: Math.max(50 * (width / 1000), 30), - pad: Math.max(4 * (width / 1000), 2) + l: Math.max(50 * (dimensions.width / 1000), 30), + r: Math.max(50 * (dimensions.width / 1000), 30), + t: Math.max(50 * (dimensions.width / 1000), 30), + b: Math.max(50 * (dimensions.width / 1000), 30), + pad: Math.max(4 * (dimensions.width / 1000), 2) } }, config: { - ...dataProcessor.current.parseConfig(props.configurationOptions), + ...parseConfig(props.configurationOptions), displayModeBar: props.devMode === "developer", responsive: true }, - width, - height + width: dimensions.width, + height: dimensions.height }; updateChartDebounced(chart, updateData); diff --git a/packages/pluggableWidgets/custom-chart-web/src/utils/ChartDataProcessor.ts b/packages/pluggableWidgets/custom-chart-web/src/utils/ChartDataProcessor.ts deleted file mode 100644 index 3f5e8144b5..0000000000 --- a/packages/pluggableWidgets/custom-chart-web/src/utils/ChartDataProcessor.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Config, Data, Layout } from "plotly.js-dist-min"; - -export class ChartDataProcessor { - parseData(staticData?: string, attributeData?: string, sampleData?: string): Data[] { - let finalData: Data[] = []; - - try { - if (staticData) { - finalData = [...finalData, ...JSON.parse(staticData)]; - } - if (attributeData) { - finalData = [...finalData, ...JSON.parse(attributeData)]; - } - if (!finalData.length && sampleData) { - finalData = [...finalData, ...JSON.parse(sampleData)]; - } - } catch (error) { - console.error("Error parsing chart data:", error); - } - - return finalData; - } - - parseLayout(staticLayout?: string, attributeLayout?: string, sampleLayout?: string): Partial { - let finalLayout: Partial = {}; - - try { - if (staticLayout) { - finalLayout = { ...finalLayout, ...JSON.parse(staticLayout) }; - } - if (attributeLayout) { - finalLayout = { ...finalLayout, ...JSON.parse(attributeLayout) }; - } - if (Object.keys(finalLayout).length === 0 && sampleLayout) { - finalLayout = { ...finalLayout, ...JSON.parse(sampleLayout) }; - } - } catch (error) { - console.error("Error parsing chart layout:", error); - } - return finalLayout; - } - - parseConfig(configOptions?: string): Partial { - if (!configOptions) { - return {}; - } - - try { - return JSON.parse(configOptions); - } catch (error) { - console.error("Error parsing chart config:", error); - return {}; - } - } - - calculateDimensions( - widthUnit: "percentage" | "pixels", - width: number, - heightUnit: "percentageOfWidth" | "pixels" | "percentageOfParent", - height: number, - containerWidth?: number, - containerHeight?: number - ): { width: number; height: number } { - let finalWidth = width; - let finalHeight = height; - - if (widthUnit === "percentage" && containerWidth) { - finalWidth = (containerWidth * width) / 100; - } - - if (heightUnit === "percentageOfWidth") { - finalHeight = (finalWidth * height) / 100; - } else if (heightUnit === "percentageOfParent" && containerHeight) { - finalHeight = (containerHeight * height) / 100; - } - - return { width: finalWidth, height: finalHeight }; - } -} diff --git a/packages/pluggableWidgets/custom-chart-web/src/utils/utils.ts b/packages/pluggableWidgets/custom-chart-web/src/utils/utils.ts new file mode 100644 index 0000000000..f4b9d44046 --- /dev/null +++ b/packages/pluggableWidgets/custom-chart-web/src/utils/utils.ts @@ -0,0 +1,53 @@ +import { Config, Data, Layout } from "plotly.js-dist-min"; + +export function parseData(staticData?: string, attributeData?: string, sampleData?: string): Data[] { + let finalData: Data[] = []; + + try { + if (staticData) { + finalData = [...finalData, ...JSON.parse(staticData)]; + } + if (attributeData) { + finalData = [...finalData, ...JSON.parse(attributeData)]; + } + if (!finalData.length && sampleData) { + finalData = [...finalData, ...JSON.parse(sampleData)]; + } + } catch (error) { + console.error("Error parsing chart data:", error); + } + + return finalData; +} + +export function parseLayout(staticLayout?: string, attributeLayout?: string, sampleLayout?: string): Partial { + let finalLayout: Partial = {}; + + try { + if (staticLayout) { + finalLayout = { ...finalLayout, ...JSON.parse(staticLayout) }; + } + if (attributeLayout) { + finalLayout = { ...finalLayout, ...JSON.parse(attributeLayout) }; + } + if (Object.keys(finalLayout).length === 0 && sampleLayout) { + finalLayout = { ...finalLayout, ...JSON.parse(sampleLayout) }; + } + } catch (error) { + console.error("Error parsing chart layout:", error); + } + return finalLayout; +} + +export function parseConfig(configOptions?: string): Partial { + if (!configOptions) { + return {}; + } + + try { + return JSON.parse(configOptions); + } catch (error) { + console.error("Error parsing chart config:", error); + return {}; + } +}