react-nativereact-native-chart-kit

How do I add Gradient Color to this line chart?


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:

enter image description here

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:

enter image description here


Solution

  • 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;
    
    

    enter image description here