blob: eb2dc8e4f2fcfc2858773dc1311f11d597f1a418 [file] [log] [blame]
/**
* 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 * as color from 'd3-color';
import {
TimeGranularity,
getTimeFormatterForGranularity,
getNumberFormatter,
NumberFormats,
ChartProps,
LegacyQueryData,
QueryFormData,
} from '@superset-ui/core';
const TIME_COLUMN = '__timestamp';
const formatPercentChange = getNumberFormatter(NumberFormats.PERCENT_SIGNED_1_POINT);
// we trust both the x (time) and y (big number) to be numeric
export interface BigNumberDatum {
[key: string]: number | null;
}
export type BigNumberFormData = QueryFormData & {
colorPicker?: {
r: number;
g: number;
b: number;
};
metric?:
| {
label: string;
}
| string;
compareLag?: string | number;
yAxisFormat?: string;
timeGrainSqla?: TimeGranularity;
};
export type BigNumberChartProps = ChartProps & {
formData: BigNumberFormData;
queriesData: (LegacyQueryData & {
data?: BigNumberDatum[];
})[];
};
export default function transformProps(chartProps: BigNumberChartProps) {
const { width, height, queriesData, formData } = chartProps;
const {
colorPicker,
compareLag: compareLag_,
compareSuffix = '',
headerFontSize,
metric = 'value',
showTrendLine,
startYAxisAtZero,
subheader = '',
subheaderFontSize,
timeGrainSqla: granularity,
vizType,
timeRangeFixed = false,
} = formData;
let { yAxisFormat } = formData;
const { data = [], from_dttm: fromDatetime, to_dttm: toDatetime } = queriesData[0];
const metricName = typeof metric === 'string' ? metric : metric.label;
const compareLag = Number(compareLag_) || 0;
const supportTrendLine = vizType === 'big_number';
const supportAndShowTrendLine = supportTrendLine && showTrendLine;
let formattedSubheader = subheader;
let mainColor;
if (colorPicker) {
const { r, g, b } = colorPicker;
mainColor = color.rgb(r, g, b).hex();
}
let trendLineData;
let percentChange = 0;
let bigNumber = data.length === 0 ? null : data[0][metricName];
let bigNumberFallback;
if (data.length > 0) {
const sortedData = (data as BigNumberDatum[])
.map(d => ({ x: d[TIME_COLUMN], y: d[metricName] }))
// sort in time descending order
.sort((a, b) => (a.x !== null && b.x !== null ? b.x - a.x : 0));
bigNumber = sortedData[0].y;
if (bigNumber === null) {
bigNumberFallback = sortedData.find(d => d.y !== null);
bigNumber = bigNumberFallback ? bigNumberFallback.y : null;
}
if (compareLag > 0) {
const compareIndex = compareLag;
if (compareIndex < sortedData.length) {
const compareValue = sortedData[compareIndex].y;
// compare values must both be non-nulls
if (bigNumber !== null && compareValue !== null && compareValue !== 0) {
percentChange = (bigNumber - compareValue) / Math.abs(compareValue);
formattedSubheader = `${formatPercentChange(percentChange)} ${compareSuffix}`;
}
}
}
if (supportTrendLine) {
// must reverse to ascending order otherwise it confuses tooltip triggers
sortedData.reverse();
trendLineData = supportAndShowTrendLine ? sortedData : undefined;
}
}
let className = '';
if (percentChange > 0) {
className = 'positive';
} else if (percentChange < 0) {
className = 'negative';
}
if (!yAxisFormat && chartProps.datasource && chartProps.datasource.metrics) {
chartProps.datasource.metrics.forEach(metricEntry => {
if (metricEntry.metric_name === metric && metricEntry.d3format) {
yAxisFormat = metricEntry.d3format;
}
});
}
const formatNumber = getNumberFormatter(yAxisFormat);
const formatTime = getTimeFormatterForGranularity(granularity);
return {
width,
height,
bigNumber,
bigNumberFallback,
className,
formatNumber,
formatTime,
headerFontSize,
subheaderFontSize,
mainColor,
showTrendLine: supportAndShowTrendLine,
startYAxisAtZero,
subheader: formattedSubheader,
trendLineData,
fromDatetime,
toDatetime,
timeRangeFixed,
};
}