From 4333a683f0eb9b62c4025c88e3fede16655d186a Mon Sep 17 00:00:00 2001
From: Yaozong Liu <750188453@qq.com>
Date: Sat, 10 Jul 2021 04:11:40 +0800
Subject: [PATCH] feat(plugin-chart-echarts): add x-filtering in gauge chart
(#1203)
* fix(plugin-chart-echarts): add gauge cross filtering
* fix(plugin-chart-echarts): fix lint
* fix(plugin-chart-echarts): use constants
---
.../src/Gauge/EchartsGauge.tsx | 74 ++++++++++++++++-
.../src/Gauge/controlPanel.tsx | 22 ++++-
.../plugin-chart-echarts/src/Gauge/index.ts | 6 +-
.../src/Gauge/transformProps.ts | 81 ++++++++++++++-----
.../plugin-chart-echarts/src/Gauge/types.ts | 16 +++-
.../plugins/plugin-chart-echarts/src/types.ts | 13 +++
6 files changed, 182 insertions(+), 30 deletions(-)
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx
index 5f57bad421f9..731aadded839 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx
@@ -16,10 +16,76 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React from 'react';
-import { EchartsProps } from '../types';
+import React, { useCallback } from 'react';
+import { GaugeChartTransformedProps } from './types';
import Echart from '../components/Echart';
+import { EventHandlers } from '../types';
-export default function EchartsGauge({ height, width, echartOptions }: EchartsProps) {
- return ;
+export default function EchartsGauge({
+ height,
+ width,
+ echartOptions,
+ setDataMask,
+ labelMap,
+ groupby,
+ selectedValues,
+ formData: { emitFilter },
+}: GaugeChartTransformedProps) {
+ const handleChange = useCallback(
+ (values: string[]) => {
+ if (!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([name]);
+ }
+ },
+ };
+
+ return (
+
+ );
}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx
index 2866dcd36122..56e21d4b11fe 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx
@@ -17,7 +17,13 @@
* under the License.
*/
import React from 'react';
-import { t, validateNonEmpty, validateInteger } from '@superset-ui/core';
+import {
+ t,
+ validateNonEmpty,
+ validateInteger,
+ isFeatureEnabled,
+ FeatureFlag,
+} from '@superset-ui/core';
import {
sharedControls,
ControlPanelConfig,
@@ -121,6 +127,20 @@ const config: ControlPanelConfig = {
},
],
['color_scheme'],
+ isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)
+ ? [
+ {
+ name: 'emit_filter',
+ config: {
+ type: 'CheckboxControl',
+ label: t('Enable emitting filters'),
+ default: DEFAULT_FORM_DATA.emitFilter,
+ renderTrigger: true,
+ description: t('Enable emmiting filters.'),
+ },
+ },
+ ]
+ : [],
[
{
name: 'font_size',
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/index.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/index.ts
index f32d67643d23..51a8e4f74ae8 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/index.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/index.ts
@@ -21,8 +21,12 @@ import controlPanel from './controlPanel';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';
import buildQuery from './buildQuery';
+import { EchartsGaugeChartProps, EchartsGaugeFormData } from './types';
-export default class EchartsGaugeChartPlugin extends ChartPlugin {
+export default class EchartsGaugeChartPlugin extends ChartPlugin<
+ EchartsGaugeFormData,
+ EchartsGaugeChartProps
+> {
constructor() {
super({
buildQuery,
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts
index 85209054eaa3..ccd099376b05 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts
@@ -18,12 +18,12 @@
*/
import {
QueryFormMetric,
- ChartProps,
CategoricalColorNamespace,
CategoricalColorScale,
DataRecord,
getNumberFormatter,
getMetricLabel,
+ DataRecordValue,
} from '@superset-ui/core';
import { EChartsOption, GaugeSeriesOption } from 'echarts';
import { GaugeDataItemOption } from 'echarts/types/src/chart/gauge/GaugeSeries';
@@ -33,6 +33,8 @@ import {
DEFAULT_FORM_DATA as DEFAULT_GAUGE_FORM_DATA,
EchartsGaugeFormData,
AxisTickLineStyle,
+ GaugeChartTransformedProps,
+ EchartsGaugeChartProps,
} from './types';
import {
DEFAULT_GAUGE_SERIES_OPTION,
@@ -40,6 +42,7 @@ import {
OFFSETS,
FONT_SIZE_MULTIPLIERS,
} from './constants';
+import { OpacityEnum } from '../constants';
const setIntervalBoundsAndColors = (
intervals: string,
@@ -71,8 +74,10 @@ const setIntervalBoundsAndColors = (
const calculateAxisLineWidth = (data: DataRecord[], fontSize: number, overlap: boolean): number =>
overlap ? fontSize : data.length * fontSize;
-export default function transformProps(chartProps: ChartProps) {
- const { width, height, formData, queriesData } = chartProps;
+export default function transformProps(
+ chartProps: EchartsGaugeChartProps,
+): GaugeChartTransformedProps {
+ const { width, height, formData, queriesData, hooks, filterState } = chartProps;
const {
groupby,
metric,
@@ -94,6 +99,7 @@ export default function transformProps(chartProps: ChartProps) {
intervals,
intervalColorIndices,
valueFormatter,
+ emitFilter,
}: EchartsGaugeFormData = { ...DEFAULT_GAUGE_FORM_DATA, ...formData };
const data = (queriesData[0]?.data || []) as DataRecord[];
const numberFormatter = getNumberFormatter(numberFormat);
@@ -115,24 +121,51 @@ export default function transformProps(chartProps: ChartProps) {
colorFn,
normalizer,
);
- const transformedData: GaugeDataItemOption[] = data.map((data_point, index) => ({
- value: data_point[getMetricLabel(metric as QueryFormMetric)] as number,
- name: groupby.map(column => `${column}: ${data_point[column]}`).join(', '),
- itemStyle: {
- color: colorFn(index),
- },
- title: {
- offsetCenter: ['0%', `${index * titleOffsetFromTitle + OFFSETS.titleFromCenter}%`],
- fontSize,
- },
- detail: {
- offsetCenter: [
- '0%',
- `${index * titleOffsetFromTitle + OFFSETS.titleFromCenter + detailOffsetFromTitle}%`,
- ],
- fontSize: FONT_SIZE_MULTIPLIERS.detailFontSize * fontSize,
- },
- }));
+ const columnsLabelMap = new Map();
+
+ const transformedData: GaugeDataItemOption[] = data.map((data_point, index) => {
+ const name = groupby.map(column => `${column}: ${data_point[column]}`).join(', ');
+ columnsLabelMap.set(
+ name,
+ groupby.map(col => data_point[col]),
+ );
+ let item: GaugeDataItemOption = {
+ value: data_point[getMetricLabel(metric as QueryFormMetric)] as number,
+ name,
+ itemStyle: {
+ color: colorFn(index),
+ },
+ title: {
+ offsetCenter: ['0%', `${index * titleOffsetFromTitle + OFFSETS.titleFromCenter}%`],
+ fontSize,
+ },
+ detail: {
+ offsetCenter: [
+ '0%',
+ `${index * titleOffsetFromTitle + OFFSETS.titleFromCenter + detailOffsetFromTitle}%`,
+ ],
+ fontSize: FONT_SIZE_MULTIPLIERS.detailFontSize * fontSize,
+ },
+ };
+ if (filterState.selectedValues && !filterState.selectedValues.includes(name)) {
+ item = {
+ ...item,
+ itemStyle: {
+ color: colorFn(index),
+ opacity: OpacityEnum.SemiTransparent,
+ },
+ detail: {
+ show: false,
+ },
+ title: {
+ show: false,
+ },
+ };
+ }
+ return item;
+ });
+
+ const { setDataMask = () => {} } = hooks;
const progress = {
show: showProgress,
@@ -223,8 +256,14 @@ export default function transformProps(chartProps: ChartProps) {
};
return {
+ formData,
width,
height,
echartOptions,
+ setDataMask,
+ emitFilter,
+ labelMap: Object.fromEntries(columnsLabelMap),
+ groupby,
+ selectedValues: filterState.selectedValues || [],
};
}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/types.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/types.ts
index 42b579b4fc8e..90058af167c9 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/types.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Gauge/types.ts
@@ -16,14 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { DEFAULT_LEGEND_FORM_DATA } from '../types';
+import { ChartDataResponseResult, ChartProps, QueryFormData } from '@superset-ui/core';
+import { DEFAULT_LEGEND_FORM_DATA, EChartTransformedProps } from '../types';
export type AxisTickLineStyle = {
width: number;
color: string;
};
-export type EchartsGaugeFormData = {
+export type EchartsGaugeFormData = QueryFormData & {
colorScheme?: string;
groupby: string[];
metric?: object;
@@ -45,9 +46,10 @@ export type EchartsGaugeFormData = {
intervals: string;
intervalColorIndices: string;
valueFormatter: string;
+ emitFilter: boolean;
};
-export const DEFAULT_FORM_DATA: EchartsGaugeFormData = {
+export const DEFAULT_FORM_DATA: Partial = {
...DEFAULT_LEGEND_FORM_DATA,
groupby: [],
rowLimit: 10,
@@ -68,4 +70,12 @@ export const DEFAULT_FORM_DATA: EchartsGaugeFormData = {
intervals: '',
intervalColorIndices: '',
valueFormatter: '{value}',
+ emitFilter: false,
};
+
+export interface EchartsGaugeChartProps extends ChartProps {
+ formData: EchartsGaugeFormData;
+ queriesData: ChartDataResponseResult[];
+}
+
+export type GaugeChartTransformedProps = EChartTransformedProps;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/types.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/types.ts
index 271b2d0436c1..029aec30354e 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/types.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/types.ts
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { DataRecordValue, SetDataMaskHook } from '@superset-ui/core';
import { EChartsOption } from 'echarts';
import { TooltipMarker } from 'echarts/types/src/util/format';
@@ -96,3 +97,15 @@ export enum LabelPositionEnum {
InsideTopRight = 'insideTopRight',
InsideBottomRight = 'insideBottomRight',
}
+
+export interface EChartTransformedProps {
+ formData: F;
+ height: number;
+ width: number;
+ echartOptions: EChartsOption;
+ emitFilter: boolean;
+ setDataMask: SetDataMaskHook;
+ labelMap: Record;
+ groupby: string[];
+ selectedValues: Record;
+}