Having trouble with react three fiber: THREE.WebGLRenderer: Context Lost - three.js

I have some kind of problem where my dice are giving the error
THREE.WebGLRenderer: Context Lost.
I am not sure but I think it has something to do with switching from use-cannon to #react-three/cannon. When I try to render D4, I get the error. The box however seems to work just fine which is why I am a bit lost on what exactly I should try next to solve this problem.
import * as THREE from 'three'
import ReactDOM from 'react-dom'
import React, { Suspense, useMemo, useState, useEffect } from 'react'
import { Canvas, useFrame, useLoader } from '#react-three/fiber'
import { Physics, useBox, usePlane, useSphere, useConvexPolyhedron } from '#react-three/cannon'
import niceColors from 'nice-color-palettes'
import './styles.css'
// import { useConvexPolyhedron } from '#react-three/cannon';
import { Tetrahedron, RoundedBox } from '#react-three/drei';
import { TestDice } from './TestDice.js'
const DiceOverview = (props) => {
// console.log('trigger check');
// console.log(dice, 'something odd');
//radius and the rest are all passed in so likely radius adjusts these values.
function Plane({ color, ...props }) {
const [ref, api] = usePlane(() => ({ ...props }))
return (
<mesh ref={ref} receiveShadow >
<planeBufferGeometry onClick={() => api.applyImpulse([0, 20, 0], [0, 0, 0])} attach="geometry" args={[1000, 1000]} />
<meshPhongMaterial attach="material" color={color} />
</mesh>
)
}
function Box() {
const [ref, api] = useBox(() => ({ mass: 1, args: [4, 4, 4], isKinematic: true }))
useFrame(state => {
const t = state.clock.getElapsedTime()
})
return (
<mesh ref={ref} castShadow receiveShadow>
<boxBufferGeometry attach="geometry" args={[4, 4, 4]} />
<meshLambertMaterial attach="material" color={'#3F00FF'} side={THREE.DoubleSide} />
</mesh>
)
}
const D4 = (props) => {
console.log(props, 'what is D4 getting?')
console.log(Tetrahedron, 'this is tetrahedron');
console.log('hello');
const radius = 1;
const tetrahedronGeometry = new THREE.TetrahedronGeometry(radius);
const [ref, api] = useConvexPolyhedron(() => {
return {
args: tetrahedronGeometry,
mass: 1,
...props,
};
});
console.log(ref, api, 'are these triggering');
return (
<Tetrahedron
args={radius}
ref={ref}
onClick={() => api.applyImpulse([0, 20, 40], [0, 0, 0])}
castShadow
receiveShadow
>
<meshNormalMaterial attach="material" />
</Tetrahedron>
);
};
const Dtest = (props) => {
return (
<RoundedBox
args={[1, 1, 1]} // Width, Height and Depth of the box
radius={0.05} // Border-Radius of the box
smoothness={4} // Optional, number of subdivisions
position={[0, 0, 10]}
>
<meshPhongMaterial attach="material" color="#f3f3f3" wireframe />
</RoundedBox>
);
};
const glProps = { alpha: false };
const cameraProps = { position: [0, -12, 16] };
// let keys = Object.keys(props)
// console.log('what is this color', niceColors[10][4])
return (
<>
<button onClick={() => { console.log('click') }}>button</button>
<button>toss</button>
<TestDice />
<div style={{ position: "relative", width: 500, height: 500 }}>
<Canvas id="myCanvas" concurrent shadowMap sRGB gl={glProps} camera={cameraProps} width={100}>
<hemisphereLight intensity={0.35} />
<spotLight position={[30, 0, 30]} angle={0.3} penumbra={1} intensity={2} castShadow shadow-mapSize-width={256} shadow-mapSize-height={256} />
<pointLight position={[-30, 0, -30]} intensity={0.5} />
<Physics className='physics' gravity={[0, 0, -60]}>
<Plane color={niceColors[10][4]} />
<Plane color={niceColors[10][1]} position={[-6, 0, 0]} rotation={[0, 0.9, 0]} />
<Plane color={niceColors[10][2]} position={[6, 0, 0]} rotation={[0, -0.9, 0]} />
<Plane color={niceColors[10][3]} position={[0, 6, 0]} rotation={[0.9, 0, 0]} />
<Plane color={niceColors[10][0]} position={[0, -6, 0]} rotation={[-0.9, 0, 0]} />
<D4 position={[-4, 0, 2]} rotation={[0, 1, 0]} />
<Dtest />
{/* {promise} */}
<Box />
</Physics>
</Canvas>
</div>
</>
);
};
export default DiceOverview;
This is my package.JSON file:
{
"name": "basictemplate",
"version": "1.0.0",
"description": "template to use in future projects",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode development --watch"
},
"repository": {
"type": "git",
"url": "git+https://github.com/jessemchung/template.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/jessemchung/template/issues"
},
"homepage": "https://github.com/jessemchung/template#readme",
"devDependencies": {
"#babel/core": "^7.15.0",
"#babel/preset-env": "^7.15.0",
"#babel/preset-react": "^7.14.5",
"babel-loader": "^8.2.2",
"css-loader": "^6.2.0",
"style-loader": "^3.2.1",
"webpack": "^5.51.1",
"webpack-cli": "^4.8.0"
},
"dependencies": {
"#react-three/cannon": "^3.0.1",
"#react-three/drei": "^7.5.0",
"#react-three/fiber": "^7.0.6",
"nice-color-palettes": "^3.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"three": "^0.132.2"
}
}
After more testing I believe the useConvexPolyhedron is what is causing trouble for me. Specifically, I think the problem is related to the args value. Perhaps something changed in the updated version in some way as this worked with use-cannon (which is now deprecated).
Long story short everyone, I messsaged the people responsible for the github and they gave a good explanation.
https://github.com/pmndrs/use-cannon/issues/274
Basically, this was deprecated and they do it differently now

Add restore Context function
restoreContext() {
const canvas = renderer.domElement;
canvas.addEventListener(
'webglcontextlost',
function (event) {
event.preventDefault();
setTimeout(function () {
renderer.forceContextRestore();
}, 1);
},
false
);
}

Related

How to add outside box shadow in react navigation bottom tabs?

I would like to add a outside box shadow in react-native-navigation.
The desired effect should look like this:
Currently when I apply styles the outside box shadow does not change:
import React, { FunctionComponent } from 'react'
import NavigatorProps from './NavigatorBottomTabs.type'
import { Screen } from '../../Module/Navigation/Navigation.type'
import Route from '../../Module/Navigation/Navigation.route'
import { ANY } from '../../Type/Type'
import TabBar from './NavigatorBottomTabs.TabBar'
const RenderScreen = (Tab: ANY) => (screen: Screen) =>
<Tab.Screen key={screen.name} {...screen} />
const NavigatorBottomTabs: FunctionComponent<NavigatorProps> = (props) => {
const Tab = props.Tab
return (
<>
<Tab.Navigator
tabBar={TabBar}
initialRouteName={Route.RootDabshboardProfileRouter}
tabBarOptions={{
borderWidth: 1,
borderColor: 'red',
marginTop: 10,
style: {
borderTopWidth: 0,
elevation: 8,
backgroundColor: '#d9d9d9',
shadowColor: '#000000',
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 1,
width: 1
}
}
}}
screenOptions={{
tabBarStyle: {
elevation: 8,
borderTopWidth: 0,
backgroundColor: '#d9d9d9',
shadowColor: '#000000',
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 1,
width: 1
}
}
}}
>
{props.screens.map(RenderScreen(Tab))}
</Tab.Navigator>
</>
)
}
export default NavigatorBottomTabs

Image Scroll Zoom in React Native

when creating a scroll view for a mobile app, a common principle could be to have an image on the very top of the list. This could be to showcase the content of the page. Examples for this could be found in the Spotify app, where an album cover is shown first, followed by a list of its songs.
import React, { Component } from 'react';
import {
View,Text,StyleSheet,ScrollView,Image, Animated, Dimensions
} from 'react-native';
HEADER_MAX_HEIGHT = Dimensions.get("window").height*0.4;
HEADER_MIN_HEIGHT = 70;
PROFILE_IMAGE_MAX_HEIGHT = 80;
PROFILE_IMAGE_MIN_HEIGHT = 40;
const IMAGE_SCALE_MAX = 20;
const LABEL_HEADER_MARGIN = 48;
import FastImage, { FastImageProps } from 'react-native-fast-image';
const AnimFastImage = Animated.createAnimatedComponent(FastImage);
class App extends Component {
constructor(props) {
super(props);
this.state = {
scrollY: new Animated.Value(0),
pan: new Animated.ValueXY()
};
}
render() {
return (
<ScrollView style={{
flex: 1,
width: '100%',
height: '100%',
backgroundColor: 'white'
}}
showsVerticalScrollIndicator={false}
alwaysBounceVertical={false}
contentContainerStyle={{ padding: 0 }}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.pan.y } } }],
{
useNativeDriver: false,
},
)}
alwaysBounceVertical={false}
contentInsetAdjustmentBehavior="never"
scrollEventThrottle={1}
>
<AnimFastImage
animStyle={{
transform: [
{
translateY: this.state.pan.y.interpolate({
inputRange: [-1000, 0],
outputRange: [-100, 0],
extrapolate: 'clamp',
}),
},
{
scale: this.state.pan.y.interpolate({
inputRange: [-3000, 0],
outputRange: [IMAGE_SCALE_MAX, 1],
extrapolate: 'clamp',
}),
},
],
}}
source={{ uri: 'https://i.picsum.photos/id/1/400/400.jpg?hmac=lOytrN6lDOH_Yx7NwwGIaCtxp6pyuH2V4hD6Eac-VI0', priority: 'high' }}
style={styles.img}
resizeMode="cover"
/>
<Animated.View
style={{
paddingHorizontal: 16,
transform: [
{
translateY: this.state.pan.y.interpolate({
inputRange: [-1000, 0],
outputRange: [LABEL_HEADER_MARGIN * IMAGE_SCALE_MAX, -80],
extrapolate: 'clamp',
}),
},
],
}}>
<Text style={{ fontWeight: 'bold', fontSize: 20}}>
Trần thanh tung
</Text>
<View style={{ height: 700 }} />
</Animated.View>
</ScrollView>
)}
}
export default App;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
img: {
backgroundColor: '#ccc',
width: '100%',
height: 350,
justifyContent: 'flex-end',
padding: 0,
},
});
But it doesn't work as I want it to. I want it to be like the user part of the telegram
what I want

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. :-)

How to get props value through drawer navigator

How to get the userdata props value in head component ?I am mapping state to
props but not able to take that value in head component.How to pass this.
Passing values to Higher order component.Provinding the code.Can someone
please go through it. How to get the userdata props value in head component ?I am mapping state to
props but not able to take that value in head component.How to pass this.
Passing values to Higher order component.Provinding the code.Can someone
please go through it
import React from "react";
import {Image, Text, View, ToastAndroid} from "react-native";
import {createDrawerNavigator} from 'react-navigation-drawer';
import {createMaterialTopTabNavigator, createStackNavigator, createAppContainer,DrawerActions} from "react-navigation";
import {Icon} from 'react-native-elements';
import DrawerContent from "./DrawerContent";
import {connect} from "react-redux";
import FirstList from "./FirstList";
import SecList from "./SecList";
import ThirList from "./ThirList";
import color from "../util/Colors";
import DashBoard from "./DashBoard";
const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
const TabNavigator = createMaterialTopTabNavigator(
{
FirstList : FirstList ,
SecList : SecList ,
},
{
tabBarOptions: {
labelStyle: {fontSize: 13},
activeTintColor: color.basecolor,
inactiveTintColor: 'black',
scrollEnabled: false,
style: {
backgroundColor: 'white',
height:45
},
indicatorStyle: {
backgroundColor: color.basecolor,
}
},
title: 'Details',
}
);
const StackNavigator1 = createStackNavigator({
TabNavigator: {
screen: TabNavigator,
navigationOptions:({navigation})=>{
return{
header: (
<Head/>
)
}
},
},
List: {
screen: ThirList
navigationOptions:({navigation})=>{
return{
header: null
}
},
},
});
const RootNav = createAppContainer(StackNavigator1);
var name;
class Head extends React.Component {
constructor(props) {
super(props);
name='';
var today = new Date();
this.state = {
'date': today.getDate() + " " + monthNames[today.getMonth()] + " " + today.getFullYear()
};
console.log(JSON.stringify(this.props)+"userdata");
}
render() {
const {date} = this.state;
return (
<View>
<View style={{flexDirection: 'row', backgroundColor: color.mainback, height: 40,padding:10}}>
<Text style={{
fontSize: 14,
textAlign: 'left',
marginLeft: 10,
flex:1,
color:color.textcolor,
fontWeight:'bold',
textAlignVertical: "center"
}}>Orders</Text>
<Text style={{
fontSize: 10,
textAlign: 'right',
marginLeft: 20,
marginRight: 20,
fontWeight: 'bold',
color:color.datetextcolor,
textAlignVertical: "center"
}}>{date}</Text>
</View>
</View>
);
}
}
class RootScreen extends React.Component {
render() {
return (
<View style={{flex: 1}}>
<RootNav/>
</View>
);
}
}
const StackNavigator = createStackNavigator({
DrawerNavigator: {
screen: RootScreen,
activeTintColor: color.basecolor,
navigationOptions: ({navigation}) => ({title: 'Home'}, {
headerLeft:
<View style={{flexDirection: 'row', marginLeft: 20}}>
<Icon name="menu" onPress={()=>navigation.dispatch(DrawerActions.toggleDrawer())} size={30} color="white"/>
<Image source={require('../images/logo.png')}
style={{height: 35, width: 150, resizeMode: 'contain'}}/>
</View>,
}
),
},
Dashboard: {
screen: DashBoard,
navigationOptions: {
headerTitle: (
<View style={{flex: 1, flexDirection: 'row', justifyContent: 'center'}}>
<View style={{flex: 1, justifyContent: 'center'}}>
<Image
source={require('../images/logo.png')}
style={{height: 35, width: 150, marginLeft: -20, resizeMode: 'contain'}}
/>
</View>
</View>
),
},
},
}, {
defaultNavigationOptions: {
headerTintColor: 'white',
headerStyle: {
backgroundColor: color.basecolor,
},
}
}
);
const DrawerNavigator = createDrawerNavigator(
{
Home: StackNavigator
},
{
contentComponent: DrawerContent,
drawerWidth: 280,
navigationOptions: {
header: null
},
}
);
function mapStateToProps(state) {
return {
userdata: state.auth.userdata
}
}
export default connect(mapStateToProps) (DrawerNavigator);
Your aim is to connect Head component to Redux Store, right?
Simply using connect() function will suffice.
The solution would be to add this line of code.
const NewHead = connect(mapStateToProps)(Head)
Replace the <Head/> with <NewHead/> in StackNavigator1
Then, access the data within the Head component in the following manner.
this.props.userdata
OR
If you want to pass data to routes when you navigate to them, you can refer to this documentation.

how to make this animate with react-native?

How to make this transform with React-Native?
i want this static position
constructor(props) {
super(props);
this.state={
loaded:false,
transform:[{ perspective: 0 },
{ translateX: width },
{ rotateY: '0deg'}],
isMenuOpen:false,
}
}
animate to this position
Animated.timing(
this.state.transform,
{toValue:[{ perspective: 850 },
{ translateX: -width * 0.24 },
{ rotateY: '60deg'}]},
).start();
how to write the animation code ?
You can't use Animated in such way... Look at Animated link you need to do next thing:
<MyComponent style={{
transform:[{ perspective: this.state.anim.interpolate({
inputRange: [0, 1],
outputRange: [0, 850],
})},
{ translateX: this.state.anim.interpolate({
inputRange: [0, 1],
outputRange: [width, -width * 0.24],
})},
{ rotateY: this.state.anim.interpolate({
inputRange: [0, 1],
outputRange: ["0deg", "60deg"],
})}],
}],
}}/>
------////------
Animated.timing(this.state.anim, {
toValue: 1
}),
------////--------
constructor(props) {
super(props);
this.state={
anim: AnimateValue(0)
}
}

Resources