import type { ChartComponentProps } from "."; import type { AllChartData } from "../constants"; import { LabelOrientation, type ChartData, XAxisCategory, messages, } from "../constants"; import { Colors } from "constants/Colors"; import { EChartsLayoutBuilder } from "./LayoutBuilders/EChartsLayoutBuilder"; export class EChartsConfigurationBuilder { fontFamily: string | undefined; #seriesConfigurationForPieChart( seriesID: string, seriesData: ChartData, showDataPointLabel: boolean, ) { let seriesName = messages.Undefined; if (seriesData.seriesName && seriesData.seriesName.length > 0) { seriesName = seriesData.seriesName; } const config = { type: "pie", radius: "60%", center: ["50%", "60%"], name: seriesName, label: { show: showDataPointLabel, fontFamily: this.fontFamily, color: Colors.DOVE_GRAY2, formatter: `{b} : {d}%`, }, encode: { itemName: XAxisCategory, tooltip: seriesID, value: seriesID, }, }; return config; } #seriesConfigForChart( props: ChartComponentProps, allSeriesData: AllChartData, ) { /** * { * series: [ { type: "pie", radius: "40%", center: ["50%", 50%]}] * } */ const configs: unknown[] = []; Object.keys(allSeriesData).forEach((seriesID, index) => { const seriesData = allSeriesData[seriesID]; let color = seriesData.color; if (index == 0 && (!color || color.length == 0)) { color = props.primaryColor; } let seriesName = messages.Undefined; if (seriesData.seriesName && seriesData.seriesName.length > 0) { seriesName = seriesData.seriesName; } let config: Record = { label: { show: props.showDataPointLabel, position: "top" }, name: seriesName, itemStyle: { color: color }, }; switch (props.chartType) { case "BAR_CHART": config = { ...config, type: "bar" }; // The series label should be on the right for bar chart (config.label as Record).position = "right"; break; case "COLUMN_CHART": config = { ...config, type: "bar" }; break; case "LINE_CHART": config = { ...config, type: "line" }; break; case "AREA_CHART": config = { ...config, type: "line", areaStyle: {}, }; break; case "PIE_CHART": config = this.#seriesConfigurationForPieChart( seriesID, seriesData, props.showDataPointLabel, ); break; } configs.push(config); }); return configs; } seriesTitleOffsetForPieChart = (props: ChartComponentProps) => { return 0.3 * props.dimensions.componentHeight - 35; }; #evaluateFontFamily(fontFamily: string | undefined) { return fontFamily === "System Default" ? "inherit" : fontFamily; } #titleConfigForPiechart( props: ChartComponentProps, allSeriesData: AllChartData, ) { const config: Record[] = []; const numSeries = Object.keys(allSeriesData).length; const interval = 100 / (numSeries + 1); Object.values(allSeriesData).forEach((seriesData, index) => { const offset = `${(index + 1) * interval}%`; config.push({ top: this.seriesTitleOffsetForPieChart(props), left: offset, textAlign: "center", text: seriesData.seriesName ?? "", }); }); return config; } #titleConfigForChart( props: ChartComponentProps, allSeriesData: AllChartData, layoutConfig: Record>, ) { /** * title: [ * { * text: "chart title", * }, * // Valid for PIE Chart only * { * * text: "2014", * top: "15%", * left: "50%", * textAlign: "center" * } * ] */ const defaultTitleConfig = { text: props.chartName, show: layoutConfig.title.show, padding: [5, 50], left: "center", textStyle: { fontFamily: this.fontFamily, fontSize: 24, color: Colors.THUNDER, overflow: "truncate", width: props.dimensions.componentWidth - 100, }, }; if (props.chartType == "PIE_CHART") { return [ defaultTitleConfig, ...this.#titleConfigForPiechart(props, allSeriesData), ]; } else { return defaultTitleConfig; } } #configForLabelOrientation(props: ChartComponentProps) { switch (props.labelOrientation) { case LabelOrientation.SLANT: return 45; case LabelOrientation.ROTATE: return 90; default: return 0; } } #defaultEChartConfig = ( layoutConfig: Record>, ): Record => { const config: Record = { legend: { show: layoutConfig.legend.show, type: "scroll", left: "center", align: "left", top: layoutConfig.legend.top, orient: "horizontal", textStyle: { fontFamily: this.fontFamily }, padding: [5, 50], }, tooltip: { trigger: "item", }, }; config.grid = { top: layoutConfig.grid.top, bottom: layoutConfig.grid.bottom, left: layoutConfig.grid.left, show: false, }; return config; }; #yAxisConfig = ( props: ChartComponentProps, layoutConfig: Record>, ) => { /** * { * type: "value", name: "Y Axis Name", nameLocation: "end" * } */ let config: Record = { show: layoutConfig.yAxis.show, }; if (props.chartType != "PIE_CHART") { config = { ...config, name: props.yAxisName, nameLocation: "middle", nameGap: layoutConfig.yAxis.nameGap, nameTextStyle: { fontSize: 14, fontFamily: this.fontFamily, color: Colors.DOVE_GRAY2, }, }; } if (props.chartType == "BAR_CHART") { config.type = "category"; } if (props.setAdaptiveYMin) { config.min = "dataMin"; } config.axisLabel = { fontFamily: this.fontFamily, color: Colors.DOVE_GRAY2, show: layoutConfig.yAxis.show, width: (layoutConfig.yAxis.axisLabel as Record).width, overflow: "break", }; return config; }; #xAxisConfig = ( props: ChartComponentProps, layoutConfig: Record>, ) => { /** * { * type: "value", name: "X Axis Name", nameLocation: "end" * } */ const config: Record = {}; let type = "category"; if (props.chartType == "BAR_CHART") { type = "value"; } config.type = type; config.axisLabel = { show: layoutConfig.xAxis.show, fontFamily: this.fontFamily, color: Colors.DOVE_GRAY2, rotate: this.#configForLabelOrientation(props), width: (layoutConfig.xAxis.axisLabel as Record).width, overflow: "break", }; if (props.chartType == "BAR_CHART" && props.setAdaptiveYMin) { config.min = "dataMin"; } if (props.chartType != "PIE_CHART") { config.name = props.xAxisName; config.nameLocation = "middle"; config.nameGap = layoutConfig.xAxis.nameGap; config.nameTextStyle = { fontSize: 14, fontFamily: this.fontFamily, color: Colors.DOVE_GRAY2, }; } config.show = layoutConfig.xAxis.show; return config; }; #scrollConfig = ( props: ChartComponentProps, layoutConfig: Record>, ) => { if (props.allowScroll) { if (props.chartType != "PIE_CHART") { return [ { show: layoutConfig.scrollBar.show, type: "slider", filterMode: "filter", start: "20", bottom: layoutConfig.scrollBar.bottom, height: layoutConfig.scrollBar.height, }, ]; } } return []; }; prepareEChartConfig(props: ChartComponentProps, allSeriesData: AllChartData) { const layoutBuilder = new EChartsLayoutBuilder({ allowScroll: props.allowScroll, height: props.dimensions.componentHeight, width: props.dimensions.componentWidth, labelOrientation: props.labelOrientation ?? LabelOrientation.AUTO, chartType: props.chartType, chartTitle: props.chartName, }); const layoutConfig: Record< string, Record > = layoutBuilder.layoutConfig; this.fontFamily = this.#evaluateFontFamily(props.fontFamily); const chartConfig: Record = this.#defaultEChartConfig(layoutConfig); chartConfig.title = this.#titleConfigForChart( props, allSeriesData, layoutConfig, ); chartConfig.xAxis = this.#xAxisConfig(props, layoutConfig); chartConfig.yAxis = this.#yAxisConfig(props, layoutConfig); chartConfig.dataZoom = this.#scrollConfig(props, layoutConfig); chartConfig.series = this.#seriesConfigForChart(props, allSeriesData); return chartConfig; } }