Smooth swipe up animation (React Native Animation) - javascript

What do I expect to do:
A modal screen that you can close by swiping up.
Inside the modal I have:
componentWillMount() {
this.animated = new Animated.Value(0);
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderMove: (e, gestureState) => {
const { dy } = gestureState;
if(dy < 0) {
this.animated.setValue(dy);
}
},
onPanResponderRelease: (e, gestureState) => {
const { dy } = gestureState;
if(dy < -100) { // Swipe up away
Animated.timing(this.animated, {
toValue: -400,
duration: 150
}).start();
this.props.hideModal();
this.doSomething();
} else if(dy > -100 && dy < 0) { // Swipe back to initial position
Animated.timing(this.animated, {
toValue: 0,
duration: 150
}).start();
}
}
})
}
This Modal appears by clicking on a button in a parent component. By default in that parent there is a state value showModal : false. Opening the Modal this state is changed to true and when closing to false.
The main problem for now is that when you swipe for closing this Modal doesn't go up smoothly and disappear. It goes up to 100px, stops on a place and starts disappearing.
If remove this.props.hideModal() this Modal goes up to the top of a screen smoothly and disappears as I want, but it is not closed completely and you can not click on any other buttons after that.
Basically, I need to run this.props.hidModal() AFTER the animation has been finished.
How can I implement smooth closing of the Modal?
I hope I described my problem understandably.

If calling this.props.hideModal() after the animatiom is finished is the fix (which I believe it is) you could pass this as a callback to .start().
Animated.timing({..}).start(this.props.hideModal)

Related

Make useEffect only run when component is in view (i.e. scrolled down to that component)

i have this code that updates a number from 2019 to 2022 but i want it to only run when the component is in view, meaning if they haven't scrolled to that part of the page the effect shouldn't run
useEffect(() => {
setTimeout(() => {
setTitle(2020)
}, 2000)
setTimeout(() => {
setTitle(2021)
}, 4000)
setTimeout(() => {
setTitle(2022)
}, 6000)
}, []);
at the moment it updates the value even when you haven't scrolled down to that part of the page, is there a way to make useEffect only activate when scrolled to that section of the page or do you need to do it completely differently?
window.addEventListener('scroll', function() {
var element = document.querySelector('#main-container');
var position = element.getBoundingClientRect();
// checking whether fully visible
if(position.top >= 0 && position.bottom <= window.innerHeight) {
console.log('Element is fully visible in screen');
}
// checking for partial visibility
if(position.top < window.innerHeight && position.bottom >= 0) {
console.log('Element is partially visible in screen');
}
});
Snippet from https://usefulangle.com/post/113/javascript-detecting-element-visible-during-scroll. Paste your code to the part where an element is fully in view. Remember to query select the element you want to have in view first.

electron browser window animations

So, I try to animate browser window in electron app.
I try to use this code to do this:
const fadeWindowOut = (
browserWindowToFadeOut,
step = 0.1,
fadeEveryXSeconds = 10
) => {
let opacity = browserWindowToFadeOut.getOpacity();
const interval = setInterval(() => {
if (opacity <= 0) window.clearInterval(interval);
browserWindowToFadeOut.setOpacity(opacity);
opacity -= step;
}, fadeEveryXSeconds);
return interval;
}
It work's correctly but I can't handle user click to icon in the taskbar.
When user clicks to icon in the taskbar, window minimized or restored by default.
I can catch events 'minimize', but I can't prevent default and do my animation before default.
// it doesn't work
mainWin.on('minimize', async (event) => {
event.preventDefault();
await doMyAnimationHere();
mainWin.minimize();
});
So, how can I run my animation before default 'minimize' event?

How to render a self-destructing paragraph at mouse position in React?

I am trying to get a paragraph to appear at the location of the mouse coordinates, but self-destruct after 1 second.
$(function(){
var fadeDelay = 1000;
var fadeDuration = 1000;
$(document).click(function(e){
var div = $('<div class="image-wrapper">')
.css({
"left": e.pageX + 'px',
"top": e.pageY + 'px'
})
.append($('<img src="" alt="myimage" />'))
.appendTo(document.body);
setTimeout(function() {
div.addClass('fade-out');
setTimeout(function() { div.remove(); }, fadeDuration);
}, fadeDelay);
});
});
The code above is from a fiddle which represents the effect that I am looking for; however, it uses jQuery - while I am working with React.
I tried following this linear process:
1 - In the state, toggle a boolean with mouse clicks
playerAttack = () => {
this.setState({ hasPlayerAttacked: true })
}
2 - In a function, when the boolean is true, return a paragraph and set the boolean back to false
renderDamageDealtParagraph = () => {
if (this.state.hasPlayerAttacked) {
return <p>{this.state.playerAttack}</p>;
this.setState({ hasPlayerAttacked: false });
}
};
However, with this approach there were too many fallacies; main one being that upon resetting the boolean back to false, the rendered paragraph immediately disappears (instead of after a timeout of 1000ms).
What is the best wait to implement something like the linked fiddle, in ReactJS using vanilla JS?
Thanks in advance to whoever might be able to help.
You can basically do something like this:
Have state to track the mouse position x and y, and two booleans isShown and shouldHide to coordinate the disappering div
On click, show the div by setting isShown to true and immediately setTimeout to start hiding it in the future by adding a class by flipping the shouldHide to true
Once the class is added, the element will fade and will trigger the transitionend event at which point you can remove the div entirely by flipping the isShown to false and shouldHide to false boolean
Sample Implementation (Sorry for the shitty code, been a while since I React-ed)
JS Fiddle
class SelfDestructDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
x: 0,
y: 0,
isShown: false,
shouldHide: false
};
this.handleClick = this.handleClick.bind(this);
this.reset = this.reset.bind(this);
}
reset() {
this.setState({
x: 0,
y: 0,
isShown: false,
shouldHide: false
});
}
handleClick(event) {
if (this.state.isShown) {
return;
}
const { clientX, clientY } = event;
this.setState({
x: clientX,
y: clientY,
isShown: true,
shouldHide: false
});
setTimeout(() => {
this.setState({ shouldHide: true });
}, 1000);
}
render() {
const p = this.state.isShown && (
<div
onTransitionEnd={this.reset}
className={`${this.state.shouldHide ? "should-hide" : ""} modal`}
style={{ top: this.state.y, left: this.state.x }}
>
Self destructing....
</div>
);
return (
<div className="container" onClick={this.handleClick}>
{p}
</div>
);
}
}
ReactDOM.render(<SelfDestructDemo />, document.querySelector("#app"));

Handling Scroll in Reactjs

I'm building a React app, and one of the main features will be a full-screen title page. When the user scrolls on the title page, the page automatically scrolls down and the header bar sticks to the top. I do not want the body overflow hidden here, because as soon as I go to put the overflow back in, the scrollbar will appear and the whole page jolts left about 5px.
I've seen this feature a lot; it's pretty common for single-page web designs. However, I can't seem to get it right. I've gotten to a decent point where the app will scroll for you, but it always bugs out when I try to scroll in the middle of the automatic scroll. This is the closest I've gotten to a solution:
import React, {Component} from 'react';
import Scroll from 'react-scroll';
class Header extends Component {
constructor() {
super();
this.state = {
scrolling: false,
inLogo: false,
sticky: "",
lastScrollPos: 0
}
/* Must bind to access 'this' */
this.handleScroll = this.handleScroll.bind(this);
this.isScrollingDown = this.isScrollingDown.bind(this);
this.scroller = Scroll.animateScroll;
}
componentDidMount() {
window.addEventListener("scroll", this.handleScroll);
Scroll.Events.scrollEvent.register('end', function(to, element) {
this.state.scrolling = false;
if(!this.state.inLogo) {
this.setState({sticky: "sticky"});
}
}.bind(this));
if(window.pageYOffset < 150) {
this.state.inLogo = true;
this.scroller.scrollToTop();
} else {
this.state.inLogo = false;
this.scroller.scrollTo(window.innerHeight);
}
}
componentDidUpdate() {
if(this.state.scrolling) {
if(this.state.inLogo) {
this.scroller.scrollToTop();
} else {
this.scroller.scrollTo(window.innerHeight);
}
}
}
handleScroll(e) {
console.log(this.state.scrolling);
if(this.state.scrolling) {
return;
}
var scrollDown = this.isScrollingDown();
var inLogo = this.isInLogo();
if(inLogo) {
if(scrollDown) {
console.log("Scrolling down in logo");
this.setState({
scrolling: true,
inLogo: false
});
}
if(!scrollDown) {
console.log("Scrolling up in logo");
this.setState({
scrolling: true,
inLogo: true,
sticky: ""
});
}
}
}
isScrollingDown() {
var scrollingDown = window.pageYOffset > this.state.lastScrollPos;
this.state.lastScrollPos = window.pageYOffset;
return scrollingDown;
}
isInLogo() {
return window.pageYOffset > 150 && window.pageYOffset < window.innerHeight;
}
render() {
return (
<div id="app-header" className={"header "+this.state.sticky}>
<div className="header-filler"></div>
<button>Contact Us</button>
<button>First</button>
</div>
);
}
}
The problem here is that when you scroll in the middle of an automatic scroll, the "end" scroll event in react-scroll is fired. So, the callback for the "end" scroll even sets this.state.scrolling to false. Now, since that's false, the scroll is handled and I setState() again, potentially making the header bar sticky.
Bottom line: the ideal solution is to disable the scroll in componentDidUpdate when it begins scrolling, and enable it again in the "end" event handler. The problem with this solution is this event handler is called when the user interrupts an automatic scroll.
Lastly, I've found some methods on stackoverflow to disable/enable scrolling, but I took them out because they didn't seem to help the "end" event handling issue. It just re-enables the scrolling anyway when the handler is fired.
Please ask questions, I'm trying really hard to explain this clearly.
Found the solution. I had to basically "continue" the scroll in my 'end' event handler if it is called before the scroll is actually finished. Here is the updated code:
import React, { Component } from 'react';
import Scroll from 'react-scroll';
class Header extends Component {
constructor() {
super();
//scroll direction: (1) - down, (2) - up
this.state = {
scrolling: false,
inLogo: false,
sticky: "",
lastScrollPos: 0
}
/* Must bind to access 'this' */
this.handleScroll = this.handleScroll.bind(this);
this.scroller = Scroll.animateScroll;
this.isScrollingDown = this.isScrollingDown.bind(this);
}
componentDidMount() {
window.addEventListener("scroll", this.handleScroll);
Scroll.Events.scrollEvent.register('end', function() {
if(window.pageYOffset == 0) {
console.log("End: "+window.pageYOffset);
this.setState({sticky: "", scrolling: false});
}
else if(window.pageYOffset == window.innerHeight) {
console.log("End: "+window.pageYOffset);
this.setState({sticky: "sticky", scrolling: false});
} else {
if(this.state.inLogo) {
this.scroller.scrollToTop();
} else {
this.scroller.scrollTo(window.innerHeight);
}
}
}.bind(this));
if(window.pageYOffset < 150) {
this.state.inLogo = true;
this.scroller.scrollTo(0);
} else {
this.state.inLogo = false;
this.scroller.scrollTo(window.innerHeight);
}
}
componentDidUpdate() {
if(this.state.scrolling) {
if(this.state.inLogo) {
this.scroller.scrollToTop();
} else {
this.scroller.scrollTo(window.innerHeight);
}
}
}
handleScroll(e) {
console.log(this.state.scrolling);
if(this.state.scrolling) {
return;
}
var scrollDown = this.isScrollingDown();
var inLogo = this.isInLogo();
if(inLogo) {
if(scrollDown) {
console.log("Scrolling down in logo");
this.setState({
scrolling: true,
inLogo: false
});
}
if(!scrollDown) {
console.log("Scrolling up in logo");
this.setState({
scrolling: true,
inLogo: true,
sticky: ""
});
}
}
}
isScrollingDown() {
var scrollingDown = window.pageYOffset > this.state.lastScrollPos;
this.state.lastScrollPos = window.pageYOffset;
return scrollingDown;
}
isInLogo() {
return window.pageYOffset > 150 && window.pageYOffset < window.innerHeight - 5;
}

Setting a jScrollPane to autoscroll left and right, but pause on click?

Fiddle: http://jsfiddle.net/RJShm/
I have a jScrollPane that currently scroll from left, to right, then back left, and stops. What I'd like is for this to continually scroll from left to right, the right to left, then repeat. I have this fairly close to working by using pane.bind('jsp-scroll-x'..., but I can't seem to get it to scroll back to the right after one cycle. Current code for that:
pane.bind('jsp-scroll-x', function (event, pos_x, at_left, at_right) {
if (at_right)
{
api.scrollToX(0);
$(this).unbind(event);
}
});
I would also like for this to stop autoscrolling when anything in the pane is clicked (scroll bar, arrows, content, anything), and it would preferably restart after a few seconds of no clicks.
So, in short, how do I:
Make the jScrollPane scroll left/right automatically
Stop autoscrolling when clicked
Restart autoscrolling after a few seconds of no clicks inside the pane
Thanks
EDIT: jScrollPane Settings, and api for your convenience.
I have updated the handler for toggling the infinite scroll and also implemented click handler to pause the scroll and resume after a timeout (5 seconds). See draft code below and check the DEMO: http://jsfiddle.net/p6jLt/
var defaultSettings = {
showArrows: true,
animateScroll: true,
animateDuration: 5000
},
pauseSettings = {
showArrows: true,
animateScroll: false
};
var pane = $('.scroll-pane').jScrollPane(defaultSettings);
var api = pane.data('jsp');
var isFirst = true,
posX = 0,
isLeft = false,
timer;
pane.bind('jsp-scroll-x', scrollFx)
.mousedown(function () {
//lets make sure the below is
//executed only once after automatic croll
if (posX != -1) {
$(this).unbind('jsp-scroll-x');
api.scrollToX(posX);
api.reinitialise(pauseSettings); //no animation
posX = -1;
}
}).mouseup(function () {
clearTimeout(timer); //clear any previous timer
timer = setTimeout(function () {
isFirst = true;
posX = 0; //reset the killer switch
api.reinitialise(defaultSettings); //animateed scroll
pane.bind('jsp-scroll-x', scrollFx); //rebind
api.scrollToX(isLeft ? 0 : api.getContentWidth()); //resume scroll
}, 5000);
});
var scroll = api.scrollToX(api.getContentWidth());
function scrollFx(event, pos_x, at_left, at_right) {
if (posX == -1) { //kill scroll
$(this).unbind(event);
return false;
}
if (at_right) {
api.scrollToX(0);
isLeft = true; //used for restart
} else if (at_left && !isFirst) {
api.scrollToX(api.getContentWidth());
isLeft = false; //used for restart
}
isFirst = false;
posX = pos_x;
}
Issues: The plugin is little buggy with scroll sometimes, but it doesn't break the infinite scroll. You may find the little hicks on scroll, but it works for the most part. Test it out thoroughly and see how it goes.

Categories

Resources