Làm cách nào để thêm Gradient Color vào biểu đồ React Native này?
Thực hiện hiện tại:
Đây là một Biểu đồ sử dụng thư viện react-native-svg với một mẹo công cụ được thêm vào nó. Tôi muốn biến màu của đường thành một gradient thay vì một màu duy nhất
Mã:
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
HỎI: Thay vì biểu đồ chỉ có màu xám, tôi muốn màu của biểu đồ là màu đỏ khi nó vượt qua một ngưỡng cụ thể, màu vàng cho giá trị khác và màu xanh lục cho giá trị thấp nhất.
Như thế này phần nào:
Những gì tôi tìm thấy:
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>
)
}
Tôi không thể tích hợp cả hai. Hãy giúp tôi.
Trả lời
Nó khá liên quan nhưng chúng tôi có thể tạo CustomLineChartthành phần của riêng mình kế thừa từ bộ LineChartphản ứng-native-chart-kit cung cấp:
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}
/>
);
}
Hầu hết mã trong kết xuất giống với LineChartthành phần chính thức (https://github.com/indiespirit/react-native-chart-kit/blob/master/src/line-chart/LineChart.tsx).
Các phần quan trọng trong mã này là gradient tuyến tính được thêm vào và dòng này trong chartConfig:
color: (opacity = 1) => 'url(#grad)'
Màu đề cập đến LinearGradientchúng tôi đã xác định bởi id của nó grad.
Kết quả trông giống như sau:
Bạn cũng có thể thêm nhiều màu hơn và chơi xung quanh với giá offsetđỡ của mỗi màu.
Bạn cũng có thể sử dụng tỷ lệ phần trăm cho gradient, nhưng bạn nên sử dụng các giá trị chính xác vì nó có lợi thế về hiệu suất so với việc sử dụng tỷ lệ phần trăm theo tài liệu: https://github.com/react-native-community/react-native-svg#lineargradient.
Điều quan trọng cần lưu ý là triển khai này không có fillShadowGradientlàm nền và nó không triển khai bóng đổ. Tôi cũng đã bỏ sót một số mã khác của bạn như mã chú giải công cụ không liên quan đến câu hỏi.