问题描述
当前实施:
这是一个使用react-native-svg库的图表,并在其中添加了工具提示。我想使线条的颜色成为渐变色,而不是单一颜色
代码:
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,${opacity})`,labelColor: (opacity = 1) => `rgba(0,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,y: data.y,visible: true });
}}
/>
</View>
)
}
export default Charts
问题: 我希望图表的颜色超过特定阈值时不再是灰色,而是希望图表颜色变为红色,另一个值则为黄色,最低值为绿色。
我发现的东西:
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>
)
}
我无法将两者整合。请帮忙。
解决方法
这很复杂,但是我们可以创建自己的CustomLineChart
组件,该组件继承自LineChart
react-native-chart-kit提供的内容:
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,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,})
: null)}
</G>
<G>
{withHorizontalLabels &&
this.renderHorizontalLabels({
...config,data: datas,paddingTop: paddingTop,paddingRight: paddingRight,formatYLabel,decimalPlaces: chartConfig.decimalPlaces,})}
</G>
<G>
{withVerticalLines &&
(withInnerLines
? this.renderVerticalLines({
...config,data: data.datasets[0].data,})
: withOuterLines
? this.renderVerticalLine({
...config,})
: null)}
</G>
<G>
{withVerticalLabels &&
this.renderVerticalLabels({
...config,labels,formatXLabel,})}
</G>
<G>
{this.renderLine({
...config,...chartConfig,data: data.datasets,})}
</G>
<G>
{withDots &&
this.renderDots({
...config,})}
</G>
<G>
{withScrollableDot &&
this.renderScrollableDot({
...config,scrollableDotHorizontalOffset,})}
</G>
<G>
{decorator &&
decorator({
...config,})}
</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,${opacity})`,}}
bezier
withInnerLines={false}
withOuterLines={false}
/>
);
}
渲染中的大多数代码与官方LineChart
组件(https://github.com/indiespirit/react-native-chart-kit/blob/master/src/line-chart/LineChart.tsx)相同。
此代码中的重要部分是添加的线性渐变和chartConfig
中的该行:
color: (opacity = 1) => 'url(#grad)'
颜色是指ID LinearGradient
所定义的grad
。
结果看起来像这样:
您还可以添加更多颜色并使用每种颜色的offset
道具。
您也可以为梯度使用百分比,但是建议使用精确值,因为根据文档https://github.com/react-native-community/react-native-svg#lineargradient,它比使用百分比具有更好的性能。
要注意的重要一点是,此实现没有以fillShadowGradient
为背景,也没有实现阴影。我还省略了一些其他代码,例如与问题无关的工具提示代码。