【问题标题】:D3 + React Native - Data point value not updating when X position changesD3 + React Native - X 位置更改时数据点值不更新
【发布时间】:2020-08-03 12:05:53
【问题描述】:

我也在尝试在this tutorialthis one 之后创建自定义折线图。一切正常,但是当我在图表上拖动手指时,我想显示当前位置的值(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>
  )
}

Cursor.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

【问题讨论】:

  • 我看不到scaleQuantile的任何用法(like const scaleLabel = scaleQuantile()...);该示例使用它来制作像const label = scaleLabel(scaleY.invert(y)); 这样的实际文本。另外,你为什么要做scaleY.invert(cursorX.__getValue()) 而不是scaleY.invert(cursorX)?如果您可以使用此示例创建 Expo Snack,那将非常有帮助。
  • 你能不能做一个expo demo之类的,这样人们可以更好地帮助你
  • @ChristosLytras 起初我使用的是scaleQuantile,但它对我不起作用,所以我决定尝试其他方法。我正在使用cursorX.__getValue(),因为sub() 返回一个复活的对象。对不起,也许我应该在帖子中添加。
  • @ChristosLytras 我创建了一个工作零食:snack.expo.io/@corasan/intrigued-truffle

标签: javascript reactjs react-native d3.js svg


【解决方案1】:

您已经使用React Native Reanimated call 来获取translationX 值更改的回调,然后在其中您可以更新文本,它必须使用setNativeProps,因为&lt;Text&gt; 组件没有有一个 text 原生属性,你必须使用 &lt;TextInput&gt; 就像在 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>
  )
}

屏幕截图示例

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

【讨论】:

  • 我还有一个问题。你知道为什么光标在指针/手指的前面或后面吗?它似乎在图表中间的指针前面移动,你知道为什么吗?
  • 这很可能是因为您将4 (const cursorX = sub(x, 4)) 减去cursorXcursorY 然后使用这些值将translationXtranslationY 转换为光标Animated.View (transform: [{ translateX: cursorX, translateY: cursorY }])。
  • 我并没有为这条线这样做,而且它似乎只发生在图表的中间,接近尾端和开头,光标和线似乎与指针对齐。抱歉,我是 d3 和 svg 的新手,所以我有点迷路了哈哈。
  • 我可以看到问题是使用translateX 的映射值;如果您将其更改为transform: [{ translateX: translationX ...,它将适用于X,但Y 会出错!
  • 是的,你是对的。如果我将光标更改为translationX,光标不会停留在行路径上。我必须想办法让它遵循线路路径和指针 hmmm。
猜你喜欢
  • 2016-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-21
相关资源
最近更新 更多