amis-rpc-design/libs/amis/packages/amis-ui/src/components/SparkLine.tsx
2023-10-07 19:42:30 +08:00

114 lines
2.6 KiB
TypeScript

import React from 'react';
import {localeable, LocaleProps} from 'amis-core';
import {themeable, ThemeProps} from 'amis-core';
import type {PlainObject} from 'amis-core';
export interface SparkLineProps extends ThemeProps, LocaleProps {
className?: string;
width: number;
height: number;
value?: Array<
| number
| {
value: number;
label?: string;
}
>;
placeholder?: string;
onClick?: (e: React.MouseEvent, value?: PlainObject) => void;
}
export class SparkLine extends React.Component<SparkLineProps> {
static defaultProps = {
width: 100,
height: 50
};
normalizeValue(item: any): number {
if (typeof item === 'number') {
return item;
} else if (item && typeof item.value === 'number') {
return item.value;
} else {
return Number(item) || 0;
}
}
renderLines() {
const {width, height, value, classnames: cx} = this.props;
const values = value!.map(item => this.normalizeValue(item));
const max = Math.max(...values);
const min = Math.min(...values);
const duration = max - min || 1;
const gap = width / (values.length - 1);
const points: Array<{
x: number;
y: number;
}> = [];
values.forEach((value, index) => {
points.push({
x: index * gap,
y: height - ((value - min) * height) / duration
});
});
const lineD = points
.map((value, index) => `${index === 0 ? 'M' : 'L'} ${value.x} ${value.y}`)
.join(' ');
const areaD = `${lineD} V ${height} L 0 ${height} Z`;
// todo 支持鼠标 hover 显示对应数据。
return (
<g>
<path className={cx(`Sparkline-area`)} d={areaD} stroke="none" />
<path className={cx(`Sparkline-line`)} d={lineD} fill="none" />
</g>
);
}
render() {
const {
classnames: cx,
className,
style,
value,
width,
height,
placeholder,
translate: __,
onClick
} = this.props;
return (
<div
className={cx(
'Sparkline',
className,
onClick ? 'Sparkline--clickable' : ''
)}
style={style}
onClick={onClick}
>
{Array.isArray(value) && value.length > 1 ? (
<svg
className={cx('Sparkline-svg')}
width={width}
height={height}
viewBox={`0 0 ${width} ${height}`}
>
{this.renderLines()}
</svg>
) : (
placeholder ?? __('placeholder.empty')
)}
</div>
);
}
}
export default themeable(localeable(SparkLine));