Framer Motion length transition on SVG line - reactjs

So if I know that I can transition an svg path with something like the below:
const pathVariants = {
inital: {
opacity: 0,
pathLength: 0
},
final: {
opacity: 1,
pathLength: 1,
transition: {
duration: 2,
ease: "easeInOut"
}
}
};
//...
<motion.path
variants={pathVariants}
/>
but I can't seem to get the syntax for a motion.line. I tried lineLength instead of pathLength, but that didn't seem to work. Thoughts?

looks like there is a workaround like so:
const lineVariants = {
animate: {
strokeDashoffset: 0,
transition: {
duration: 1
}
},
initial: {
strokeDashoffset: 100
}
};
//...
<motion.line
variants={lineVariants}
animate="animate"
initial="initial"
x1={lineX1}
y1={lineY1}
x2={lineX2}
y2={lineY2}
strokeWidth={stroke}
pathLength="100"
strokeDasharray="100"
/>

Related

Why framer-motion does not animate array of items, like single items?

I'm using framer-motion to animate a list.
I want items to slide from left, one by one.
Following the docs, I can animate the items one by one, when they are single, but not when mapping through an array.
const items = ["one", "two", "three"];
function App() {
const list = {
visible: {
opacity: 1,
transition: {
when: "beforeChildren",
staggerChildren: 0.3,
},
},
hidden: {
opacity: 0,
transition: {
when: "afterChildren",
},
},
};
const item = {
visible: { opacity: 1, x: 0 },
hidden: {
opacity: 0,
x: "-100vw",
},
};
return (
<motion.ul initial="hidden" animate="visible" variants={list}>
// This does not work as expected.
{items.map((item, i) => (
<motion.li variants={item}>{i}</motion.li>
))}
// This works fine!
<motion.li variants={item}>item</motion.li>
<motion.li variants={item}>item</motion.li>
<motion.li variants={item}>item</motion.li>
</motion.ul>
);
}
What am I doing wrong?
What is the way of using staggerChildren: 0.3, in an array?
Thanks
I've found a way!
Credits to Leigh
const items = ["one", "two", "three"];
function App() {
const itemVariants = {
initial: { x: "-100vw", opacity: 0 },
animate: { x: 0, opacity: 1 },
};
return (
<ul>
{items.map((item, i) => (
<motion.li
variants={itemVariants}
initial="initial"
animate="animate"
transition={{ duration: 0.3, delay: i * 0.8 }}>
{i}
</motion.li>
))}
</ul>
);
}

"Unsafe assignment of an any value" when using react-transition-group with TypeScript

I have various #typescript-eslint errors when using the Transition component from react-transition-group.
I followed the official React Transition Group small example for JS but with TypeScript + ESLint on my project I'm getting the following error: Unsafe assignment of an any value.
Another related error which is element implicitly has an 'any' type because expression of type 'string' can't be used to index type.
const transition = {
transitionStyles: {
entering: { opacity: 0, transform: 'translateX(0rem)' },
entered: { opacity: 1, transform: 'translateX(0rem)' },
exiting: { opacity: 1, transform: 'translateX(2rem)' },
exited: { opacity: 0, transform: 'translateX(-2rem)' },
unmounted: { opacity: 0, transform: 'translateX(-2rem)' },
} as { [key: string]: React.CSSProperties },
};
<Transition in timeout={700}>
{(state) => (
<div style={{ ...transition.transitionStyles[state] }}>
/* ... */
</div>
)}
</Transition>
You need to cast the state variable as a string, because it's by default a TransitionStatus (declared from react-transition-group):
{(state: string) => (
<div style={{ ...transition.transitionStyles[state] }}>
/* ... */
</div>
)}
Then proceed to cast the transitionStyles any object into a typed object, which returns for each key a React.CSSProperties object. This can be done like this:
const transition = {
transitionStyles: {
entering: { opacity: 0, transform: 'translateX(0rem)' },
entered: { opacity: 1, transform: 'translateX(0rem)' },
exiting: { opacity: 1, transform: 'translateX(2rem)' },
exited: { opacity: 0, transform: 'translateX(-2rem)' },
unmounted: { opacity: 0, transform: 'translateX(-2rem)' },
} as { [key: string]: React.CSSProperties }
};

Animation using react-spring interpolate function not working

I am trying to understand how the react-spring interpolation works.
Here is my spring:
const { x } = useSpring({ from: { x: 0 }, x: 100, config: { duration: 1000 } })
Here is how I am using it:
...
return (
<animated.div style={{
background: "lightblue",
height: "100%",
width: x.interpolate([0, 0.5, 1], [0, 100, 0]).interpolate(x => `${x}%`)
}} />
)
The interpolation happens but it is not rendered.
Here is a sandbox:
https://codesandbox.io/s/amazing-panini-fzn54?fontsize=14&hidenavigation=1&theme=dark
Can you help me figure out what's wrong with this code?
It is almost there. If you want to use range, in the interpolation from [0, 0.5, 1] to [0, 100, 0] Then you should change the x value between 0 and 1.
So I would change this part:
const { x } = useSpring({ from: { x: 0 }, x: 1, config: { duration: 1000 } })
I also fixed the codesandbox, but it is a little different it uses the renderprops api.
https://codesandbox.io/s/tender-varahamihira-6nic7?file=/src/App.js:63-123

add additional style if iPhoneX

I have a helper function is.iphone('x') to check for iphone x and I want some styles to get added to the styles.icon and styles.textContainer and styles.container if true. This needs to happen inside the render method. However, when I try to run my code:
const styles = {
addToCartButton: {
borderRadius: 0,
width: windowWidth,
},
container: {
overflow: 'hidden',
},
innerContainer: {
width: 2 * windowWidth,
flexDirection: 'row',
},
checkoutButton: {
borderRadius: 0,
width: windowWidth,
},
icon: {
backgroundColor: accentColor,
},
textContainer: {},
}
export class CartButton extends Component {
checkoutButtonColor = new Animated.Value(3)
xOffset = new Animated.Value(-windowWidth)
dynamicStyles = {
transform: [ { translateX: this.xOffset } ],
}
checkoutDynamicStyles = {
backgroundColor: this.checkoutButtonColor.interpolate({
inputRange: [ 0, 3 ],
outputRange: [ color('b'), accentColor ],
}),
}
animate = () => {
Animated.sequence([
Animated.timing(this.xOffset, {
toValue: 0,
duration: 500,
useNativeDriver: true,
}),
Animated.timing(this.checkoutButtonColor, {
toValue: 0,
duration: 250,
userNativeDriver: true,
}),
]).start()
}
)
}
render () {
if (is.iphone('x')) {
styles.icon.paddingBottom = spacing
styles.textContainer.paddingBottom = spacing
styles.container.marginBottom = spacingSizes.large
}
return (
<View style={styles.container}>
<Animated.View style={[ styles.innerContainer, this.dynamicStyles ]}>
{this.renderCheckout()}
{this.renderAddToCart()}
</Animated.View>
</View>
)
}
}
I get the error "you are attempting to set Key 'paddingBottom' with value '14' (spacing =14) on an object that is meant to be immutable and has been frozen. How to do this any suggestions?
Update your code and replace style={styles.container} by style={[styles.container, is.iphone('x') ? { marginBottom: spacing } : {}]} and do the same where you use the icon style.

Gauge Series of Highcharts with React not the Solid Gauge but Gauge Series

https://www.highcharts.com/demo/gauge-speedometer
Need this chart in React. Implemented Solid Gauge but was not able to implement this Gauge Series.
Here is the Sandbox for reference where the Solid Gauge is working but not series graph. Uncommenting the GaugeSeries leads to tooltip of null error.
https://codesandbox.io/s/38rk6wvnrq
Your plotOptions should be part of chart options in
<HighchartsChart
chart=
I suggest changing the name of the variable, so it will not be misleading - e.g. to chartOptions.
Second, and the most important problem is caused by a typo - series type is gauge and not guage the:
<Series id="series" name="Value" data={[80]} type="guage" />
Based on the code:
import React, { Component } from "react";
import Highcharts from "highcharts";
require("highcharts/highcharts-more")(Highcharts);
require("highcharts/modules/exporting")(Highcharts);
import {
HighchartsChart,
withHighcharts,
Series,
XAxis,
YAxis,
Tooltip
} from "react-jsx-highcharts";
const plotOptions = {
plotBackgroundColor: null,
plotBackgroundImage: null,
plotBorderWidth: 0,
plotShadow: false
};
const paneOptions = {
startAngle: -120,
endAngle: 120,
background: [
{
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [[0, "#FFF"], [1, "#333"]]
},
borderWidth: 0,
outerRadius: "109%"
},
{
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [[0, "#333"], [1, "#FFF"]]
},
borderWidth: 1,
outerRadius: "107%"
},
{
backgroundColor: "#DDD",
borderWidth: 0,
outerRadius: "105%",
innerRadius: "103%"
}
]
};
const GraphRender = ({ data }) => {
return (
<div className="gauge-empty">
<div className="no-data">Data Unavaialble</div>
<HighchartsChart
chart={{ type: "gauge" }}
plotOptions={plotOptions}
pane={paneOptions}
>
<Tooltip padding={10} hideDelay={250} shape="square" />
<XAxis />
<YAxis
id="myAxis"
min={0}
max={100}
minorTickInterval="auto"
minorTickWidth={1}
minorTickLength={10}
minorTickPosition="inside"
minorTickColor="#666"
tickPixelInterval={30}
tickWidth={2}
tickPosition="inside"
tickLength={10}
tickColor="#666"
labels={{
step: 2,
rotation: "auto"
}}
title={{
text: ""
}}
plotBands={[
{
from: 0,
to: 60,
color: "#55BF3B" // green
},
{
from: 60,
to: 80,
color: "#DDDF0D" // yellow
},
{
from: 80,
to: 100,
color: "#DF5353" // red
}
]}
>
<Series id="series" name="Value" data={[80]} type="guage" />
</YAxis>
</HighchartsChart>
</div>
);
};
const Gauge = ({ data }) => <GraphRender data={data} />;
export default withHighcharts(Gauge, Highcharts);
(I have not resolved the problem with the chart option - you can move the options into the correct place if you want them to work. I'm not sure if you want them or if those were set only for the demo purpose)

Resources