I'm trying to find a way to interpolate color, particularly fill for an SVG. I had no luck with hex codes, so I moved to a consistent rgb() value, but am finding that though the integer changes, it doesn't interpolate. What's do you recommend as best practice for animating color?
Here's a reduced test case:
http://codepen.io/sdras/pen/a25064109af93ebc8b3d17b9755583ae?editors=1010
Thanks!
Sarah
@sdras The color does not interpolate because rgb() requires integer values from 0 to 255, but the spring is high-precision and generates decimals with floating point, for example 49.91165769112001 -- only the initial and the final states are integers (50 and 34), that's why the first and last colors are rendered properly.
The best practice is to make a separate spring for color, from 0 to 1, and use it as a parameter for the color interpolation.
<Motion style={{
fill: spring(this.state.open ? 50 : 34),
rotate: spring(this.state.open ? 0 : 180),
color: spring(this.state.open ? 0 : 1),
}}>
{({ fill, rotate, color }) => {
const rgba = {
r: Math.round(color * 255),
g: Math.round(color * 255),
b: Math.round(color * 255),
a: 1.0,
};
return (
<svg viewBox="0 0 803.9 738.1" aria-labelledby="title">
<title>React-Motion</title>
<polygon
style={{
WebkitTransform: `rotate(${rotate}deg)`,
transform: `rotate(${rotate}deg)`,
fill: `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`,
opacity: 1.0, // The `cls-4` puts `opacity` style, the override is for `rgba` example purposes.
}}
className="cls-4" points="406.4 16 644.8 428.9 168 428.9 406.4 16" />
</svg>
);
}}
</Motion>
For more complex color manipulation, a library such as https://www.npmjs.com/package/color might be useful.
@sdras rgb(${Math.round(fill)}, ${Math.round(fill)}, ${Math.round(fill)}) -- but it will be difficult to see the difference between 34 and 50... try cranking one up to 255 to be sure it's working.
@sompylasar thanks! that makes great sense. I'll do that.
Do you think it might be good to have color interpolation, such as hex values, added as a feature? Maybe it's something I can work on to contribute.
@sdras I don't think there is a place for color interpolation in the react-motion core. Node modules should generally go Unix-way: do one thing and do it well.
It's not so hard to interpolate a composite value such as RGB color given a single 0.0 -> 1.0 parameter, _there is even a module specifically for that_ (https://github.com/miguelmota/interpolate-rgb).
Probably, there should be some short "how-to" on interpolation of arbitrary values, including colors, in the README of react-motion, with a reference to https://en.wikipedia.org/wiki/Linear_interpolation (and to other kinds of interpolation, if needed).
@chenglou, the author, might have another opinion.
@sdras you can make an own module with react-motion dependency.
It is not hard to interpolate colors, but it is always good to have one stable implemented solution and use it when needed without re-implementation. So I think a module for color interpolation and something like awesome-react-motion page with list of all useful stuff for react-motion is the best solution.
Where can I find more info on the best way to animate colors with react-motion?
React motion does not operate "style" (I agree that is a misleading name for prop). It only applies function over any number you pass. This way it can stay minimal and you have all power to interpolate any number-related values.
<Motion defaultStyle={{whatever: 0}} style={{whatever: spring(1)}}>
{({whatever}) => (
<div style={{color: `rgb(${255 * whatever}, ${255 * whatever}, ${255 * whatever})`}}>
Hey, I'm transitioning color!
</div>
)}
</Motion>
Use Motion as the way to manipulate number and then use that number to derive any other numeric value.
PS: sigh, I wish prop would not be called as style to avoid ~100000 opened issues similar to this one.
Added generic issue to cover this in README #494