Skip to content

Commit

Permalink
feat: conditional coloring for big number chart (#23064)
Browse files Browse the repository at this point in the history
Co-authored-by: Gerold Busch <[email protected]>
  • Loading branch information
gbusch and Gerold Busch authored May 1, 2023
1 parent fd3030f commit 61d8a0b
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const getColorFunction = (
colorScheme,
}: ConditionalFormattingConfig,
columnValues: number[],
alpha?: boolean,
) => {
let minOpacity = MIN_OPACITY_BOUNDED;
const maxOpacity = MAX_OPACITY;
Expand Down Expand Up @@ -176,17 +177,21 @@ export const getColorFunction = (
const compareResult = comparatorFunction(value, columnValues);
if (compareResult === false) return undefined;
const { cutoffValue, extremeValue } = compareResult;
return addAlpha(
colorScheme,
getOpacity(value, cutoffValue, extremeValue, minOpacity, maxOpacity),
);
if (alpha === undefined || alpha) {
return addAlpha(
colorScheme,
getOpacity(value, cutoffValue, extremeValue, minOpacity, maxOpacity),
);
}
return colorScheme;
};
};

export const getColorFormatters = memoizeOne(
(
columnConfig: ConditionalFormattingConfig[] | undefined,
data: DataRecord[],
alpha?: boolean,
) =>
columnConfig?.reduce(
(acc: ColorFormatters, config: ConditionalFormattingConfig) => {
Expand All @@ -204,6 +209,7 @@ export const getColorFormatters = memoizeOne(
getColorFromValue: getColorFunction(
config,
data.map(row => row[config.column!] as number),
alpha,
),
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,25 @@ describe('getColorFunction()', () => {
expect(colorFunction(150)).toBeUndefined();
});

it('getColorFunction BETWEEN_OR_EQUAL without opacity', () => {
const colorFunction = getColorFunction(
{
operator: COMPARATOR.BETWEEN_OR_EQUAL,
targetValueLeft: 50,
targetValueRight: 100,
colorScheme: '#FF0000',
column: 'count',
},
countValues,
false,
);
expect(colorFunction(25)).toBeUndefined();
expect(colorFunction(50)).toEqual('#FF0000');
expect(colorFunction(75)).toEqual('#FF0000');
expect(colorFunction(100)).toEqual('#FF0000');
expect(colorFunction(125)).toBeUndefined();
});

it('getColorFunction BETWEEN_OR_LEFT_EQUAL', () => {
const colorFunction = getColorFunction(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
import { smartDateFormatter, t } from '@superset-ui/core';
import { GenericDataType, smartDateFormatter, t } from '@superset-ui/core';
import {
ControlPanelConfig,
D3_FORMAT_DOCS,
D3_TIME_FORMAT_OPTIONS,
Dataset,
getStandardizedControls,
sections,
} from '@superset-ui/chart-controls';
Expand Down Expand Up @@ -89,6 +90,45 @@ export default {
},
},
],
[
{
name: 'conditional_formatting',
config: {
type: 'ConditionalFormattingControl',
renderTrigger: true,
label: t('Conditional Formatting'),
description: t('Apply conditional color formatting to metric'),
shouldMapStateToProps() {
return true;
},
mapStateToProps(explore, _, chart) {
const verboseMap = explore?.datasource?.hasOwnProperty(
'verbose_map',
)
? (explore?.datasource as Dataset)?.verbose_map
: explore?.datasource?.columns ?? {};
const { colnames, coltypes } =
chart?.queriesResponse?.[0] ?? {};
const numericColumns =
Array.isArray(colnames) && Array.isArray(coltypes)
? colnames
.filter(
(colname: string, index: number) =>
coltypes[index] === GenericDataType.NUMERIC,
)
.map(colname => ({
value: colname,
label: verboseMap[colname] ?? colname,
}))
: [];
return {
columnOptions: numericColumns,
verboseMap,
};
},
},
},
],
],
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
import {
ColorFormatters,
getColorFormatters,
} from '@superset-ui/chart-controls';
import {
getNumberFormatter,
GenericDataType,
Expand All @@ -40,6 +44,7 @@ export default function transformProps(
forceTimestampFormatting,
timeFormat,
yAxisFormat,
conditionalFormatting,
} = formData;
const refs: Refs = {};
const { data = [], coltypes = [] } = queriesData[0];
Expand Down Expand Up @@ -71,6 +76,12 @@ export default function transformProps(

const { onContextMenu } = hooks;

const defaultColorFormatters = [] as ColorFormatters;

const colorThresholdFormatters =
getColorFormatters(conditionalFormatting, data, false) ??
defaultColorFormatters;

return {
width,
height,
Expand All @@ -81,5 +92,6 @@ export default function transformProps(
subheader: formattedSubheader,
onContextMenu,
refs,
colorThresholdFormatters,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,29 @@ class BigNumberVis extends React.PureComponent<BigNumberVizProps> {
}

renderHeader(maxHeight: number) {
const { bigNumber, headerFormatter, width } = this.props;
const { bigNumber, headerFormatter, width, colorThresholdFormatters } =
this.props;
// @ts-ignore
const text = bigNumber === null ? t('No data') : headerFormatter(bigNumber);

const hasThresholdColorFormatter =
Array.isArray(colorThresholdFormatters) &&
colorThresholdFormatters.length > 0;

let numberColor;
if (hasThresholdColorFormatter) {
colorThresholdFormatters!.forEach(formatter => {
const formatterResult = bigNumber
? formatter.getColorFromValue(bigNumber as number)
: false;
if (formatterResult) {
numberColor = formatterResult;
}
});
} else {
numberColor = 'black';
}

const container = this.createTemporaryContainer();
document.body.append(container);
const fontSize = computeMaxFontSize({
Expand All @@ -156,6 +175,7 @@ class BigNumberVis extends React.PureComponent<BigNumberVizProps> {
style={{
fontSize,
height: maxHeight,
color: numberColor,
}}
onContextMenu={onContextMenu}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
QueryFormMetric,
TimeFormatter,
} from '@superset-ui/core';
import { ColorFormatters } from '@superset-ui/chart-controls';
import { BaseChartProps, Refs } from '../types';

export interface BigNumberDatum {
Expand Down Expand Up @@ -94,4 +95,5 @@ export type BigNumberVizProps = {
xValueFormatter?: TimeFormatter;
formData?: BigNumberWithTrendlineFormData;
refs: Refs;
colorThresholdFormatters?: ColorFormatters;
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ const JustifyEnd = styled.div`
`;

const colorSchemeOptions = (theme: SupersetTheme) => [
{ value: theme.colors.success.light1, label: t('green') },
{ value: theme.colors.alert.light1, label: t('yellow') },
{ value: theme.colors.error.light1, label: t('red') },
{ value: theme.colors.success.light1, label: t('success') },
{ value: theme.colors.alert.light1, label: t('alert') },
{ value: theme.colors.error.light1, label: t('error') },
{ value: theme.colors.success.dark1, label: t('success dark') },
{ value: theme.colors.alert.dark1, label: t('alert dark') },
{ value: theme.colors.error.dark1, label: t('error dark') },
];

const operatorOptions = [
Expand Down

0 comments on commit 61d8a0b

Please sign in to comment.