From 6136d7027a9471ae8bda6b0c9077b903b837d1a3 Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Thu, 3 Jun 2021 20:05:00 +0800 Subject: [PATCH 01/10] fix(plugin-chart-echarts): waterfall --- .../Waterfall/Stories.tsx | 46 +++ .../plugin-chart-echarts/Waterfall/data.ts | 30 ++ .../src/Waterfall/EchartsWaterfall.tsx | 91 +++++ .../src/Waterfall/buildQuery.ts | 29 ++ .../src/Waterfall/controlPanel.tsx | 158 ++++++++ .../src/Waterfall/images/thumbnail.png | Bin 0 -> 74973 bytes .../src/Waterfall/index.ts | 55 +++ .../src/Waterfall/transformProps.ts | 349 ++++++++++++++++++ .../src/Waterfall/types.ts | 62 ++++ plugins/plugin-chart-echarts/src/index.ts | 1 + 10 files changed, 821 insertions(+) create mode 100644 packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx create mode 100644 packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/data.ts create mode 100644 plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx create mode 100644 plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts create mode 100644 plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx create mode 100644 plugins/plugin-chart-echarts/src/Waterfall/images/thumbnail.png create mode 100644 plugins/plugin-chart-echarts/src/Waterfall/index.ts create mode 100644 plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts create mode 100644 plugins/plugin-chart-echarts/src/Waterfall/types.ts diff --git a/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx new file mode 100644 index 0000000000..3cd31f39d0 --- /dev/null +++ b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core'; +import { boolean, withKnobs, select } from '@storybook/addon-knobs'; +import { EchartsWaterfallChartPlugin } from '@superset-ui/plugin-chart-echarts'; +import transformProps from '@superset-ui/plugin-chart-echarts/src/Waterfall/transformProps'; +import data from './data'; +import { withResizableChartDemo } from '../../../../shared/components/ResizableChartDemo'; + +new EchartsWaterfallChartPlugin().configure({ key: 'echarts-waterfall' }).register(); + +getChartTransformPropsRegistry().registerValue('echarts-waterfall', transformProps); + +export default { + title: 'Chart Plugins|plugin-chart-echarts/Waterfall', + decorators: [withKnobs, withResizableChartDemo], +}; + +export const Waterfall = ({ width, height }) => { + return ( + + ); +}; diff --git a/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/data.ts b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/data.ts new file mode 100644 index 0000000000..0a8c398ab2 --- /dev/null +++ b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/data.ts @@ -0,0 +1,30 @@ +export default [ + { due_to_group: 'Facebook', period: '2020', 'SUM(decomp_volume)': 1945565.5 }, + { due_to_group: 'Competitor TV Advertising', period: '2019', 'SUM(decomp_volume)': 1213252 }, + { due_to_group: 'Online Advertising', period: '2018', 'SUM(decomp_volume)': 999990 }, + { due_to_group: 'COREBASE', period: '2017', 'SUM(decomp_volume)': 852094 }, + { due_to_group: 'COREBASE', period: '2018', 'SUM(decomp_volume)': 736576 }, + { due_to_group: 'DISPLAY', period: '2017', 'SUM(decomp_volume)': 621608 }, + { due_to_group: 'DISPLAY', period: '2018', 'SUM(decomp_volume)': 388904 }, + { due_to_group: 'Facebook', period: '2019', 'SUM(decomp_volume)': 94909 }, + { due_to_group: 'Online Advertising', period: '2017', 'SUM(decomp_volume)': 81334 }, + { due_to_group: 'Halo TV', period: '2018', 'SUM(decomp_volume)': 66828 }, + { due_to_group: 'Halo TV', period: '2017', 'SUM(decomp_volume)': 46818 }, + { due_to_group: 'Competitor TV Advertising', period: '2017', 'SUM(decomp_volume)': 25252 }, + { due_to_group: 'Facebook', period: '2017', 'SUM(decomp_volume)': 23932 }, + { due_to_group: 'DFSI', period: '2017', 'SUM(decomp_volume)': 21466 }, + { due_to_group: 'Coupons', period: '2017', 'SUM(decomp_volume)': 11160 }, + { due_to_group: 'Facebook', period: '2018', 'SUM(decomp_volume)': 9444 }, + { due_to_group: 'DFSI', period: '2019', 'SUM(decomp_volume)': 8785 }, + { due_to_group: 'Competitive Coupons', period: '2017', 'SUM(decomp_volume)': 8724 }, + { due_to_group: 'Competitive Coupons', period: '2019', 'SUM(decomp_volume)': 8724 }, + { due_to_group: 'Coupons', period: '2019', 'SUM(decomp_volume)': 2950 }, + { due_to_group: 'BB Display', period: '2019', 'SUM(decomp_volume)': 1844 }, + { due_to_group: 'BB Display', period: '2017', 'SUM(decomp_volume)': 1844 }, + { due_to_group: 'Email', period: '2017', 'SUM(decomp_volume)': 810 }, + { due_to_group: 'OTHER', period: '2017', 'SUM(decomp_volume)': 78 }, + { due_to_group: 'Email', period: '2019', 'SUM(decomp_volume)': -987000 }, + { due_to_group: 'Email', period: '2020', 'SUM(decomp_volume)': -998988 }, + { due_to_group: 'Online Advertising', period: '2020', 'SUM(decomp_volume)': -1500000.7 }, + { due_to_group: 'Online Advertising', period: '2019', 'SUM(decomp_volume)': -1671652 }, +]; diff --git a/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx b/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx new file mode 100644 index 0000000000..91147986a8 --- /dev/null +++ b/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useCallback } from 'react'; +import Echart from '../components/Echart'; +import { EventHandlers } from '../types'; +import { WaterfallChartTransformedProps } from './types'; + +export default function EchartsWaterfall({ + height, + width, + echartOptions, + setDataMask, + labelMap, + groupby, + selectedValues, + formData, +}: WaterfallChartTransformedProps) { + const handleChange = useCallback( + (values: string[]) => { + if (!formData.emitFilter) { + return; + } + + const groupbyValues = values.map(value => labelMap[value]); + + setDataMask({ + extraFormData: { + filters: + values.length === 0 + ? [] + : groupby.map((col, idx) => { + const val = groupbyValues.map(v => v[idx]); + if (val === null || val === undefined) + return { + col, + op: 'IS NULL', + }; + return { + col, + op: 'IN', + val: val as (string | number | boolean)[], + }; + }), + }, + filterState: { + value: groupbyValues.length ? groupbyValues : null, + selectedValues: values.length ? values : null, + }, + }); + }, + [groupby, labelMap, setDataMask, selectedValues], + ); + + const eventHandlers: EventHandlers = { + click: props => { + const { name } = props; + const values = Object.values(selectedValues); + if (values.includes(name)) { + handleChange(values.filter(v => v !== name)); + } else { + handleChange([...values, name]); + } + }, + }; + + return ( + + ); +} diff --git a/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts b/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts new file mode 100644 index 0000000000..de259db93e --- /dev/null +++ b/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { buildQueryContext } from '@superset-ui/core'; +import { EchartsWaterfallFormData } from './types'; + +export default function buildQuery(formData: EchartsWaterfallFormData) { + return buildQueryContext(formData, baseQueryObject => [ + { + ...baseQueryObject, + groupby: [formData.x_axis_column, formData.period_column], + }, + ]); +} diff --git a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx new file mode 100644 index 0000000000..1f3fffb46d --- /dev/null +++ b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx @@ -0,0 +1,158 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { FeatureFlag, isFeatureEnabled, t, validateNonEmpty } from '@superset-ui/core'; +import { + ColumnOption, + formatSelectOptions, + sections, + sharedControls, +} from '@superset-ui/chart-controls'; +import { DEFAULT_FORM_DATA } from '../Pie/types'; + +const { emitFilter, showLegend } = DEFAULT_FORM_DATA; + +const xAxisColumn: typeof sharedControls.groupby = { + type: 'SelectControl', + label: t('XAxis column'), + description: t('Choose table column that will be displayed on XAxis in chart'), + multi: false, + optionRenderer: c => , + valueRenderer: c => , + valueKey: 'column_name', + mapStateToProps: ({ datasource }) => ({ + options: datasource?.columns || [], + }), + validators: [validateNonEmpty], +}; + +const periodColumn: typeof sharedControls.groupby = { + type: 'SelectControl', + label: t('Period column'), + description: t('Choose table column that will split data to periods'), + multi: false, + optionRenderer: c => , + valueRenderer: c => , + valueKey: 'column_name', + mapStateToProps: ({ datasource }) => ({ + options: datasource?.columns || [], + }), + validators: [validateNonEmpty], +}; + +export default { + controlPanelSections: [ + sections.legacyTimeseriesTime, + { + label: t('Query'), + expanded: true, + controlSetRows: [ + ['metric'], + ['adhoc_filters'], + [ + { + name: 'x_axis_column', + config: xAxisColumn, + }, + ], + [ + { + name: 'period_column', + config: periodColumn, + }, + ], + ['row_limit'], + ], + }, + { + label: t('Chart Options'), + expanded: true, + controlSetRows: [ + ['color_scheme'], + isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) + ? [ + { + name: 'emit_filter', + config: { + type: 'CheckboxControl', + label: t('Enable emitting filters'), + default: emitFilter, + renderTrigger: true, + description: t('Enable emmiting filters.'), + }, + }, + ] + : [], + [ + { + name: 'show_legend', + config: { + type: 'CheckboxControl', + label: t('Show legend'), + renderTrigger: true, + default: showLegend, + description: t('Whether to display a legend for the chart'), + }, + }, + ], + // eslint-disable-next-line react/jsx-key + [

{t('Y Axis')}

], + [ + { + name: 'y_axis_label', + config: { + type: 'TextControl', + label: t('Y Axis Label'), + renderTrigger: true, + default: '', + }, + }, + ], + ['y_axis_format'], + // eslint-disable-next-line react/jsx-key + [

{t('X Axis')}

], + [ + { + name: 'x_axis_label', + config: { + type: 'TextControl', + label: t('X Axis Label'), + renderTrigger: true, + default: '', + }, + }, + ], + [ + { + name: 'x_ticks_layout', + config: { + type: 'SelectControl', + label: t('X Tick Layout'), + choices: formatSelectOptions(['auto', 'flat', '45°', '90°', 'staggered']), + default: 'auto', + clearable: false, + renderTrigger: true, + description: t('The way the ticks are laid out on the X-axis'), + }, + }, + ], + ], + }, + ], +}; diff --git a/plugins/plugin-chart-echarts/src/Waterfall/images/thumbnail.png b/plugins/plugin-chart-echarts/src/Waterfall/images/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..62e048cbfc4247a8dfa44404e24a68db079c7b61 GIT binary patch literal 74973 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 M|8I8S%)iI}FEkQjUjP6A literal 0 HcmV?d00001 diff --git a/plugins/plugin-chart-echarts/src/Waterfall/index.ts b/plugins/plugin-chart-echarts/src/Waterfall/index.ts new file mode 100644 index 0000000000..266d891697 --- /dev/null +++ b/plugins/plugin-chart-echarts/src/Waterfall/index.ts @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regardin + * g copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { ChartMetadata, ChartPlugin, t } from '@superset-ui/core'; +import buildQuery from './buildQuery'; +import controlPanel from './controlPanel'; +import transformProps from './transformProps'; +import thumbnail from './images/thumbnail.png'; +import { EchartsWaterfallChartProps, EchartsWaterfallFormData } from './types'; + +export default class EchartsWaterfallChartPlugin extends ChartPlugin< + EchartsWaterfallFormData, + EchartsWaterfallChartProps +> { + /** + * The constructor is used to pass relevant metadata and callbacks that get + * registered in respective registries that are used throughout the library + * and application. A more thorough description of each property is given in + * the respective imported file. + * + * It is worth noting that `buildQuery` and is optional, and only needed for + * advanced visualizations that require either post processing operations + * (pivoting, rolling aggregations, sorting etc) or submitting multiple queries. + */ + constructor() { + super({ + buildQuery, + controlPanel, + loadChart: () => import('./EchartsWaterfall'), + metadata: new ChartMetadata({ + credits: ['https://echarts.apache.org'], + description: 'Waterfall (Apache ECharts)', + name: t('Waterfall'), + thumbnail, + }), + transformProps, + }); + } +} diff --git a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts new file mode 100644 index 0000000000..fccc3ade5c --- /dev/null +++ b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts @@ -0,0 +1,349 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + CategoricalColorNamespace, + DataRecord, + DataRecordValue, + getMetricLabel, + getNumberFormatter, + NumberFormatter, + t, +} from '@superset-ui/core'; +import { EChartsOption, BarSeriesOption } from 'echarts'; +import { CallbackDataParams } from 'echarts/types/src/util/types'; +import { + WaterfallChartTransformedProps, + EchartsWaterfallFormData, + EchartsWaterfallChartProps, +} from './types'; +import { extractGroupbyLabel, getColtypesMapping } from '../utils/series'; +import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults'; + +const TOTAL_MARK = '__TOTAL__'; +const STACK_MARK = 'stack'; + +const LEGEND = { + INCREASE: t('Increase'), + DECREASE: t('Decrease'), + TOTAL: t('Total'), +}; + +function formatTooltip({ + params, + numberFormatter, +}: { + params: any; + numberFormatter: NumberFormatter; +}) { + const increaseParams = params[1]; + const decreaseParams = params[2]; + const totalParams = params[3]; + + const htmlMaker = (params: any) => + ` +
${params.name}
+
+ ${params.marker} + ${ + params.seriesName + }: + ${numberFormatter( + params.value, + )} +
+ `; + + if (increaseParams.value !== '-') { + return htmlMaker(increaseParams); + } + if (decreaseParams.value !== '-') { + return htmlMaker(decreaseParams); + } + if (totalParams.value !== '-') { + return htmlMaker(totalParams); + } + return ''; +} + +function transformer( + data: DataRecord[], + periodColumn: string, + xAxisColumn: string, + valueColumn: string, +) { + // Sort by period (ascending) + const sortedData = data.sort( + (a, b) => + Number.parseInt(a[periodColumn] as string, 10) - + Number.parseInt(b[periodColumn] as string, 10), + ); + + // Group by period (temporary map) + const groupedData = sortedData.reduce((acc, cur) => { + const period = cur[periodColumn] as string; + const periodData = acc.get(period) || []; + periodData.push(cur); + acc.set(period, periodData); + return acc; + }, new Map()); + + let transformedData: DataRecord[] = []; + let isFirstPeriod = true; + groupedData.forEach((value, key) => { + let tempValue = value; + // Calc total per period + const sum = tempValue.reduce((acc, cur) => acc + (cur[valueColumn] as number), 0); + // Push total per period to the end of period values array + tempValue.push({ + [xAxisColumn]: key, + [periodColumn]: TOTAL_MARK, + [valueColumn]: sum, + }); + // Remove first period and leave only last one + if (isFirstPeriod) { + const lastItem = tempValue[tempValue.length - 1]; + tempValue = [lastItem]; + isFirstPeriod = false; + } + transformedData = transformedData.concat(tempValue); + }); + + return transformedData; +} + +export default function transformProps( + chartProps: EchartsWaterfallChartProps, +): WaterfallChartTransformedProps { + const { width, height, formData, hooks, filterState, queriesData } = chartProps; + const { data = [] } = queriesData[0]; + const { setDataMask = () => {} } = hooks; + const coltypeMapping = getColtypesMapping(queriesData[0]); + const { + colorScheme, + groupby = [], + metric = '', + periodColumn, + xAxisColumn, + xTicksLayout, + showLegend, + yAxisLabel, + xAxisLabel, + yAxisFormat, + emitFilter, + } = formData as EchartsWaterfallFormData; + const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); + const numberFormatter = getNumberFormatter(yAxisFormat); + const formatter = (params: CallbackDataParams) => { + const { value, seriesName } = params; + let formattedValue = numberFormatter(value as number); + if (seriesName === LEGEND.DECREASE) { + formattedValue = `-${formattedValue}`; + } + return formattedValue; + }; + + const metricLabel = getMetricLabel(metric); + + const transformedData = transformer(data, periodColumn, xAxisColumn, metricLabel); + + const assistData: (number | string)[] = []; + const increaseData: (number | string)[] = []; + const decreaseData: (number | string)[] = []; + const totalData: (number | string)[] = []; + + transformedData.forEach((data, index, self) => { + const totalSumUpToCur = self.slice(0, index + 1).reduce((prev, cur, i) => { + // Ignore calculation on period column except first period + if (cur[periodColumn] !== TOTAL_MARK || i === 0) { + return prev + (cur[metricLabel] as number); + } + return prev; + }, 0); + + const value = data[metricLabel] as number; + const isNegative = value < 0; + if (data[periodColumn] === TOTAL_MARK) { + increaseData.push('-'); + decreaseData.push('-'); + assistData.push('-'); + totalData.push(totalSumUpToCur); + } else if (isNegative) { + increaseData.push('-'); + decreaseData.push(Math.abs(value)); + assistData.push(totalSumUpToCur); + totalData.push('-'); + } else { + increaseData.push(value); + decreaseData.push('-'); + assistData.push(totalSumUpToCur - value); + totalData.push('-'); + } + }); + + const labelMap = transformedData.reduce((acc: Record, datum) => { + const label = extractGroupbyLabel({ + datum, + groupby, + coltypeMapping, + }); + return { + ...acc, + [label]: groupby.map(col => datum[col]), + }; + }, {}); + + const selectedValues = (filterState.selectedValues || []).reduce( + (acc: Record, selectedValue: string) => { + const index = transformedData.findIndex(({ name }) => name === selectedValue); + return { + ...acc, + [index]: selectedValue, + }; + }, + {}, + ); + + let axisLabel; + if (xTicksLayout === '45°') axisLabel = { rotate: -45 }; + else if (xTicksLayout === '90°') axisLabel = { rotate: -90 }; + else if (xTicksLayout === 'flat') axisLabel = { rotate: 0 }; + else if (xTicksLayout === 'staggered') axisLabel = { rotate: -45 }; + else axisLabel = { show: true }; + + const series: BarSeriesOption[] = [ + { + name: 'assist', + type: 'bar', + stack: STACK_MARK, + itemStyle: { + borderColor: 'rgba(0,0,0,0)', + color: 'rgba(0,0,0,0)', + }, + emphasis: { + itemStyle: { + borderColor: 'rgba(0,0,0,0)', + color: 'rgba(0,0,0,0)', + }, + }, + data: assistData, + }, + { + name: LEGEND.INCREASE, + type: 'bar', + stack: STACK_MARK, + label: { + show: true, + position: 'top', + formatter, + }, + itemStyle: { + color: colorFn(LEGEND.INCREASE), + }, + data: increaseData, + }, + { + name: LEGEND.DECREASE, + type: 'bar', + stack: STACK_MARK, + label: { + show: true, + position: 'bottom', + formatter, + }, + itemStyle: { + color: colorFn(LEGEND.DECREASE), + }, + data: decreaseData, + }, + { + name: LEGEND.TOTAL, + type: 'bar', + stack: STACK_MARK, + label: { + show: true, + position: 'top', + formatter, + }, + itemStyle: { + color: colorFn(LEGEND.TOTAL), + }, + data: totalData, + }, + ]; + + const echartOptions: EChartsOption = { + grid: { + ...defaultGrid, + top: 30, + bottom: 30, + left: 20, + right: 20, + }, + legend: { + show: showLegend, + data: [LEGEND.INCREASE, LEGEND.DECREASE, LEGEND.TOTAL], + }, + xAxis: { + type: 'category', + data: transformedData.map(row => row[xAxisColumn] as string), + name: xAxisLabel, + nameTextStyle: { + padding: [15, 0, 0, 0], + }, + nameLocation: 'middle', + axisLabel, + }, + yAxis: { + ...defaultYAxis, + type: 'value', + nameTextStyle: { + padding: [0, 0, 20, 0], + }, + nameLocation: 'middle', + name: yAxisLabel, + + axisLabel: { formatter: numberFormatter }, + }, + tooltip: { + ...defaultTooltip, + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + formatter: (params: any) => + formatTooltip({ + params, + numberFormatter, + }), + }, + series, + }; + + return { + formData, + width, + height, + echartOptions, + setDataMask, + emitFilter, + labelMap, + groupby, + selectedValues, + }; +} diff --git a/plugins/plugin-chart-echarts/src/Waterfall/types.ts b/plugins/plugin-chart-echarts/src/Waterfall/types.ts new file mode 100644 index 0000000000..68bc213ee9 --- /dev/null +++ b/plugins/plugin-chart-echarts/src/Waterfall/types.ts @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + ChartDataResponseResult, + ChartProps, + DataRecordValue, + QueryFormData, + QueryFormMetric, + SetDataMaskHook, +} from '@superset-ui/core'; +import { EChartsOption } from 'echarts'; +import { EchartsLegendFormData } from '../types'; + +export type WaterfallFormXTicksLayout = '45°' | '90°' | 'auto' | 'flat' | 'staggered'; + +export type EchartsWaterfallFormData = QueryFormData & + EchartsLegendFormData & { + metric: QueryFormMetric; + yAxisLabel: string; + xAxisLabel: string; + yAxisFormat: string; + xTicksLayout?: WaterfallFormXTicksLayout; + emitFilter: boolean; + }; + +export const DEFAULT_FORM_DATA: Partial = { + showLegend: true, + emitFilter: false, +}; + +export interface EchartsWaterfallChartProps extends ChartProps { + formData: EchartsWaterfallFormData; + queriesData: ChartDataResponseResult[]; +} + +export interface WaterfallChartTransformedProps { + formData: EchartsWaterfallFormData; + height: number; + width: number; + echartOptions: EChartsOption; + emitFilter: boolean; + setDataMask: SetDataMaskHook; + labelMap: Record; + groupby: string[]; + selectedValues: Record; +} diff --git a/plugins/plugin-chart-echarts/src/index.ts b/plugins/plugin-chart-echarts/src/index.ts index 1f39843beb..bd8eb7ab72 100644 --- a/plugins/plugin-chart-echarts/src/index.ts +++ b/plugins/plugin-chart-echarts/src/index.ts @@ -32,6 +32,7 @@ export { default as EchartsRadarChartPlugin } from './Radar'; export { default as EchartsFunnelChartPlugin } from './Funnel'; export { default as EchartsTreeChartPlugin } from './Tree'; export { default as EchartsTreemapChartPlugin } from './Treemap'; +export { default as EchartsWaterfallChartPlugin } from './Waterfall'; /** * Note: this file exports the default export from EchartsTimeseries.tsx. From 75c5d0d7157487578be91cdc3947f630a56ae04d Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Sat, 5 Jun 2021 11:06:00 +0800 Subject: [PATCH 02/10] fix(plugin-chart-echarts): rename --- .../src/Waterfall/buildQuery.ts | 2 +- .../src/Waterfall/controlPanel.tsx | 16 +++++----- .../src/Waterfall/transformProps.ts | 32 ++++++++----------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts b/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts index de259db93e..0550d3a719 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts @@ -23,7 +23,7 @@ export default function buildQuery(formData: EchartsWaterfallFormData) { return buildQueryContext(formData, baseQueryObject => [ { ...baseQueryObject, - groupby: [formData.x_axis_column, formData.period_column], + groupby: [formData.category, formData.breakdown], }, ]); } diff --git a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx index 1f3fffb46d..307ec7c204 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx +++ b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx @@ -28,9 +28,9 @@ import { DEFAULT_FORM_DATA } from '../Pie/types'; const { emitFilter, showLegend } = DEFAULT_FORM_DATA; -const xAxisColumn: typeof sharedControls.groupby = { +const Category: typeof sharedControls.groupby = { type: 'SelectControl', - label: t('XAxis column'), + label: t('Category'), description: t('Choose table column that will be displayed on XAxis in chart'), multi: false, optionRenderer: c => , @@ -42,9 +42,9 @@ const xAxisColumn: typeof sharedControls.groupby = { validators: [validateNonEmpty], }; -const periodColumn: typeof sharedControls.groupby = { +const Breakdown: typeof sharedControls.groupby = { type: 'SelectControl', - label: t('Period column'), + label: t('Breakdown'), description: t('Choose table column that will split data to periods'), multi: false, optionRenderer: c => , @@ -67,14 +67,14 @@ export default { ['adhoc_filters'], [ { - name: 'x_axis_column', - config: xAxisColumn, + name: 'category', + config: Category, }, ], [ { - name: 'period_column', - config: periodColumn, + name: 'breakdown', + config: Breakdown, }, ], ['row_limit'], diff --git a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts index fccc3ade5c..ed5a758df9 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts @@ -81,22 +81,16 @@ function formatTooltip({ return ''; } -function transformer( - data: DataRecord[], - periodColumn: string, - xAxisColumn: string, - valueColumn: string, -) { +function transformer(data: DataRecord[], breakdown: string, category: string, metric: string) { // Sort by period (ascending) const sortedData = data.sort( (a, b) => - Number.parseInt(a[periodColumn] as string, 10) - - Number.parseInt(b[periodColumn] as string, 10), + Number.parseInt(a[breakdown] as string, 10) - Number.parseInt(b[breakdown] as string, 10), ); // Group by period (temporary map) const groupedData = sortedData.reduce((acc, cur) => { - const period = cur[periodColumn] as string; + const period = cur[breakdown] as string; const periodData = acc.get(period) || []; periodData.push(cur); acc.set(period, periodData); @@ -108,12 +102,12 @@ function transformer( groupedData.forEach((value, key) => { let tempValue = value; // Calc total per period - const sum = tempValue.reduce((acc, cur) => acc + (cur[valueColumn] as number), 0); + const sum = tempValue.reduce((acc, cur) => acc + (cur[metric] as number), 0); // Push total per period to the end of period values array tempValue.push({ - [xAxisColumn]: key, - [periodColumn]: TOTAL_MARK, - [valueColumn]: sum, + [category]: key, + [breakdown]: TOTAL_MARK, + [metric]: sum, }); // Remove first period and leave only last one if (isFirstPeriod) { @@ -138,8 +132,8 @@ export default function transformProps( colorScheme, groupby = [], metric = '', - periodColumn, - xAxisColumn, + breakdown, + category, xTicksLayout, showLegend, yAxisLabel, @@ -160,7 +154,7 @@ export default function transformProps( const metricLabel = getMetricLabel(metric); - const transformedData = transformer(data, periodColumn, xAxisColumn, metricLabel); + const transformedData = transformer(data, breakdown, category, metricLabel); const assistData: (number | string)[] = []; const increaseData: (number | string)[] = []; @@ -170,7 +164,7 @@ export default function transformProps( transformedData.forEach((data, index, self) => { const totalSumUpToCur = self.slice(0, index + 1).reduce((prev, cur, i) => { // Ignore calculation on period column except first period - if (cur[periodColumn] !== TOTAL_MARK || i === 0) { + if (cur[breakdown] !== TOTAL_MARK || i === 0) { return prev + (cur[metricLabel] as number); } return prev; @@ -178,7 +172,7 @@ export default function transformProps( const value = data[metricLabel] as number; const isNegative = value < 0; - if (data[periodColumn] === TOTAL_MARK) { + if (data[breakdown] === TOTAL_MARK) { increaseData.push('-'); decreaseData.push('-'); assistData.push('-'); @@ -301,7 +295,7 @@ export default function transformProps( }, xAxis: { type: 'category', - data: transformedData.map(row => row[xAxisColumn] as string), + data: transformedData.map(row => row[category] as string), name: xAxisLabel, nameTextStyle: { padding: [15, 0, 0, 0], From dd9868b637c62ed4282bbbc3bb4f10e2e3325e90 Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Sat, 5 Jun 2021 16:52:35 +0800 Subject: [PATCH 03/10] fix(plugin-chart-echarts): remove some unused code --- .../src/Waterfall/EchartsWaterfall.tsx | 66 +------------------ .../src/Waterfall/transformProps.ts | 48 ++------------ .../src/Waterfall/types.ts | 2 - 3 files changed, 6 insertions(+), 110 deletions(-) diff --git a/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx b/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx index 91147986a8..d423ff0a21 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx +++ b/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx @@ -16,76 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useCallback } from 'react'; +import React from 'react'; import Echart from '../components/Echart'; -import { EventHandlers } from '../types'; import { WaterfallChartTransformedProps } from './types'; export default function EchartsWaterfall({ height, width, echartOptions, - setDataMask, - labelMap, - groupby, - selectedValues, - formData, }: WaterfallChartTransformedProps) { - const handleChange = useCallback( - (values: string[]) => { - if (!formData.emitFilter) { - return; - } - - const groupbyValues = values.map(value => labelMap[value]); - - setDataMask({ - extraFormData: { - filters: - values.length === 0 - ? [] - : groupby.map((col, idx) => { - const val = groupbyValues.map(v => v[idx]); - if (val === null || val === undefined) - return { - col, - op: 'IS NULL', - }; - return { - col, - op: 'IN', - val: val as (string | number | boolean)[], - }; - }), - }, - filterState: { - value: groupbyValues.length ? groupbyValues : null, - selectedValues: values.length ? values : null, - }, - }); - }, - [groupby, labelMap, setDataMask, selectedValues], - ); - - const eventHandlers: EventHandlers = { - click: props => { - const { name } = props; - const values = Object.values(selectedValues); - if (values.includes(name)) { - handleChange(values.filter(v => v !== name)); - } else { - handleChange([...values, name]); - } - }, - }; - - return ( - - ); + return ; } diff --git a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts index ed5a758df9..f079add6ba 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts @@ -19,7 +19,6 @@ import { CategoricalColorNamespace, DataRecord, - DataRecordValue, getMetricLabel, getNumberFormatter, NumberFormatter, @@ -27,13 +26,9 @@ import { } from '@superset-ui/core'; import { EChartsOption, BarSeriesOption } from 'echarts'; import { CallbackDataParams } from 'echarts/types/src/util/types'; -import { - WaterfallChartTransformedProps, - EchartsWaterfallFormData, - EchartsWaterfallChartProps, -} from './types'; -import { extractGroupbyLabel, getColtypesMapping } from '../utils/series'; +import { EchartsWaterfallFormData, EchartsWaterfallChartProps } from './types'; import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults'; +import { EchartsProps } from '../types'; const TOTAL_MARK = '__TOTAL__'; const STACK_MARK = 'stack'; @@ -121,16 +116,11 @@ function transformer(data: DataRecord[], breakdown: string, category: string, me return transformedData; } -export default function transformProps( - chartProps: EchartsWaterfallChartProps, -): WaterfallChartTransformedProps { - const { width, height, formData, hooks, filterState, queriesData } = chartProps; +export default function transformProps(chartProps: EchartsWaterfallChartProps): EchartsProps { + const { width, height, formData, queriesData } = chartProps; const { data = [] } = queriesData[0]; - const { setDataMask = () => {} } = hooks; - const coltypeMapping = getColtypesMapping(queriesData[0]); const { colorScheme, - groupby = [], metric = '', breakdown, category, @@ -139,7 +129,6 @@ export default function transformProps( yAxisLabel, xAxisLabel, yAxisFormat, - emitFilter, } = formData as EchartsWaterfallFormData; const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const numberFormatter = getNumberFormatter(yAxisFormat); @@ -190,29 +179,6 @@ export default function transformProps( } }); - const labelMap = transformedData.reduce((acc: Record, datum) => { - const label = extractGroupbyLabel({ - datum, - groupby, - coltypeMapping, - }); - return { - ...acc, - [label]: groupby.map(col => datum[col]), - }; - }, {}); - - const selectedValues = (filterState.selectedValues || []).reduce( - (acc: Record, selectedValue: string) => { - const index = transformedData.findIndex(({ name }) => name === selectedValue); - return { - ...acc, - [index]: selectedValue, - }; - }, - {}, - ); - let axisLabel; if (xTicksLayout === '45°') axisLabel = { rotate: -45 }; else if (xTicksLayout === '90°') axisLabel = { rotate: -90 }; @@ -330,14 +296,8 @@ export default function transformProps( }; return { - formData, width, height, echartOptions, - setDataMask, - emitFilter, - labelMap, - groupby, - selectedValues, }; } diff --git a/plugins/plugin-chart-echarts/src/Waterfall/types.ts b/plugins/plugin-chart-echarts/src/Waterfall/types.ts index 68bc213ee9..78e7d45ee6 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/types.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/types.ts @@ -36,12 +36,10 @@ export type EchartsWaterfallFormData = QueryFormData & xAxisLabel: string; yAxisFormat: string; xTicksLayout?: WaterfallFormXTicksLayout; - emitFilter: boolean; }; export const DEFAULT_FORM_DATA: Partial = { showLegend: true, - emitFilter: false, }; export interface EchartsWaterfallChartProps extends ChartProps { From dd4684e12f8ea38a0ac4dddbd0af9b2ca7dce577 Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Sat, 5 Jun 2021 16:53:29 +0800 Subject: [PATCH 04/10] fix(plugin-chart-echarts): remove some unused code --- .../src/Waterfall/controlPanel.tsx | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx index 307ec7c204..d8d3c1bd76 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx +++ b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx @@ -17,7 +17,7 @@ * under the License. */ import React from 'react'; -import { FeatureFlag, isFeatureEnabled, t, validateNonEmpty } from '@superset-ui/core'; +import { t, validateNonEmpty } from '@superset-ui/core'; import { ColumnOption, formatSelectOptions, @@ -26,7 +26,7 @@ import { } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from '../Pie/types'; -const { emitFilter, showLegend } = DEFAULT_FORM_DATA; +const { showLegend } = DEFAULT_FORM_DATA; const Category: typeof sharedControls.groupby = { type: 'SelectControl', @@ -85,20 +85,6 @@ export default { expanded: true, controlSetRows: [ ['color_scheme'], - isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) - ? [ - { - name: 'emit_filter', - config: { - type: 'CheckboxControl', - label: t('Enable emitting filters'), - default: emitFilter, - renderTrigger: true, - description: t('Enable emmiting filters.'), - }, - }, - ] - : [], [ { name: 'show_legend', From 0d8778d06e380b1c3896f7dc60ef5e117c184a26 Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Sat, 5 Jun 2021 17:44:24 +0800 Subject: [PATCH 05/10] fix(plugin-chart-echarts): add unit test --- .../Waterfall/Stories.tsx | 4 +- .../test/Waterfall/buildQuery.test.ts | 37 ++++++++++ .../test/Waterfall/transformProps.test.ts | 71 +++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 plugins/plugin-chart-echarts/test/Waterfall/buildQuery.test.ts create mode 100644 plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts diff --git a/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx index 3cd31f39d0..0eb96cbb7a 100644 --- a/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx +++ b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx @@ -24,8 +24,8 @@ export const Waterfall = ({ width, height }) => { queriesData={[{ data }]} formData={{ metric: `SUM(decomp_volume)`, - xAxisColumn: 'due_to_group', - periodColumn: 'period', + category: 'due_to_group', + breakdown: 'period', x_ticks_layout: '45°', adhocFilters: [ { diff --git a/plugins/plugin-chart-echarts/test/Waterfall/buildQuery.test.ts b/plugins/plugin-chart-echarts/test/Waterfall/buildQuery.test.ts new file mode 100644 index 0000000000..c701977ec7 --- /dev/null +++ b/plugins/plugin-chart-echarts/test/Waterfall/buildQuery.test.ts @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import buildQuery from '../../src/Waterfall/buildQuery'; + +describe('Waterfall buildQuery', () => { + const formData = { + datasource: '5__table', + granularity_sqla: 'ds', + metric: 'foo', + category: 'bar', + breakdown: 'baz', + viz_type: 'my_chart', + }; + + it('should build query fields from form data', () => { + const queryContext = buildQuery(formData); + const [query] = queryContext.queries; + expect(query.metrics).toEqual(['foo']); + expect(query.groupby).toEqual(['bar', 'baz']); + }); +}); diff --git a/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts b/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts new file mode 100644 index 0000000000..9b2e73b4b7 --- /dev/null +++ b/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { ChartProps } from '@superset-ui/core'; +import transformProps from '../../src/Waterfall/transformProps'; + +describe('Waterfall tranformProps', () => { + const formData = { + colorScheme: 'bnbColors', + datasource: '3__table', + granularity_sqla: 'ds', + metric: 'sum', + category: 'foo', + breakdown: 'bar', + }; + const chartProps = new ChartProps({ + formData, + width: 800, + height: 600, + queriesData: [ + { + data: [ + { foo: 'Sylvester', bar: '2019', sum: 10 }, + { foo: 'Arnold', bar: '2019', sum: 3 }, + { foo: 'Sylvester', bar: '2020', sum: -10 }, + { foo: 'Arnold', bar: '2020', sum: 5 }, + ], + }, + ], + }); + + it('should tranform chart props for viz', () => { + expect(transformProps(chartProps)).toEqual( + expect.objectContaining({ + width: 800, + height: 600, + echartOptions: expect.objectContaining({ + series: [ + expect.objectContaining({ + data: ['-', 3, 3, '-'], + }), + expect.objectContaining({ + data: ['-', '-', 5, '-'], + }), + expect.objectContaining({ + data: ['-', 10, '-', '-'], + }), + expect.objectContaining({ + data: [13, '-', '-', 8], + }), + ], + }), + }), + ); + }); +}); From 08cdd6f1f315b8d9140344eab85318d7d3233086 Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Sun, 6 Jun 2021 20:19:30 +0800 Subject: [PATCH 06/10] =?UTF-8?q?fix(plugin-chart-echarts):=20change=20tra?= =?UTF-8?q?nsformProps=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Waterfall/buildQuery.ts | 3 +- .../src/Waterfall/controlPanel.tsx | 3 +- .../src/Waterfall/transformProps.ts | 138 ++++++++++++------ .../src/Waterfall/types.ts | 2 + .../test/Waterfall/transformProps.test.ts | 89 ++++++++--- 5 files changed, 161 insertions(+), 74 deletions(-) diff --git a/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts b/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts index 0550d3a719..1f9d8449f4 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts @@ -20,10 +20,11 @@ import { buildQueryContext } from '@superset-ui/core'; import { EchartsWaterfallFormData } from './types'; export default function buildQuery(formData: EchartsWaterfallFormData) { + const { category, breakdown } = formData; return buildQueryContext(formData, baseQueryObject => [ { ...baseQueryObject, - groupby: [formData.category, formData.breakdown], + groupby: breakdown ? [category, breakdown] : [category], }, ]); } diff --git a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx index d8d3c1bd76..2d2040e17c 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx +++ b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx @@ -45,7 +45,7 @@ const Category: typeof sharedControls.groupby = { const Breakdown: typeof sharedControls.groupby = { type: 'SelectControl', label: t('Breakdown'), - description: t('Choose table column that will split data to periods'), + description: t('Add additional data for each category'), multi: false, optionRenderer: c => , valueRenderer: c => , @@ -53,7 +53,6 @@ const Breakdown: typeof sharedControls.groupby = { mapStateToProps: ({ datasource }) => ({ options: datasource?.columns || [], }), - validators: [validateNonEmpty], }; export default { diff --git a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts index f079add6ba..041ccf2a4b 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts @@ -25,12 +25,13 @@ import { t, } from '@superset-ui/core'; import { EChartsOption, BarSeriesOption } from 'echarts'; -import { CallbackDataParams } from 'echarts/types/src/util/types'; +import { CallbackDataParams, OptionDataValue } from 'echarts/types/src/util/types'; +import { BarDataItemOption } from 'echarts/types/src/chart/bar/BarSeries'; import { EchartsWaterfallFormData, EchartsWaterfallChartProps } from './types'; import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults'; import { EchartsProps } from '../types'; -const TOTAL_MARK = '__TOTAL__'; +const TOTAL_MARK = t('Total'); const STACK_MARK = 'stack'; const LEGEND = { @@ -76,42 +77,63 @@ function formatTooltip({ return ''; } -function transformer(data: DataRecord[], breakdown: string, category: string, metric: string) { - // Sort by period (ascending) - const sortedData = data.sort( - (a, b) => - Number.parseInt(a[breakdown] as string, 10) - Number.parseInt(b[breakdown] as string, 10), - ); - - // Group by period (temporary map) - const groupedData = sortedData.reduce((acc, cur) => { - const period = cur[breakdown] as string; - const periodData = acc.get(period) || []; - periodData.push(cur); - acc.set(period, periodData); +function transformer({ + data, + breakdown, + category, + metric, +}: { + data: DataRecord[]; + breakdown: string; + category: string; + metric: string; +}) { + // Group by category (temporary map) + const groupedData = data.reduce((acc, cur) => { + const categoryLabel = cur[category] as string; + const categoryData = acc.get(categoryLabel) || []; + categoryData.push(cur); + acc.set(categoryLabel, categoryData); return acc; }, new Map()); - let transformedData: DataRecord[] = []; - let isFirstPeriod = true; - groupedData.forEach((value, key) => { - let tempValue = value; - // Calc total per period - const sum = tempValue.reduce((acc, cur) => acc + (cur[metric] as number), 0); - // Push total per period to the end of period values array - tempValue.push({ - [category]: key, - [breakdown]: TOTAL_MARK, - [metric]: sum, + const transformedData: DataRecord[] = []; + + if (breakdown) { + let isFirst = true; + groupedData.forEach((value, key) => { + let tempValue = value; + // Calc total per period + const sum = tempValue.reduce((acc, cur) => acc + (cur[metric] as number), 0); + // Push total per period to the end of period values array + tempValue.push({ + [category]: key, + [breakdown]: TOTAL_MARK, + [metric]: sum, + }); + // Remove first period and leave only last one + if (isFirst) { + const lastItem = tempValue[tempValue.length - 1]; + tempValue = [lastItem]; + isFirst = false; + } + transformedData.push(...tempValue); }); - // Remove first period and leave only last one - if (isFirstPeriod) { - const lastItem = tempValue[tempValue.length - 1]; - tempValue = [lastItem]; - isFirstPeriod = false; - } - transformedData = transformedData.concat(tempValue); - }); + } else { + let total = 0; + groupedData.forEach((value, key) => { + const sum = value.reduce((acc, cur) => acc + (cur[metric] as number), 0); + transformedData.push({ + [category]: key, + [metric]: sum, + }); + total += sum; + }); + transformedData.push({ + [category]: TOTAL_MARK, + [metric]: total, + }); + } return transformedData; } @@ -122,7 +144,7 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): const { colorScheme, metric = '', - breakdown, + breakdown = '', category, xTicksLayout, showLegend, @@ -143,17 +165,25 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): const metricLabel = getMetricLabel(metric); - const transformedData = transformer(data, breakdown, category, metricLabel); + const transformedData = transformer({ + data, + breakdown, + category, + metric: metricLabel, + }); - const assistData: (number | string)[] = []; - const increaseData: (number | string)[] = []; - const decreaseData: (number | string)[] = []; - const totalData: (number | string)[] = []; + const assistData: (BarDataItemOption | OptionDataValue | OptionDataValue[])[] = []; + const increaseData: (BarDataItemOption | OptionDataValue | OptionDataValue[])[] = []; + const decreaseData: (BarDataItemOption | OptionDataValue | OptionDataValue[])[] = []; + const totalData: (BarDataItemOption | OptionDataValue | OptionDataValue[])[] = []; transformedData.forEach((data, index, self) => { - const totalSumUpToCur = self.slice(0, index + 1).reduce((prev, cur, i) => { - // Ignore calculation on period column except first period - if (cur[breakdown] !== TOTAL_MARK || i === 0) { + const totalSum = self.slice(0, index + 1).reduce((prev, cur, i) => { + if (breakdown) { + if (cur[breakdown] !== TOTAL_MARK || i === 0) { + return prev + (cur[metricLabel] as number); + } + } else if (cur[category] !== TOTAL_MARK) { return prev + (cur[metricLabel] as number); } return prev; @@ -161,20 +191,20 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): const value = data[metricLabel] as number; const isNegative = value < 0; - if (data[breakdown] === TOTAL_MARK) { + if (data[breakdown] === TOTAL_MARK || data[category] === TOTAL_MARK) { increaseData.push('-'); decreaseData.push('-'); assistData.push('-'); - totalData.push(totalSumUpToCur); + totalData.push(totalSum); } else if (isNegative) { increaseData.push('-'); decreaseData.push(Math.abs(value)); - assistData.push(totalSumUpToCur); + assistData.push(totalSum); totalData.push('-'); } else { increaseData.push(value); decreaseData.push('-'); - assistData.push(totalSumUpToCur - value); + assistData.push(totalSum - value); totalData.push('-'); } }); @@ -186,6 +216,18 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): else if (xTicksLayout === 'staggered') axisLabel = { rotate: -45 }; else axisLabel = { show: true }; + let xAxisData = []; + if (breakdown) { + xAxisData = transformedData.map(row => { + if (row[breakdown] === TOTAL_MARK) { + return row[category] as string; + } + return row[breakdown] as string; + }); + } else { + xAxisData = transformedData.map(row => row[category] as string); + } + const series: BarSeriesOption[] = [ { name: 'assist', @@ -261,7 +303,7 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): }, xAxis: { type: 'category', - data: transformedData.map(row => row[category] as string), + data: xAxisData, name: xAxisLabel, nameTextStyle: { padding: [15, 0, 0, 0], diff --git a/plugins/plugin-chart-echarts/src/Waterfall/types.ts b/plugins/plugin-chart-echarts/src/Waterfall/types.ts index 78e7d45ee6..19be2fcdfd 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/types.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/types.ts @@ -36,6 +36,8 @@ export type EchartsWaterfallFormData = QueryFormData & xAxisLabel: string; yAxisFormat: string; xTicksLayout?: WaterfallFormXTicksLayout; + category: string; + breakdown?: string; }; export const DEFAULT_FORM_DATA: Partial = { diff --git a/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts b/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts index 9b2e73b4b7..5ab60409fd 100644 --- a/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts +++ b/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts @@ -20,31 +20,74 @@ import { ChartProps } from '@superset-ui/core'; import transformProps from '../../src/Waterfall/transformProps'; describe('Waterfall tranformProps', () => { - const formData = { - colorScheme: 'bnbColors', - datasource: '3__table', - granularity_sqla: 'ds', - metric: 'sum', - category: 'foo', - breakdown: 'bar', - }; - const chartProps = new ChartProps({ - formData, - width: 800, - height: 600, - queriesData: [ - { - data: [ - { foo: 'Sylvester', bar: '2019', sum: 10 }, - { foo: 'Arnold', bar: '2019', sum: 3 }, - { foo: 'Sylvester', bar: '2020', sum: -10 }, - { foo: 'Arnold', bar: '2020', sum: 5 }, - ], - }, - ], + const data = [ + { foo: 'Sylvester', bar: '2019', sum: 10 }, + { foo: 'Arnold', bar: '2019', sum: 3 }, + { foo: 'Sylvester', bar: '2020', sum: -10 }, + { foo: 'Arnold', bar: '2020', sum: 5 }, + ]; + + it('should tranform chart props for viz when breakdown not exist', () => { + const formData1 = { + colorScheme: 'bnbColors', + datasource: '3__table', + granularity_sqla: 'ds', + metric: 'sum', + category: 'bar', + }; + const chartProps = new ChartProps({ + formData: formData1, + width: 800, + height: 600, + queriesData: [ + { + data, + }, + ], + }); + expect(transformProps(chartProps)).toEqual( + expect.objectContaining({ + width: 800, + height: 600, + echartOptions: expect.objectContaining({ + series: [ + expect.objectContaining({ + data: [0, 8, '-'], + }), + expect.objectContaining({ + data: [13, '-', '-'], + }), + expect.objectContaining({ + data: ['-', 5, '-'], + }), + expect.objectContaining({ + data: ['-', '-', 8], + }), + ], + }), + }), + ); }); - it('should tranform chart props for viz', () => { + it('should tranform chart props for viz when breakdown exist', () => { + const formData1 = { + colorScheme: 'bnbColors', + datasource: '3__table', + granularity_sqla: 'ds', + metric: 'sum', + category: 'bar', + breakdown: 'foo', + }; + const chartProps = new ChartProps({ + formData: formData1, + width: 800, + height: 600, + queriesData: [ + { + data, + }, + ], + }); expect(transformProps(chartProps)).toEqual( expect.objectContaining({ width: 800, From 83cb0ea21b1824b66c4252560afda7a40fd6ac2c Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Sun, 6 Jun 2021 21:52:18 +0800 Subject: [PATCH 07/10] fix(plugin-chart-echarts): ci --- .../plugins/plugin-chart-echarts/Waterfall/Stories.tsx | 6 +++--- .../plugin-chart-echarts/src/Waterfall/transformProps.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx index 0eb96cbb7a..42d19f9674 100644 --- a/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx +++ b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core'; -import { boolean, withKnobs, select } from '@storybook/addon-knobs'; +import { withKnobs } from '@storybook/addon-knobs'; import { EchartsWaterfallChartPlugin } from '@superset-ui/plugin-chart-echarts'; import transformProps from '@superset-ui/plugin-chart-echarts/src/Waterfall/transformProps'; import data from './data'; @@ -24,8 +24,8 @@ export const Waterfall = ({ width, height }) => { queriesData={[{ data }]} formData={{ metric: `SUM(decomp_volume)`, - category: 'due_to_group', - breakdown: 'period', + breakdown: 'due_to_group', + category: 'period', x_ticks_layout: '45°', adhocFilters: [ { diff --git a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts index 041ccf2a4b..d7e29a7333 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts @@ -216,7 +216,7 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): else if (xTicksLayout === 'staggered') axisLabel = { rotate: -45 }; else axisLabel = { show: true }; - let xAxisData = []; + let xAxisData: string[] = []; if (breakdown) { xAxisData = transformedData.map(row => { if (row[breakdown] === TOTAL_MARK) { From a5c064b48761989e5068bc90c6590b92f44cbeb9 Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Sun, 12 Sep 2021 22:52:11 +0800 Subject: [PATCH 08/10] feat: fix some problems --- .../src/Waterfall/buildQuery.ts | 4 +- .../src/Waterfall/controlPanel.tsx | 100 +++++--------- .../src/Waterfall/images/thumbnail.png | Bin 74973 -> 77020 bytes .../src/Waterfall/index.ts | 7 +- .../src/Waterfall/transformProps.ts | 125 +++++++++--------- .../src/Waterfall/types.ts | 4 +- plugins/plugin-chart-echarts/src/controls.tsx | 2 +- 7 files changed, 106 insertions(+), 136 deletions(-) diff --git a/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts b/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts index 1f9d8449f4..947a9eb98b 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/buildQuery.ts @@ -20,11 +20,11 @@ import { buildQueryContext } from '@superset-ui/core'; import { EchartsWaterfallFormData } from './types'; export default function buildQuery(formData: EchartsWaterfallFormData) { - const { category, breakdown } = formData; + const { series, columns } = formData; return buildQueryContext(formData, baseQueryObject => [ { ...baseQueryObject, - groupby: breakdown ? [category, breakdown] : [category], + groupby: columns?.length ? [series, columns] : [series], }, ]); } diff --git a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx index 2d2040e17c..a44c03f8b8 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx +++ b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx @@ -17,73 +17,24 @@ * under the License. */ import React from 'react'; -import { t, validateNonEmpty } from '@superset-ui/core'; -import { - ColumnOption, - formatSelectOptions, - sections, - sharedControls, -} from '@superset-ui/chart-controls'; -import { DEFAULT_FORM_DATA } from '../Pie/types'; +import { t } from '@superset-ui/core'; +import { ControlPanelConfig, formatSelectOptions, sections } from '@superset-ui/chart-controls'; +import { legendSection, showValueControl } from '../controls'; -const { showLegend } = DEFAULT_FORM_DATA; - -const Category: typeof sharedControls.groupby = { - type: 'SelectControl', - label: t('Category'), - description: t('Choose table column that will be displayed on XAxis in chart'), - multi: false, - optionRenderer: c => , - valueRenderer: c => , - valueKey: 'column_name', - mapStateToProps: ({ datasource }) => ({ - options: datasource?.columns || [], - }), - validators: [validateNonEmpty], -}; - -const Breakdown: typeof sharedControls.groupby = { - type: 'SelectControl', - label: t('Breakdown'), - description: t('Add additional data for each category'), - multi: false, - optionRenderer: c => , - valueRenderer: c => , - valueKey: 'column_name', - mapStateToProps: ({ datasource }) => ({ - options: datasource?.columns || [], - }), -}; - -export default { +const config: ControlPanelConfig = { controlPanelSections: [ sections.legacyTimeseriesTime, { label: t('Query'), expanded: true, - controlSetRows: [ - ['metric'], - ['adhoc_filters'], - [ - { - name: 'category', - config: Category, - }, - ], - [ - { - name: 'breakdown', - config: Breakdown, - }, - ], - ['row_limit'], - ], + controlSetRows: [['metric'], ['adhoc_filters'], ['series'], ['columns'], ['row_limit']], }, { label: t('Chart Options'), expanded: true, controlSetRows: [ - ['color_scheme'], + ['color_scheme', 'label_colors'], + [showValueControl], [ { name: 'show_legend', @@ -91,26 +42,23 @@ export default { type: 'CheckboxControl', label: t('Show legend'), renderTrigger: true, - default: showLegend, + default: false, description: t('Whether to display a legend for the chart'), }, }, ], - // eslint-disable-next-line react/jsx-key - [

{t('Y Axis')}

], [ { - name: 'y_axis_label', + name: 'rich_tooltip', config: { - type: 'TextControl', - label: t('Y Axis Label'), + type: 'CheckboxControl', + label: t('Rich tooltip'), renderTrigger: true, - default: '', + default: true, + description: t('Shows a list of all series available at that point in time'), }, }, ], - ['y_axis_format'], - // eslint-disable-next-line react/jsx-key [

{t('X Axis')}

], [ { @@ -137,7 +85,29 @@ export default { }, }, ], + [

{t('Y Axis')}

], + [ + { + name: 'y_axis_label', + config: { + type: 'TextControl', + label: t('Y Axis Label'), + renderTrigger: true, + default: '', + }, + }, + ], + ['y_axis_format'], ], }, ], + controlOverrides: { + columns: { + label: t('Breakdowns'), + description: t('Defines how each series is broken down'), + multi: false, + }, + }, }; + +export default config; diff --git a/plugins/plugin-chart-echarts/src/Waterfall/images/thumbnail.png b/plugins/plugin-chart-echarts/src/Waterfall/images/thumbnail.png index 62e048cbfc4247a8dfa44404e24a68db079c7b61..91ef20f515f921cf210256da932fdf1cea1daa19 100644 GIT binary patch literal 77020 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 literal 74973 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
xryPW)G(^6%IkCGf(F_ zfs1*k`9&(|-T>|Itoy>#yFAYH0P|AQ6H|mO<9i-19IFn%wncTVnABm|Ect|7mnJ4E z%b4{8FFHq?Xp1p3apwq}ow{$QIXO1*q3ZG0E$fjCO{8^5YiV_KH-muI^^w&}w;WBQ z267NRvCja1K6)Qk-zfdbQq1ZN18`$ zqC~k+a|$bhWhqGE+=QihtCU!HSAAKyelAQhcjR3IT3Y19~s1tb0f zXj9lAOmsvu3#rB~mdzz??tZ7-f!f$Sy^h4+XO@PjBXQ^V8qXu*Z<5*aw7F;ud~;Qz zTjCc^6<<`ml?RNAZ1zVt2g}KguCm(86dwF(XxY0ByuOr@pRo%}5%nNg7i8M*x`>Aa zir-nOV7fh3sX5zHP5RW*2s(iqKMy()I+ucOg-`Q)$z6U?+JT#vSvy;uN^|qM-GcQ} zB&ujbkRTf>6{&s#4co1P?FwgKk0F}V)D#%)fgG6kK&pt_>@w&zlUl^#=3*q}!%k4?QB@VLwd6#Af8ck#KBM5i3_zkaY!&72#mihA^XS5U4n`##CA+T=R1z&@SC`esSBcG4D|oiA_-oD*EPQj?~l=%DwK{MM2OU)SiJMvnpjhIIjCmbOPpTfFKlnP4RI=e4H z%JXsU);TsA7HUQq^TiY^JNFv>_`)Ez6Dq8pHAi>zjWAoXYH+_Ma#-cQjWQG#ceQ^j zPNgEjO+-|NeG4Z;!*n%KTKnv#EaiJ&>=>fptG)o`Gj+r+oAds$WtY*-LYYJK<;9rk zJ&*$358q$3U3hVBxHRL#L;W;%7-)WAxXnPDk#>uAzH!QC*k~0uI7`VLk^B7L5CFAzpJdi<+2mYR*;Ft z;dI$D08!s;G_W1-aiJl(nfjxsZ@{m1HM(-7x6x`NG#`-2k zUVtwfE3$(QU7rITN-BQtuyx+`%3^n`qCBM3;>UZgs}9PjqrpLjC}|LevE!7Z)7 zlJOO<(Uc+A=|4#pS$s|wy$t!E)FvZI?(^uKcM!qv97=w)wxhSKlU+56T0Cc9(ijuJ z)y5-Y`L3mKA0qWG=%If5ywX{sp3O3i9bA0Lj*s9sN_@?9x52G6ST`D`A z*WmSi;m&XWTm~o*T9jN0jD)XUxPr|8wOzPh7kcbKIc_&TXKqNwNOk)zPc?C|*F+7w zJ@3MN#`*OGMD$gQb7p6Z*Vb6f3lKB9_Bx1}rCY`$7D%X>Zu_ZTu=;;KCG5mdU+)kH z%xvCj@%cHAE6L36%R8>i+je&z^WiB4Qw{Dh15M~2-#y)0oq2y0Pmt+O2c3g9Gh-$n ze@rV;zq%qlM_s$Wob*ESG}LPP9Qz2XK*iDie(ZFp@vQx`3Ru*`T+KhZ55#_M@p~fv zKdFg=LiF7CcPv?=jWgD~mkZtO;H<_rGlHcfDTjF99z^&*0v%-u7kL&EzOCw&&>oUF zP9c;THkaMwmSD%})}_kbh*qG3O5J}hhW}z^kZ%j62w_C#9+mBkmVmt^EElqSob|e5 zf*Z%5^K_*s7!hZDjjw~CL~5XO6Rxt02S!`*2hLv*^vM9)(}AhibsHz+SP?TaRw!54(=%60Bu6b=cDFTif*aNA(0J#la0eFbR z4?PKKldP%TNmo4iLwwUd$!B6>887AWs`Atn4*b4I<&T@de9eF+Fza9D*mAyMu+%o+L;;&&n*8Je6|6`BFbB&6lZ%vhT~5K+$@dX)f($;t;XUE)P%J@ts`h z0Z|=&d58i%1$ju3OjoIvn~A_mtMOzer*)5N)EL};1W-c#k#tZB-z=33GI_&2p>3!7 z-4v4K?^cl5)eZGzLV*|%mq7q8-A&vnapgH7f`hoYQy_&{#^uJ%1Jn+JCLahRGb8CB zdiK8{MEDoWrhnU%w+3FzSVVPF$wtp;#`h>YQ=`-Jmazz108{xbFM8N$GQAsU-_Woe z(Au{vK&%KQ)$?UN>pBy+Gu%KnqwD$A>f{pI&ZsyBDxHzs=s5GEGd@NBK`v*A)i5ix zG+(Dm%RE$-yll2BetqAJ?JLSqn(4X(ylMYCMT_Kn<6d2C5--qRUdazO@V>LkF>X3X z>L@UPKQsu@2LTO2S#0Sc`Cj6lJvTw`L{EbDr&a}d(mQ8Pm+Z8@PS$3kcw$R9mzv!8 z>6WL@hZtjg$XO@NA9{j*0Qn_FZf$r~tA9wMC5Pe}BN}dlBzYhGP`hcWq3D9XwndYy zet%1}EZIF&-AnPf-LD|w9>G5nMGEPgc}d}@qx)AcO;{YP3iJi&e$rpCKm8pg{@;!g4>kAe@#y$=(&yGc?P_hev^KSE z^LgLm7M1X#Y#?#grqYU*@szZj4R~SLT1@8?&_*kr#hDjm$7Zd^Tr`gkUOK8d7p$@* z;@e>ItRJ(u}lqWcC zCK6P)Sy+D6!FB6yyW}csZ{#=*g-cLZ-^}TYaMoaLam;2cmm~8@sKj7^Cq3_ZA29mr6H`Ox`v%;XN_hv4ycUbCoV6drru*)a!uG#!{QL$Zj^-Z zb2j;ng+8&#QNTz?kWO7@;tst@8J)z$l3?`#^CK z%Xj~_QE^l;hM_UGy+)T{_2`#R$I+Vbl@d5>cJ(aovOqY%JorHTW(rB@GuPe2edjec z|AFhSU^3X+bxU$?T7X%g^HkqVQR^^f$qCLCrp)%+>75aH5=SI|VNcSWUT>)Sl0pCm zh5sWDx~Y(PZ2cd+E_DCzS3ghp_^ z{A#Mf6cP&5Ka1r@@NYWqpRLDLcL=%>Wg+*!1jwxv0rK$3w zH2AFbpVGZWL>u!7>1zs($u#VqLR~9u zi^o>P_Zud-6_+I_b6Q-s%J9#eQdw0Qlq2n2Xnf%^v}CY)p8RMT9)~CQ&=om0K9)9m zj03RfBfD8^9yOl3*4~(PJDKJEaqz+__@$KHepWRK`k8IG^+edA^+O({4j3VIcwoA* z3|`1Xd#*!RGu6(FpISE@3U--Fx}%s+ejioWwNhYMfA(GzuSa?t z=QQ5UV$zUT8(P|bCbBo!xtsc#yoPkZe4-mvDs0sSpVDeQax}gx-b2^0yMNU+ftJH^ zWkrawl<;swcmciH6%D7N*npgdW0n!&m%Sgvtt-^pH)HQChZTFlT3q8Y zg81KyxmmD9(EF{o_m2+rv+p_dut#`D}A==71^tVbh%*LV(!zuM3&NGvNfi$tNOG6oB+kN zsBiU`wTf{p@T3g%6q!Tui@kPc(!biNO69TdzeazUTak-xqAWb;&3Pq;fi#6r*F+N- z_4`sHnS2N?2UDNkzMS8Za}QhNTxr%@v~FHD$Q7#6e{gA6G7^3EM(T$&P_BpA*PE3DV1|)oU^jX=< zc%|~SsEdKHrgknJcq-z-mO8t^WX{IxzCly#)Q5@e5!etKf=EzYr0uo5`gWoj&FTKL z_0lQ!H2eh2^?e^b-hx<;8ZGwA*LN9lM)P7bbodaYk9PNzfz&u)K0YqZ;|%?ebJiN9TEDT+T*`(_9w zxB^W#3~WHM3=_sDv=*;#-|;l&?tZY`ThM{fCdT)QN?w<%+h!EiekjZcMM$X-P`-iN z=Z30wN+0dNIQQtcpZ~kZeG~*blq8QLOJA9jABg|gGADms;MwoBjf8cI%*wnt_ndP5 zq@!%~oO&AX&RPxMd60yM-y@K?3`HvMSBg|KD|2~XPT3uNLl59eB!6@zBa~&!L^AP@ zyhr3ecn`|5hb4rrprEAf9Qwn^VaPJ)m~I9I!wTaYilPU9q#FkLv-3a6A-C_g9dC6` z9po+6`&M$d5S{g!PzjjZO55PR>nJYE$)B@PdpOwHTC97P+~|yN;$E`_=LXvl9V?P8Wg#ggCHa~L8iUDQ(C0DU z%>tTto*qA8TpKQ+j?GNx*NZN`f}5J|8?joY@_-R7UNgWAFdNkI{7UjizB;MECMQv?ebk5@LzKa@fK>P9}SaugnWYqbJ{Hl+z z6an-MEduMSJ7)tw24ScAJo<={7uzj1Ocziy=RtjpqF-fk-x|{1MC5U|_8Nnef^mBC=MrPA0O?{8#K329xB_>;IM@O-Cm}4F!Rct8!)%pz++Zvn7AzM=1di~J)i6^!4 z3B3%KEYUfcCGO$6*4Gz~g($IlHCi=qe6&faXfm0|(V#sWfQVAdoZ84G7<6U~PS-e| zyaUCa|4?zPKCZ7Amve`=TeoSXX+`~4R0^%!W3#9#jta9Br}CQjAG<#05d52MSYC-~ zEbc@cFk%+IHC^IM!W!nn?g-ya3y5j~=C?fLY+m4fiyafHNUVp0> zKv?h(CA9x)^@6)359BJcRV$!r;nQv-+4BqWM=j&L%tLcdubE|6J{V7cAMKU-36GD% zEIqb6G%d~89g}M-#v-&@Z&Zlrn^RF0Y^MpTg^Y!^_ZQbY-w*O}P>sT82OxsXeu)?D133*93|dMkEnEW+F&oyI)6!7TJ}&v+6#9i-8eU4?UXKr&ygYDq2)~; zdEm?kZ?iG9n0w9lRhpAetfdj0_dr52fz+S;riaNS$bFfg?*RtBWJ)#WA13(B>U9;_>J1Iz{6 zZ9_}*f#@hFAsv3|70YgcXMEih_4C=D0&CKQ6s)h~Xv=YRC|U##Wgo8zIV=VMg915VV^Qrjb|>=jRo*+*_)TgFIU zTLtYef8z(*pSJxS;>7d4x_V&7uT@u{AhnWR+bW0BKqiuO1}c^g8TN4Waq-j@eeV)tNFA6e?kf@ z@R=0&w&Fj_xd@`l`9d#3UsB9Wlny74EcY6ASx^L|!lar7^P#ziT0H`52w2Li24w-z zVb)-PyU7Z`C@h=DZM%5|$$z@N8%ieVrDVno)SCQk(ZO4SE3bNW*-0da&S+E&bg&Tn z_RIF4}39)<} zTyhl@eq|U0>Pz}AhzF=BMO49dbwO&uqxqDjfP0b4$l42#&GE!9g0gSCf!8?uiv(@pWTa3LsA z>DFHe{MJPXf&)QhqL4nXwlKE@#|z%?yvMXSZQO0 zT}-*?=yx^~azu@A#^;iuc}e2e+a*^}*a36S?Dz+9 zh^rYKQ?WJE$A+3y!pb_!=8$|P!Tec;QPzYq22$@OT|+V*QhW=-@J<#RW#9vn>zG`CmPT&qyvHaMOGx?l&MN3z zs9P*nq46q8x??C$s>=4-H7lzMV9ZPxdhUI`jm{**Gb^ck;F0@W#+3|?(6~yYd;&}v zedY}OvR{B%G21Vo1098*^^?-{D8*6u%Aqx?ycmbq?=)|Bv}fbIpEGl}f-VM#fIvc- zlvx>B!uNa)b%JDNhdXZdSzIeF*9hi031XP{eJ1s%XZQSWVKGw=qXY!C*6lPssB(Sbpi zAsg<*k^UNPoSlpB98RO|crJ*w>&~OEzveH#{)^ELd|N367TBSi0~13}#(Ro`Ib~Hk zLefOHMK4~8$YAmE``YQ zi+LdJfOv+DVGWGGw8c~{Yhb1CRv{RocqpLlfnDsK_Z62=ZQNT1h1?PEp!2yW3tYn9 zr(oEHYOWzMm(U?z)Y;B?BNCzVSVr>PoCW^!EU(PQLA4bgaieC)T zGh$8Ue}QDv3LeIXf!vq_7Rzw;&K_m3gM|rP&l-k2obx=QqS$LETn*Z8d$zDex7;%p zR%Atn+`MyHBDhu0WZ@rA{%?W)@8Qw-&lG6T{^{+1JZFGNgd&*#Ps}bK3ZO7o4&LAG z*dfPG2f3l;-GPTo9L`AJ8QcqyGx6%t@5U-1ozjfGx8&0)@EY;F);8U*Yo9d5bbIja zPdt~deA~Fcc=!_@uHc=o<00cu{MYhueO>8)Mr+)4khDYA?>FLamHu0$|9>qQ{jJi! zS2Ez0zg3#jUjH3-{s+U(|28lEvu(S6#!(s@5wD2KBQK<_47772ngN<%#5K{unZ~82 zVH*v@oMAaIR}~c}I%Rr|LE?}wjZkQc{zz+2efb5ApxJISTOPMK>6rrIf-q6N)n%|k z!OSGU`j(bFW;&RoQ;te)Q zQmV83kBmj3J<(hyTgs%?UASY|59Scydhy=U1aT)X-?7l3-0T$6rXJx}a37rIWaw23 z4h)1fNXcAbrprc7KgoO2rE~3r{tkPM(!EVX(g3#d$bFmj$(dKtA`jPviqKh03&Ugb z?pN=f{U}3u@tSCY+{Ox<2ED1O)-l%4lMuBiu(aOxS!o=dbTV?&(A&w;1!oaNi z;Uu=nO`r#Jlf<67$-g){!~0`$S(JOL{5X;g`(%{Tx@stXM%-v=r?+0?TbVL4bFo1_>C6174wq;iOw=ff~GS63J zl7?~GtZ^wy%@zBMNfaw^{b9|kDW`w8-mUGldnoG8vy2Rxx=VBhrbS4G5G4FUnUU-< zepZB#X!7Ed&#av4Q((EXcOZG^bsSeMv5B2!4_p*J7&jnk^X>axPNk-j0s^}`7CttV zz!OojyS&yiLk)Fe+9$b2pPp+YLzbx4D}bhY2T6S67JtufvtR>0CmZ^lph1vQUX0kq zTUIYm({}+}#%+5b#s(6VKM6NI{^kxO|GEz5pi}~BYLI2lNrQ}&rrhbwFTX&tpMB(o zRh4|+jVz&h)N6%Es^qB_gL^$HA!i2@hKXVT$2}`60+G_k6;a(J@TPeymlxR|Jva2Y z1dKGW7586hV+^A$un8y62x(|&XuioxJE8`TJVN~8zw$2BVhkYESKrrp7PlaG<@$=U5_+3+;1E`J*cVZ{tL12m+|vKd|V1neo6w9St`V3T2}TzDJz=+WB-I)0i}$l7>iH`8X@TqQ8H1&sH}c~ zVf3?5oc#x(VEN&MIhqTDzH|Sb!3P4{ycnV56>Dwuihx@56Bbtq#cf$u)$1hO*}PhViW$vztSvCFt7>7D?Ly;H2ZtD@ZjN01S6_~`d!)ZUj zeO6@RMrKaPMiywpNNIL%8CL@q5V^uOV1eg@3tQI~jA||qj35#%0yr|6D~qT@2maE6 ztktX-J)(tA60{UOZru&^mB?IGcpo~6Ttm7n0;u+Lfs~rsJf_zDJ6T`(LH(ow343gmc{w;v9Q?R4^8qIzl`A&ExW}NAZqjH( zlKgLL&SV8(!+JlV^LtRTJ9InenxPY4OxVnZs*ReucQT2TTRrjR-9H|7GE5(0mQ7Gf_paIC{jg(1kmbXg>Yetauo0C~~k|G|mwQ*ja zaQL*_)FrJRO6mxG@6PvwAanVMx_|xwf8j|YzqovzY$&i|dTsQGQE8G*knhL<0vt`o zB7atmt_>LrxtvpcxRwZ@Mv{7^V}4Map!2_TBx@+cFK(%44^*N3%`c4>VZQn$xFQ*7 zIRX6Ap-*J?HB>@#t){@7n9ljXvd3Rf{Kqp)kgk+T6*6lHA`N)9TL0**SXvVwiE-36DD%E(7s`{@5gWSR#>xuk+yj*{65l7Q?cy-` z42Rws-`*V$Md*HF{3+#pvXUM{E;_WEK5i^bq(M+ZwoNQweM(+AA#&Hdf98@yT*dMl z*@5uxQ)UDPROAwyq9ALbAp5?JQ*0X2a&mLK zH68!{a3h4rup8{8jfLijTLiEsz4%LqwAvAX0>q}uSj9tF4p$lT;HLj-0Uq@^*p&8; z9tf#%si%(*RIp>ypL(FghGiax0*cis)(R<_4Y9bP0cHva+2=H~Y9>ztgyT`S~h7Yf_%^yu&}*fj=zJyFD|@h^WuG~CBuB?73{dKwz=h9x^Kbho1&Xx2l(z^Fh>n;D4KXX1$`rwi z7EP=GnC-L&p6tB`QrY5LOQ~~a8S_-1hPl1>el>Zo(97^eM(%T6^HUhQt8vVkmNV0v z<&F5tp7;hJMC0!0Zdo+tdy?Nx3V~io zpRbONhL+aLUQC3@h7N|j^vQ=#s$EhrmIDv_CG3H+c1!yjAQDnT_UuCG*R~P$Ninyk z?zRbt<(kS1tRY=o<=42Q$hWEQfea zw4g&)Vu(}Soo~EEdkS<8=$SBPmJwC3FaiIfwX%!WE3Cp-(iFus$ld$$)`rBJKbBb` z7jt8BC#~uZ9JjovA$w5gLPZM?td3ECuqz*b1v{d|5a2iE0jA~mr}6~xXo2?K#Mawd z>Mg;vb*5NJv@Jc5tG(T#s@k*KrDx~3YTijbu-pvwEUC1pwn)YJXP;SDVCCz@R`-@3 zY{?$L+UNJTh8t=_M{cd9abpWYa(DRjU2I3D`>wpU<@5JzG7ga&v(AZ`;7Nl~2R3#b z&lwn8Q`RH7ypBFo@d35f238Ni^!Xe=^Rn5tB_e3&WQ%Rt9?0J6qh(r5(vS7vtLF6i`6VZGuxikd@0!v&nj6%`N59uSwg zVY&)QhQca`jVcxPisi4s!ht# zC=s^7Ppmr`rv@woYILVF0Q&v{yR5%oezE%{<>@xm>qgPoXqv@3GZv~-hNngTYirO}P25$Mu!7T(o$rR+@3WoT+@p8dl83fF7_vGdd_l$e4~*1u?^Rwh6`2{6I=9 zo5zajetD5j@k;smO6UV~L+3NJemfk$)}-2Mk}T8GZTXxu8fPBzw@1KBd*khWi@UH= z7owt};O2?xO!JM`x|6n$BHbyoh{}F@2;Sr^x?8H;jPX}&eSayQ?`TrDAiZg8P&dzO zzi{-Ch2wPBJfCgQbD71Q-^>Ux#U24eZj(v9<1j>Vs0d1RQO82|9 zg@O%*0a|K_<4;80h~~UPBqiEDDe4@htiF}^{SFDi8pgHuGkS7{(=^oC5Bt{fFY9X{ z!Sfvjkk`I!Y4Pkx{b@0}DS3GO!KNY}OEm&ZX_gFoAo&)HC{iz`C^28(t-yS|Mb%m^ zcW!V#w%N5DX>hy`-6^lHKVNHoqy1*UzRb+GqL_bfiDhwlqVP?@1rM8~?WK zr6gS!)rh0->WK zy#%BrbW{kPM3AoFd*eR;d+#`BydTfFpYHmSk$gxp)^E+Zp7}hp9E<(X6Gtk{qeg|^ z@h<3US~Eyc@xkVW^#xRCQehz*=F{jprno7Y5ey{|#|M}vDNrjB3Rs8hI9XiW)Mje? z-oY?n%#1LYMoFP1o6S_(rX08bFw)0O<;+m|k`%}Z!bw_?07tOqr#8a;G&w1)m*O_Ykj9okRdg(!!nPwJ=8M!f% zUC_=@q{2?*99?@C)faqD5pM=$@Ed7ja>+p8?!m1})qL+Tzt{c99rrJ5n_D16gW}7E z_)zwG$$y$x>yMHlm>Zu_jLNOyZlZYIV=MIm8YK18T0)1^sEf zZ{8!as(~@SBpFxInlWJKT81Fa*Oj5&Yrcvs`EeQIaTf}Rhv+UyLrb-2$BQhkTt>N{1KXf0{+ic^)#FxgCZyn2Y zES2wEc?GqQk5x>Xl%8dA)Afs|q;tfd1{Zn{0IjB17w$21ej0@L$5h7l%odnyJpe7U zvj6U$RxpJEtIhO{wG?2bp3}=}n~t_7P${(`0uph{eSCf@tf^>z_0MH3I}TdxGd7^v zEh`iXSvRqq95eB z$Ya8aw}D2b-+=1h@{&~3WM2x{-Pw=|=vv;_?b1EfUH$3v~P&+jY$E`8ZtZo zEwJBF)Xjd#LqiUXVMmQD zo`2M?eCe&F)RMSB zs^GD!biZ$ons(KN^1T~3To`abQi(4m!oW&X3;l4f02#SL;;6T{ifme$JYVnNT=Xq& zOK$UwW(LfHn_-Q`+vY4D-+*}hEqU`pjGw^%ykymn96-S}=~$;|YS^W3f;t;AR2JKy zI!8J$CZaI@NI@8PU?vM%nZ69pQR$ z5-pAf5-$C4FYi6K!OzQgx85m4(h?7W&#z4Nekp{SPSmgKERM?VC=1mpggWTZBf$p0 zF}jCQb!vt8?L9}%q_@IPB3%;1Tp7#BdXc&%ePe(mVGNMLBY`D0~h zx8>yq^-|f>xCIX5)%n#|sxOY86d_FqB<|8&ICTMpd@YIn2E2 zTk2(ChgbFDgdj>5=Qlq!)Rs){VT!hZB5BQz6^E`19Lmwfl3awu>Rjp=F zl@(Piv zT$Rw|KagXRj~F6%bhL@8xL<6viN{fr)XW;PxAV&*10;1-Wg`P0<*sm#TlMFc&3_XC zxuK;{w>|KFE_cE5Z)MS_I$TmQ1x0iHDXuO=Y8s?nxwvL{euAqKZFuAjBa^+*sT&m; znB~FLW2Cze+sV68k9NM3S=@ey;+YvSlPKscsqvILaG=!fC1&~;Mo`??X?=NfZLa(9 zcbD3Gs~=ytk55*w+~j<*V7aTy$c@AL6py8gIO&6T`dV`Xm!>7T2EtGaX) z-L2E*eNw3C%9b-%w%ex_O(JQ^M>3@QW)>uw`@tSOue$Q;fV^#Df;+UdeS`Ma*w3l; zXOIP`-u#oIFZQvX7O=gQpzR1|=ovG;L?)O#F&IYMK_p87>CzW7C+5`mEF&ZZegHcBKh%l-MO#79D}Ir$7(xx}+qz-6IU{ z^oTrzI|C2V=%ivX3_CkVip^Q88RWC={>z%5#_+fv&iE^($Sn;CIQr%|k!aT_GNpoC zSk_r=RP)aFelUPTX=T8%$@)vGX@O3r+zy7Lj&WM+bk4b#mA7(XMecrjlGPx_YKiqw zP3X1){)9h9PVbD6D_eiC-pM^fb0k~`DwD=_Tn^Kb@qCzm)lqY;>8yUvIi!LOs!Q5F z&kZCz!II*4MsuoXkVRe;3y6^g1d6w_Y;VFn>YEFzm;BK>u3ar67@$yl|UiQ78D5s%k31AZxR@36<03ye zyME|8kV;>%Mok5K`G#*J3WAp=4;13Evg}?FiS(43Ixo}3?!jv1HHP$XgubGUn(T`7 zAnRIeY4hFUp5N&vi1AG@LsYnv4=q1^h>IzH_w)|`DPMe)y|Q8msG%xaXQr`J z41UDpcC!qU*f<3oeav;m?*k)qGvS$naeayHz z?jfUJT3OqqQL33X?R}x>{syCVGDlD0KBP9m(K8V+9xIK6Af{tzKlfj1Fso5%jeck; zV>uoCvpFj}1CUPO%`rea-ntJ#;y9v!7*X-sf*TB6%I7Nf;Z2vT{Q;YS8C_}Y^yq$t zy~wuKta#5n@hErPjCtC$%vWgj6?p{atJO?Mf{6S3((PM}k>Tc<&FP`wX+P+}4`DWm z85BlL+E!ew3UrBTYzb1hB<0?Q0=`29qch`HuJcdJqdx>*%jzK|)jheAxJPG-bP!cP zCHGM^cjnfIKqw0_j#)DVLLO!Pm}=7`*WrTZYho974_*p)USi6`4Z4YR&iJw8Wd#qe zI0&gWY2k?)E& z*U2PvV#VhxwTOZ5V1~qhsNJat8-UF_4E~j8lE^{iRaNoIN5-`rl#U=tc}L*H#t2(4 zL!0NckGFy|&8RvH{z(c>fZFuBPHr#etlFmiUQAlM2;c9k@L8EJd!`)pgQjH9%II#l zH&SKx@v4N^Ihg?Nstc;;1dBL#VqMni{)`loPr$d(-UtJDi38=yH%ZXD7v3!q*qk=Y6=%* z`F&QtqqT9mpwmKODEyt=TRqBoGI`L9kc^{3 zte0cBU9CAIyOy{AG?_UNI3{{Vy;{bhtjhB_qa^%co_xO-RUwFwkRsb=ekD1Ji1U_S za&P~NG8qP6L*-!_&`!ewT3MNy70U+~s=kj4nd!DWT++QI)|Ssj;kG9|p}17z$Q{8U2Vt$RC~PPsXXr(&uD;O1L4HYUMG>0L&rWqs`uVkM+s zR$oafX>av*pIBo@8Jz;2d77u2loys?d3Wu5%L$BnA}*HH4*NFXLP#KIWOfPTAwdiB zMeQb^YJbed{q=uyn*3K|zk>Hu-QHBCtezU-SF|H{{a`>lrpj$_@MNq!h(DKk2T+p> zs^NJqtG^$d5d2t=)jCb>*_<-Xc@fc;GhAKokp^)pC&P$yxhKCrYUfk z|09u2PPv=ybp>8hr6DJqTp5eh4p)D}43}JtND$TzV~z`70Jz6ZD={W&7^23nk7#n$ zkC02bm}|08A5o($F-ncrv*tG9lN)bN{%g@IBfGx4d&r$+3T+l@ATN4H;$eA{6G!|E z%}R1FR~4|_923>^>A}eJM%E>29bOkiw~_#lb%&%AoR}RQEp^57XcQRWO3TaPg-!R- zBEAfxEF#(s)njS>Ftqjq`-tv_+OhQ{yLI#7FOfl}h-B1`G`p@!jLw|u;QsdLZq-CB zmeiDPaXIZEec=jU+EdzGeM-NB(cM$xw}BzJjCX`68=g#}NwWM0jkQ%bwby_L>0EJh zS@LFj&~Onu-YHqZ1^^l6-)2W9gDqE;hSU$6cUs&WTu zr0W-z`canrMTz;FzL}3wa`XJ7y5nN_^PU_Xp-p9ISv(?>RiFOBG4)4f?`iT-Jq+kN z0ok4fDI}8SidU-7JMXCdgo`PMy{z2j_x;NHHTw$!G5(Un=V9GmohE(gDAsvgaeG>+ zHH%VOSQVcWL%kl~k8$MmAosX{GTP~(@1Lx^E45{} zn>JBZ-ZY`i9QjfOKDqk%*yN)>esdZ>%`9IHzNYkeUPk`0t(#LeV^K^>({JwfGwZ}W zOFbjHLsh5nB{FYu>1YtTAtqB#tc9WW5xKB2?u9&yjz|YkiOF&{;Z`?^AR+Dhw>%bO zc0kao5pE3M$bePxLF#&ce0s&ncL;|e>pkc6Ez7pzZ z)irn4ih61*;{B8q?+aWMjCltP1|Dct;M`)9kK}(NP5)hQWyLY@14iAp%Bu@lb)uZA z)a;(G12}~MX}HjGggbe720;~oD*gGus3y=KKrgv3rs2HV)05OieHc1r(4Pv3kd^sn z1(9s1`H=J0NH!BVwbVKSde9V}K0K=G`&S8ByU)h(mD&danbU?S;?I&LimVo(bYtvxW-24v=_oE)0>^;a=;tk=^eZ|?^)^)FL?bgb^swh5O58Q@ zrWzgshgr9Fvm3?Ugdy%|nom!QcL3~MIX_KJ_iR@WS#oc|NZ@0}woc2#-JG>^p7?#z zli!ywfz9^F=x3@+U1KkToef3I8mx;z<#e#|I-CwPy=M~1(2%Yfd^8Vpg zW=aVFWFHvI!4-FMQqdHB33-bjL$a+fQ0BILumoSIf}rmOhi5i0fC z)5AEP&1toen1$R6952SztVb1djK{X3Ue+ENHtf<<$jx7-=;G*=N{f)BmZwJFQ(<-6DjalOh($06 zI_`0!$!JN=ZpkC9M0r9zXtX@2L3KEb&;}A-w~|U?Vj+6DxkVv%4r@7MU}SK>p0#02 z-piJyf8~xPnwtP#_hbY6!RxZL|cEhv_rF@N~a4!>NWPbMH>) z^xg^y!Ax0xf6r5hZgCwkQ1nW2AI4&GBjcOIQMtKp8kb?;1rEo(cs3#XD$lhvJiki5 z%XvuD%lpiWZlAo;c&e|*dUTm6*o$zrti8O$tF}Q8Gu2lGiA>&y}ffa`?7w5!g#9r>_)|>$1W-AYG>39 z`duZw>L)i5UGmMRiZuG2ETjWKN#EAUO$VPYOsdY}7KJju__9VyD(&Fmw+TOBw_S-poSmlNX6_)~jCldgg zK$n`gqvNF%b`!C7^qOe1eLqmfJ1k~hr!%=nR6yY2De~e;Xi>+F^iJ5SFRWRmPVoEP zl-y^9HnVnef_>#C;QL06)-xDgJVuJNpbrR1zJG5=# zj9#=;?K~OC&*&{K@UQW--8}^^M7hSB{aL1GFr8@h;G(Z@oSv~Fu5lBRB@bD`Ma7N! zVfARMu@5rd$E7-GEE1K(inVkThxt9%=OlPbOo=3>=D~xdfF?aZtPY)oZ$<0-G86-5 zG2oPodX!3~#f9k(GVOtL>NcLO!_dBD>8GC#+yvPYVu>o6=Rbiw*3a*G`%C7fZ9;kA zN)%wc&GClzXOo#9e;#JtB+p%-lgD$PYZ+h;rPrl**?P$Z;gvy(24k*V3rGb=mNiL~ zEXQVZOq1N+>IN@7kbytr%TB!wh9eIGQ+%tYUD-v$HeH`GUId7)&Zrbv_Ae&lPd>6N zkzBjob1Lek69td@(3Q>8K3ES`OJtMKo-lE}LUjuj)$}!{^p;P#_Su?UyPlI&WRj6y z;Wj_(zB|65{zdn=-``Alsk603f#&eCpEmENmGf4YW9U}?!XJd=G%jM41Mw-F+^!QP z=Kx4$@Zs|ZH>#(I;H+^x>;UY*D3MOl(7VqoM?*P2&Oi+Yz^QI{#s@Mc8g7^wISEpU zW7kQ0{OwruCilj#Ci0=N+EXA@so~wcT#@wh}|m( z#5?Rg!S63*$Y@Ed7PMi-H2pnO$Uh822EE4m$2sT2$nr(!M4cO0aV!XAqv7|_(D9qn zegz{MH&;`X&&g_8&-_`jR2ndeJwH0(DPAY+%V$X*P6);3IASs$ld?sNdZ1f zD{!@MxY{>vJo;>z-UTgKh8*F=g_|xQ&3hA9Bh9B#%0(v=9I;8R4XLxia7O2da^Yd+ zL#g)ytR3hUYD-fN_AXPT`9)tK>@M0catEya^7H+Q?k(5hyH;ApR%+0-5Q`5q2DxI< zBl9DBQ=6hXE^C%KX5qP{^g>3mAR-X5%a}#K)sAWB1z+LzMdUW1?d+)E2WK@ZITw0t z6Q6FcwC=8qM_Rkcd$Y*fzksgy4|P}$KpRJMs$t{zLH1aZuhJWKizM`l;7&%GFN?xgLxa7PG?l+iq_T);=?QcZb= z0*=eeU8`d{dMwU2F;O7*;u;62;GY{A$NJ&%qsX$1aakxLBIgv*dE@J3AAZa?&hTWQ z=NUph7$n*H%4`ot-tF)D_q9c$&UWX{38S5QoX!0ALi^{!(;A4 z@?G}YZ?C99Z=5`ZaFgQu@6C^Hu(A2Ug-6yGvcqECTvRkF?_}3IKXpRc9`0>NuaS8+ z;l@fBhgr-Wh@Acz8$SCgKOZ7m`CutzTQNm3(iRzxc=zm{^t^s1CwR|!6RftN9HvM3 zOX3~UP_1RP$cjnuU9saVvFpV8W?Cm{HYq7(qmz|B+}n81kRO@!QBsgjYJ56Enr@g` zt!q(Zq|UekAL)R0jgZ*-L3dJ>P5-!!3pb*5T{XvJ&YZ*}yrg!0aGt|xsV2Se)`9sN z20zR>p`IbWfw!~3&03!$bj<+CwcC78rq92R$iQHe>G*H5;u3k=4=dbus+$=`ukC|w zF39-%2J#9HZvAy=&YjpyEJiL6u1>tHEy=v*mG;(%9Y}>h9x3g`c(Vb;DyytIv@lk58`LNZr`Adi^Lde$U&k{|B^dsjL2ddl} zEEZ=*i#;$OHu<-}=&N70C>Yb!X8rk4rcSVOWP3NgwlSLUENfEt0!{CPsk|%FWtO<@ zT}h&M02E7XNl045i|okwI(PD%(~mM+I>H(p6nHP)LavC~n#jd1O#09j%l~jl`%f(Q0GBt0g3*CDZd~J2qIovTrxR%$IyFJP26PJ zar|`B$5G2GS3N~3g-LC$(&55g3SXO4NkLGs4p!LWtT~^7%aUj`nijP_EGq1PD%|uU zicoI9f4yh4%+0k=z1cxkXz;r2vzGK_)6K5eLesv(0!f{qHAKFoyksYRY{z>B7MB3m zJ7Xr+a<}tnIK9f%Xj1P$A3QD%IFe(t)txS+EBCyEau#?4BGI~>)CIT@yFt@$2iI$3 z&vUt1beYD*$#Zm)nb@uvF+Or$U)kx8wiIT8LeXuXAZK3c76-e?_dNhUY2 zml7V{HRrg$Kiqa*K-819EmcT&5hB$nlTu}#r;5$P8PtA*;o4CEyi&$xpzJ%#y?Cd0 z)FG3I(GhQ${MK-Kf|oG}*y#3Z+r*Rgc z8{WR70pNMH`4>ObT6%P=q@ZhV!~UI+nwfh-8Xl2>Rwg=EGOEwdHzB%dUkS(8Y0Gna z!sl`SfOJK_!-ed|itxagj`_K<-g5}U^C!`~xvb~Jtkap+v%7=i5&4KFZ>(Jsnhqir zCqPv8MJL9tDqh7qh%AdCA$ThhFL@&t2W{seS!alclF7j~GrUV0m&-0)Kl~Tuhx1ro z)%FV}xN^MiUdciw1PQ+#bk-jo3mMWYGR~8#^Cmd6CTGlw7a}n<{gL3X*MhB|fd?4@ z4X!V|yu(t|{rd(Zyl(%w3fr7EXcJ>shA2m>5lo{D8J}U-+v$4pMt$had4^;k==ve8 z7y&^(V*elO&^MjJm}bPP=4Zy?Nu*i?@NM)>IDt2vF;4g}-^54KWhQ(@j(;ADMg;t) z)GNoamnL3}K2Gm2P*GB&_DC6jaDF`x)`c-KJpudQmD{5)l9H;Oc3fA!b+q!tblzro zWBplrhK|fa_*IYkhfSC3?tNRo<9Y%|lU^Ii#znscGs-QB%qnLAHEkg2IO+_hVf=Le zrIqeY3YgRo+YO_tW}10RQx?db6sZ0cA4EDpx@coLsk5dnBv#I&;bpwHwdX~+)Q)|MmRT$ z8@FEap-HONx)&0MYnMuU7i_&DK0p`7V;4~`h2`a;?%^41*7{?4Jq|*0*u>~GWpLCw zxKLB_n*Gqy`TZ;lkjGO6^ux|<79yjG9G5ZR#4&yv%1XHO;^IF#<(WGHQ`br_v$c8T z=AkZcuGTY_)K-SJmR^L~f(D;Y4L0#yetg)}GE8I3JMSjt{tY4Fmn}lV6mL5{fZe&; znAqLl5B@p1zZ_;$_t(;(2E{nDQa<+rAaT5id}X2d$)AE&!QTxpJss~mf|PuG)$|es z)&_m|a8O0qM@9c5eXDq!>XX@qu{~)xiO2FbBCSnLuLYi}k-3XN{J#2hY(FSGU;iP< znblXs)a;qC_76MnB1BB2@#72&^|m-&zkQeOurny zBPuFBcN0He)}=Y2idvxxmByPkrl`NAxo0{!br2<_jS^pN8oVZtESCHHRn+Z#6@K&k5Xi3mK9UnM^@d9P; zPDwA4C-|aqaZF5Ejga4EM*)%lGU&s<oncweSXbaXOUCyK9=X}&&0_PC=o*mH zNsoSn6Kcos@3mu>YNqfrp>GfKhN>FtEC*)lgB$<@^lD|&D}+d5#j0IltqcubLj1i|-E$dzAXA-Ft0RaQE@6$v}9cb?fy7v+<41&N+f%$QY3?F6Jq@ z*g;%55XZNI4sJ+2hzD!nbGXhMZ62|u#=a%He?il3V=1*p+U@h_QlasM>Prvn&Ser5 zz$5-b?o<0tt*z~6i{6Ai=iJNEOB>wveUrl;J9Q(-B1>iLWWpUY?n=Xq#>@70T5LmY z2Js28&vR+(SIBtgP*q^EAs|?_M0>iRF8VPFIKYoRb~Aq@4^X;@7s&Jb_Y|J!e<%yu zGFt};)72%uHalnj7BEo%miIin`dvZsm$q5@cVn!pmH%4Zw>v`*+Hal9>zWQl>);Zj zRlnr|YV`Mi2W3|pdjKqbD{VlhvF>z}5l~tj&SU9aL@%;W)hLDlUm#C>A1AabX^wHP~Q(wDMAwE=PEV!4p4nG=_97wpdc<=JBq`WgS<=Y;Z zJ9G1_aV>kp6FCe%6Ns$8o@^|6_1^*pKYhz~DH-)Y#mlz8qCgYMN9-;&9ZD}R467D$ z_)~2mAYgR1;Wr`wD-rCn$;M6}lA#24@@%9<%0p>9a?;(hxO|58At}J2m3zj&zHmCi z`VDf$c{@j?HtY>1@%Nq*zXsVQZ}ZVTfZ6R4W1Hh3Vtk*vluTWtp2_}Te#>w`met?v zD}tmv8&50k;Ohi-`uTY>gn!QzjH>l+vvOazPxT=rw?a-o zl}`mv6sIT^oz-Qd@`REm+>}AnOQtFYbs2LBx zK&JDo;>&< z#p$`I8z8(4RAI0XzD@w!XkfOfGGtT34=;=lq>t2M1@;i3@ z88fcjQLaYWChKao(KkAHs7cURPahBF1C#GV^*QpnWVKC*X`XII!S*})>cN3+B1;Ul zvlU)8+Zw>tbGZas8KEoz@XQx=-;A%6LQwgldj%fpxO9xFFMq=d2EdKI@RSPDb;u4=!RhdCWdk$gYbvzF)0#b7a zbnfrC;N;&*MNTeW@|>`gGq z3t7+YI&3~IAzZd+CmoY9#PJmQX)^U6=Z5|tGY8DApQql4t9;hy{kqPQb0&JqN&_%U z(v#0in=cRPEGEarnG4weFd4P!(#CbOt0S2=~Mdty}pyRrjCG^Nqw42gh1Zl&vjqA$$jUmTY(S=R2tR_gR5i^mvNTnh`b4WKMggl%}rA-CIg!6EOkskn)Qi-${_AFp8V zakHzM17YpS?a&^NH-EKz({xnO2V$+nPev@7)Fda8W@LXcMHCr%v3wTtWxGL@rJog8 zNzpAGzT(^Q>0Kh;?bWXIFy7P__aV^)BUrW-d^Y%tskB7tk{mnjy{Wef-jnQ#X zXEI*~$;qLdhG-#f>l9V9@~??|KF;YMl8xR;NG|}(NguIZLnK?z8wo93!#nWCW8Xtq zDLflJmq!Uhb1<-|DKgNhTx(E)CUq|3Da~xoe8A)FK3|(M68iX0?SwIGjuNiKzKI7S zHkv)Y-7;$!9aAx)Ld?hM`V_Ff0}7Ohn{Hy6@Loj^hRQmL=Tf;f@F2H_n*{T_1HP@rC?vB{eLa_IN1h4 z_Jl<}`SJ3Z0y>wvbU=0LaUB|sY%{z2E$eV-ueY4tH;djjy>s5l=z%M~ew$cVj>jU^ z^k%Z0LAm|^^qv3x_B`Ir`VP8{=(W77;xZu(5ZKs>^;h>w1b@Ox16esxT!WnyTq9%x@@{AsrMT?G0T|) zZ4$fUFurO9K|GY?9w9SiJRqqp6P2>mVG-8da#xIz*HK}O3kYdmpj*dTqrT@efXOYC z{-b%!ajQGtIX4%iM4dOE^#XCE%E=C`tk@ql{Bp|hUwmJBWdPQ=JQrORGL~?%{>iDr z*{-%|)*Xih;Fl8SNp$mL{VRJNpR8We#m(Nmb#@E>)Td)L6P93|L5H? zr_#F1t9_d>J)N(r{??h#&?vdlAcegOCD{`i!{2hxbmU!<+mI zP^>U9kfLTlpq1q(p8so2@$4UL9~4+iiMZcOxaHEBhyr|Sfe>_L-r;DsUUz#1OZ^dz zzoz_Z@Vh6MT>t!(E^iJV340AOv7{2oOMl>u4SJe7so&4d9qYftnkD@>8`_*FZ=$R{!>|jSmDZ59ptHlTj1MwXM0&eX4p)%y!cMr-VIWC zPKRfh^Us$H-EH$L%5771cx1%kUzJhJlQ^vG|5F)d&)<`_ga5>H{KswjZyz4oi3DE^%pMrXFl2?(9;7RmmxS!d zP;?Z#c{Yk)Y}AgS|A5JxO0F~I>wfHgx|>&BN-kN64C)OpFVc8GsYZya zPO2i!Jl&R)nm;6i4YP!=yZQ(Yd!fJzHN2m6u z9+1i~TAtbv^Dm~3{EkqinPsS{guC5EecPW8v#$TQE#T|9rE`Z~47(ctsNO3G^E@Jl zkce_eep`+sSbJtYL~8WY&ggD8WbFyVOdwe<=kyqMqJg*8oA4c+Ss#7i@1s6w&3j{4 z%{P$=DE&keuOuc)p0A`8$3?;JCz-6exp4uOur-6kYY&l2T(_*CYvS>}<_mso|9Xr? zg#VKxnOIW!BQqUJxsWmNE3VgVtweXA!U%8`$r^X?zhsnNc{0_$<%MJ1+_*ZbzV}X@ z`!K9aS$B`bg7vnWvz$OX>S<&1EZ}Mb1b$LBXY{8h{!lV~EAzC$MWQzIHz*{m?hUSc zG{hwdYLz0sf`6%t*uStjB#JkD;<|Gl2%&rvjEx#HxJ$9aBib#4Q z2n1gGrx;-^!*!GwH=Nek&M2zf4P37FhU_+GiQ-QZY=s~nb%oS_UV5-2AMAN-x_A>> znuK_Ctjao=mX+3%-FquG!**$Zws;vyOtoCa2P>;q`SQE_pTlS!l)2bneBilc7sFnY zulVR2!tjWlDeHd%Z@4z7?LQ)_!S?!V35^bOlHVm<;aW1gJ8ri#BnkSWolLH&iN{i? zEfe_XmZ1)7XKOyOoJ@BXn^mY(>3n5?Rx$pK?nILUrLVgI0T>HOP+iTsR_vtV$XAID zvp@$IBuM`>pA=8~CQ`M1JR?Um%8V}9j~8=}d}J^pM3*@B6#AhZSH|+eqw-QC3S-(i z0dwoDZ=*{D%k4KlAI)P*+B@VyP7PDM+&2~p|4LmIxcDEMSN^|8%%t~=M%^;Clu#m) zIZP#05w3TMoyeH-p@127vMe40gAqOPr{M8>d={rNGdg9UUJgu;aNJTvu*yDl>lMLO zI3=3v{l*Ih=Sl57DjOikH+cmOnkzZpZ?z|2d&?7}|5^uPpc5vWK@yt-&8&98>N~Wp zQzWDSvoMA`-Vv%V+)07(7_M{A8Qd4|0`!kE?}lk#X`tH$f>5q)y0daZiVL{}-O^E- zbDZ^8ykq!$Dbc-y7kp-V4Bs1C)}@_k0Jdl`Xdj_e^QN-=7!fTsA*0z&kpaG_!Y%$x zPv;i)$Tola3z`>!3U{H4H zw>&$^RFigTGHQnQ*DtB?e{UTNu9-Tfip!XDE7T|pGWwcvq2#_Ze3FH`nJFiE+)5HO zp7_NE9fc>D>1Du+#KSv}@g0jbDqvVL(GecWyLG(EoN+p(^i`*01&{Z{OdLT69udJ%+{BH$yb5Tjsl*GxA1D zjsYtH_Lb!JA3F00sIE?hu7yLa?7YW!fS$iyfU8UV2n~v~k}OESpTdqP1-Mfq!1B4E zB*%X^8J;Quk-1I`1 zjq>`FN`-PLnqU?S7;O#Oob1q~jXf^yS~LnSe%q`olvI+yPoR0Q8LdcMsuZrx*<|#m8?|7gvTzqkBbnsx4H_sZH-|oDqX%y#t)19 zjDvCS+ckzd`(Cy!h$+qwNbD=TP3L@YBr*yZHd*ZPh{DprhjDu+!xjma)hp(BAKac{ zTuzjzsHibN8`E=H?m8~I1s2Lvsy==s;Tci#jwW9LXifOl$&J*`FvOYg*G&sP_xJy= M|8I8S%)iI}FEkQjUjP6A diff --git a/plugins/plugin-chart-echarts/src/Waterfall/index.ts b/plugins/plugin-chart-echarts/src/Waterfall/index.ts index 266d891697..e249bc93d6 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/index.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/index.ts @@ -45,9 +45,12 @@ export default class EchartsWaterfallChartPlugin extends ChartPlugin< loadChart: () => import('./EchartsWaterfall'), metadata: new ChartMetadata({ credits: ['https://echarts.apache.org'], - description: 'Waterfall (Apache ECharts)', - name: t('Waterfall'), + category: t('Evolution'), + description: '', + exampleGallery: [], + name: t('Waterfall Chart'), thumbnail, + tags: [], }), transformProps, }); diff --git a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts index d7e29a7333..96940fb255 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts @@ -32,7 +32,7 @@ import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults'; import { EchartsProps } from '../types'; const TOTAL_MARK = t('Total'); -const STACK_MARK = 'stack'; +const ASSIST_MARK = t('assist'); const LEGEND = { INCREASE: t('Increase'), @@ -43,14 +43,12 @@ const LEGEND = { function formatTooltip({ params, numberFormatter, + richTooltip, }: { params: any; numberFormatter: NumberFormatter; + richTooltip: boolean; }) { - const increaseParams = params[1]; - const decreaseParams = params[2]; - const totalParams = params[3]; - const htmlMaker = (params: any) => `
${params.name}
@@ -60,37 +58,42 @@ function formatTooltip({ params.seriesName }: ${numberFormatter( - params.value, + params.data, )} `; - if (increaseParams.value !== '-') { - return htmlMaker(increaseParams); - } - if (decreaseParams.value !== '-') { - return htmlMaker(decreaseParams); - } - if (totalParams.value !== '-') { - return htmlMaker(totalParams); + if (richTooltip) { + const [, increaseParams, decreaseParams, totalParams] = params; + if (increaseParams.data !== '-' || increaseParams.data === null) { + return htmlMaker(increaseParams); + } + if (decreaseParams.data !== '-') { + return htmlMaker(decreaseParams); + } + if (totalParams.data !== '-') { + return htmlMaker(totalParams); + } + } else if (params.seriesName !== ASSIST_MARK) { + return htmlMaker(params); } return ''; } function transformer({ data, - breakdown, - category, + columns, + series, metric, }: { data: DataRecord[]; - breakdown: string; - category: string; + columns: string; + series: string; metric: string; }) { - // Group by category (temporary map) + // Group by series (temporary map) const groupedData = data.reduce((acc, cur) => { - const categoryLabel = cur[category] as string; + const categoryLabel = cur[series] as string; const categoryData = acc.get(categoryLabel) || []; categoryData.push(cur); acc.set(categoryLabel, categoryData); @@ -99,38 +102,31 @@ function transformer({ const transformedData: DataRecord[] = []; - if (breakdown) { - let isFirst = true; + if (columns?.length) { groupedData.forEach((value, key) => { - let tempValue = value; + const tempValue = value; // Calc total per period - const sum = tempValue.reduce((acc, cur) => acc + (cur[metric] as number), 0); + const sum = tempValue.reduce((acc, cur) => acc + ((cur[metric] as number) ?? 0), 0); // Push total per period to the end of period values array tempValue.push({ - [category]: key, - [breakdown]: TOTAL_MARK, + [series]: key, + [columns]: TOTAL_MARK, [metric]: sum, }); - // Remove first period and leave only last one - if (isFirst) { - const lastItem = tempValue[tempValue.length - 1]; - tempValue = [lastItem]; - isFirst = false; - } transformedData.push(...tempValue); }); } else { let total = 0; groupedData.forEach((value, key) => { - const sum = value.reduce((acc, cur) => acc + (cur[metric] as number), 0); + const sum = value.reduce((acc, cur) => acc + ((cur[metric] as number) ?? 0), 0); transformedData.push({ - [category]: key, + [series]: key, [metric]: sum, }); total += sum; }); transformedData.push({ - [category]: TOTAL_MARK, + [series]: TOTAL_MARK, [metric]: total, }); } @@ -144,13 +140,15 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): const { colorScheme, metric = '', - breakdown = '', - category, + columns = '', + series, xTicksLayout, showLegend, yAxisLabel, xAxisLabel, yAxisFormat, + richTooltip, + showValue, } = formData as EchartsWaterfallFormData; const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const numberFormatter = getNumberFormatter(yAxisFormat); @@ -167,8 +165,8 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): const transformedData = transformer({ data, - breakdown, - category, + columns, + series, metric: metricLabel, }); @@ -179,19 +177,19 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): transformedData.forEach((data, index, self) => { const totalSum = self.slice(0, index + 1).reduce((prev, cur, i) => { - if (breakdown) { - if (cur[breakdown] !== TOTAL_MARK || i === 0) { - return prev + (cur[metricLabel] as number); + if (columns?.length) { + if (cur[columns] !== TOTAL_MARK || i === 0) { + return prev + ((cur[metricLabel] as number) ?? 0); } - } else if (cur[category] !== TOTAL_MARK) { - return prev + (cur[metricLabel] as number); + } else if (cur[series] !== TOTAL_MARK) { + return prev + ((cur[metricLabel] as number) ?? 0); } return prev; }, 0); const value = data[metricLabel] as number; const isNegative = value < 0; - if (data[breakdown] === TOTAL_MARK || data[category] === TOTAL_MARK) { + if (data[columns] === TOTAL_MARK || data[series] === TOTAL_MARK) { increaseData.push('-'); decreaseData.push('-'); assistData.push('-'); @@ -217,22 +215,22 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): else axisLabel = { show: true }; let xAxisData: string[] = []; - if (breakdown) { + if (columns?.length) { xAxisData = transformedData.map(row => { - if (row[breakdown] === TOTAL_MARK) { - return row[category] as string; + if (row[columns] === TOTAL_MARK) { + return row[series] as string; } - return row[breakdown] as string; + return row[columns] as string; }); } else { - xAxisData = transformedData.map(row => row[category] as string); + xAxisData = transformedData.map(row => row[series] as string); } - const series: BarSeriesOption[] = [ + const barSeries: BarSeriesOption[] = [ { - name: 'assist', + name: ASSIST_MARK, type: 'bar', - stack: STACK_MARK, + stack: 'stack', itemStyle: { borderColor: 'rgba(0,0,0,0)', color: 'rgba(0,0,0,0)', @@ -248,9 +246,9 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): { name: LEGEND.INCREASE, type: 'bar', - stack: STACK_MARK, + stack: 'stack', label: { - show: true, + show: showValue, position: 'top', formatter, }, @@ -262,9 +260,9 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): { name: LEGEND.DECREASE, type: 'bar', - stack: STACK_MARK, + stack: 'stack', label: { - show: true, + show: showValue, position: 'bottom', formatter, }, @@ -276,9 +274,9 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): { name: LEGEND.TOTAL, type: 'bar', - stack: STACK_MARK, + stack: 'stack', label: { - show: true, + show: showValue, position: 'top', formatter, }, @@ -324,17 +322,16 @@ export default function transformProps(chartProps: EchartsWaterfallChartProps): }, tooltip: { ...defaultTooltip, - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, + appendToBody: true, + trigger: richTooltip ? 'axis' : 'item', formatter: (params: any) => formatTooltip({ params, numberFormatter, + richTooltip, }), }, - series, + series: barSeries, }; return { diff --git a/plugins/plugin-chart-echarts/src/Waterfall/types.ts b/plugins/plugin-chart-echarts/src/Waterfall/types.ts index 19be2fcdfd..aea69879e0 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/types.ts +++ b/plugins/plugin-chart-echarts/src/Waterfall/types.ts @@ -36,8 +36,8 @@ export type EchartsWaterfallFormData = QueryFormData & xAxisLabel: string; yAxisFormat: string; xTicksLayout?: WaterfallFormXTicksLayout; - category: string; - breakdown?: string; + series: string; + columns?: string; }; export const DEFAULT_FORM_DATA: Partial = { diff --git a/plugins/plugin-chart-echarts/src/controls.tsx b/plugins/plugin-chart-echarts/src/controls.tsx index e170febf7c..b3e3e0ef2b 100644 --- a/plugins/plugin-chart-echarts/src/controls.tsx +++ b/plugins/plugin-chart-echarts/src/controls.tsx @@ -94,7 +94,7 @@ export const legendSection = [ [legendMarginControl], ]; -const showValueControl = { +export const showValueControl = { name: 'show_value', config: { type: 'CheckboxControl', From f61edf0712e5353bae5ca75fbe3ba3538d5d1cc2 Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Sun, 12 Sep 2021 23:02:10 +0800 Subject: [PATCH 09/10] fix: test --- .../plugin-chart-echarts/Waterfall/Stories.tsx | 4 ++-- .../test/Waterfall/buildQuery.test.ts | 4 ++-- .../test/Waterfall/transformProps.test.ts | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx index 42d19f9674..77d55aefc8 100644 --- a/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx +++ b/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Waterfall/Stories.tsx @@ -24,8 +24,8 @@ export const Waterfall = ({ width, height }) => { queriesData={[{ data }]} formData={{ metric: `SUM(decomp_volume)`, - breakdown: 'due_to_group', - category: 'period', + columns: 'due_to_group', + series: 'period', x_ticks_layout: '45°', adhocFilters: [ { diff --git a/plugins/plugin-chart-echarts/test/Waterfall/buildQuery.test.ts b/plugins/plugin-chart-echarts/test/Waterfall/buildQuery.test.ts index c701977ec7..d3e3c82496 100644 --- a/plugins/plugin-chart-echarts/test/Waterfall/buildQuery.test.ts +++ b/plugins/plugin-chart-echarts/test/Waterfall/buildQuery.test.ts @@ -23,8 +23,8 @@ describe('Waterfall buildQuery', () => { datasource: '5__table', granularity_sqla: 'ds', metric: 'foo', - category: 'bar', - breakdown: 'baz', + series: 'bar', + columns: 'baz', viz_type: 'my_chart', }; diff --git a/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts b/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts index 5ab60409fd..dbcffbf5f9 100644 --- a/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts +++ b/plugins/plugin-chart-echarts/test/Waterfall/transformProps.test.ts @@ -33,7 +33,7 @@ describe('Waterfall tranformProps', () => { datasource: '3__table', granularity_sqla: 'ds', metric: 'sum', - category: 'bar', + series: 'bar', }; const chartProps = new ChartProps({ formData: formData1, @@ -75,8 +75,8 @@ describe('Waterfall tranformProps', () => { datasource: '3__table', granularity_sqla: 'ds', metric: 'sum', - category: 'bar', - breakdown: 'foo', + series: 'bar', + columns: 'foo', }; const chartProps = new ChartProps({ formData: formData1, @@ -95,16 +95,16 @@ describe('Waterfall tranformProps', () => { echartOptions: expect.objectContaining({ series: [ expect.objectContaining({ - data: ['-', 3, 3, '-'], + data: [0, 10, '-', 3, 3, '-'], }), expect.objectContaining({ - data: ['-', '-', 5, '-'], + data: [10, 3, '-', '-', 5, '-'], }), expect.objectContaining({ - data: ['-', 10, '-', '-'], + data: ['-', '-', '-', 10, '-', '-'], }), expect.objectContaining({ - data: [13, '-', '-', 8], + data: ['-', '-', 13, '-', '-', 8], }), ], }), From 40540414f2ebf05d3c4b6fc8827b3a66782352fe Mon Sep 17 00:00:00 2001 From: stephenLYZ <750188453@qq.com> Date: Mon, 13 Sep 2021 23:09:01 +0800 Subject: [PATCH 10/10] fix: lint --- plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx index a44c03f8b8..c3627a316a 100644 --- a/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx +++ b/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { t } from '@superset-ui/core'; import { ControlPanelConfig, formatSelectOptions, sections } from '@superset-ui/chart-controls'; -import { legendSection, showValueControl } from '../controls'; +import { showValueControl } from '../controls'; const config: ControlPanelConfig = { controlPanelSections: [