blob: 769201c749e6889a47be28c94bb0cee9ddb3f8fe [file] [log] [blame]
/* eslint-disable class-methods-use-this */
/**
* 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 React from 'react';
import {
Sparkline,
LineSeries,
PointSeries,
HorizontalReferenceLine,
VerticalReferenceLine,
WithTooltip,
} from '@data-ui/sparkline';
import { getTextDimension, formatNumber } from '@superset-ui/core';
interface Props {
ariaLabel: string;
className?: string;
height: number;
numberFormat: string;
renderTooltip: ({ index }: { index: number }) => void;
showYAxis: boolean;
width: number;
yAxisBounds: Array<number>;
data: Array<number>;
}
interface TooltipProps {
onMouseLeave: () => void;
onMouseMove: () => void;
tooltipData: {
index: number;
};
}
interface Yscale {
min?: number;
max?: number;
}
const MARGIN = {
top: 8,
right: 8,
bottom: 8,
left: 8,
};
const tooltipProps = {
style: {
opacity: 0.8,
},
offsetTop: 0,
};
function getSparklineTextWidth(text: string) {
return (
getTextDimension({
text,
style: {
fontSize: '12px',
fontWeight: 200,
letterSpacing: 0.4,
},
}).width + 5
);
}
function isValidBoundValue(value?: number) {
// @ts-ignore
return value !== null && value !== undefined && value !== '' && !Number.isNaN(value);
}
class SparklineCell extends React.Component<Props, {}> {
renderHorizontalReferenceLine(value?: number, label?: string) {
return (
<HorizontalReferenceLine
reference={value}
labelPosition="right"
renderLabel={() => label}
stroke="#bbb"
strokeDasharray="3 3"
strokeWidth={1}
/>
);
}
render() {
const {
width = 300,
height = 50,
data,
ariaLabel,
numberFormat = undefined,
yAxisBounds = [undefined, undefined],
showYAxis = false,
renderTooltip = () => <div />,
} = this.props;
const yScale: Yscale = {};
let hasMinBound = false;
let hasMaxBound = false;
if (yAxisBounds) {
const [minBound, maxBound] = yAxisBounds;
hasMinBound = isValidBoundValue(minBound);
if (hasMinBound) {
yScale.min = minBound;
}
hasMaxBound = isValidBoundValue(maxBound);
if (hasMaxBound) {
yScale.max = maxBound;
}
}
let min: number | undefined;
let max: number | undefined;
let minLabel: string;
let maxLabel: string;
let labelLength = 0;
if (showYAxis) {
const [minBound, maxBound] = yAxisBounds;
min = hasMinBound ? minBound : data.reduce((acc, current) => Math.min(acc, current), data[0]);
max = hasMaxBound ? maxBound : data.reduce((acc, current) => Math.max(acc, current), data[0]);
minLabel = formatNumber(numberFormat, min);
maxLabel = formatNumber(numberFormat, max);
labelLength = Math.max(getSparklineTextWidth(minLabel), getSparklineTextWidth(maxLabel));
}
const margin = {
...MARGIN,
right: MARGIN.right + labelLength,
};
return (
<WithTooltip tooltipProps={tooltipProps} hoverStyles={null} renderTooltip={renderTooltip}>
{({ onMouseLeave, onMouseMove, tooltipData }: TooltipProps) => (
<Sparkline
ariaLabel={ariaLabel}
width={width}
height={height}
margin={margin}
data={data}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
{...yScale}
>
{showYAxis && this.renderHorizontalReferenceLine(min, minLabel)}
{showYAxis && this.renderHorizontalReferenceLine(max, maxLabel)}
<LineSeries showArea={false} stroke="#767676" />
{tooltipData && (
<VerticalReferenceLine
reference={tooltipData.index}
strokeDasharray="3 3"
strokeWidth={1}
/>
)}
{tooltipData && (
<PointSeries points={[tooltipData.index]} fill="#767676" strokeWidth={1} />
)}
</Sparkline>
)}
</WithTooltip>
);
}
}
export default SparklineCell;