Skip to content

Commit

Permalink
feat(legacy-preset-chart-big-number): add timestamp above number (apa…
Browse files Browse the repository at this point in the history
…che#1278)

* feat(legacy-preset-chart-big-number): add timestamp above number

* add timestamp formatting

* revert to fallback warning when no timestamp

* fix smart date formatting

* fix test

Co-authored-by: Ivan Krsnik <ivan.krsnik@unipart.io>
  • Loading branch information
2 people authored and zhaoyongjie committed Nov 26, 2021
1 parent 13519fd commit c4bc66a
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 7 deletions.
Expand Up @@ -41,6 +41,7 @@ const CHART_MARGIN = {

const PROPORTION = {
// text size: proportion of the chart container sans trendline
KICKER: 0.1,
HEADER: 0.3,
SUBHEADER: 0.125,
// trendline size: proportion of the whole chart container
Expand Down Expand Up @@ -80,11 +81,14 @@ type BigNumberVisProps = {
fromDatetime?: number;
toDatetime?: number;
headerFontSize: number;
kickerFontSize: number;
subheader: string;
subheaderFontSize: number;
showTimestamp?: boolean;
showTrendLine?: boolean;
startYAxisAtZero?: boolean;
timeRangeFixed?: boolean;
timestamp?: number;
trendLineData?: TimeSeriesDatum[];
mainColor: string;
};
Expand All @@ -97,7 +101,9 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps, {}> {
formatNumber: defaultNumberFormatter,
formatTime: smartDateVerboseFormatter,
headerFontSize: PROPORTION.HEADER,
kickerFontSize: PROPORTION.KICKER,
mainColor: BRAND_COLOR,
showTimestamp: false,
showTrendLine: false,
startYAxisAtZero: true,
subheader: '',
Expand All @@ -123,8 +129,8 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps, {}> {
}

renderFallbackWarning() {
const { bigNumberFallback, formatTime } = this.props;
if (!bigNumberFallback) return null;
const { bigNumberFallback, formatTime, showTimestamp } = this.props;
if (!bigNumberFallback || showTimestamp) return null;
return (
<span
className="alert alert-warning"
Expand All @@ -136,6 +142,36 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps, {}> {
);
}

renderKicker(maxHeight: number) {
const { timestamp, showTimestamp, formatTime, width } = this.props;
if (!showTimestamp) return null;

const text = timestamp === null ? '' : formatTime(timestamp);

const container = this.createTemporaryContainer();
document.body.append(container);
const fontSize = computeMaxFontSize({
text,
maxWidth: width,
maxHeight,
className: 'kicker',
container,
});
container.remove();

return (
<div
className="kicker"
style={{
fontSize,
height: maxHeight,
}}
>
{text}
</div>
);
}

renderHeader(maxHeight: number) {
const { bigNumber, formatNumber, width } = this.props;
const text = bigNumber === null ? t('No data') : formatNumber(bigNumber);
Expand Down Expand Up @@ -273,7 +309,7 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps, {}> {
}

render() {
const { showTrendLine, height, headerFontSize, subheaderFontSize } = this.props;
const { showTrendLine, height, kickerFontSize, headerFontSize, subheaderFontSize } = this.props;
const className = this.getClassName();

if (showTrendLine) {
Expand All @@ -284,6 +320,7 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps, {}> {
<div className={className}>
<div className="text-container" style={{ height: allTextHeight }}>
{this.renderFallbackWarning()}
{this.renderKicker(Math.ceil(kickerFontSize * (1 - PROPORTION.TRENDLINE) * height))}
{this.renderHeader(Math.ceil(headerFontSize * (1 - PROPORTION.TRENDLINE) * height))}
{this.renderSubheader(
Math.ceil(subheaderFontSize * (1 - PROPORTION.TRENDLINE) * height),
Expand All @@ -296,6 +333,8 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps, {}> {

return (
<div className={className} style={{ height }}>
{this.renderFallbackWarning()}
{this.renderKicker(kickerFontSize * height)}
{this.renderHeader(Math.ceil(headerFontSize * height))}
{this.renderSubheader(Math.ceil(subheaderFontSize * height))}
</div>
Expand Down Expand Up @@ -328,6 +367,12 @@ export default styled(BigNumberVis)`
}
}
.kicker {
font-weight: ${({ theme }) => theme.typography.weights.light};
line-height: 1em;
padding-bottom: 2em;
}
.header-line {
font-weight: ${({ theme }) => theme.typography.weights.normal};
position: relative;
Expand All @@ -345,6 +390,7 @@ export default styled(BigNumberVis)`
}
&.is-fallback-value {
.kicker,
.header-line,
.subheader-line {
opacity: 0.5;
Expand Down
Expand Up @@ -17,7 +17,13 @@
* under the License.
*/
import { t } from '@superset-ui/core';
import { ControlPanelConfig, formatSelectOptions, sections } from '@superset-ui/chart-controls';
import {
ControlPanelConfig,
D3_FORMAT_DOCS,
D3_TIME_FORMAT_OPTIONS,
formatSelectOptions,
sections,
} from '@superset-ui/chart-controls';
import React from 'react';
import { headerFontSize, subheaderFontSize } from '../sharedControls';

Expand Down Expand Up @@ -56,6 +62,36 @@ const config: ControlPanelConfig = {
},
],
['y_axis_format'],
[
{
name: 'show_timestamp',
config: {
type: 'CheckboxControl',
label: t('Show Timestamp'),
renderTrigger: true,
default: false,
description: t('Whether to display the timestamp'),
},
},
],
[
{
name: 'time_format',
config: {
type: 'SelectControl',
freeForm: true,
label: t('Timestamp format'),
renderTrigger: true,
choices: D3_TIME_FORMAT_OPTIONS,
default: '%d-%m-%Y %H:%M:%S',
description: D3_FORMAT_DOCS,
visibility(props) {
const { show_timestamp } = props.form_data;
return !!show_timestamp;
},
},
},
],
[
{
name: 'show_trend_line',
Expand Down
Expand Up @@ -19,12 +19,14 @@
import * as color from 'd3-color';
import {
extractTimegrain,
getTimeFormatterForGranularity,
getNumberFormatter,
getTimeFormatter,
getTimeFormatterForGranularity,
NumberFormats,
ChartProps,
LegacyQueryData,
QueryFormData,
smartDateFormatter,
} from '@superset-ui/core';

const TIME_COLUMN = '__timestamp';
Expand Down Expand Up @@ -63,8 +65,10 @@ export default function transformProps(chartProps: BigNumberChartProps) {
colorPicker,
compareLag: compareLag_,
compareSuffix = '',
timeFormat,
headerFontSize,
metric = 'value',
showTimestamp,
showTrendLine,
startYAxisAtZero,
subheader = '',
Expand All @@ -90,6 +94,7 @@ export default function transformProps(chartProps: BigNumberChartProps) {
let trendLineData;
let percentChange = 0;
let bigNumber = data.length === 0 ? null : data[0][metricName];
let timestamp = data.length === 0 ? null : data[0][TIME_COLUMN];
let bigNumberFallback;

if (data.length > 0) {
Expand All @@ -99,9 +104,12 @@ export default function transformProps(chartProps: BigNumberChartProps) {
.sort((a, b) => (a.x !== null && b.x !== null ? b.x - a.x : 0));

bigNumber = sortedData[0].y;
timestamp = sortedData[0].x;

if (bigNumber === null) {
bigNumberFallback = sortedData.find(d => d.y !== null);
bigNumber = bigNumberFallback ? bigNumberFallback.y : null;
timestamp = bigNumberFallback ? bigNumberFallback.x : null;
}

if (compareLag > 0) {
Expand Down Expand Up @@ -139,7 +147,10 @@ export default function transformProps(chartProps: BigNumberChartProps) {
}

const formatNumber = getNumberFormatter(yAxisFormat);
const formatTime = getTimeFormatterForGranularity(granularity);
const formatTime =
timeFormat === smartDateFormatter.id
? getTimeFormatterForGranularity(granularity)
: getTimeFormatter(timeFormat);

return {
width,
Expand All @@ -152,9 +163,11 @@ export default function transformProps(chartProps: BigNumberChartProps) {
headerFontSize,
subheaderFontSize,
mainColor,
showTimestamp,
showTrendLine: supportAndShowTrendLine,
startYAxisAtZero,
subheader: formattedSubheader,
timestamp,
trendLineData,
fromDatetime,
toDatetime,
Expand Down
Expand Up @@ -117,7 +117,7 @@ describe('BigNumber', () => {
expect(transformed.bigNumberFallback).not.toBeNull();

// should successfully formatTime by ganularity
expect(transformed.formatTime(new Date('2020-01-01'))).toStrictEqual('2020 Q1');
expect(transformed.formatTime(new Date('2020-01-01'))).toStrictEqual('2020-01-01 00:00:00');
});

it('should respect datasource d3 format', () => {
Expand Down

0 comments on commit c4bc66a

Please sign in to comment.