水平滚动和SVG路径图之间的对齐-React Native

时间:2019-02-21 13:47:11

标签: javascript react-native animation react-native-android

我正在尝试使用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',
  }
})

my app

0 个答案:

没有答案