I am using the react-native-chart-kit library to create a line chart in my React Native application. Currently, I have implemented a basic line chart with a single color for the line. However, I would like to enhance the visualization by making the color of the line gradient-based rather than a single color.
Could someone provide guidance or an example of how to achieve this using the react-native-chart-kit library? Specifically, I am looking for ways to customize the line color to be a gradient that transitions smoothly along the line. Any help or code snippets would be greatly appreciated. Thank you!
Current Implementation:
Code:
import { useCallback, useEffect, useState } from 'react'
import { ActivityIndicator, Dimensions, ScrollView, StyleSheet, View } from 'react-native'
import { LineChart } from 'react-native-chart-kit'
import { ChartData } from 'react-native-chart-kit/dist/HelperTypes'
import { Line } from 'react-native-svg'
import { RegularText } from 'shared/ui/texts'
import { TChartData, TDotProps } from '../types'
import { PromotionStats } from 'shared/generated/types/graphql'
import { isIos } from 'shared/lib'
const chartHeight = 250
export const StatsChart = ({ data }: { data: TChartData }) => {
const [chartData, setChartData] = useState<ChartData | undefined>()
const parseData = useCallback(() => {
if (data) {
let chartLabels: string[] = []
let chartValues: number[] = []
let copy: PromotionStats = JSON.parse(JSON.stringify(data))
copy?.views?.viewsPerDate.reverse().forEach(day => {
if (day?.date) {
chartLabels.push(day.date.split('.')[0])
chartValues.push(day.count + 1)
}
setChartData({
labels: chartLabels,
datasets: [
{
data: chartValues,
strokeWidth: 5,
color: (opacity = 1) => 'rgb(63,0,241)',
},
],
})
})
}
}, [data])
useEffect(() => {
if (data) parseData()
}, [data])
const [clickedDot, setClickedDot] = useState<TDotProps | undefined>()
return (
<View style={styles.container}>
{chartData === undefined ? (
<ActivityIndicator />
) : (
<ScrollView
showsHorizontalScrollIndicator={false}
style={{ flex: 1, width: '100%' }}
horizontal={true}>
<LineChart
onDataPointClick={dot => {
setClickedDot(dot)
}}
renderDotContent={dot => {
return (
<View>
{dot.index === clickedDot?.index && (
<View
style={{
minWidth: 50,
position: 'absolute',
top: dot.y - 35,
left: dot.x - 25,
alignItems: 'center',
}}>
<RegularText>{dot.indexData}</RegularText>
</View>
)}
{dot.index === clickedDot?.index ? (
<View
style={[styles.clickedDot, { top: dot.y - 10, left: dot.x - 10 }]}>
<View style={styles.clickedInnerDot} />
</View>
) : (
<View style={[styles.dot, { top: dot.y - 7, left: dot.x - 7 }]}>
<View style={styles.innerDot} />
</View>
)}
<Line
strokeDasharray={'3'}
opacity={0.4}
fill={'black'}
stroke={'black'}
strokeWidth={1}
x1={dot.x}
x2={dot.x}
y1={dot.y}
y2={chartHeight - 50}
/>
</View>
)
}}
hidePointsAtIndex={[0]}
fromZero={true}
transparent
withHorizontalLines={false}
withHorizontalLabels={false}
withInnerLines={false}
chartConfig={{
color: (opacity = 1) => 'url(#grad)',
labelColor: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
fillShadowGradientFrom: '#F10086',
fillShadowGradientTo: 'white',
fillShadowGradientFromOffset: 0,
fillShadowGradientToOpacity: 0,
fillShadowGradientOpacity: isIos ? 0.5 : 0.3,
barPercentage: 1,
paddingRight: 0,
}}
style={{ paddingRight: 0, paddingTop: 20 }}
height={chartHeight}
width={5 * Dimensions.get('screen').width}
data={chartData}
bezier
/>
</ScrollView>
)}
</View>
)
}
How I want to make it look:
Instead of just the blue line I want to make it to look like this:
I am able to implement it by creating a CustomLineChart as suggested here
import React from "react";
import { LineChart } from 'react-native-chart-kit'
import { AbstractChartConfig } from "react-native-chart-kit/dist/AbstractChart";
import { LinearGradient, Path, Stop } from "react-native-svg";
class CustomLineChart extends LineChart {
renderLine = ({
width,
height,
paddingRight,
paddingTop,
data,
}: Pick<
AbstractChartConfig,
"data" | "width" | "height" | "paddingRight" | "paddingTop"
>) => {
const output: React.JSX.Element[] = [];
if(!data) return []
data.forEach((dataset, index) => {
const bezierPoints = this.getBezierLinePoints(dataset, {
width,
height,
paddingRight,
paddingTop,
data
});
const gradientColors = ["#F10086", "#3F00F1"];
output.push(
<LinearGradient
key={`line-gradient-${index}`}
id={`line-gradient-${index}`}
x1="0%"
y1="0%"
x2="100%"
y2="0%"
>
<Stop offset="0%" stopColor={gradientColors[0]} />
<Stop offset="100%" stopColor={gradientColors[1]} />
</LinearGradient>,
<Path
key={`line-${index}`}
d={bezierPoints}
fill="none"
stroke={`url(#line-gradient-${index})`}
strokeWidth={this.getStrokeWidth(dataset)}
strokeDasharray={dataset.strokeDashArray}
strokeDashoffset={dataset.strokeDashOffset}
/>
);
});
return output;
};
}
export default CustomLineChart;