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

Support multi-stop gradients for track and progress #23

Open
jlarmstrongiv opened this issue Nov 23, 2020 · 4 comments
Open

Support multi-stop gradients for track and progress #23

jlarmstrongiv opened this issue Nov 23, 2020 · 4 comments

Comments

@jlarmstrongiv
Copy link

jlarmstrongiv commented Nov 23, 2020

I love how smooth this implementation of a circular slider is! My end goal is to create a hue slider for a color picker.

Luckily, svg stop-color accepts transparent as a value. Translucent colors with stop-opacity are not currently supported as props in this library.

The main problem is the trackColor, which is eventually passed down to the svg circle as stroke={trackColor}. Unfortunately, the stroke does not support the css gradient syntax. Instead, it requires a linearGradient definition within the svg. The current implementation of the progress bar supports two color gradients, but not the near infinite (~360) multi-color gradient needed for the color picker.

I think it would be great to upgrade the stroke of the trackColor and the progress bar at the same time. I noticed this library prides itself on having zero dependencies; otherwise, I would suggest parsing colors via tinycolor.

I think it would be great to have a new color and gradient syntax for the trackColor and the progress bar. Perhaps a syntax like:

const example = (
  <CircularSlider
    trackColor="#eeeeee"
    progressGradient={[
      "#ffb347",
      {
        offset: '100%',
        stopColor: "#ffcc33",
        stopOpacity: 0.5,
      },
    ]}
  />
);

Implemented like:

const createColorStops = (color, index, colors) => {
  if (typeof color === "string") {
    color = { stopColor: color };
  }
  let { offset, stopColor, stopOpacity } = color;

  if (index === 0) {
    return (
      <stop
        offset={offset ?? `0%`}
        stopColor={stopColor}
        stopOpacity={stopOpacity ?? 1}
      />
    );
  } else if (index === gradients.length - 1) {
    return (
      <stop
        offset={offset ?? `100%`}
        stopColor={stopColor}
        stopOpacity={stopOpacity ?? 1}
      />
    );
  } else {
    return (
      <stop
        offset={offset ?? `${(100 / (gradients.length - 1)) * index}%`}
        stopColor={stopColor}
        stopOpacity={stopOpacity ?? 1}
      />
    );
  }
};

const svg = (props) => {
  const {
    label,
    trackGradient, 
    progressGradient, 
    trackColor, 
    progressColor, 
  } = props;

  let defs;
  if (trackGradient || progressGradient) {
    defs = (
      <defs>
        {trackGradient && (
          <linearGradient id={`${label}-track`} x1="100%" x2="0%">
            {trackGradient.map(createColorStops)}
          </linearGradient>
        )}
        {progressGradient && (
          <linearGradient id={`${label}-progress`} x1="100%" x2="0%">
            {progressGradient.map(createColorStops)}
          </linearGradient>
        )}
      </defs>
    );
  }

  return (
    <svg>
      {defs}
      <circle stroke={trackColor || `url(#${label}-track)`} />
      <path stroke={progressColor || `url(#${label}-progress)`} />
    </svg>
  );
};

My only other comment on the implementation is that we could cache the defs with React.useMemo, since we don’t need to recalculate that on every input change.

Of course, changing the syntax would probably mean a major version bump. If you’re okay with that, I could formalize a pull request. Anyway, thanks for this awesome library!

TODO: references

@fseehawer
Copy link
Owner

Hi @jlarmstrongiv, I always appreciate it when someone contributes to my library. You are welcomed to create a PR. Thanks!

@dev2-piniada
Copy link

progressGradient

@jlarmstrongiv hi do you have working sample for multi stops

@jlarmstrongiv
Copy link
Author

@dev2-piniada The example code above should work for multiple color stops. Unfortunately, my project ended up going in a different direction and I was unable to finish a PR for it.

@monecchi
Copy link

monecchi commented May 30, 2022

That would be a great feature! I was hoping I could mimic a kelvin color temperature gradient, but now I see this is not yet implemented... Awesome Circular Slider by the way!

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

4 participants