xanderdeseyn / react-native-responsive-linechart

A customizable and responsive line or area chart for react-native
https://react-native-responsive-linechart.surge.sh
MIT License
202 stars 46 forks source link

Vertical line cursor & hide the tooltips when the user press out #46

Closed lohenyumnam closed 3 years ago

lohenyumnam commented 3 years ago

Hi, I have tried almost all the other available Chart packages for RN, and I have to say this one is my favorite. Thank you for this beautiful library.

For a few days, I have been struggling with a few things.

  1. How can I add a vertical line cursor which follows the tooltips? (just like the one with App stock app) IMG_0603

  2. I want to show the tooltips when the user press on the chart area and hide the tooltips when the user press out, just like pans on the chart area (Currently it show the tooltips on tap and won't hide until use drag on chart area)

xanderdeseyn commented 3 years ago

Hi, thanks for the kind words!

  1. You can create a custom Tooltip component, check out Tooltip.tsx for an example!
  2. I've tried to do this before, but I always bumped into some edge cases with TapResponder (eg. detecting 3 taps when only pressed once etc.), but I'll have another look at it asap!
lohenyumnam commented 3 years ago

Hi, thanks for the kind words!

1. You can create a custom Tooltip component, check out Tooltip.tsx for an example!

Thanks for the hit.

I was able to add the custom VerticaCursor with tooltips using this component as Tooltips

const VerticaCursor = (props) => {
  const { x, y } = props.position;
  const { x: xValue, y: yValue } = props.value;
  return (
    <G>
      <G y={-36} x={x - 75 / 2}>
        <Rect
          height={35}
          width={75}
          stroke={"grey"}
          fill={"white"}
          ry={10}
          rx={10}
        />
        <TextSvg
          x={75 / 2}
          dy={20}
          alignmentBaseline={"middle"}
          textAnchor={"middle"}
          stroke={"rgb(134, 65, 244)"}
        >
          {`${yValue}`}
        </TextSvg>
      </G>
      <VLine
        key={"zero-axis"}
        x1={x}
        x2={x}
        y1={0}
        y2={300 - 60}
        stroke={"red"}
        // strokeDasharray={[1, 10]}
        strokeWidth={2}
      />
    </G>
  );
};
2. I've tried to do this before, but I always bumped into some edge cases with TapResponder (eg. detecting 3 taps when only pressed once etc.), but I'll have another look at it asap!

Thank You, Hoping for the best.

xanderdeseyn commented 3 years ago

v5.4.2 introduces a new prop on Line: hideTooltipOnDragEnd

Set to true if the tooltip should be hidden when the user stops dragging the chart.

Please close this if your issue is resolved by this :)

lohenyumnam commented 3 years ago

v5.4.2 introduces a new prop on Line: hideTooltipOnDragEnd

Set to true if the tooltip should be hidden when the user stops dragging the chart.

Please close this if your issue is resolved by this :)

Thank you for these options. I think I explain it wrong. When the user taps on the chart the tooltips show up. and now that tooltips are showing the tooltips won't hide until the user drag on it. but what I am trying to achieve is, when the user Lift up the finger off the screen (onPressOut) I want the tooltips to hide automatically (maybe after a few sec or immediately).

lohenyumnam commented 3 years ago

Ok, I was able to solve the problem by creating a new Line base on your code and add a few things to it.

I add a tooltip timer, which will be fire at a defined time when the user taps on the chart. this is optional and will only fire if the user added the value of hideTooltipAfter.

usage

<Line
        hideTooltipAfter={2000}
        tooltipComponent={
          <VerticalCursor
            padding={styles.padding}
            charStyles={styles.chart}
            textColor={color}
          />
        }
      />
React.useEffect(() => {
    const scaledPoints = scalePointsToDimensions(
      data,
      viewportDomain,
      dimensions
    );
    const newIndex = calculateTooltipIndex(scaledPoints, lastTouch?.position);

    let tooltipTimer;

    if (lastTouch?.type === "panEnd") {
      if (hideTooltipOnDragEnd) {
        setTooltipIndex(undefined);
      }
      onTooltipSelectEnd();
    } else if (newIndex !== tooltipIndex && lastTouch) {
      // tooltips will automatically hide after the a define time
      if (hideTooltipAfter) {
        tooltipTimer = setTimeout(() => setTooltipIndex(undefined), 1000);
      }

      setTooltipIndex(newIndex);
      if (
        typeof onTooltipSelect === "function" &&
        typeof newIndex === "number" &&
        data.length > newIndex
      ) {
        onTooltipSelect(data[newIndex], newIndex);
      }
    } else if (newIndex === tooltipIndex && lastTouch?.type === "tap") {
      setTooltipIndex(undefined);
    }

    return () => {
      clearTimeout(tooltipTimer);
    };
  }, [data, viewportDomain, domain, dimensions, lastTouch]);

I can send a PR if you like. ☺️

xanderdeseyn commented 3 years ago

Ahh okay I see! In the current release the user can still remove the tooltip by tapping again btw. But a release after a certain time is definitely useful. I will integrate your code asap, but have to check for some edge cases as well

xanderdeseyn commented 3 years ago

Should work in v5.4.3 :)

lohenyumnam commented 3 years ago

Thank you. its perfect.