Solvedvictory native Gradient with VictoryPie

FormidableLabs/victory#688 shows how to use gradients with VictoryPie for React - how can it be accomplished with React Native? I've tried to translate it to the following code, but the gradient only works for the polygon and not VictoryPie (which is not rendered at all):

import React, {Component} from 'react';
import {
    View,
} from 'react-native';
import {Defs, LinearGradient, Polygon, Stop, Svg} from "react-native-svg";

export default class Test extends Component {
    render() {
        return(
            <View>
                <Svg style={{width: "100%", height: 200}}>
                    <Defs>
                        <LinearGradient id="gradient1"
                                        x1="0%" y1="0%" x2="0%" y2="100%"
                        >
                            <Stop offset="0%" stopColor="blue"/>
                            <Stop offset="100%" stopColor="red"/>
                        </LinearGradient>
                    </Defs>
                    <Polygon fill="url(#gradient1)" points='0,0 15,0 0,71'/>
                </Svg>
                <VictoryPie
                    height={300}
                    width={300}
                    colorScale={[
                        "url(#gradient1)",
                    ]}
                    data={[1]}
                />
            </View>
        )
    }
}

Any help would be very much appreciated! :)

10 Answers

✔️Accepted Answer

@jenskuhrjorgensen I recently dealt with this and did find a solution by placing the Defs directly inside an outer VictoryChart. Here's what worked:

import React from 'react'
import styled from 'styled-components/native'
import { Defs, Stop, LinearGradient } from 'react-native-svg'
import { VictoryChart, VictoryArea } from 'victory-native'
import ThemeGraph from '../../config/themeGraph'
import Reading from '../../types/Reading'
import theme from '../../config/theme'

const Container: any = styled.View`
  flex-grow: 1;
  overflow: visible;
`

interface Props {
  readings?: Reading[]
}

export class GraphUvIndex extends React.Component<Props, any> {
  public static defaultProps: Partial<Props> = {
    readings: []
  }
  public render() {
    const { readings } = this.props
    return (
      <Container>
        <VictoryChart
          theme={ThemeGraph}
          style={{
            parent: {
              width: '100%',
              height: 'auto',
              marginTop: -20,
              marginLeft: -10,
              marginBottom: -10,
              overflow: 'visible',
            },
            data: {
              overflow: 'visible',
            }
          }}
          scale={{x: 'time', y: 'linear'}}
        >
          <Defs>
            <LinearGradient id='gradientStroke'
              x1='0%'
              x2='0%'
              y1='0%'
              y2='100%'
            >
            <Stop offset='20%'  stopColor={theme.gradients.violet.start} />
            <Stop offset='40%'  stopColor={theme.gradients.orange.start} />
            <Stop offset='80%'  stopColor={theme.gradients.yellow.start} />
            <Stop offset='100%' stopColor={theme.gradients.green.start}  />
            </LinearGradient>
            <LinearGradient id='gradientFill'
              x1='0%'
              x2='0%'
              y1='0%'
              y2='100%'
            >
              <Stop offset='20%'  stopColor={theme.gradients.violet.start} stopOpacity='0.3' />
              <Stop offset='40%'  stopColor={theme.gradients.orange.start} stopOpacity='0.3' />
              <Stop offset='80%'  stopColor={theme.gradients.yellow.start} stopOpacity='0.3' />
              <Stop offset='100%' stopColor={theme.gradients.green.start}  stopOpacity='0.3' />
            </LinearGradient>
          </Defs>
          <VictoryArea
            style={{
              data: {
                fill: 'url(#gradientFill)',
                stroke: 'url(#gradientStroke)',
                strokeWidth: 2,
                strokeLinejoin: 'round',
                overflow: 'visible',
              },
              parent: {
                overflow: 'visible',
              }
            }}
            animate={{
              duration: 2000,
              onLoad: { duration: 1000 }
            }}
            interpolation='linear'
            domain={{
              // x: [0, 24],
              y: [0, 13]
            }}

            data={readings}
            x={(d) => new Date(d.date * 1000) }
            y='uvIndex'
          />
        </VictoryChart>
      </Container>
    )
  }
}

Other Answers:

@jenskuhrjorgensen no problem. I took it that your issue was similar to mine in that you're wanting to use #gradient1 as the fill for your pie elements. I found that in order to be able to reference those defs, they have to reside within the same SVG. In your example you have a separate Svg and Defs as a sibling to what ultimately is another Svg element (created by VictoryPie). I'm curious if doing the following would achieve what you're going for:

import React, {Component} from 'react';
import {
    View,
} from 'react-native';
import {Defs, LinearGradient, Polygon, Stop, Svg} from "react-native-svg";

export default class Test extends Component {
  render() {
    return(
      <View>
        <VictoryChart>
          <Defs>
            <LinearGradient id="gradient1"
              x1="0%" y1="0%" x2="0%" y2="100%"
            >
              <Stop offset="0%" stopColor="blue"/>
              <Stop offset="100%" stopColor="red"/>
            </LinearGradient>
          </Defs>
          <VictoryPie
            height={300}
            width={300}
            colorScale={[
              "url(#gradient1)",
            ]}
            data={[1]}
          />
        </VictoryChart>
      </View>
    )
  }
}

More Issues: