我正在尝试使用SVG将数据绘制为带有 Path 的折线图,我使用了 d3-scale 缩放x和y值,以绘制我使用 d3-shape 的线,并使用 svg-path-properties 来计算线的长度。
我设法做到了,现在,我希望能够在绿色部分中水平滚动光标,并将图表的 x 和 y 值显示它。
我创建了一个Animated.View(进行插值),里面有光标。我使用ref来管理光标位置并更改标签的值,只有第一个和最后一个都可以。
但是,标签显示的值与图表的值不符。
任何提示或帮助将不胜感激!
这里是my code
的小吃这是我的Chart.js代码:
import React from 'react'
import { StyleSheet, View, Dimensions, Animated, TextInput } from 'react-native'
import { Svg, Path} from 'react-native-svg'
import * as path from 'svg-path-properties'
import * as shape from 'd3-shape'
import { scaleTime, scaleLinear } from 'd3-scale'
const d3 = { shape }
const height = 200
const { width } = Dimensions.get('window')
const verticalPadding = 5
const cursorRadius = 10
export default class Chart extends React.Component {
cursor = React.createRef()
label = React.createRef()
state = {
x: new Animated.Value(0),
ready: false,
}
moveCursor(value) {
const { x, y } = this.properties.getPointAtLength(this.lineLength - value)
if (this.label.current) {
const labelY = this.scaleY.invert(y)
const labelX = this.scaleX.invert(x)
this.label.current.setNativeProps({ text: `${Math.round(labelY)}-${labelX}` })
}
}
componentDidMount() {
const { data, yMax, yMin } = this.props
this.scaleX = scaleTime().domain([data[0].x, data[data.length - 1].x]).range([0, width])
this.scaleY = scaleLinear().domain([yMin, yMax]).range([height - verticalPadding, verticalPadding])
this.line = d3.shape.line()
.x(d => this.scaleX(d.x))
.y(d => this.scaleY(d.y))
.curve(d3.shape.curveBasis)(data)
this.properties = path.svgPathProperties(this.line)
this.lineLength = this.properties.getTotalLength()
this.setState({ ready: true }, () => {
this.state.x.addListener(({ value }) => this.moveCursor(value));
this.moveCursor(0)
})
}
render() {
const { line, lineLength } = this
const { ready, x } = this.state
if (!ready) {
return null
}
const translateX = x.interpolate({
inputRange: [0, width],
outputRange: [width - (cursorRadius * 2), 0],
extrapolate: 'clamp',
})
return (
<View style={styles.root}>
<Svg {...{ width, height }}>
<Path d={line} fill="transparent" stroke="blue" strokeWidth={5} />
</Svg>
<View style={styles.scroll}>
<Animated.View style={[styles.cursor, { transform: [{ translateX }] }]}>
<View ref={this.cursor} />
</Animated.View>
<Animated.ScrollView
style={StyleSheet.absoluteFill}
contentContainerStyle={{ width: lineLength * 2 }}
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16} //we want our own onScroll to be called every 16ms
bounces={false}
// onScroll function
onScroll={Animated.event([
{
nativeEvent: {
contentOffset: { x },
},
},
],
{ useNativeDriver: true },
)}
horizontal
/>
</View>
<View>
<TextInput editable={false} selectTextOnFocus={false} ref={this.label} />
</View>
</View>
)
}
}
const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: 'yellow'
},
scroll: {
height: 100,
backgroundColor: 'green'
},
cursor: {
position: 'absolute',
top: 0,
left: 0,
width: cursorRadius * 2,
height: cursorRadius * 2,
borderRadius: cursorRadius,
borderColor: '#367be2',
borderWidth: 3,
backgroundColor: 'white',
}
})