plouc / nivo

nivo provides a rich set of dataviz components, built on top of the awesome d3 and React libraries
https://nivo.rocks
MIT License
13.08k stars 1.02k forks source link

max width for a column (Bar chart) #315

Closed zhe1ka closed 5 years ago

zhe1ka commented 5 years ago

hey, first of all, thanks for a great library :)

I create a chart bar dynamically and I don't know how many exactly there will be columns inside. This rage can be from 1 till 20. When there are 20 columns - it looks good but when there are only 1 or 2 - it doesn't look good. is it possible to have a maxWidth for columns? in docs I only found width for the whole chart which doesn't suit for my case. Thanks)

rpearce commented 5 years ago

One thing that might help is the padding option, which can be a value between 0 and 1. Try padding={0.7}!

plouc commented 5 years ago

Sorry but I won't add this option to the API, someone also opened an issue asking for minWidth :), but IMO padding is sufficient and you can adjust its value depending on number of bars, another (radical) option is to use a custom component for bars.

corneliusellen commented 5 years ago

@plouc I'm adding my plus one to adding bar width to the API. It would be really great to see this feature so we wouldn't have to create an entire custom bar component. In my case, adjusting the padding is not a good solution because I want more space in between the bars without making them thinner.

jeanfrancois8512 commented 3 years ago

@plouc What is the formula to calculate the padding value if I want my bar to always have a fixed widht of 22px ?

kamilms21 commented 3 years ago

@plouc What is the formula to calculate the padding value if I want my bar to always have a fixed widht of 22px ?

Did you find solution?

jeanfrancois8512 commented 3 years ago

Yes, I use an other library.

Le lun. 16 août 2021 15 h 59, Kamil Kowalczyk @.***> a écrit :

@plouc https://github.com/plouc What is the formula to calculate the padding value if I want my bar to always have a fixed widht of 22px ?

Did you find solution?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/plouc/nivo/issues/315#issuecomment-899744433, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEOLNK5ZZE3W65CZ3DBLLVLT5FNYHANCNFSM4F4NTKJQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

luanmm commented 2 years ago

Sorry but I won't add this option to the API, someone also opened an issue asking for minWidth :), but IMO padding is sufficient and you can adjust its value depending on number of bars, another (radical) option is to use a custom component for bars.

In my case, it was a rule from UX/UI team, but there are indeed some use-cases that justify creating a "maxWidth" prop for bar charts (the "minWidth" I couldn't see the point to be honest).

If anyone may need something like that, this is the way I could achieve it:

const BAR_MAX_WIDTH = 12;

const CustomBarComponent = ({ bar: { x, y, width, height, color } }) => {
  const w = width > BAR_MAX_WIDTH ? BAR_MAX_WIDTH : width;

  return (
    <rect 
      x={x + width / 2 - w / 2} 
      y={y} 
      width={w} 
      height={height} 
      rx={Math.min(w, height) / 2} 
      fill={color} />
  );
};

And, of course, reference it in the chart component:

    <ResponsiveBar
      barComponent={CustomBarComponent}
      ...
      />

It doesn't seem to be a complicated thing to add in the library (it may be just one line like the "w" variable calculation in my example) and there are use cases for it (sometimes by UX rules, or because we have a responsive chart changing with window resize, or because we have a dynamic number of columns and the padding option is not so trivial to calculate, and so on).

My workaround (or any need for custom components) is not a great solution, because, besides the working result, it messes up with standard behaviors (like animation).

IMHO the issue should be reopened and this option should be considered for this library.

Anyway, thanks for all the efforts regarding this library. It is a great work that the collaborators have done.

bradlocking commented 1 year ago

Hey all - thought i'd pop a small custom solution to supporting max-width's on bars for really simple charts. We initially went for the solution that @luanmm offered, though we also needed the max-width alongside the ability to enable default tooltips when interacting with the bar itself. nivo's BarItem component has all of that logic baked in, so used it, and modified the properties powering the width of the bar as overrides.

const CustomBarComponent = <RawDatum extends BarDatum>(props: Props<RawDatum>) => {
    const {
        bar: { data, ...bar },
        style,
    } = props;

    const w = Math.min(bar.width, BAR_MAX_WIDTH);
    const x = bar.x + bar.width / 2 - w / 2;

    const [spring, setSpring] = useSpring(() => ({
        width: w,
        transform: `translate(${x}, ${bar.y})`,
    }));

    useEffect(() => {
        setSpring({ width: w, transform: `translate(${x}, ${bar.y})` });
    }, [w, setSpring, x, bar]);

    return <BarItem {...props} bar={{ ...bar, data, x, width: w }} style={{ ...style, ...spring }} />;
};

Setting the width with this approach wasn't the only thing to worry about - as we also needed to make sure the bar is positioned correctly, so using react-spring to translate the bar itself allowed that to happen.

meessour commented 1 year ago

Hey all - thought i'd pop a small custom solution to supporting max-width's on bars for really simple charts. We initially went for the solution that @luanmm offered, though we also needed the max-width alongside the ability to enable default tooltips when interacting with the bar itself. nivo's BarItem component has all of that logic baked in, so used it, and modified the properties powering the width of the bar as overrides.

const CustomBarComponent = <RawDatum extends BarDatum>(props: Props<RawDatum>) => {
    const {
        bar: { data, ...bar },
        style,
    } = props;

    const w = Math.min(bar.width, BAR_MAX_WIDTH);
    const x = bar.x + bar.width / 2 - w / 2;

    const [spring, setSpring] = useSpring(() => ({
        width: w,
        transform: `translate(${x}, ${bar.y})`,
    }));

    useEffect(() => {
        setSpring({ width: w, transform: `translate(${x}, ${bar.y})` });
    }, [w, setSpring, x, bar]);

    return <BarItem {...props} bar={{ ...bar, data, x, width: w }} style={{ ...style, ...spring }} />;
};

Setting the width with this approach wasn't the only thing to worry about - as we also needed to make sure the bar is positioned correctly, so using react-spring to translate the bar itself allowed that to happen.

If you have a misplaced label inside the bar component you might also want to add labelX to the useSpring function like this:

const [spring, setSpring] = useSpring(() => ({
    width: w,
    labelX: w / 2,
    transform: `translate(${x}, ${bar.y})`,
}));

useEffect(() => {
    setSpring({ width: w, labelX: w / 2, transform: `translate(${x}, ${bar.y})` });
}, [w, setSpring, x, bar]);

I also experienced some weird animations when dynamically changing the graph content, I had to add animate={false} to ResponsiveBar

joshi-sanjay commented 1 year ago

@plouc any formula to calculate the padding dynamically to keep the bar width fixed?

meessour commented 1 year ago

@plouc any formula to calculate the padding dynamically to keep the bar width fixed?

Or how this can be achieved when using the Canvas version of the bar chart

plouc commented 1 year ago

I don't have a formula for this, but maybe looking at the d3 example could help defining one: https://observablehq.com/@d3/d3-scaleband.

yairEO commented 2 weeks ago

@plouc - I beg you to reconsider your verdict of closing this issue. I implore you.

I am also a maintainer of many open-source web components and know how it is like when people ask you for features but this is really basic.

Designers provide us developers with designs for constant bars widths - no matter the number of bars, either 1 or 2 bars or 50. doesn't matter. The UI is what the design departments dictates their desires and it's not such a big deal.

Below screenshot is from the design needs for my client and I don't want to disappoint my client by saying it cannot be done:

image

I cannot use padding because this is not a serious solution when the data can be anything from a few bars to many, while the total width of the chart remains the same (many charts on the same page using the same width and should have the same bar's width)

I am begging you to please give this a second thought....🙏