michael-s-molina commented on code in PR #33146: URL: https://github.com/apache/superset/pull/33146#discussion_r2072059247
########## superset-frontend/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx: ########## @@ -37,13 +158,326 @@ export default function EchartsWaterfall( }, }; + const getSubtotalOptions = (options: EChartsCoreOption) => { + if (!useFirstValueAsSubtotal) return options; + + const xAxisData = [ + ...((options.xAxis as { data: (string | number)[] }).data || []), + ]; + + const processedSeries = ((options.series as any[]) || []).map(series => { + const newData = series.data.map((dataPoint: any, index: number) => { + if (index !== 0) return dataPoint; + + const isTransparent = + dataPoint?.itemStyle?.color && + dataPoint.itemStyle.color === 'transparent'; + + if (isTransparent) return dataPoint; + + if (dataPoint.value === '-') return dataPoint; + + const updatedColor = `rgba(${totalColor.r}, ${totalColor.g}, ${totalColor.b}, ${totalColor.a})`; + return { + ...dataPoint, + itemStyle: { + ...dataPoint.itemStyle, + color: updatedColor, + borderColor: updatedColor, + }, + }; + }); + + return { + ...series, + data: newData, + }; + }); + + return { + ...options, + xAxis: { + ...(options.xAxis as any), + data: xAxisData, + }, + series: processedSeries, + }; + }; + + const getShowTotalOptions = (options: EChartsCoreOption) => { + if (showTotal) return options; + + const totalsIndex = + ((options.series as any[]) || []) + .find(series => series.name === 'Total') + ?.data.map((dataPoint: any, index: number) => + dataPoint.value !== '-' ? index : -1, + ) + .filter((index: number) => index !== -1) || []; + + const xAxisData = [ + ...((options.xAxis as { data: (string | number)[] }).data || []), + ].filter((_, index) => !totalsIndex.includes(index)); + + const filteredSeries = ((options.series as any[]) || []).map(series => ({ + ...series, + data: series.data.filter( + (_: any, index: number) => !totalsIndex.includes(index), + ), + })); + + return { + ...options, + xAxis: { + ...(options.xAxis as any), + data: xAxisData, + }, + series: filteredSeries, + }; + }; + + const getSortedOptions = (options: EChartsCoreOption) => { + if (sortXAxis === 'none') return options; + const xAxisData = [ + ...((options.xAxis as { data: (string | number)[] }).data || []), + ]; + + const sortedData = [...xAxisData]; + + sortedData.sort((a, b) => { + if (typeof a === 'number' && typeof b === 'number') { + return sortXAxis === 'asc' ? a - b : b - a; + } + const aStr = String(a); + const bStr = String(b); + return sortXAxis === 'asc' + ? aStr.localeCompare(bStr) + : bStr.localeCompare(aStr); + }); + + const indexMap = new Map(xAxisData.map((val, index) => [val, index])); + + const sortedSeries = ((options.series as any[]) || []).map(series => ({ + ...series, + data: sortedData.map(value => { + const index = indexMap.get(value); + return index !== undefined ? (series as any).data[index] : null; + }), + })); + + return { + ...options, + xAxis: { + ...(options.xAxis as any), + data: sortedData, + }, + series: sortedSeries, + }; + }; + + const getFlippedOptions = (options: EChartsCoreOption) => { + if (orientation === 'vertical') return options; + + return { + ...options, + xAxis: { + ...((options.yAxis as any) || {}), + type: 'value', + axisLine: { + show: true, + lineStyle: { + color: theme.colors.grayscale.light3, + width: 1, + }, + }, + splitLine: { + show: true, + lineStyle: { + color: theme.colors.grayscale.light2, + width: 1, + type: 'solid', + }, + }, + name: (options.yAxis as any)?.name || '', + nameLocation: 'middle', + }, + yAxis: { + ...((options.xAxis as any) || {}), + type: 'category', + axisLine: { show: true }, + data: [...(options.xAxis as any).data].reverse(), + name: (options.xAxis as any)?.name || '', + nameLocation: 'middle', + }, + series: Array.isArray(options.series) + ? options.series.map((series: any) => ({ + ...series, + encode: { + x: series.encode?.y, + y: series.encode?.x, + }, + data: [...series.data].reverse(), + label: { + ...(series.label || {}), + position: series.name === 'Decrease' ? 'left' : 'right', + }, + })) + : [], + }; + }; + + const getFormattedAxisOptions = (options: EChartsCoreOption) => { + const { xTicksLayout, xTicksWrapLength } = props.formData; + + // If no formatting needed, return original options + if (boldLabels === 'none' && xTicksLayout !== 'flat') { + return options; + } + + // Get total indices for bold formatting + const totalsIndex = ['total', 'both'].includes(boldLabels) + ? ((options.series as any[]) || []) + .find(series => series.name === 'Total') + ?.data.map((dataPoint: any, index: number) => + dataPoint.value !== '-' ? index : -1, + ) + .filter((index: number) => index !== -1) || [] + : []; + + const formatText = (value: string, index: number) => { + // Handle bold formatting first + let formattedValue = value; + + if (orientation === 'vertical') { + if (index === 0 && ['subtotal', 'both'].includes(boldLabels)) { + formattedValue = `{subtotal|${value}}`; + } else if (totalsIndex.includes(index) && ['total', 'both'].includes(boldLabels)) { + formattedValue = `{total|${value}}`; + } + } else { + const axisData = (options.yAxis as { data?: any[] })?.data || []; + const isLast = index === axisData.length - 1; + if (isLast && ['subtotal', 'both'].includes(boldLabels)) { + formattedValue = `{subtotal|${value}}`; + } else if (totalsIndex.includes(index) && ['total', 'both'].includes(boldLabels)) { + formattedValue = `{total|${value}}`; + } + } + + // get the width of xAxis to calculate the maxCharsPerLine + const getAxisRange = (options: EChartsCoreOption) => { Review Comment: For example, using a combination of [interval](https://echarts.apache.org/en/option.html#xAxis.axisLabel.interval), [overflow](https://echarts.apache.org/en/option.html#xAxis.axisLabel.overflow), and [width](https://echarts.apache.org/en/option.html#xAxis.axisLabel.width), I can have something like: ``` axisLabel.interval = 0; axisLabel.overflow = 'break'; axisLabel.width = 25; ``` <img width="1904" alt="Screenshot 2025-05-02 at 16 25 13" src="https://github.com/user-attachments/assets/14699bfb-d181-4698-92d8-465d51197dd9" /> Here's a [live editor](https://echarts.apache.org/examples/en/editor.html?c=bar-waterfall2&code=PYBwLglsB2AEC8sDeAoWtJgDYFMBcya6GOAHmAQOQCCAxrQK4C2DWAhmDgCawDqHOAE4AzNliywAwgAs2gsJSIBfADREwwYFkggCqYhkEQA5saFU2pCAGdKag5ZsAFYBGidBeogbABPEPiwlNayXMAA7ooGqt6wwsCCTBweBMIM0LSQMLAAFCBybEzWAJSEBui4YBhyANyx6BDCufmChdYA2gCMALqwAGR9sC1tXd0AdABuYgw4sACE8IiUALSUpfrl6GByCEMFRaN1m0qwOFjWsxub24K7wwcATN1H5Ur1sII4YAyCcDf9gxuY2ghVmAGoggAeABGggA9AA-SiwCFAi5GHDWAByoJRQVgVDxQKmWBmL3Qbwp9lguDM0C4XgMXA4bAI7UoAFFSAFoBdbCoggBJDLAJg4SjdZTU4xGBllYi4YQUIIAZgApHZYkZjNJlZQACwa6noaHAMAaJhUdWagy0GDbNwAGTY0LOBDAghmUqIpGoVmsjOIfgCVFoAmMCV8NuIzO2BByaQyWTgOXW70qNJsVUQ7We73itxyGYgu06NVgJchiAeD3LEDBYLTmwqWbGIAYIRylCxwAmOCYrtuyIhEGK5OIlPKn2-v0z1jA46UxVTxtgjmsztdWEDBjcHhJBAADKv0L2hMIsBEqLCcGwANbRgzhCBcMDSAgPACsq8nMXQvj9GwdwwfxAkoEkZiiWA_1gdEIExNlYiuYgQTFKgnHYWgcGkLQuCER8g1A685AI9B5zYWg7yoAAVM0xFI2CIFwdx3U9HATwrTgmAAZT8XBgIMU1BDwwRJC0BIqA9NheRaHB3AY9A7UvTwgikmS5DkhR3hggx-xAWRrCA-VNggLjeN8fjjObISRLE5TJNadTPnkjjbXElTKDU6xZP k94KW0jjY1ZWB2mPWAAE5DzCzoHn1b9YE6T8VWilUAHYADYBU6NLMoSz9Ok6LL0oADnCrLis_XLOn1cL4pi8KHgFMLIui2K6qSlKMqynKsvywqEpKsqEoqqqarqh4GslaJV2Q9BULA4U7TFBjgzA6ESI48jKJouisAY9gtwE4gQivQwZlcoZgEM5NJNAKDpveIK2RagUVTi17wpVAUVjsIJVm6urUuKgUHmK3Kfu-_6_t-l7YDe-KVU-yHfohhKVUB4HYFB8GodRn6ponGb3nmqguR5PkVqIoJ1sEBitqooJaO2PaOIOt0rIME7wlY86_Mu66oGga8zQte7Ccelk2Tx3Goc6Q9McS_VkeV6Gss6IaVXS_qHkPL7Vf11G5YVz8lYNmXfoKjWtZB3WCf89BJSUGogA) where you can play with the settings. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org For additional commands, e-mail: notifications-h...@superset.apache.org