2

我正在尝试按照本教程教程创建自定义折线图。一切正常,但是当我在图表上拖动手指时,我想显示当前位置的值(iOS 上的线股应用程序或 Robinhood 应用程序)。起初,它显示一个值,但它是静态的并且不会更新。

LineChart.js

const d3 = {
  scale,
  shape,
}
const height = 300
const { width } = Dimensions.get('window')
const verticalPadding = 30

export default function LineChart({ data = exampleData }) {
  const minX = minBy(data, el => moment(el.label, 'LT'))
  const maxX = maxBy(data, el => moment(el.label, 'LT'))
  const minY = minBy(data, el => el.value)
  const maxY = maxBy(data, el => el.value)
  const scaleX = scaleTime()
    .domain([moment(minX.label, 'LT'), moment(maxX.label, 'LT')])
    .range([0, width])
  const scaleY = scaleLinear()
    .domain([minY.value, maxY.value])
    .range([height - verticalPadding, verticalPadding])
  const line = d3.shape
    .line()
    .x(d => scaleX(moment(d.label, 'LT')))
    .y(d => scaleY(d.value))
    .curve(d3.shape.curveBasis)(data)

  return (
    <View style={styles.container}>
      <Svg {...{ width, height }}>
        <Path d={line} fill="transparent" stroke={GREEN} strokeWidth="2" />
      </Svg>
      <View style={{ ...StyleSheet.absoluteFill, width }}>
        <Cursor d={line} scaleY={scaleY} scaleX={scaleX} data={data} />
      </View>
    </View>
  )
}

游标.js

const { Value } = Animated
const { width } = Dimensions.get('window')

export default ({ d, scaleY, scaleX, data }) => {
  const translationX = new Value(0)
  const path = parsePath(d)
  const length = interpolate(translationX, {
    inputRange: [0, width],
    outputRange: [0, path.totalLength],
  })
  const { x, y } = getPointAtLength(path, length)
  const translateX = x
  const cursorX = sub(x, 4)
  const cursorY = sub(y, 4)
  const text = scaleY.invert(cursorX.__getValue())
  const onGestureEvent = event([
    {
      nativeEvent: {
        x: translationX,
      },
    },
  ])

  return (
    <PanGestureHandler onGestureEvent={onGestureEvent}>
      <Animated.View>
        <Animated.View style={{ transform: [{ translateX }], ...styles.label }}>
          <Animated.Text style={{ color: 'white' }}>{text}</Animated.Text>
        </Animated.View>
        <Animated.View style={[styles.line, { transform: [{ translateX }] }]} />
        <Animated.View
          style={[
            styles.cursor,
            { transform: [{ translateX: cursorX, translateY: cursorY }] },
          ]}
        />
      </Animated.View>
    </PanGestureHandler>
  )
}

这是上面代码的结果:

当前的

编辑 这里是小吃的链接:https ://snack.expo.io/@clytras/intrigued-truffle

4

1 回答 1

3

您已经使用React Native Reanimated call来获取translationX值更改的回调,然后在其中您可以更新它必须使用的文本,setNativeProps并且由于<Text>组件没有text本机道具,您必须<TextInput>revolut-chart示例中一样使用:

光标组件代码

// Changed imports
import React, { useEffect, useRef } from 'react';
import { Dimensions, TextInput } from 'react-native';
import Animated, { event, interpolate, sub, useCode, call } from 'react-native-reanimated';

...

export default function Cursor({ d, scaleY, scaleX, data }) {
  // Create a ref for the TextInput component
  const textRef = useRef();

  const translationX = new Value(0)
  const path = parsePath(d)
  const length = interpolate(translationX, {
    inputRange: [0, width],
    outputRange: [0, path.totalLength],
  })
  const { x, y } = getPointAtLength(path, length)
  const translateX = x
  const cursorX = sub(x, 4)
  const cursorY = sub(y, 4)
  // const text = scaleY.invert(cursorX.__getValue())
  const onGestureEvent = event([
    {
      nativeEvent: {
        x: translationX,
      },
    },
  ]);

  // Update text value using xValue = 0 when the component is mounted
  useEffect(() => {
    updateText(0);
  }, []);

  // Create reanimated code to get a translationX change callback
  useCode(() => {
    return call([translationX], (value) => {
      // On translationX value change update the text using the value
      updateText(value);
    })
  }, [translationX]);

  // Function to update the text based on current translationX value
  function updateText(xValue) {
    const { x, y } = getPointAtLength(path, xValue);
    const cursorX = sub(x, 4)
    const updated = scaleY.invert(cursorX.__getValue());

    // Use setNativeProps to update the TextInput component text prop
    textRef.current.setNativeProps({ text: `${updated.toFixed(5)}` })
  }

  return (
    <PanGestureHandler onGestureEvent={onGestureEvent}>
      <Animated.View>
        <Animated.View style={{ transform: [{ translateX }], ...styles.label }}>
          <TextInput ref={textRef} style={{ color: 'white' }}/>
        </Animated.View>
        <Animated.View style={[styles.line, { transform: [{ translateX }] }]} />
        <Animated.View
          style={[
            styles.cursor,
            { transform: [{ translateX: cursorX, translateY: cursorY }] },
          ]}
        />
      </Animated.View>
    </PanGestureHandler>
  )
}

示例屏幕截图

RN D3 图表

您可以在此处查看更新的 Expo Snack:https ://snack.expo.io/@clytras/intrigued-truffle

于 2020-04-24T17:59:55.557 回答