You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by di...@apache.org on 2022/08/22 13:17:58 UTC

[superset] 09/36: fix(plugin-chart-echarts): gauge chart enhancements and fixes (#21007)

This is an automated email from the ASF dual-hosted git repository.

diegopucci pushed a commit to branch chore/drill-to-detail-modal-tests
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 6fc21d8bbbf7f5ac3b15befe6f3fc74f70c6d12f
Author: Stephen Liu <75...@qq.com>
AuthorDate: Tue Aug 16 21:54:17 2022 +0800

    fix(plugin-chart-echarts): gauge chart enhancements and fixes (#21007)
    
    * fix(plugin-chart-echarts): gauge chart enhancements and fixes
    
    * fix lint
---
 .../src/Gauge/controlPanel.tsx                     |  6 +-
 .../src/Gauge/transformProps.ts                    | 79 +++++++++++++++-------
 .../plugin-chart-echarts/src/Gauge/types.ts        |  8 +--
 3 files changed, 60 insertions(+), 33 deletions(-)

diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx
index 14f5460c8a..7ffa62fda0 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx
@@ -17,7 +17,7 @@
  * under the License.
  */
 import React from 'react';
-import { t, validateNonEmpty, validateInteger } from '@superset-ui/core';
+import { t } from '@superset-ui/core';
 import {
   sharedControls,
   ControlPanelConfig,
@@ -82,8 +82,7 @@ const config: ControlPanelConfig = {
             config: {
               type: 'TextControl',
               isInt: true,
-              default: String(DEFAULT_FORM_DATA.minVal),
-              validators: [validateNonEmpty, validateInteger],
+              default: DEFAULT_FORM_DATA.minVal,
               renderTrigger: true,
               label: t('Min'),
               description: t('Minimum value on the gauge axis'),
@@ -95,7 +94,6 @@ const config: ControlPanelConfig = {
               type: 'TextControl',
               isInt: true,
               default: DEFAULT_FORM_DATA.maxVal,
-              validators: [validateNonEmpty, validateInteger],
               renderTrigger: true,
               label: t('Max'),
               description: t('Maximum value on the gauge axis'),
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts
index 59a2e21f8e..edd31d9d0d 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts
@@ -28,6 +28,7 @@ import {
 } from '@superset-ui/core';
 import { EChartsCoreOption, GaugeSeriesOption } from 'echarts';
 import { GaugeDataItemOption } from 'echarts/types/src/chart/gauge/GaugeSeries';
+import { CallbackDataParams } from 'echarts/types/src/util/types';
 import range from 'lodash/range';
 import { parseNumbersList } from '../utils/controls';
 import {
@@ -80,6 +81,12 @@ const calculateAxisLineWidth = (
   overlap: boolean,
 ): number => (overlap ? fontSize : data.length * fontSize);
 
+const calculateMin = (data: GaugeDataItemOption[]) =>
+  2 * Math.min(...data.map(d => d.value as number).concat([0]));
+
+const calculateMax = (data: GaugeDataItemOption[]) =>
+  2 * Math.max(...data.map(d => d.value as number).concat([0]));
+
 export default function transformProps(
   chartProps: EchartsGaugeChartProps,
 ): GaugeChartTransformedProps {
@@ -115,12 +122,7 @@ export default function transformProps(
   const data = (queriesData[0]?.data || []) as DataRecord[];
   const numberFormatter = getNumberFormatter(numberFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme as string);
-  const normalizer = maxVal;
   const axisLineWidth = calculateAxisLineWidth(data, fontSize, overlap);
-  const axisLabels = range(minVal, maxVal, (maxVal - minVal) / splitNumber);
-  const axisLabelLength = Math.max(
-    ...axisLabels.map(label => numberFormatter(label).length).concat([1]),
-  );
   const groupbyLabels = groupby.map(getColumnLabel);
   const formatValue = (value: number) =>
     valueFormatter.replace('{value}', numberFormatter(value));
@@ -130,12 +132,6 @@ export default function transformProps(
     FONT_SIZE_MULTIPLIERS.titleOffsetFromTitle * fontSize;
   const detailOffsetFromTitle =
     FONT_SIZE_MULTIPLIERS.detailOffsetFromTitle * fontSize;
-  const intervalBoundsAndColors = setIntervalBoundsAndColors(
-    intervals,
-    intervalColorIndices,
-    colorFn,
-    normalizer,
-  );
   const columnsLabelMap = new Map<string, DataRecordValue[]>();
 
   const transformedData: GaugeDataItemOption[] = data.map(
@@ -196,6 +192,33 @@ export default function transformProps(
 
   const { setDataMask = () => {}, onContextMenu } = hooks;
 
+  const min = minVal ?? calculateMin(transformedData);
+  const max = maxVal ?? calculateMax(transformedData);
+  const axisLabels = range(min, max, (max - min) / splitNumber);
+  const axisLabelLength = Math.max(
+    ...axisLabels.map(label => numberFormatter(label).length).concat([1]),
+  );
+  const normalizer = max;
+  const intervalBoundsAndColors = setIntervalBoundsAndColors(
+    intervals,
+    intervalColorIndices,
+    colorFn,
+    normalizer,
+  );
+  const splitLineDistance =
+    axisLineWidth + splitLineLength + OFFSETS.ticksFromLine;
+  const axisLabelDistance =
+    FONT_SIZE_MULTIPLIERS.axisLabelDistance *
+      fontSize *
+      FONT_SIZE_MULTIPLIERS.axisLabelLength *
+      axisLabelLength +
+    (showSplitLine ? splitLineLength : 0) +
+    (showAxisTick ? axisTickLength : 0) +
+    OFFSETS.ticksFromLine -
+    axisLineWidth;
+  const axisTickDistance =
+    axisLineWidth + axisTickLength + OFFSETS.ticksFromLine;
+
   const progress = {
     show: showProgress,
     overlap,
@@ -204,7 +227,7 @@ export default function transformProps(
   };
   const splitLine = {
     show: showSplitLine,
-    distance: -axisLineWidth - splitLineLength - OFFSETS.ticksFromLine,
+    distance: -splitLineDistance,
     length: splitLineLength,
     lineStyle: {
       width: FONT_SIZE_MULTIPLIERS.splitLineWidth * fontSize,
@@ -219,22 +242,14 @@ export default function transformProps(
     },
   };
   const axisLabel = {
-    distance:
-      axisLineWidth -
-      FONT_SIZE_MULTIPLIERS.axisLabelDistance *
-        fontSize *
-        FONT_SIZE_MULTIPLIERS.axisLabelLength *
-        axisLabelLength -
-      (showSplitLine ? splitLineLength : 0) -
-      (showAxisTick ? axisTickLength : 0) -
-      OFFSETS.ticksFromLine,
+    distance: -axisLabelDistance,
     fontSize,
     formatter: numberFormatter,
     color: gaugeSeriesOptions.axisLabel?.color,
   };
   const axisTick = {
     show: showAxisTick,
-    distance: -axisLineWidth - axisTickLength - OFFSETS.ticksFromLine,
+    distance: -axisTickDistance,
     length: axisTickLength,
     lineStyle: gaugeSeriesOptions.axisTick?.lineStyle as AxisTickLineStyle,
   };
@@ -243,8 +258,14 @@ export default function transformProps(
     formatter: (value: number) => formatValue(value),
     color: gaugeSeriesOptions.detail?.color,
   };
-  let pointer;
+  const tooltip = {
+    formatter: (params: CallbackDataParams) => {
+      const { name, value } = params;
+      return `${name} : ${formatValue(value as number)}`;
+    },
+  };
 
+  let pointer;
   if (intervalBoundsAndColors.length) {
     splitLine.lineStyle.color =
       INTERVAL_GAUGE_SERIES_OPTION.splitLine?.lineStyle?.color;
@@ -269,8 +290,8 @@ export default function transformProps(
       type: 'gauge',
       startAngle,
       endAngle,
-      min: minVal,
-      max: maxVal,
+      min,
+      max,
       progress,
       animation,
       axisLine: axisLine as GaugeSeriesOption['axisLine'],
@@ -280,11 +301,19 @@ export default function transformProps(
       axisTick,
       pointer,
       detail,
+      tooltip,
+      radius:
+        Math.min(width, height) / 2 - axisLabelDistance - axisTickDistance,
+      center: ['50%', '55%'],
       data: transformedData,
     },
   ];
 
   const echartOptions: EChartsCoreOption = {
+    tooltip: {
+      appendToBody: true,
+      trigger: 'item',
+    },
     series,
   };
 
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts
index 7ae2a55595..4824d579c4 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts
@@ -35,8 +35,8 @@ export type EchartsGaugeFormData = QueryFormData & {
   groupby: QueryFormColumn[];
   metric?: string;
   rowLimit: number;
-  minVal: number;
-  maxVal: number;
+  minVal: number | null;
+  maxVal: number | null;
   fontSize: number;
   numberFormat: string;
   animation: boolean;
@@ -59,8 +59,8 @@ export const DEFAULT_FORM_DATA: Partial<EchartsGaugeFormData> = {
   ...DEFAULT_LEGEND_FORM_DATA,
   groupby: [],
   rowLimit: 10,
-  minVal: 0,
-  maxVal: 100,
+  minVal: null,
+  maxVal: null,
   fontSize: 15,
   numberFormat: 'SMART_NUMBER',
   animation: true,