Why does Scrolltrigger not update my dynamically x value on window resize? - window

First things first. I absolutely love GSAP and their Scrolltrigger. Everything works fine, but unfortunately, the object I move on the x-axis based on scroll does not update when the user resizes his browser window.'
The x value is based on a formula I wrote.
Here is a part of the function later added in a master timeline with matchMedia Scrolltrigger:
var seoShowBenefitsTl = gsap.timeline();
seoShowBenefitsTl.addLabel("first Benefit")
.to(".anim-screen-item-0", {opacity: 0, duration: 0.5}, "first Benefit")
.to(seoATFHardware, {x: () => (document.documentElement.clientWidth - seoATFHardware.clientWidth) / 2 + calculateOffsetToElement(document.querySelector('.anim-point-item.--revenue'), 120, "right"), duration: 1, ease: Power3.in, onUpdate: function() {
if (this.progress() >= 0.5) {
document.querySelector('.anim-screen-item.--revenue').classList.add("js-screen-item-engaged");
document.querySelector('.anim-point-item.--revenue').classList.add("js-point-item-engaged");
} else {
document.querySelector('.anim-screen-item.--revenue').classList.remove("js-screen-item-engaged");
document.querySelector('.anim-point-item.--revenue').classList.remove("js-point-item-engaged");
}
}}, "first Benefit")
//some more code
return seoShowBenefitsTl
Thank you so much in advance!

Make sure you add the actual tween to the ScrollTrigger timeline, not a timeline. This helps making sure the values get update easier because of the following point.
Use invalidateOnRefresh: true on the ScrollTrigger timeline.
Doing those things results in this demo.

Related

Framer motion complex scroll animation

Hello everyone I'm trying to make a complex animation And I'm new to the framer motion so I need help if it's possible.
I'm trying to do this animation
all the animation will be revealed when scrolling but I don't Know How?
I tried this example but I think it will not take me any where example
So, Any clue please?
Thanks in advance.
i think useAnimationControls will help, but i think there is another better solution or another way, but any way i wish this help you here is the documentation, it says that it returns a promise (and also can be used in async function with await).
like the following code:
import { useAnimationControls, motion } from "framer-motion"
export default function App() {
let controls = useAnimationControls()
controls
.start({
opacity: 1,
backgroundColor: "red",
color: "white",
})
.then(() =>
controls.start({
color: "black",
backgroundColor: "lightgreen",
x: -100,
})
)
.then(() => {
controls.start({
opacity: 0,
x: 100,
})
})
return (
<>
<motion.div initial={{ opacity: 0 }} animate={controls}>
hi there
</motion.div>
</>
)
}
the above code will do these things below respectively:
will increase the opacity to 1 and change the color & bg color
then it will change color & bg color again and change the x position
then will decrease the opacity to 0 and x position too
here is another animation library that is simple and also may be useful to use named animejs, and also they have a friend and non-boaring documentation you can check it here

Can I cause React Native's Switch component to animate when changing its state when not being directly pressed by the user?

In my React Native project I'm using the Switch component. It can be switched directly by pressing it, but I also want to let the user change it by pressing nearby related items.
It of course animates the switching when pressed, but when I changed its state using setState() it just jumps directly to the other position without animation.
Is there a way I can programmatically trigger the animation when changing its state from code?
(There is a question with a similar wording but it seems to be to an unrelated problem I can't quite work out.)
Depends a little on the approach you're taking, but I'd say your best bet is with Animated (which is part of React Native).
You can do something like this:
render(){
var animVal = new Animated.Value(0);
Animated.timing(animVal, {toValue: 1, duration: 300}).start();
var animatedViewStyles =
{
marginLeft: animVal.interpolate({
inputRange: [0, 1],
outputRange: this.state.switchOn ? [100, 0] : [0, 100],
}),
// add some other styles here
color: 'green'
};
}
return (
<Animated.View style={animatedViewStyles}>
<TouchableHighlight onPress(() => this.setState({switchOn: !this.state.switchOn}))><Text>This is my switch</Text></TouchableHighlight>
</Animated.View>
);
See the docs https://facebook.github.io/react-native/docs/animated.html for more info.

Hammer.js breaks vertical scroll when horizontal pan

I'm using Hammer.js to look for horizontal pan gestures, I've devised a simple function to clicks a button when panned left or right. It works okay, except the vertical scroll doesn't do anything on a touch device, or it's really glitchy and weird.
Here's the function:
var panelSliderPan = function() {
// Pan options
myOptions = {
// possible option
};
var myElement = document.querySelector('.scroll__inner'),
mc = new Hammer.Manager(myElement);
mc.add(new Hammer.Pan(myOptions));
// Pan control
var panIt = function(e) {
// I'm checking the direction here, my common sense says it shouldn't
// affect the vertical gestures, but it blocks them somehow
// 2 means it's left pan
if (e.direction === 2) {
$('.controls__btn--next').click();
// 4 == right
} else if (e.direction === 4) {
$('.controls__btn--prev').click();
}
};
// Call it
mc.on("panstart", function(e) {
panIt(e);
});
};
I've tried to add a horizontal direction to the recognizer but it didn't really help (not sure if I did it even right):
mc = new Hammer.Manager(myElement, {
recognizers: [
[Hammer.Pan,{ direction: Hammer.DIRECTION_HORIZONTAL }],
]
});
Thanks!
Try setting the touch-action property to auto.
mc = new Hammer.Manager(myElement, {
touchAction: 'auto',
recognizers: [
[Hammer.Pan,{ direction: Hammer.DIRECTION_HORIZONTAL }],
]
});
From the hammer.js docs:
When you set the touchAction to auto it doesnt prevent any defaults, and Hammer would probably break. You have to call preventDefault manually to fix this. You should only use this if you know what you're doing.
User patforna is correct. You need to adjust the touch-action property. This will fix scrolling not working when you have hammer bound on a big element in mobile.
You create a Hammer instance like so
var h = new Hammer(options.contentEl, {
touchAction : 'auto'
});
I was working on a pull to refresh feature, so I need the pan event.
Add the recognizers.
h.get( 'pan' ).set({
direction : Hammer.DIRECTION_VERTICAL,
});
h.on('panstart pandown panup panend', eventHandler);
Inside the eventhandler, you'd look at the event that was triggered and manually call on event.preventDefault() when you require it. This is applicable for hammer 2.0.6.
For anyone who's looking the pull to refresh code was taken from - https://github.com/apeatling/web-pull-to-refresh
My problem was that vertical scroll was toggling a sidebar that was supposed to show/hide on horizontal pan/swipe. After looking at the event details, I realized that Hammer probably triggers panleft and panright event based on X delta and doesn't consider Y delta, so my quick solution was to check the pan direction in my handler:
this.$data.$hammer.on('panleft', (e) => {
if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
return;
}
this.isVisible = true;
});
I was stuck on this for several days. Hope this will fix your problem.
mc = new Hammer(myElement, {
inputClass: Hammer.SUPPORT_POINTER_EVENTS ? Hammer.PointerEventInput : Hammer.TouchInput,
touchAction: 'auto',
});
When the relevant gesture is triggered, we applied a css class to the element, that would set the touch-action to none.
mc.on('panmove panstart', event => {
mc.addClass('is-dragging');
}
);
.is-dragging {
touch-action: none !important;
}
Hammer 2.x does not support vertical swipe/pan. Documentation says:
Notes:
When calling Hammer() to create a simple instance, the pan and swipe recognizers are configured to only detect horizontal gestures
You can however use older 1.1.x version, which supports vertical gestures
——
Clarification: this refers to a ‘simple instance’ which is when you don’t pass in any recognizer configuration as the second parameter. In other words these are the defaults but can (and usually should) be overridden.

KineticJS : get image array id

Here is the problem :
I have a canvas, and four (would be more in future, but 4 for testing...anyway, doesn't matter) images that can be "poped" into the canvas by clicking on it.
Each image can be present multiple times in the canvas.
So far, poping is working fine, images are draggable... But I can't add some resize or zIndex function as I can only select the last image add to the canvas.
In a ideal world, I would like, by clicking/dragging an image, put it on top of the canvas, and kinda "select" it, so that I can connect the resize functions to the image.
But with the array of images, I can't manage to identify properly the item dragged, and can't use (or don't manage to use) the selectors.
Thank you.
EDIT : some code
var imgCpt = 0;
var image = [];
function addDetails(img) {
imgCpt++;
var imageObj = new Image();
imageObj.onload = function() {
image[imgCpt] = new Kinetic.Image({
x: 0,
y: 0,
image: imageObj,
draggable: true,
id:image[imgCpt]
});
image[imgCpt].setX((stage.getWidth()/2) - (image[imgCpt].getWidth()/2));
image[imgCpt].setY((stage.getHeight()/2) - (image[imgCpt].getHeight()/2));
eval(image[imgCpt]).on('click', function() {
alert(eval(imgCpt));
});
layer.add(image[imgCpt]);
stage.add(layer);
};
imageObj.src = 'uploads/'+img;
}
I've already tried different solutions : multiple layer, and acting on it instead of acting on image, working with shapes filled with image instead of image, but it's always the same problem : I can't get the id of the concerned element (instead of the id of the last insert element)
This version works with array, but I tried yersterday to build the image id with eval(); without more success.
Thank you for your help
EDIT² : sorry to insist, but I would really be glad to have some assistance on this point, even if I think it's more JS related than pure KineticJS related.
Thank you.
Ok Guys, just solved the problem :
eval("image["+imgCpt+"].on('click', function() {alert("+imgCpt+");});");
Instead of :
eval(image[imgCpt]).on('click', function() {
alert(eval(imgCpt));
});
Now time to set a true action behind the click.
Thank you for helping ;)

g.raphael bar chart and updating/animating the values

I'm working on some bar charts and need to update the chart values. The only way I've found to do this is to redraw the whole thing. Isn't there a way to simple update the bars? And if so what I'm really hoping to do is animate that change. Any suggestions?
http://jsfiddle.net/circlecube/MVwwq/
Here's what you want (updated Fiddle).
You were on the right track for creating a new bar chart. The only issue is, you don't want to "display" that bar chart, but you want to use its bars for animation. While this does generate a new graph which we later throw away (using remove()), it seems to be Raphael best practice.
function b_animate(){
//First, create a new bar chart
var c2 = bars.g.barchart(200, 0, 300, 400, [bdata], {stacked: false, colors:["#999","#333","#666"]});
//Then for each bar in our chart (c), animate to our new chart's path (c2)
$.each(c.bars[0], function(k, v) {
v.animate({ path: c2.bars[0][k].attr("path") }, 200);
v.value[0] = bdata[k][0];
});
//Now remove the new chart
c2.remove();
}
This is not complete, as we haven't animated the legends to match the new chart, but this technique applied to the labels should get you there. Basically, we need to re-map the hovers to show new labels (and remove the old labels).
Hopefully, this should work exactly like you hoped. Let me know if you have any issues. Enjoy!
I had to adapt the above code to get this to work with Raphaël 2.1.0 and g.Raphael 0.51 and JQuery 1.9.1:
function b_animate(){
var c2 = bars.barchart(10, 10, 500, 450, bdata, { colors:custom_colors});
$.each(c.bars, function(k, v) {
v.animate({ path: c2.bars[k][0].attr("path") }, 500);
v[0].value = bdata[k][0];
});
c2.remove();}
Hope this helps!

Resources