106 lines
3.8 KiB
TypeScript
106 lines
3.8 KiB
TypeScript
import DateFormatter from '../helper/DateFormatter'
|
|
import NoData from './NoData'
|
|
import NumberFormatter from '../helper/NumberFormatter'
|
|
import React, { memo, useCallback } from 'react'
|
|
import TooltipComponent from './TooltipComponent'
|
|
import { default as ReactResizeDetector } from 'react-resize-detector'
|
|
import { emphasize } from '@material-ui/core/styles'
|
|
import { mapCurveType } from './mapCurveType'
|
|
import { PlotCurveTypes } from '../../reducers/Charts'
|
|
import { Point, Tooltip } from './Model'
|
|
import { Theme, withTheme } from '@material-ui/core'
|
|
import { useCustomXDomain } from './effects/useCustomXDomain'
|
|
import { useCustomYDomain } from './effects/useCustomYDomain'
|
|
import 'react-vis/dist/style.css'
|
|
const { XYPlot, LineMarkSeries, YAxis, HorizontalGridLines, Hint } = require('react-vis')
|
|
const abbreviate = require('number-abbreviate')
|
|
|
|
export interface Props {
|
|
data: Array<{ x: number; y: number }>
|
|
theme: Theme
|
|
interpolation?: PlotCurveTypes
|
|
range?: [number?, number?]
|
|
timeRangeStart?: number
|
|
color?: string
|
|
}
|
|
|
|
export default withTheme(
|
|
memo((props: Props) => {
|
|
const [width, setWidth] = React.useState(300)
|
|
const [tooltip, setTooltip] = React.useState<Tooltip | undefined>()
|
|
const detectResize = React.useCallback((newWidth) => setWidth(newWidth), [])
|
|
|
|
const hintFormatter = React.useCallback(
|
|
(point: any) => [
|
|
{ title: <b>Time</b>, value: <DateFormatter timeFirst={true} date={new Date(point.x)} /> },
|
|
{ title: <b>Value</b>, value: <NumberFormatter value={point.y} /> },
|
|
{ title: <b>Raw</b>, value: <span>{point.y}</span> },
|
|
],
|
|
[]
|
|
)
|
|
|
|
const onMouseLeave = React.useCallback(() => {
|
|
setTooltip(undefined)
|
|
}, [])
|
|
|
|
const showTooltip = React.useCallback((point: Point, something: { event: MouseEvent }) => {
|
|
if (!something) {
|
|
return
|
|
}
|
|
setTooltip({ point, value: hintFormatter(point), element: something.event.target as any })
|
|
}, [])
|
|
|
|
const paletteColor =
|
|
props.theme.palette.type === 'light' ? props.theme.palette.secondary.dark : props.theme.palette.primary.light
|
|
const color = props.color ? props.color : paletteColor
|
|
|
|
const highlightSelectedPoint = useCallback(
|
|
(point: Point) => {
|
|
const highlight = tooltip && tooltip.point.x === point.x && tooltip.point.y === point.y
|
|
return highlight ? emphasize(color, 0.8) : color
|
|
},
|
|
[tooltip, color]
|
|
)
|
|
|
|
const formatYAxis = useCallback((num: number) => abbreviate(num), [])
|
|
|
|
const xDomain = useCustomXDomain(props)
|
|
const yDomain = useCustomYDomain(props)
|
|
|
|
const data = props.data
|
|
const hasData = data.length > 0
|
|
const dummyDomain = [-1, 1]
|
|
const dummyData = [{ x: -2, y: -2 }]
|
|
return (
|
|
<div>
|
|
<div style={{ height: '150px', width: '100%', position: 'relative' }}>
|
|
{data.length === 0 ? <NoData /> : null}
|
|
<XYPlot
|
|
width={width}
|
|
height={180}
|
|
yDomain={hasData ? yDomain : dummyDomain}
|
|
xDomain={hasData ? xDomain : dummyDomain}
|
|
onMouseLeave={onMouseLeave}
|
|
>
|
|
<HorizontalGridLines />
|
|
<YAxis width={45} tickFormat={formatYAxis} />
|
|
<LineMarkSeries
|
|
color={color}
|
|
colorType="literal"
|
|
getColor={highlightSelectedPoint}
|
|
onValueMouseOver={showTooltip}
|
|
size={3}
|
|
data={hasData ? data : dummyData}
|
|
curve={mapCurveType(props.interpolation)}
|
|
/>
|
|
<Hint value={{ x: 0, y: 0 }} style={{ pointerEvents: 'none' }}>
|
|
<TooltipComponent tooltip={tooltip} theme={props.theme} />
|
|
</Hint>
|
|
</XYPlot>
|
|
<ReactResizeDetector handleWidth={true} onResize={detectResize} />
|
|
</div>
|
|
</div>
|
|
)
|
|
})
|
|
)
|