primefaces / primereact

The Most Complete React UI Component Library
https://primereact.org
MIT License
6.99k stars 1.06k forks source link

MeterGroup: Percentages always based on max 100 #6610

Closed Tubbbe closed 6 months ago

Tubbbe commented 6 months ago

Describe the bug

Hello, I've seen a strange behavior on MeterGroup, when I have a single item, or several items, the calculated percentage is never correct. I have the impression that it's always based on a max=100, and varying the max property has no impact on the percentage value. See my link for several examples

Reproducer

https://stackblitz.com/edit/vitejs-vite-3fc5kp?file=src%2FApp.tsx

PrimeReact version

10.6.5

React version

17.x

Language

TypeScript

Build / Runtime

Create React App (CRA)

Browser(s)

Firefox 125.0.3 ; Brave 1.65.123

Steps to reproduce the behavior

  1. Add a MeterGroup <MeterGroup values={[{ label: 'Red', value: 100, color: 'red' }]} max={200} />
  2. You'll see the progressbar is correct, but not the percentage
  3. You can add several values

Expected behavior

The percentages may be based on the max property : MeterGroupValue::value / MeterGroupBase::max You can see my examples on the link above

melloware commented 6 months ago

Here is the code it looks like it uses Max differently than we think?

    let totalPercent = 0;
    let precentages = [];

    values.map((item) => {
        totalPercent = totalPercent + item.value;
        precentages.push(Math.round((item.value / totalPercent) * 100));
    });

    const calculatePercentage = (meterValue = 0) => {
        const percentageOfItem = ((meterValue - min) / (max - min)) * 100;

        return Math.round(Math.max(0, Math.min(100, percentageOfItem)));
    };
Tubbbe commented 6 months ago

Hello,

This code calculating percentages is correct.

Currently, the code displaying the value label is (MeterGroup.js line 130):

return (
    <li key={index} {...labelItemProps}>
        {labelIcon}
        <span {...labelProps}>
            {item?.label} {item?.value && `(${item?.value}%)`}
        </span>
    </li>
);

As you can see, value is always displayed as a percentage, which is irrelevant. So I tried changing it to this, and it works with my examples:

const calculatedPercantage = calculatePercentage(item.value);

return (
    <li key={index} {...labelItemProps}>
        {labelIcon}
        <span {...labelProps}>
            {item?.label} {`(${calculatedPercantage}%)`}
        </span>
    </li>
);

I don't know if it's the right fix, but it seems to give the right result.

melloware commented 6 months ago

@Tubbbe that is the correct fix and I submitted a PR. I checked PrimeVue and their code is doing what yours is.