react-native-svg-charts
react-native-svg-charts copied to clipboard
How can we make charts interactive and a feedback vertical line? (See the gif in the description)
I want to achieve behavior as you can see in the gif. How to add that vertical line (light gray line in the gif ), which moves with user's gesture and gives the feedback on the graph value where is our gesture or tap is placed..
Interested in the same thing, please @salmandayal keep me posted if you find a reasonable solution
@mikevercoelen The only solution seems to work is to right custom component which will work with the GestureHandler and determine the X and Y of the Tap position and update the highlighted values. I'm still working on it.
Use PanResponse to get the gesture, calculate the select positon by the moveX. Then add some <G/>
under the chart
I came up with this! Let me know if there is a better way!
import React, {useState} from 'react';
import {View, StyleSheet} from 'react-native';
import {LineChart as SVGLineChart} from 'react-native-svg-charts';
import {Line} from 'react-native-svg';
export const LineChart = ({data, hasTooltip = false}) => {
const {theme, styles} = useStyles();
const [locationX, setX] = useState(null);
const [trigger, setTrigger] = useState(false);
const getColor = (values = []) => {
const filteredValues = values.filter(item => item);// Remove the NULL
const color = filteredValues.slice(-1).pop() > filteredValues[0] ? theme.green : theme.red;
return color;
}
const VerticalLine = ({ x, width }) => (
<Line
key={ 'zero-axis' }
y1={ '0%' }
y2={ '100%' }
x1={ width ? x(Math.floor(locationX*data.length/width)) : x(0)}
x2={ width ? x(Math.floor(locationX*data.length/width)) : x(0)}
stroke={ 'grey' }
strokeDasharray={ [ 4, 8 ] }
strokeWidth={ 2 }
/>
)
const PriceText = ({x, y, width}) => {
const value = width ? data[Math.floor(locationX*data.length/width)] : '--';
const changeValue = data?.[0] ? '(' + ((value/data[0] - 1)*100).toFixed(2)+'%)' : '--'
const color = value != '--' ? value >= data[0] ? theme.green : theme.red : theme.text;
return (
<View style={styles.priceTextContainer}>
<StyledText style={[styles.priceText, {color}]}>{value}</StyledText>
<StyledText style={[styles.priceText, {marginLeft: WP(1), color}]}>{changeValue}</StyledText>
</View>
)
}
return (
<View style={styles.chartContainer}
onMoveShouldSetResponder={hasTooltip ? (evt) => {setTrigger(true); return true} : false}
onResponderTerminate={hasTooltip ? (evt) => setTimeout(() => setTrigger(false), 5000) : false}
onResponderRelease={hasTooltip ? (evt) => setTimeout(() => setTrigger(false), 5000) : false}
onResponderMove={hasTooltip ? (evt) => setX(evt.nativeEvent.locationX) : false}
>
<SVGLineChart
style={styles.chart]}
data={ data }
svg={{ stroke: getColor(data) }}
contentInset={ { bottom: 0 } }
>
{hasTooltip && trigger && <VerticalLine />}
{hasTooltip && trigger && <PriceText />}
</SVGLineChart>
</View>
);
}
I make a snack example, I hope it can help you . Interactive Chart
I've been looking for something that can do what this demo does for like 3 days, thank you thank you thank you for sharing!
@shivchawla's solution works, but we randomly get the vertical line rendered twice while dragging, for a few milliseconds. Then the wrong vertical line disappears and only the correct one (i.e. the one under the user's finger) stays visible.
Is anyone experiencing the same? This seems to happen more often if you drag slowly, less frequently if you drag quickly from side to side.
@39otrebla Have your tried using fixed value for chart color or stabilizing color
with React.useMemo
const color = React.useMemo(() => {
const filteredValues = data.filter((item) => item); // Remove the NULL
return filteredValues.slice(-1).pop() > filteredValues[0] ? 'green' : 'red';
}, [data]);
<SVGLineChart
style={styles.chart}
data={data}
svg={{ stroke: color }}
contentInset={{ bottom: 0 }}>
{(hasTooltip && trigger) && <VerticalLine />}
{(hasTooltip && trigger) && <PriceText />}
</SVGLineChart>