I want to use konva.js node nesting in react app. I need help on how to use it.
Thanks in advance.
I can advise you to use react-konva library
https://github.com/konvajs/react-konva
The examples with the draggable circles:
import React, { Component } from 'react';
import Konva from 'konva';
import { render } from 'react-dom';
import { Stage, Layer, Circle, Text } from 'react-konva';
class App extends Component {
handleDragStart = e => {
e.target.setAttrs({
scaleX: 1.3,
scaleY: 1.3
});
};
handleDragEnd = e => {
e.target.to({
duration: 0.5,
scaleX: 1,
scaleY: 1
});
};
render() {
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Text text="You can drag a circle" />
{[...Array(10)].map(i => (
<Circle
key={i}
x={Math.random() * window.innerWidth}
y={Math.random() * window.innerHeight}
radius={20}
fill="green"
opacity={0.8}
draggable
onDragStart={this.handleDragStart}
onDragEnd={this.handleDragEnd}
/>
))}
</Layer>
</Stage>
);
}
}
render(<App />, document.getElementById('root'));
You need to add react, konva, react-dom and react-konva dependencies
Related
I'm trying to scale my model and change its position, but its not happening- I must be missing something. It's not webpack as the rest is updating fine and the model is loading. I used gltfjsx to create this file.
export default function Model({ ...props }) {
const group = useRef()
const { nodes } = useGLTF('./mymodel')
const material = useMemo(() => {
if (props.layer === DEFAULT_LAYER) return new THREE.MeshStandardMaterial({ color: new THREE.Color('rgba(62,53,105,1)'), roughness: 0.2, metalness: 0.9 })
else return new THREE.MeshBasicMaterial({ color: new THREE.Color('rgba(52,95,75,1)') })
}, [props.layer]);
return (
<group ref={group} dispose={null} position={[0,-500,0]} scale={[0.01, 0.01, 0.01]} {...props}>
<mesh geometry={nodes.Node.geometry} material={material}
layers={props.layer} receiveShadow castShadow />
</group>
)
}
export default function App() {
return (
<>
<Canvas camera={{ position: [0, 20, 12], fov: 35, near: 0.1, far: 2000 }} gl={{ antialias: true }} onCreated={state => state.gl.setClearColor( 0xffffff, 0)}>
<Suspense fallback={null}>
<Stage intensity={1}>
<Model layer = {DEFAULT_LAYER} />
</Stage>
</Suspense>
</Canvas>
<Loader />
</>
)
}
I have placed scale and position in the Model, mesh and group objects but none make a difference. How come? I can't change my camera position either.
My imports for Model.jsx:
import {useRef, useMemo} from 'react'
import { useGLTF } from '#react-three/drei'
import * as THREE from 'three'
My imports for App.jsx:
import React, { Suspense, useRef, useMemo } from 'react'
import { Canvas, useThree, useFrame } from '#react-three/fiber'
import { Loader, useFBO, Stage, Effects, Environment, OrbitControls } from '#react-three/drei'
import Model from './FortunaDraco'
import { FXAAShader } from 'three-stdlib'
import { AdditiveBlendingShader } from './shaders/AdditiveBlendingShader'
import { VolumetricLightShader } from './shaders/VolumetricLightShader'
import './App.css'
For anyone having this issue it was because of Stage
Hello everyone and thank you for reading,
I'm new to redux and Iv been trying to connect a grandchild component with the store, but for some reason It doesn't work.
The child component (called canvas) uses the store as well and doesn't show any problem, but when I'm trying to get the same data in a component I call from within the child component I get: "Uncaught Error: could not find react-redux context value; please ensure the component is wrapped in a Provider tag"
I searched for the solution on the internet and everybody suggests to wrap the app component in provider tags inside index.js, but I already did that in the beginning
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {createStore} from 'redux';
import allReducer from './reducers'
import { Provider } from 'react-redux';
const store = createStore(allReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
ReactDOM.render(
// <React.StrictMode>
<Provider store={store}>
<App/>
</Provider>,
//</React.StrictMode>,
document.getElementById('root')
);
App.js
import React from 'react';
import "./App.css";
import { Canvas } from "./components/Canvas";
export default function App() {
return (
<div className="main-div">
<Canvas/>
</div>
);
}
relevant data from canvas.js (child component)
import { Stage, Layer, Rect } from 'react-konva';
.
.
.
.
const theTextObjs = TextObjs.map((text,key) => {
return (
<TextBox
//some irrelevant props
/>
{/* some irrelevant info and other components . . . */}
)});
.
.
.
.
return(
<Stage
width={ window.innerWidth * 2}
height={ window.innerHeight * 2}
//style={{ border: '1px solid grey' }}
ref={stageRef}
>
<Layer>
<Rect
x = {0}
y= {0}
width={ window.innerWidth * 2}
height={ window.innerHeight * 2}
fill={"white"}
stroke={"white"}
strokeWidth={5}
/>
{theTextObjs}
</Layer>
</Stage>
//some more components
)
inside of TextBox.js (grandchild component)
import React from "react";
import { useSelector} from 'react-redux';
export function TextBox({textEditVisible, textX,fill,textY,textValue,fontSize,width,height,fontStyle,align,id,onDragStart,isSelected,onClick,onChangeEnd,onContextMenu,onChangeEdit,onClickedit,onKeyDownEdit,event}) {
const selectedTextObj = useSelector(state => state.selectedTextObj)
const TextObjs = useSelector(state => state.TextObjs)
const dispatch = useDispatch()
//
//some irrelevant info
// ...
return (
<>
{/* more irrelevant info */}
</>
);
}
When using a different React renderer such as Konva, you need to wrap the components within the different Renderer within a new provider. In the case of Konva, the children of Stage.
See this issue.
const store = useStore()
return ( <Stage
width={ window.innerWidth * 2}
height={ window.innerHeight * 2}
//style={{ border: '1px solid grey' }}
ref={stageRef}
>
<Provider store={store}>
<Layer>
<Rect
x = {0}
y= {0}
width={ window.innerWidth * 2}
height={ window.innerHeight * 2}
fill={"white"}
stroke={"white"}
strokeWidth={5}
/>
{theTextObjs}
</Layer>
</Provider>
</Stage>
I was using react-three-fiber package and wanted to implement camera movement feature with mouse move instead of mouse click. For example, if you visit roundme.com then you will see a picture of a tour and when you move mouse camera, kinda, moves towards the position of pointer. So, to achieve it I decided to get current position of mouse and put that position to OrbitControls like this:
import React, { Suspense, useRef } from "react";
import { Canvas } from "react-three-fiber";
import { Html, OrbitControls } from "drei";
import "../../styles/index.css";
import { ReactReduxContext, Provider } from "react-redux";
import Portals from "../Portal/portal.component";
const Panorama = () => {
const mouse = useRef({ x: 0, y: 0 });
function getMousePos(e) {
console.log(e.clientX, e.clientY);
return { x: e.clientX, y: e.clientY };
}
return (
<>
<ReactReduxContext.Consumer>
{({ store }) => (
<Canvas
onMouseMove={(e) => (mouse.current = getMousePos(e))}
invalidateFrameloop
concurrent
camera={{ position: [50, 0, 0.1] }}
>
<OrbitControls
enableZoom={true}
enablePan={true}
dampingFactor={1}
minDistance={10}
maxDistance={500}
autoRotate
zoomSpeed={5}
autoRotateSpeed={0.5}
rotateSpeed={-1.4}
/>
<Suspense
fallback={
<Html center style={{ color: "white" }}>
loading...
</Html>
}
>
<Provider store={store}>
<Portals />
</Provider>
</Suspense>
</Canvas>
)}
</ReactReduxContext.Consumer>
</>
);
};
export default Panorama;
But camera does not move when I move mouse.
I'm not sure if you can use this same pattern with drei's OrbitControls, but here is how you can achieve it with the camera-controls package:
import CameraControls from 'camera-controls'
CameraControls.install({ THREE })
extend({ CameraControls })
function Controls() {
const ref = useRef()
const camera = useThree((state) => state.camera)
const gl = useThree((state) => state.gl)
useFrame((state, delta) => {
// update camera angles according to mouse position
ref.current.azimuthAngle = -state.mouse.x
ref.current.polarAngle = Math.PI / 2 + state.mouse.y
ref.current.update(delta)
})
return <cameraControls ref={ref} args={[camera, gl.domElement]} />
}
And then simply put <Controls /> inside of your <Canvas />.
i'm trying to create 2 layers (Images) that cannot overlap,
So they can still dragged freely, but won't showed over each other.
I've tried using zIndex or a blank Rect, but can't figure out how to make 2 draggable layers that can't overlap (Very similar to overflow: hidden behavior)
a GIF is attached to show the problem, each layer shouldn't be visible behind the divider line.
return (
<Stage width={size.width} height={size.height}>
{stateImages.map((imageConfig) => {
index++
return <Layer><Image
x={size.width/2 * index}
y={0}
image={imageConfig.image}
draggable
/>
</Layer>
})}
{stateImages.length > 1 &&
<Layer>
<Rect
x={size.width / 2}
y={0}
width={4}
height={size.height}
fill="white"
shadowBlur={10}
zIndex={2}
/>
</Layer>
}
</Stage>
)
You can use clip https://konvajs.org/docs/clipping/Clipping_Regions.html#page-title for that use case:
import React, { Component } from "react";
import { render } from "react-dom";
import { Stage, Layer, Image, Group } from "react-konva";
import useImage from "use-image";
// the first very simple and recommended way:
const MyImage = () => {
const [image] = useImage("https://i.imgur.com/ktWThtZ.png");
return <Image image={image} draggable />;
};
class App extends Component {
render() {
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Group
clipX={0}
clipY={0}
clipWidth={window.innerWidth / 2}
clipHeight={window.innerHeight}
>
<MyImage />
</Group>
<Group
x={window.innerWidth / 2}
clipX={0}
clipY={0}
clipWidth={window.innerWidth / 2}
clipHeight={window.innerHeight}
>
<MyImage />
</Group>
</Layer>
</Stage>
);
}
}
render(<App />, document.getElementById("root"));
https://codesandbox.io/s/react-konva-clip-images-demo-onp3w?file=/src/index.js
I'm developing a React Native app that using a ScrollView. I want to display an amount of items (A card with title and a child component).
The problem comes when I have to render each item, while the parent renders ok, the child does not.
I don't know where could be the issue, here's my code:
import React, {Component} from 'react';
import {View, Text} from 'react-native';
const mismo =[
'Mismo',
'Mismo',
'Mismo',
'Mismo',
'Mismo'
];
class Mismo extends Component {
renderMismo2(){
mismo.map((item) =>{
return(
<View>
<Text>{item}</Text>
</View>
)
})
}
render(){
return(
<View>
{this.renderMismo2()}
</View>
);
}
}
export default Mismo;
=================================
import React, {Component} from 'react';
import {View, Text, ScrollView} from 'react-native';
import {Card} from 'react-native-elements';
import PriceCard from '../components/PriceCard';
import Mismo from '../components/Mismo';
class OrderPricingCard extends Component{
renderAllPrices(){
this.props.data.orders.map((item, i) => {
return(
<View>
<PriceCard
key={item.transporterName}
data={item}
/>
</View>
);
})
}
renderMismo(){
return(
<Mismo />
);
}
render () {
return (
<Card
containerStyle={styles.cardContainer}
title={`Pedido: ${this.props.data.id}`}
>
<ScrollView
horizontal
>
{this.renderMismo()}
{this.renderAllPrices()}
</ScrollView>
</Card>
);
}
}
const styles = {
cardContainer:{
borderRadius: 10,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
}
}
export default OrderPricingCard;
This can be an easy mistake to make! I've done it several times. What's happened is you've forgotten the return statement for the render methods (renderMismo2() and renderAllPrices()) found in each component. Although the map methods correctly have return statements, you're not actually returning anything from the functions themselves.
If you were to console.log() either of those function calls above the return in the React render() method, you would see undefined in the console.
Here's what they would look like corrected.
renderAllPrices(){
// added the 'return' keyword to begin the line below
return this.props.data.orders.map((item, i) => {
return(
<View>
<PriceCard
key={item.transporterName}
data={item}
/>
</View>
);
})
}
renderMismo2(){
// same here, added the 'return' keyword
return mismo.map((item) =>{
return(
<View>
<Text>{item}</Text>
</View>
)
})
}
I tested the above in a React Native sandbox and it works. Hope that helps!