Comment ajouter une couleur de dégradé à ce graphique natif React?
Mise en œuvre actuelle:
Ceci est un graphique utilisant la bibliothèque react-native-svg avec une info-bulle ajoutée. Je veux faire de la couleur de la ligne un dégradé plutôt qu'une seule couleur
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: Au lieu que le graphique ait juste du gris, je veux que la couleur du graphique soit rouge lorsqu'il dépasse un seuil spécifique, jaune pour une autre valeur et vert pour la valeur la plus basse.
Comme ça un peu:
Ce que j'ai trouvé:
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>
)
}
Je ne suis pas en mesure d'intégrer les deux. Veuillez aider.
Réponses
C'est assez compliqué mais nous pouvons créer notre propre CustomLineChartcomposant qui hérite du LineChartkit react-native-chart-kit fourni:
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}
/>
);
}
La plupart du code dans le rendu le même que le LineChartcomposant officiel (https://github.com/indiespirit/react-native-chart-kit/blob/master/src/line-chart/LineChart.tsx).
Les parties importantes de ce code sont le dégradé linéaire qui est ajouté et cette ligne dans le chartConfig:
color: (opacity = 1) => 'url(#grad)'
La couleur fait référence au que LinearGradientnous avons défini par son identifiant grad.
Le résultat ressemble à ceci:
Vous pouvez également ajouter plus de couleurs et jouer avec l' offsetaccessoire de chacun.
Vous pouvez également utiliser des pourcentages pour le dégradé, mais il est recommandé d'utiliser des valeurs exactes car cela présente des avantages en termes de performances par rapport à l'utilisation de pourcentages selon la documentation: https://github.com/react-native-community/react-native-svg#lineargradient.
Il est important de noter que cette implémentation n'a pas d' fillShadowGradientarrière-plan et n'implémente pas l'ombre. J'ai également omis certains de vos autres codes, comme le code de l'infobulle, qui n'est pas pertinent pour la question.