How to add side effects while running an Animated animation sequence? - animation

Im trying to build a countdown timer, and for each count i want play a sound. The animation works fine but i want to know if i can play the sound when running an animation in a sequence.
CODE:
Animated.sequence([
Animated.timing(this.state.moveY3, {
toValue: 50,
duration: 1000,
useNativeDrive: true,
easing: Easing.spring
}), // play sound
Animated.timing(this.state.moveY3, {
toValue: 100,
duration: 100,
useNativeDrive: true,
}),
Animated.timing(this.state.moveY2, {
toValue: 50,
duration: 1000,
useNativeDrive: true,
easing: Easing.spring
}), //play sound
Animated.timing(this.state.moveY2, {
toValue: 100,
duration: 500,
useNativeDrive: true,
}),
Animated.timing(this.state.moveY1, {
toValue: 50,
duration: 1000,
useNativeDrive: true,
easing: Easing.spring
}), // play sound
Animated.timing(this.state.moveY1, {
toValue: 100,
duration: 500,
useNativeDrive: true,
}),
]).start()
Note: I know how to play sound, Im using the react-native-sound package, Im just confused as to how to the play the sound at each count.

Into the start() method of each Animation a callback can be added which is executed upon completion of the animation.
So instead of writing all your animation in a sequence you could break it up into smaller parts, like so:
// Run animation
animation1.start(() => {
playSound1();
Animated.sequence([
animation2,
animation3,
]).start(() => {
playSound2();
Animated.sequence([
animation4,
animation5,
]).start(() => {
playSound3();
animation6.start();
})
})
});
// Move animations into variables so that the execution of the animation is more readable
const animation1 = Animated.timing(this.state.moveY3, {
toValue: 50,
duration: 1000,
useNativeDrive: true,
easing: Easing.spring
});
const animation2 = Animated.timing(this.state.moveY3, {
toValue: 100,
duration: 100,
useNativeDrive: true,
}),
const animation3 = Animated.timing(this.state.moveY2, {
toValue: 50,
duration: 1000,
useNativeDrive: true,
easing: Easing.spring
}),
...
By moving some stuff of the first bit into other functions you could reduce the nesting a bit and make it more readable.. but it should work like that..

Related

AmCharts5 broken slices in PieChart

With any interaction, everything is restored. How to fix it?
Sometimes it loads normally, sometimes crookedly
I didn't do anything unusual in the code.
root.setThemes([
am5themes_Animated.new(root),
responsive
]);
chart = root.container.children.push(
am5percent.PieChart.new(root, {
endAngle: 270,
layout: root.horizontalLayout,
innerRadius: am5.percent(50),
})
);
series = object.series.push(
am5percent.PieSeries.new(root, {
name: "Series",
valueField: "value",
categoryField: "category",
endAngle: 270,
maxHeight: 300,
colors: colorSet,
legendLabelText: "{category}",
legendValueText: "",
alignLabels: true,
})
);

BottomSheet animation in react-native doesnt work properly for the first time

I'm trying to create this animation for my bottomsheet ,so initially when my homescreen loads, the bottomsheet pops up from below with a spring animation and then when the user swipes up , the bottomsheet also swipes up witha spring animation to it, and again if the user swipes down the bottomsheet comes back to its original position with a spring animation to it.
The only problem i'm facing is that, the first swipe up that i make after the initial popping up spring animation happens, the animation for the swiping up, doesnt happen smoothly, and it snaps to the upper position in just an instant without showing any spring like animation
Here is my code for my BottomSheet.
import * as React from "react";
import { SCREEN_HEIGHT } from "../../assets/constants";
import { StyleSheet, Animated, TextInput, View } from "react-native";
import { PanGestureHandler } from "react-native-gesture-handler";
import { Easing } from "react-native-reanimated";
import BottomSheetStack from "./BottomSheetStack";
export default class BottomSheet extends React.Component {
constructor(props) {
super(props);
this.BottomSheet = new Animated.Value(0);
this.state = {
isOpen: false,
isLoading: false,
isPanChanged: false,
};
}
componentDidMount() {
setTimeout(() => this.animateTranslate(), 1000);
}
animateTranslate() {
Animated.spring(this.BottomSheet, {
toValue: 1,
duration: 500,
useNativeDriver: true,
easing: Easing.ease,
}).start();
}
translateDrawer() {
return this.BottomSheet.interpolate({
inputRange: [0, 1],
outputRange: [SCREEN_HEIGHT, SCREEN_HEIGHT / 1.48],
});
}
animateBottomSheetUp() {
this.BottomSheet.setValue(0);
Animated.spring(this.BottomSheet, {
toValue: 1,
duration: 100,
useNativeDriver: true,
easing: Easing.ease,
}).start();
}
animateBottomSheetDown() {
this.BottomSheet.setValue(0);
Animated.spring(this.BottomSheet, {
toValue: 1,
duration: 100,
useNativeDriver: true,
easing: Easing.ease,
}).start();
}
handlePanGesture(props) {
this.setState({ isLoading: true });
if (!this.state.isPanChanged) {
this.setState({ isPanChanged: true });
}
if (!this.state.isOpen && props.nativeEvent.translationY > 0) {
this.animateBottomSheetUp();
this.setState({ isOpen: true });
} else if (this.state.isOpen && props.nativeEvent.translationY < 0) {
this.animateBottomSheetDown();
this.setState({ isOpen: false });
}
}
openBottomSheetHandler() {
return this.BottomSheet.interpolate({
inputRange: [0, 1],
outputRange: [SCREEN_HEIGHT / 1.48, SCREEN_HEIGHT / 2.1],
});
}
closeBottomSheetHandler() {
return this.BottomSheet.interpolate({
inputRange: [0, 1],
outputRange: [SCREEN_HEIGHT / 2.1, SCREEN_HEIGHT / 1.48],
});
}
render() {
return (
<PanGestureHandler
onGestureEvent={(props) => this.handlePanGesture(props)}
>
<Animated.View
style={{
...StyleSheet.absoluteFill,
height: SCREEN_HEIGHT - SCREEN_HEIGHT / 2.2,
backgroundColor: "#ffffff",
elevation: 10,
transform: [
{
translateY: !this.state.isLoading
? this.translateDrawer()
: !this.state.isOpen && this.state.isPanChanged
? this.openBottomSheetHandler()
: this.closeBottomSheetHandler(),
},
],
alignItems: "center",
borderRadius: 15,
}}
>
<View style={styles.bottomSheetLine} />
<TextInput
value={this.state.name}
style={styles.searchBox}
placeholder="Search"
placeholderTextColor="#5DB075"
/>
<BottomSheetStack {...this.props.navigation} />
</Animated.View>
</PanGestureHandler>
);
}
}
const styles = StyleSheet.create({
searchBox: {
height: 45,
width: `85%`,
backgroundColor: "#ffffff",
borderRadius: 10,
color: "#5DB075",
paddingLeft: 20,
fontSize: 14,
letterSpacing: 0.5,
top: 20,
fontFamily: "regular",
borderColor: "#5DB075",
borderWidth: 1,
},
bottomSheetLine: {
height: 5,
backgroundColor: "#5DB075",
width: 70,
borderRadius: 5,
top: 5,
},
});
Please suggest me some idea on how i can achieve this, or any other method that can be used to achieve this.
So, apparently, somewhere i found that spring animation, toValue:1 doesnt actually go upto 1, and it slightly crosses 1. So that's why my animation was behaving like that i guess.
The solution to this was, i simply changed my toValue for animateBottomSheetUp and animateBottomSheetDown , went to higher value, i.e toValue:2 for animateBottomSheetUp .
My changes in my code are very minor , it looks like this ,
also i removed all the this.BottomSheet.setValue(/*somevalue*/) from my code.
for animateBottomSheetUp:
animateBottomSheetUp() {
Animated.spring(this.BottomSheet, {
toValue: 2, // made this change from 1 to 2
duration: 100,
useNativeDriver: true,
easing: Easing.ease,
}).start();
}
and the openBottomSheetHandler & closeBottomSheetHandler looks like this now,
openBottomSheetHandler() {
return this.BottomSheet.interpolate({
inputRange: [1, 2],
outputRange: [SCREEN_HEIGHT / 1.48, SCREEN_HEIGHT / 2.1],
});
}
closeBottomSheetHandler() {
return this.BottomSheet.interpolate({
inputRange: [1, 2],
outputRange: [SCREEN_HEIGHT / 1.48, SCREEN_HEIGHT / 2.1],
});
}
I'm posting this answer if anybody faces the same problem,
Though i have worked around this problem, but i still feel there must be a better way to do this,if anybody has any better way , please answer. :-)

An image into three.js scene is blurred on some screen resolutions

I try to create some object that a user could able by mouse rotate use Three.js and webgl. It's displaying fine when a screen has a full HD resolution (1960x1080) but when a user screen had resolution roughly 1366x768 object is ugly (blurred). Most notably text on the image.
Originally image has the resolution 1024x748 and the scene has a size roughly 530x270.
Clear - https://ibb.co/0s7W2hk
Blurred - https://ibb.co/tzCkq6W (in some cases blur corruption have more influence)
I connect the model to the scene by next code
// ...
scene.add({
genotype: VOLUMETRIC_OBJECT,
phenotype: MODELLED_MESH,
data: {
model: 'assets/FBX 2013/model.FBX',
position: {
x: 0,
y: isMobile ? 0.05 : 0.375,
z: 0,
},
scale: isMobile ? {
x: 70e-3,
y: 70e-3,
z: 70e-3,
} : {
x: 75e-3,
y: 75e-3,
z: 75e-3,
},
name: 'model',
material: {
hb_03_label1Model: {
map: 'assets/mm1.jpg',
alphaMap: 'assets/mam1.jpg',
color: 0xffffff,
specular: new Color(0xffffff),
shininess: 5,
transparent: true,
opacity: 1,
needsUpdate: true,
},
body_hb_03Model: {
normalMap: 'assets/mnm2.jpg',
color: 0xaaaaaa,
specular: new Color(0xFFFFFF),
opacity: 0.35,
shininess: 100,
transparent: true,
needsUpdate: true,
normalScale: {
x: 1,
y: 1,
},
},
hb_03_leqidoModel: {
type: MATERIAL__SHADER,
map: 'assets/mm3.jpg',
thicknessMap: 'assets/mtm3.jpg',
specularMap: 'assets/msm3.jpg',
normalMap: 'assets/mnm3.jpg',
repeat: [10, 10],
color: 0xffffff,
refractionRatio: 0.985,
reflectivity: 0.15,
diffuse: new Vector3(1, 0.3, 0.3),
thicknessColor: new Vector3(0.11, 0.11, 0.11),
needsUpdate: true,
uniformsNeedUpdate: true,
},
hb_03_cappaModel: {
color: 0x00AD16,
needsUpdate: true,
},
},
},
},
(model) => {
// ...
},
)
Update 1:
In my case when I change mag and min filters to Linear, I have strong sharpness and text not readable, again.
I think, for the best result, I need to use mag filter as Linear and min filter as LinearMipMapLinearFilter with the generated by myself mipmap.
But, currently, generate custom mipmap so strong for me. I did increase anisotropy for texture, and text is displayed acceptable

cytoscape.js sequential animation

I want to have an animation where the nodes get colored then the edges get colored. I looked at the other questions regarding animation in cytoscape.js and tried stacking promise statements to no avail.
I'm also unclear as to what it is the queue does, setting the boolean for both the edge and node to true, false or staggered seems to have no difference on the animation as they both animate at the same time.
This is the code I have so far:
var a = cy.edges().animate({
position: { x: 100, y: 100 },
style: { lineColor: '#a79' }}, {duration: 1000},
{queue: 1}
);
var b = cy.nodes().animate({
position: { x: 100, y: 100 },
style: { backgroundColor: 'blue' }},
{duration: 1000},
{queue: 1}
);
a.animation().play().promise().then(b.animation().play());
edit
So I wrapped the animate command in a function to get the desired result
cy.on('tap', 'node', function(evt){
cy.nodes().animate(
{
position: { x: 100, y: 100 },
style: { lineColor: 'pink' }
},
{
duration: 1000,
queue: true
}
);
Although hardcoding animations is not ideal, I would still like to know how to do it with the promise commands.
It looks ok, the only thing I see is:
var a = cy.edges().animate(
{
position: { x: 100, y: 100 },
style: { lineColor: '#a79' }
},
{
duration: 1000,
queue: true
}
);
var b = cy.nodes().animate(
{
position: { x: 100, y: 100 },
style: { backgroundColor: 'blue' }
},
{
duration: 1000, // This goes together in one brace
queue: true // Use a boolean maybe
}
);
a.animation().play().promise().then(function () {
b.animation().play());
}
The documentation does exactly that, maybe this solves the problem :)

Animation - How to turn animated values into real values via interpolate

I'm trying to simultaneously restrict the values of my animation (using clamp as well as interpolate) but also get the values out of the interpolation so I can use them. Specifically because I want to update a piece of state with them and create an observable from that. I just can't figure out how to extract the 'real' value out of the AnimatedValue that is produced by the interpolation (in this case state.panValue). I've tried
this.state.panValue.value
and
this.state.panValue._value
and they come back as undefined. If anyone could help me out would be amazing!
EDIT: I'd also be really happy to just have the
this.state.pan.x
variable updated within the limits so I can skip the whole updating the state variable 'panValue' thing. A nice guy on Facebook suggested that I could implement this limit somehow inside the onPanResponderMove by switching the variable to a function or something but I've tried several things and all I get are errors, I guess because I don't really know how to 'safely' amend these animated values.
onPanResponderMove: Animated.event([
null,
{ dx: this.state.pan.x },
]),
Original Code:
import React, { Component } from 'react';
import {
View,
Animated,
PanResponder,
Text,
} from 'react-native';
import styles from './styles';
class ClockInSwitch extends Component {
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY(),
panValue: 0,
};
}
componentWillMount() {
this._animatedValueX = 0;
this._animatedValueY = 0;
this.state.pan.x.addListener((value) => {
this._animatedValueX = value.value;
this.setState({
panValue: this.state.pan.x.interpolate({
inputRange: [-30, 0, 120,],
outputRange: [-10, 0, 120,],
extrapolate: 'clamp',
}),
});
});
this._panResponder = PanResponder.create({
// Ask to be the responder:
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
this.state.pan.setOffset({
x: this._animatedValueX,
});
this.state.pan.setValue({ x: 0, y: 0 });
},
onPanResponderMove: Animated.event([
null,
{ dx: this.state.pan.x },
]),
onPanResponderTerminationRequest: (evt, gestureState) => true,
onPanResponderRelease: (evt, gestureState) => {
this.state.pan.flattenOffset();
Animated.timing(this.state.pan, {
toValue: 0,
duration: 500,
}).start();
},
onPanResponderTerminate: (evt, gestureState) => {
},
onShouldBlockNativeResponder: (evt, gestureState) => {
return true;
},
});
}
componentWillUnMount() {
this.state.pan.x.removeAllListeners();
}
render() {
const animatedStyle = {
transform: [{
translateX: this.state.panValue,
},
],
};
return (
<View>
<Text>{this.state.pan.x._value}</Text>
<View style={styles.buttonStyle}>
<Animated.View
style={[styles.sliderButtonStyle, animatedStyle]}
{...this._panResponder.panHandlers}
/>
</View>
</View>
);
}
}
export default ClockInSwitch;
I think this is what you're looking for. I'm using exponent so your declaration for vector icons would probably need to be changed. Cheers!
/**
* #providesModule ClockInSwitch
* #flow
*/
import React, {Component} from 'react';
import {View, Animated, StyleSheet, PanResponder, Text} from 'react-native';
import {FontAwesome} from '#exponent/vector-icons';
export class ClockInSwitch extends Component {
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY(),
panValue: 0
};
}
componentWillMount() {
this._panResponder = PanResponder.create({
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: (e, gestureState) => {
this
.state
.pan
.setValue({x: 0, y: 0});
},
//here's where you can check, constrain and store values
onPanResponderMove: (evt, gestureState) => {
// 300 is the width of the red container (will leave it to you to calculate this
// dynamically) 100 is the width of the button (90) plus the 5px margin on
// either side of it (10px total)
var newXVal = (gestureState.dx < 300 - 100)
? gestureState.dx
: 300 - 100;
this
.state
.pan
.x
.setValue(newXVal);
//set this state for display
this.setState({panValue: newXVal});
},
onPanResponderRelease: (e, {vx, vy}) => {
this
.state
.pan
.flattenOffset();
Animated
.spring(this.state.pan, {
toValue: 0,
duration: 400,
overshootClamping: true
})
.start();
this.setState({panValue: 0});
}
});
}
componentWillUnMount() {
this
.state
.pan
.x
.removeAllListeners();
}
render() {
//decouple the value from the state object
let {pan} = this.state;
let [translateX,
translateY] = [pan.x, pan.y];
let translateStyle = {
transform: [{
translateX
}, {
translateY
}]
};
return (
<View>
<Text style={styles.leftText}>Power Button Demo</Text>
<View style={styles.buttonStyle}>
<Animated.View
style={[styles.sliderButtonStyle, translateStyle]}
{...this._panResponder.panHandlers}>
<FontAwesome
name="power-off"
color="#EA2E49"
style={{
alignSelf: "center",
marginHorizontal: 10
}}
size={36}/>
</Animated.View>
</View>
<Text style={styles.rightText}>{this.state.panValue}: x value</Text>
</View>
);
}
}
export default ClockInSwitch;
const styles = StyleSheet.create({
sliderButtonStyle: {
borderColor: '#FCFFF5',
borderStyle: 'solid',
borderWidth: .5,
backgroundColor: '#FCFFF5',
borderRadius: 45,
height: 90,
width: 90,
justifyContent: 'center',
textAlign: 'center',
marginHorizontal: 5,
shadowColor: '#333745',
shadowOffset: {
width: 2,
height: 2
},
shadowOpacity: .6,
shadowRadius: 5
},
buttonStyle: {
borderColor: '#FCFFF500',
backgroundColor: '#DAEDE255',
borderStyle: 'solid',
borderWidth: 1,
height: 100,
width: 300,
justifyContent: 'center',
borderRadius: 50,
margin: 5,
flexDirection: 'column'
},
rightText: {
justifyContent: 'center',
textAlign: 'right',
fontWeight: '100',
marginHorizontal:15,
fontSize: 20,
color: '#FCFFF5',
marginVertical:25,
flexDirection: 'column'
},
leftText: {
justifyContent: 'center',
textAlign: 'left',
fontWeight: '100',
marginHorizontal:15,
fontSize: 24,
color: '#FCFFF5',
marginVertical:25,
flexDirection: 'column'
}
});

Resources