FormidableLabs / victory-native-xl

A charting library for React Native with a focus on performance and customization.
https://commerce.nearform.com/open-source/victory-native
724 stars 52 forks source link

[repack only] useChartPressState does not work with newer versions of Reanimated #227

Open michaeltugby0 opened 7 months ago

michaeltugby0 commented 7 months ago

Prerequisites

Describe Your Environment

What version of victory-native-xl are you using? (can be found by running npm list --depth 0 victory-native) 40.1.0

What version of React and React Native are you using? React: 18.2.0 React Native: 0.73.6

What version of Reanimated and React Native Skia are you using? Reanimated: 3.8.1 Skia: 1.2.0

Are you using Expo or React Native CLI? React Native CLI + Repack

What platform are you on? (e.g., iOS, Android) Android

Describe the Problem

There seems to be a compatibility issue with newer versions of Reanimated when using useChartPressState. The bug first occurred in 3.7.0 of Reanimated (3.6.3 is the last I could get working). From my initial testing, the gesture handlers are all fine and activating as expected. However, the shared values are not updating. I suspect it may be because of the way the shared values are being updated here, which goes against what Reanimated recommends here (the last point, to be specific).

Expected behavior: [What you expect to happen] isActive to switch to true when a user presses on their device.

Actual behavior: [What actually happens] Nothing happens because isActive never changes to true.

Additional Information

Reproduction: https://github.com/michaeltugby0/victory-native-reanimated-bug

nirmaanlabs commented 7 months ago

I have the same problem @michaeltugby0 what version you ended up using then ?

zibs commented 7 months ago

Thanks for calling this out. Hopefully can take a look shortly.

michaeltugby0 commented 7 months ago

I have the same problem @michaeltugby0 what version you ended up using then ?

@nirmaanlabs 3.6.3 was the latest one I could get working.

zibs commented 7 months ago

Hey @michaeltugby0 and @nirmaanlabs -- I'm looking into this and can't really reproduce the issue. It seems like it's working fine to me, but maybe I'm misunderstanding something? Can you provide more details, or better yet, and example application and explain the issue more thoroughly?

Thanks!

Below is what I spun up and tested with:

    "@shopify/react-native-skia": "^1.0.3",
    "react": "18.2.0",
    "react-native": "0.73.3",
    "react-native-gesture-handler": "^2.14.1",
    "react-native-reanimated": "3.8.1",
    "victory-native": "^40.1.0"
import * as React from 'react';
import {View} from 'react-native';
import {CartesianChart, Line, useChartPressState} from 'victory-native';
import {Circle} from '@shopify/react-native-skia';
import {type SharedValue} from 'react-native-reanimated';

export function MyChart() {
  const {state, isActive} = useChartPressState({x: 0, y: {highTmp: 0}});
  const {state: state2, isActive: isActive2} = useChartPressState({
    x: 0,
    y: {highTmp: 0},
  });

  return (
    <View style={{height: 300}}>
      <CartesianChart
        data={DATA}
        xKey="day"
        yKeys={['highTmp']}
        axisOptions={{}}
        chartPressState={[state, state2]}>
        {({points}) => (
          <>
            <Line points={points.highTmp} color="red" strokeWidth={3} />
            {isActive && (
              <ToolTip x={state.x.position} y={state.y.highTmp.position} />
            )}
            {isActive2 && (
              <ToolTip x={state2.x.position} y={state2.y.highTmp.position} />
            )}
          </>
        )}
      </CartesianChart>
    </View>
  );
}

function ToolTip({x, y}: {x: SharedValue<number>; y: SharedValue<number>}) {
  return <Circle cx={x} cy={y} r={8} color="black" />;
}

const DATA = Array.from({length: 31}, (_, i) => ({
  day: i,
  highTmp: 40 + 30 * Math.random(),
}));
michaeltugby0 commented 7 months ago

Hey @zibs, thanks for looking into it! I suspect there must be some other element that's causing the problem. I have some free time over the weekend, so I'll see if I can get a repro going for you.

michaeltugby0 commented 7 months ago

Hey again @zibs, managed to reproduce it. Strangely, it only occurs when building with Repack. I've attached a link to the repo at the end of the original post.

zibs commented 6 months ago

I'm not as familiar with Repack myself, nor why it would be handling this differently, so if either of you want to take a stab at this, please feel free!

nirmaanlabs commented 6 months ago

It is working for me now @zibs @michaeltugby0

KonarkRajMisra commented 6 months ago

how did you get it to work @nirmaanlabs?

dvelaren commented 2 months ago

Hello. I have also a problem with useChartPressState. I'm streaming data from an MQTT server every 5 secs and I don't know why but the useChartPressState always returns in state.x.position and state.y.temperature.position a value of 0. If I use static data it does work... Here is my code:

import {
  CartesianChart,
  Line,
  Scatter,
  useChartPressState,
} from "victory-native";
import { useFont } from "@shopify/react-native-skia";
import { formatDate } from "../../utils/helpers";
import ToolTip from "./Tooltip";
import inter from "../../assets/inter-medium.ttf";
import { View } from "react-native";
import { useColorScheme } from "nativewind";

export default function Plot({ data }) {
  const { state, isActive } = useChartPressState({
    x: 0,
    y: { temperature: 0, humidity: 0 },
  });
  const font = useFont(inter, 12);
  const xTicks = data.length <= 5 ? data.length : 5;
  const { colorScheme } = useColorScheme();
  const isDarkMode = colorScheme === "dark";

  return (
    <View className="bg-slate-700 dark:bg-white p-4 h-80 w-80 rounded-md">
      <CartesianChart
        data={data}
        xKey="date"
        yKeys={["temperature", "humidity"]}
        domain={{ y: [0, 100] }}
        axisOptions={{
          font: font,
          formatXLabel: (date) => formatDate(new Date(date)),
          tickCount: { x: xTicks - 1, y: 10 },
          labelColor: isDarkMode ? "black" : "white",
          lineColor: {
            grid: {
              x: "#c5c5c5",
              y: "#c5c5c5",
            },
            frame: "#c5c5c5",
          },
        }}
        chartPressState={state}
      >
        {({ points }) => (
          <>
            <Line points={points.temperature} color="red" strokeWidth={2} />
            {isActive && (
              <ToolTip x={state.x.position} y={state.y.temperature.position} />
            )}
            <Scatter radius={3} points={points.temperature} color={"red"} />
            <Line points={points.humidity} color="blue" strokeWidth={2} />
            <Scatter radius={3} points={points.humidity} color={"blue"} />
          </>
        )}
      </CartesianChart>
    </View>
  );
}