Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PieChart focusOnPress stops working when onPress prop is provided #564

Closed
sclavijo93 opened this issue Mar 2, 2024 · 5 comments
Closed

Comments

@sclavijo93
Copy link

Description

When the onPress prop is uncommented and passed to the PieChart component, the focusOnPress functionality ceases to work. This means the pie chart section does not focus as expected when pressed. However, if the onPress prop is commented out, the focus functionality works correctly again. The desired outcome is for the focused pie chart section to update the center content based on the selected item, while also maintaining the visual focus effect.

Steps to reproduce:

  1. Implement a PieChart component with focusOnPress, data, and other required props.
  2. Provide an onPress handler function to the PieChart component to update the state with the selected item's data.
  3. Run the application and observe that pressing on a pie chart section updates the state but does not visually focus the pressed section.
  4. Comment out the onPress prop in the PieChart component.
  5. Observe that the focus functionality works correctly without the onPress prop.

Expected behavior:

When a section of the pie chart is pressed, the application should both focus on the pressed section visually and update the center content based on the selected item.

Example code
import React from 'react';
import { View } from 'react-native';
import { PieChart, pieDataItem } from 'react-native-gifted-charts';
import { SafeAreaView } from 'react-native-safe-area-context';

import { Card, Text } from '@atoms';

import styles from './styles';
import { ReportCreditLineGraphicScreenProps } from './types';

const ReportCreditLineGraphicScreen: React.FC<
  ReportCreditLineGraphicScreenProps
> = () => {
  const [selectedData, setSelectedData] = React.useState<pieDataItem>({
    value: 40,
    color: '#93FCF8',
    gradientCenterColor: '#3BE9DE',
    text: 'Good',
  });

  const handlePieChartItemPress = (item: pieDataItem, index: number) => {
    setSelectedData(item);
  };

  const pieData = [
    {
      value: 47,
      color: '#009FFF',
      gradientCenterColor: '#006DFF',
      text: 'Excellent',
    },
    {
      value: 40,
      color: '#93FCF8',
      gradientCenterColor: '#3BE9DE',
      focused: true,
      text: 'Good',
    },
    {
      value: 16,
      color: '#BDB2FA',
      gradientCenterColor: '#8F80F3',
      text: 'Okay',
    },
    {
      value: 3,
      color: '#FFA5BA',
      gradientCenterColor: '#FF7F97',
      text: 'Poor',
    },
  ];

  const renderDot = (color) => {
    return (
      <View
        style={{
          height: 10,
          width: 10,
          borderRadius: 5,
          backgroundColor: color,
          marginRight: 10,
        }}
      />
    );
  };

  const renderLegendComponent = () => {
    return (
      <>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'center',
            marginBottom: 10,
          }}>
          <View
            style={{
              flexDirection: 'row',
              alignItems: 'center',
              width: 120,
              marginRight: 20,
            }}>
            {renderDot('#006DFF')}
            <Text style={{ color: 'white' }}>Excellent: 47%</Text>
          </View>
          <View
            style={{ flexDirection: 'row', alignItems: 'center', width: 120 }}>
            {renderDot('#8F80F3')}
            <Text style={{ color: 'white' }}>Okay: 16%</Text>
          </View>
        </View>
        <View style={{ flexDirection: 'row', justifyContent: 'center' }}>
          <View
            style={{
              flexDirection: 'row',
              alignItems: 'center',
              width: 120,
              marginRight: 20,
            }}>
            {renderDot('#3BE9DE')}
            <Text style={{ color: 'white' }}>Good: 40%</Text>
          </View>
          <View
            style={{ flexDirection: 'row', alignItems: 'center', width: 120 }}>
            {renderDot('#FF7F97')}
            <Text style={{ color: 'white' }}>Poor: 3%</Text>
          </View>
        </View>
      </>
    );
  };

  return (
    <View
      style={{
        paddingVertical: 100,
        backgroundColor: '#34448B',
        flex: 1,
      }}>
      <View
        style={{
          margin: 20,
          padding: 16,
          borderRadius: 20,
          backgroundColor: '#232B5D',
        }}>
        <Text style={{ color: 'white', fontSize: 16, fontWeight: 'bold' }}>
          Performance
        </Text>
        <View style={{ padding: 20, alignItems: 'center' }}>
          <PieChart
            focusOnPress
            data={pieData}
            donut
            showGradient
            sectionAutoFocus
            radius={90}
            innerRadius={60}
            innerCircleColor={'#232B5D'}
            centerLabelComponent={() => {
              return (
                <View
                  style={{ justifyContent: 'center', alignItems: 'center' }}>
                  <Text
                    style={{
                      fontSize: 22,
                      color: 'white',
                      fontWeight: 'bold',
                    }}>
                    {selectedData?.value}%
                  </Text>
                  <Text style={{ fontSize: 14, color: 'white' }}>
                    {selectedData?.text}
                  </Text>
                </View>
              );
            }}
            // onPress={handlePieChartItemPress}
          />
        </View>
        {renderLegendComponent()}
      </View>
    </View>
  );
};

export default ReportCreditLineGraphicScreen;

Platform:

react-native: 0.71.16
react-native-gifted-charts version: 1.4.7

@denlahodnyi
Copy link

I have the same issue. onPress always returns a 0 index after selecting an already focused section. The index param is correct only for the newly selected section.

@conorwaltersUno
Copy link

+1 experiencing same issue

Tried using the labelOnPress but it is not registering this event at all with focusOnPress being passed in

@cyril-apart
Copy link

Hi,

i don't understand why the props.onPress() in src/PieChart/main.tsx (line 193) override the expected behaviour.

Here is a patch where expected behaviours works

react-native-gifted-charts+1.4.10.patch

@christophby
Copy link
Contributor

christophby commented May 16, 2024

For me adding zIndex: -1, to the <View> component react-native-gifted-charts/src/PieChart/index.tsx fixed it for Android (iOS was working before)

image

-> I created a PR #635

@Abhinandan-Kushwaha
Copy link
Owner

Abhinandan-Kushwaha commented Jul 23, 2024

Hi @sclavijo93 👋
In your example, the focus is not working properly when used along with the onPress prop.
This is because you are updating the state in the onPress event (through setSelectedData). This is the re-render of the entire chart and setting the selectedIndex to -1.

You can fix the issue by making the pieData a state variable and updating the focused property in the pieData in the onPress event.
Basically, you need to add the below code in your handlePieChartItemPress method-

setPieData([...pieData].map((item, ind) => ({...item, focused: ind===index})))

So your final code should be-

import React, {useState} from 'react';
import {View} from 'react-native';
import {PieChart, pieDataItem} from 'react-native-gifted-charts';
import {SafeAreaView} from 'react-native-safe-area-context';

import {Card, Text} from '@atoms';

import styles from './styles';
import {ReportCreditLineGraphicScreenProps} from './types';

const ReportCreditLineGraphicScreen: React.FC<
  ReportCreditLineGraphicScreenProps
> = () => {
  const [selectedData, setSelectedData] = React.useState<pieDataItem>({
    value: 40,
    color: '#93FCF8',
    gradientCenterColor: '#3BE9DE',
    text: 'Good',
  });

  const handlePieChartItemPress = (item: pieDataItem, index: number) => {
    setSelectedData(item);
    setPieData(
      [...pieData].map((item, ind) => ({...item, focused: ind === index})),
    );
  };

  const [pieData, setPieData] = useState([
    {
      value: 47,
      color: '#009FFF',
      gradientCenterColor: '#006DFF',
      text: 'Excellent',
    },
    {
      value: 40,
      color: '#93FCF8',
      gradientCenterColor: '#3BE9DE',
      focused: true,
      text: 'Good',
    },
    {
      value: 16,
      color: '#BDB2FA',
      gradientCenterColor: '#8F80F3',
      text: 'Okay',
    },
    {
      value: 3,
      color: '#FFA5BA',
      gradientCenterColor: '#FF7F97',
      text: 'Poor',
    },
  ]);

  const renderDot = color => {
    return (
      <View
        style={{
          height: 10,
          width: 10,
          borderRadius: 5,
          backgroundColor: color,
          marginRight: 10,
        }}
      />
    );
  };

  const renderLegendComponent = () => {
    return (
      <>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'center',
            marginBottom: 10,
          }}>
          <View
            style={{
              flexDirection: 'row',
              alignItems: 'center',
              width: 120,
              marginRight: 20,
            }}>
            {renderDot('#006DFF')}
            <Text style={{color: 'white'}}>Excellent: 47%</Text>
          </View>
          <View
            style={{flexDirection: 'row', alignItems: 'center', width: 120}}>
            {renderDot('#8F80F3')}
            <Text style={{color: 'white'}}>Okay: 16%</Text>
          </View>
        </View>
        <View style={{flexDirection: 'row', justifyContent: 'center'}}>
          <View
            style={{
              flexDirection: 'row',
              alignItems: 'center',
              width: 120,
              marginRight: 20,
            }}>
            {renderDot('#3BE9DE')}
            <Text style={{color: 'white'}}>Good: 40%</Text>
          </View>
          <View
            style={{flexDirection: 'row', alignItems: 'center', width: 120}}>
            {renderDot('#FF7F97')}
            <Text style={{color: 'white'}}>Poor: 3%</Text>
          </View>
        </View>
      </>
    );
  };

  return (
    <View
      style={{
        paddingVertical: 100,
        backgroundColor: '#34448B',
        flex: 1,
      }}>
      <View
        style={{
          margin: 20,
          padding: 16,
          borderRadius: 20,
          backgroundColor: '#232B5D',
        }}>
        <Text style={{color: 'white', fontSize: 16, fontWeight: 'bold'}}>
          Performance
        </Text>
        <View style={{padding: 20, alignItems: 'center'}}>
          <PieChart
            focusOnPress
            data={pieData}
            donut
            showGradient
            sectionAutoFocus
            radius={90}
            innerRadius={60}
            innerCircleColor={'#232B5D'}
            centerLabelComponent={() => {
              return (
                <View style={{justifyContent: 'center', alignItems: 'center'}}>
                  <Text
                    style={{
                      fontSize: 22,
                      color: 'white',
                      fontWeight: 'bold',
                    }}>
                    {selectedData?.value}%
                  </Text>
                  <Text style={{fontSize: 14, color: 'white'}}>
                    {selectedData?.text}
                  </Text>
                </View>
              );
            }}
            // onPress={handlePieChartItemPress}
          />
        </View>
        {renderLegendComponent()}
      </View>
    </View>
  );
};

export default ReportCreditLineGraphicScreen;

The output of the above code is-

pieFocus.mov

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants