如何向这个 React Native 图表添加渐变颜色? [英] How do I add Gradient Colour to this React Native Chart?

查看:52
本文介绍了如何向这个 React Native 图表添加渐变颜色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前实施:

这是一个使用 react-native-svg 库并添加了工具提示的图表.我想让线条的颜色变成渐变而不是单色

代码:

import React, { useState } from 'react'从'react-native'导入{视图、文本、尺寸}从'react-native-chart-kit'导入{ LineChart }import { Rect, Text as TextSVG, Svg } from "react-native-svg";const 图表 = () =>{让 [tooltipPos, setTooltipPos] = useState({ x: 0, y: 0, visible: false, value: 0 })返回 (<查看><折线图数据={{标签:[一月"、二月"、三月"、四月"、五月"、六月"],数据集:[{数据: [100, 110, 90, 130, 80, 103]}]}}width={Dimensions.get("window").width}高度={250}yAxisLabel="$"yAxisSuffix=k"yAxisInterval={1}图表配置={{背景颜色:白色",backgroundGradientFrom: "#fbfbfb",backgroundGradientTo: "#fbfbfb",小数位数:2,颜色:(不透明度= 1)=>`rgba(0, 0, 0, ${opacity})`,labelColor:(不透明度= 1)=>`rgba(0, 0, 0, ${opacity})`,风格: {边界半径:0},propsForDots:{r:6",笔画宽度:0",中风:#fbfbfb"}}}贝塞尔风格={{边距垂直:8,边界半径:6}}装饰器={() =>{返回 tooltipPos.visible ?<查看><Svg><矩形 x={tooltipPos.x - 15}y={tooltipPos.y + 10}宽度=40"高度=30"填充=黑色"/><文本SVGx={工具提示Pos.x + 5}y={tooltipPos.y + 30}填充=白色"fontSize=16"fontWeight=粗体"textAnchor="中间">{工具提示Pos.value}</TextSVG></Svg></查看>: 空值}}onDataPointClick={(数据)=>{让 isSamePoint = (tooltipPos.x === data.x&&tooltipPos.y === data.y)是同一点?setTooltipPos((previousState) => {返回 {...以前的状态,值:数据值,可见:!previousState.visible}}):setTooltipPos({ x: data.x, value: data.value, y: data.y,visible: true });}}/></查看>)}导出默认图表

问题:我希望图表的颜色不是只有灰色,而是在超过特定阈值时为红色,黄色表示另一个值,绿色表示最低值.

有点像这样:

我发现了什么:

render() {常量数据 = [ 50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80 ]const Gradient = () =>(<Defs key={'gradient'}><LinearGradient id={'gradient'} x1={'0'} y={'0%'} x2={'100%'} y2={'0%'}><停止偏移={'0%'} stopColor={'rgb(134, 65, 244)'}/><停止偏移={'100%'} stopColor={'rgb(66, 194, 244)'}/></线性梯度></Defs>)返回 (<折线图样式={ { 高度:200 } }数据={数据}contentInset={ ​​{ 顶部:20,底部:20 } }SVG={{笔画宽度:2,笔画:'url(#gradient)',}}><网格/><梯度/></LineChart>)}

我无法将两者结合起来.请帮忙.

解决方案

它相当复杂,但我们可以创建我们自己的 CustomLineChart 组件,该组件继承自 LineChart react-native-chart-kit 提供:

class CustomLineChart extends LineChart {使成为() {常量{宽度,高度,数据,withScrollableDot = false,withShadow = 真,withDots = true,withInnerLines = true,withOuterLines = 真,withHorizo​​ntalLines = true,withVerticalLines = true,withHorizo​​ntalLabels = true,withVerticalLabels = true,样式 = {},装饰师,在数据点点击,垂直标签旋转 = 0,水平标签旋转 = 0,formatYLabel = (yLabel) =>y标签,formatXLabel = (xLabel) =>x标签,细分,透明=假,图表配置,} = this.props;const {scrollableDotHorizo​​ntalOffset} = this.state;const {labels = []} = 数据;常量{边界半径 = 0,填充顶部 = 16,填充右 = 64,边距 = 0,边距右 = 0,填充底部 = 0,} = 风格;常量配置 = {宽度,高度,垂直标签旋转,水平标签旋转,};const datas = this.getDatas(data.datasets);让 count = Math.min(...datas) =​​== Math.max(...datas) ?1:4;如果(段){计数 = 段;}const LegendOffset = this.props.data.legend ?高度 * 0.15 : 0;返回 (<视图样式={样式}><SVG高度={高度 + paddingBottom + legendOffset}宽度={宽度 - 边距 * 2 - 边距右}><定义><LinearGradient id="grad"x1=0"y1=0"x2=0"y2=1"><停止偏移=0"stopColor=红色"stopOpacity=1"/><停止偏移=1"stopColor=蓝色"stopOpacity=1"/></线性梯度></Defs><矩形宽度=100%"高度={高度+图例偏移}rx={边界半径}ry={边界半径}填充=白色"fillOpacity={透明 ?0:1}/>{this.props.data.legend &&this.renderLegend(config.width, legendOffset)}<G x=0"y={legendOffset}><G>{withHorizo​​ntalLines &&(带内线?this.renderHorizo​​ntalLines({...配置,计数:计数,填充顶部,填充权,}): withOuterLines?this.renderHorizo​​ntalLine({...配置,填充顶部,填充权,}): 空值)}</G><G>{withHorizo​​ntalLabels &&this.renderHorizo​​ntalLabels({...配置,计数:计数,数据:数据,填充顶:填充顶,填充右:填充右,格式Y标签,十进制位置:chartConfig.decimalPlaces,})}</G><G>{withVerticalLines &&(带内线?this.renderVerticalLines({...配置,数据:data.datasets[0].data,填充顶:填充顶,填充右:填充右,}): withOuterLines?this.renderVerticalLine({...配置,填充顶:填充顶,填充右:填充右,}): 空值)}</G><G>{withVerticalLabels &&this.renderVerticalLabels({...配置,标签,填充顶:填充顶,填充右:填充右,格式X标签,})}</G><G>{this.renderLine({...配置,...图表配置,填充右:填充右,填充顶:填充顶,数据:data.datasets,})}</G><G>{withDots &&this.renderDots({...配置,数据:data.datasets,填充顶:填充顶,填充右:填充右,在数据点点击,})}</G><G>{withScrollableDot &&this.renderScrollableDot({...配置,...图表配置,数据:data.datasets,填充顶:填充顶,填充右:填充右,在数据点点击,可滚动点水平偏移,})}</G><G>{装饰器&&装饰器({...配置,数据:data.datasets,填充顶部,填充权,})}</G></G></Svg>{withScrollableDot &&(<滚动视图style={StyleSheet.absoluteFill}contentContainerStyle={{width: width * 2}}显示Horizo​​ntalScrollIndicator={false}scrollEventThrottle={16}onScroll={Animated.event([{本机事件:{contentOffset: {x: scrollableDotHorizo​​ntalOffset},},},])}水平的反弹={假}/>)}</查看>);}}功能应用(){返回 (<自定义折线图数据={{标签:['一月','二月','三月','四月','五月','六月'],数据集:[{数据:[100, 110, 90, 130, 80, 103],},],}}width={Dimensions.get('window').width}高度={250}图表配置={{backgroundGradientFrom: '#fbfbfb',backgroundGradientTo: '#fbfbfb',颜色:(不透明度= 1)=>'网址(#grad)',labelColor:(不透明度= 1)=>`rgba(0, 0, 0, ${opacity})`,}}贝塞尔withInnerLines={false}withOuterLines={false}/>);}

渲染中的大部分代码与官方 LineChart 组件(


您还可以添加更多颜色并使用每个颜色的 offset 道具.

您也可以为梯度使用百分比,但建议使用精确值,因为它比根据文档使用百分比具有性能优势:https://github.com/react-native-community/react-native-svg#lineargradient.


需要注意的是,这个实现没有 fillShadowGradient 作为背景,也没有实现阴影.我还遗漏了您的一些其他代码,例如与问题无关的工具提示代码.

Current Implementation:

This is a Chart using react-native-svg library with a tool-tip added to it. I want to make the color of the line into a gradient rather than a single color

Code:

import React, { useState } from 'react'
import { View, Text, Dimensions } from 'react-native'
import { LineChart } from 'react-native-chart-kit'
import { Rect, Text as TextSVG, Svg } from "react-native-svg";

const Charts = () => {
    let [tooltipPos, setTooltipPos] = useState({ x: 0, y: 0, visible: false, value: 0 })

    return (
        <View>
            <LineChart
                data={{
                    labels: ["January", "February", "March", "April", "May", "June"],
                    datasets: [
                        {
                            data: [
                                100, 110, 90, 130, 80, 103
                            ]
                        }
                    ]
                }}
                width={Dimensions.get("window").width}
                height={250}
                yAxisLabel="$"
                yAxisSuffix="k"
                yAxisInterval={1}
                chartConfig={{
                    backgroundColor: "white",
                    backgroundGradientFrom: "#fbfbfb",
                    backgroundGradientTo: "#fbfbfb",
                    decimalPlaces: 2,
                    color: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
                    labelColor: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
                    style: {
                        borderRadius: 0
                    },
                    propsForDots: {
                        r: "6",
                        strokeWidth: "0",
                        stroke: "#fbfbfb"
                    }
                }}
                bezier
                style={{
                    marginVertical: 8,
                    borderRadius: 6
                }}

                decorator={() => {
                    return tooltipPos.visible ? <View>
                        <Svg>
                            <Rect x={tooltipPos.x - 15} 
                                y={tooltipPos.y + 10} 
                                width="40" 
                                height="30"
                                fill="black" />
                                <TextSVG
                                    x={tooltipPos.x + 5}
                                    y={tooltipPos.y + 30}
                                    fill="white"
                                    fontSize="16"
                                    fontWeight="bold"
                                    textAnchor="middle">
                                    {tooltipPos.value}
                                </TextSVG>
                        </Svg>
                    </View> : null
                }}

                onDataPointClick={(data) => {

                    let isSamePoint = (tooltipPos.x === data.x 
                                        && tooltipPos.y === data.y)

                    isSamePoint ? setTooltipPos((previousState) => {
                        return { 
                                  ...previousState,
                                  value: data.value,
                                  visible: !previousState.visible
                               }
                    })
                        : 
                    setTooltipPos({ x: data.x, value: data.value, y: data.y, visible: true });

                }}
            />
        </View>
    )
}

export default Charts

QUESTION: Instead of the chart having just grey, I want the color of the chart as red when it goes above a specific threshold, yellow for another value and green for the lowest value.

Like this somewhat:

What I found:

render() {

    const data = [ 50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80 ]

    const Gradient = () => (
      <Defs key={'gradient'}>
        <LinearGradient id={'gradient'} x1={'0'} y={'0%'} x2={'100%'} y2={'0%'}>
          <Stop offset={'0%'} stopColor={'rgb(134, 65, 244)'}/>
          <Stop offset={'100%'} stopColor={'rgb(66, 194, 244)'}/>
        </LinearGradient>
      </Defs>
    )

    return (
      <LineChart
        style={ { height: 200 } }
        data={ data }
        contentInset={ { top: 20, bottom: 20 } }
        svg={{
          strokeWidth: 2,
          stroke: 'url(#gradient)',
        }}
      >
        <Grid/>
        <Gradient/>
      </LineChart>
    )
  }

I am not able to integrate the two. Please help.

解决方案

It's quite involved but we can create our own CustomLineChart component that inherits from the LineChart react-native-chart-kit provides:

class CustomLineChart extends LineChart {
  render() {
    const {
      width,
      height,
      data,
      withScrollableDot = false,
      withShadow = true,
      withDots = true,
      withInnerLines = true,
      withOuterLines = true,
      withHorizontalLines = true,
      withVerticalLines = true,
      withHorizontalLabels = true,
      withVerticalLabels = true,
      style = {},
      decorator,
      onDataPointClick,
      verticalLabelRotation = 0,
      horizontalLabelRotation = 0,
      formatYLabel = (yLabel) => yLabel,
      formatXLabel = (xLabel) => xLabel,
      segments,
      transparent = false,
      chartConfig,
    } = this.props;

    const {scrollableDotHorizontalOffset} = this.state;
    const {labels = []} = data;
    const {
      borderRadius = 0,
      paddingTop = 16,
      paddingRight = 64,
      margin = 0,
      marginRight = 0,
      paddingBottom = 0,
    } = style;

    const config = {
      width,
      height,
      verticalLabelRotation,
      horizontalLabelRotation,
    };

    const datas = this.getDatas(data.datasets);

    let count = Math.min(...datas) === Math.max(...datas) ? 1 : 4;
    if (segments) {
      count = segments;
    }

    const legendOffset = this.props.data.legend ? height * 0.15 : 0;

    return (
      <View style={style}>
        <Svg
          height={height + paddingBottom + legendOffset}
          width={width - margin * 2 - marginRight}>
          <Defs>
            <LinearGradient id="grad" x1="0" y1="0" x2="0" y2="1">
              <Stop offset="0" stopColor="red" stopOpacity="1" />
              <Stop offset="1" stopColor="blue" stopOpacity="1" />
            </LinearGradient>
          </Defs>
          <Rect
            width="100%"
            height={height + legendOffset}
            rx={borderRadius}
            ry={borderRadius}
            fill="white"
            fillOpacity={transparent ? 0 : 1}
          />
          {this.props.data.legend &&
            this.renderLegend(config.width, legendOffset)}
          <G x="0" y={legendOffset}>
            <G>
              {withHorizontalLines &&
                (withInnerLines
                  ? this.renderHorizontalLines({
                      ...config,
                      count: count,
                      paddingTop,
                      paddingRight,
                    })
                  : withOuterLines
                  ? this.renderHorizontalLine({
                      ...config,
                      paddingTop,
                      paddingRight,
                    })
                  : null)}
            </G>
            <G>
              {withHorizontalLabels &&
                this.renderHorizontalLabels({
                  ...config,
                  count: count,
                  data: datas,
                  paddingTop: paddingTop,
                  paddingRight: paddingRight,
                  formatYLabel,
                  decimalPlaces: chartConfig.decimalPlaces,
                })}
            </G>
            <G>
              {withVerticalLines &&
                (withInnerLines
                  ? this.renderVerticalLines({
                      ...config,
                      data: data.datasets[0].data,
                      paddingTop: paddingTop,
                      paddingRight: paddingRight,
                    })
                  : withOuterLines
                  ? this.renderVerticalLine({
                      ...config,
                      paddingTop: paddingTop,
                      paddingRight: paddingRight,
                    })
                  : null)}
            </G>
            <G>
              {withVerticalLabels &&
                this.renderVerticalLabels({
                  ...config,
                  labels,
                  paddingTop: paddingTop,
                  paddingRight: paddingRight,
                  formatXLabel,
                })}
            </G>
            <G>
              {this.renderLine({
                ...config,
                ...chartConfig,
                paddingRight: paddingRight,
                paddingTop: paddingTop,
                data: data.datasets,
              })}
            </G>
            <G>
              {withDots &&
                this.renderDots({
                  ...config,
                  data: data.datasets,
                  paddingTop: paddingTop,
                  paddingRight: paddingRight,
                  onDataPointClick,
                })}
            </G>
            <G>
              {withScrollableDot &&
                this.renderScrollableDot({
                  ...config,
                  ...chartConfig,
                  data: data.datasets,
                  paddingTop: paddingTop,
                  paddingRight: paddingRight,
                  onDataPointClick,
                  scrollableDotHorizontalOffset,
                })}
            </G>
            <G>
              {decorator &&
                decorator({
                  ...config,
                  data: data.datasets,
                  paddingTop,
                  paddingRight,
                })}
            </G>
          </G>
        </Svg>
        {withScrollableDot && (
          <ScrollView
            style={StyleSheet.absoluteFill}
            contentContainerStyle={{width: width * 2}}
            showsHorizontalScrollIndicator={false}
            scrollEventThrottle={16}
            onScroll={Animated.event([
              {
                nativeEvent: {
                  contentOffset: {x: scrollableDotHorizontalOffset},
                },
              },
            ])}
            horizontal
            bounces={false}
          />
        )}
      </View>
    );
  }
}

function App() {
  return (
    <CustomLineChart
      data={{
        labels: ['January', 'February', 'March', 'April', 'May', 'June'],
        datasets: [
          {
            data: [100, 110, 90, 130, 80, 103],
          },
        ],
      }}
      width={Dimensions.get('window').width}
      height={250}
      chartConfig={{
        backgroundGradientFrom: '#fbfbfb',
        backgroundGradientTo: '#fbfbfb',
        color: (opacity = 1) => 'url(#grad)',
        labelColor: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
      }}
      bezier
      withInnerLines={false}
      withOuterLines={false}
    />
  );
}

Most of the code in the render the same as the official LineChart component (https://github.com/indiespirit/react-native-chart-kit/blob/master/src/line-chart/LineChart.tsx).

The important parts in this code are the linear gradient that is added and this line in the chartConfig:

color: (opacity = 1) => 'url(#grad)'

The color refers to the LinearGradient we've defined by its id grad.


The result looks something like this:


You can also add more colors and play around with the offset prop of each.

You can also use percentages for the gradient, but it's recommended to use exact values as it has performance advantages over using percentages according to the documentation: https://github.com/react-native-community/react-native-svg#lineargradient.


Important to note is that this implementation doesn't have a fillShadowGradient as a background and it doesn't implement the shadow. I've also left out some of your other code like the tooltip code that isn't relevant to the question.

这篇关于如何向这个 React Native 图表添加渐变颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆