Improve tooltip behavior of charts

This commit is contained in:
Thomas Nordquist
2019-07-12 17:05:35 +02:00
parent ecdecd8626
commit ff148a8e3c

View File

@@ -1,16 +1,13 @@
import DateFormatter from '../helper/DateFormatter' import DateFormatter from '../helper/DateFormatter'
import NumberFormatter from '../helper/NumberFormatter' import NumberFormatter from '../helper/NumberFormatter'
import Portal from '@material-ui/core/Portal' import React, { useCallback, useState } from 'react'
import React, { useRef, useCallback, useState } from 'react'
import { default as ReactResizeDetector } from 'react-resize-detector' import { default as ReactResizeDetector } from 'react-resize-detector'
import { emphasize, fade } from '@material-ui/core/styles'
import { Paper, Popper, Theme, Typography, withTheme } from '@material-ui/core'
import { PlotCurveTypes } from '../../reducers/Charts' import { PlotCurveTypes } from '../../reducers/Charts'
import { Theme, Typography, withTheme, Popper, Paper } from '@material-ui/core'
import { useCustomXDomain } from './useCustomXDomain' import { useCustomXDomain } from './useCustomXDomain'
import 'react-vis/dist/style.css' import 'react-vis/dist/style.css'
import { number } from 'prop-types' const { XYPlot, LineMarkSeries, Hint, YAxis, HorizontalGridLines } = require('react-vis')
import { fade } from '@material-ui/core/styles'
import { toggleAdvancedSettings } from '../../actions/ConnectionManager'
const { XYPlot, LineMarkSeries, Hint, XAxis, YAxis, HorizontalGridLines, Highlight, MouseEvent } = require('react-vis')
const abbreviate = require('number-abbreviate') const abbreviate = require('number-abbreviate')
export interface Props { export interface Props {
@@ -48,10 +45,15 @@ function useToggle(initialState: boolean): [boolean, () => void, (value: boolean
return [value, toggle, setValue] return [value, toggle, setValue]
} }
interface Point {
x: any
y: any
}
export default withTheme((props: Props) => { export default withTheme((props: Props) => {
const [hintStaysOpen, toggleHintStaysOpen, setStaysOpen] = useToggle(false) const [hintStaysOpen, toggleHintStaysOpen, setStaysOpen] = useToggle(false)
const [width, setWidth] = React.useState(300) const [width, setWidth] = React.useState(300)
const [tooltip, setTooltip] = React.useState<{ value: any; element: any } | undefined>() const [tooltip, setTooltip] = React.useState<{ value: any; point: Point; element: any } | undefined>()
const detectResize = React.useCallback(newWidth => setWidth(newWidth), []) const detectResize = React.useCallback(newWidth => setWidth(newWidth), [])
const hintFormatter = React.useCallback((point: any) => { const hintFormatter = React.useCallback((point: any) => {
@@ -62,34 +64,32 @@ export default withTheme((props: Props) => {
] ]
}, []) }, [])
const hideTooltip = React.useCallback(() => {
if (!hintStaysOpen) {
setTooltip(undefined)
}
}, [hintStaysOpen])
const onMouseLeave = React.useCallback(() => { const onMouseLeave = React.useCallback(() => {
setStaysOpen(false) setStaysOpen(false)
setTooltip(undefined) setTooltip(undefined)
}, []) }, [])
const showTooltip = React.useCallback((value: any, something: { event: MouseEvent }) => { const showTooltip = React.useCallback((point: Point, something: { event: MouseEvent }) => {
if (!something) { if (!something) {
return return
} }
setTooltip({ value: hintFormatter(value), element: something.event.target }) setTooltip({ point, value: hintFormatter(point), element: something.event.target })
}, []) }, [])
const onValueClick = React.useCallback( const paletteColor =
(value: any, something: { event: MouseEvent }) => { props.theme.palette.type === 'light' ? props.theme.palette.secondary.dark : props.theme.palette.primary.light
toggleHintStaysOpen() const color = props.color ? props.color : paletteColor
console.log('onValueClick')
showTooltip(value, something) 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
}, },
[toggleHintStaysOpen] [tooltip, color]
) )
const getAnchorElement = useCallback(() => tooltip && tooltip.element, [tooltip])
const xDomain = useCustomXDomain(props) const xDomain = useCustomXDomain(props)
return React.useMemo(() => { return React.useMemo(() => {
@@ -99,12 +99,6 @@ export default withTheme((props: Props) => {
? [props.range[0] || calculatedDomain[0], props.range[1] || calculatedDomain[1]] ? [props.range[0] || calculatedDomain[0], props.range[1] || calculatedDomain[1]]
: calculatedDomain : calculatedDomain
let color: string =
props.theme.palette.type === 'light' ? props.theme.palette.secondary.dark : props.theme.palette.primary.light
if (props.color) {
color = props.color
}
const hasData = data.length > 0 const hasData = data.length > 0
const dummyDomain = [-1, 1] const dummyDomain = [-1, 1]
const dummyData = [{ x: -2, y: -2 }] const dummyData = [{ x: -2, y: -2 }]
@@ -122,16 +116,20 @@ export default withTheme((props: Props) => {
<HorizontalGridLines /> <HorizontalGridLines />
<YAxis width={45} tickFormat={(num: number) => abbreviate(num)} /> <YAxis width={45} tickFormat={(num: number) => abbreviate(num)} />
<LineMarkSeries <LineMarkSeries
color={color} colorType="literal"
getColor={highlightSelectedPoint}
onValueMouseOver={showTooltip} onValueMouseOver={showTooltip}
onValueMouseOut={hideTooltip}
onValueClick={onValueClick}
size={3} size={3}
data={hasData ? data : dummyData} data={hasData ? data : dummyData}
curve={mapCurveType(props.interpolation)} curve={mapCurveType(props.interpolation)}
/> />
<Hint value={{}}> <Hint
<Popper open={Boolean(tooltip)} placement="top" anchorEl={tooltip && tooltip.element}> value={{}}
style={{
pointerEvents: 'none',
}}
>
<Popper open={Boolean(tooltip)} placement="top" anchorEl={getAnchorElement}>
<div <div
style={{ style={{
paddingBottom: '8px', paddingBottom: '8px',