Cada um de vocês pode precisar trabalhar com gráficos ao construir um aplicativo React. Ou você precisará renderizar um grande número de elementos com eficiência e obter alto desempenho ao redesenhar os elementos. Pode ser uma animação ou algum tipo de componente interativo. Naturalmente, a primeira coisa que vem à mente é o Canvas. Mas então surge a pergunta: "Que contexto usar?" Temos uma escolha - contexto 2d ou WebGl . E os gráficos 2D? Nem tudo é tão óbvio aqui.
Ao trabalhar em tarefas de alto desempenho, tentamos ambas as soluções para determinar na prática qual dos dois contextos seria mais eficiente. Como esperado, WebGl derrotou o contexto 2d, então parece que a escolha é direta.
. , WebGl. , , 2d context. , , – . pixi.js three.js – , .
Pixi.js three.js
, : pixi.j 2d-, three.js – 3d. , 2d 3d? , 3d- . , .
, : “ ?”. Camera – , scene renderer. . , , . , – scene. , , – scene. camera , renderer – , 3d- 2d-.
, , , , . , , , – . , z, . , .
, three.js 2d-. ? three.js.
-, . , : pixi.js – , three.js – three.interaction.
, , . pixi.js , . ? . . three.js, , .
– SVG. , SVG , , . three.js , pixi.js – .
, three.js . , , 3d-, pixi.js .
, – three.js.
Three.js React
– react- “” three.js.
react – react-three-fiber. , , . , three.js react-three-fiber .
, . drei storybook . , , , - .
– react. view - ? .
, three.js . , ES6 – .
. , – .
three.js three.js. , .
class Three {
constructor({
canvasContainer,
sceneSizes,
rectSizes,
color,
colorChangeHandler,
}) {
// this
this.sceneSizes = sceneSizes;
this.colorChangeHandler = colorChangeHandler;
this.initRenderer(canvasContainer); //
this.initScene(); //
this.initCamera(); //
this.initInteraction(); //
this.renderRect(rectSizes, color); //
this.render(); //
}
initRenderer(canvasContainer) {
// ( WebGL2)
// antialias
this.renderer = new THREE.WebGLRenderer({antialias: true});
//
this.renderer.setSize(this.sceneSizes.width, this.sceneSizes.height);
// -,
canvasContainer.appendChild(this.renderer.domElement);
}
initScene() {
//
this.scene = new THREE.Scene();
//
this.scene.background = new THREE.Color("white");
}
initCamera() {
// ( 2d)
this.camera = new THREE.OrthographicCamera(
this.sceneSizes.width / -2, //
this.sceneSizes.width / 2, //
this.sceneSizes.height / 2, //
this.sceneSizes.height / -2, //
100, //
-100 //
);
//
this.camera.position.set(
this.sceneSizes.width / 2, // x
this.sceneSizes.height / -2, // y
1 // z
);
}
initInteraction() {
// ( )
new Interaction(this.renderer, this.scene, this.camera);
}
render() {
// ( )
this.renderer.render(this.scene, this.camera);
}
renderRect({width, height}, color) {
// - "height" "width"
const geometry = new THREE.PlaneGeometry(width, height);
// "color"
const material = new THREE.MeshBasicMaterial({color});
// -
this.rect = new THREE.Mesh(geometry, material);
//
this.rect.position.x = this.sceneSizes.width / 2;
this.rect.position.y = -this.sceneSizes.height / 2;
// "three.interaction"
//
this.rect.on("click", () => {
//
this.colorChangeHandler();
});
this.scene.add(this.rect);
}
//
rectColorChange(color) {
//
this.rect.material.color.set(color);
// ( )
this.render();
}
}
ThreeContauner, React- Three.
import {useRef, useEffect, useState} from "react";
import Three from "./Three";
//
const sceneSizes = {width: 800, height: 500};
const rectSizes = {width: 200, height: 200};
const ThreeContainer = () => {
const threeRef = useRef(); // canvas
const three = useRef(); // , ,
const [color, colorChange] = useState("blue"); //
// Handler ,
const colorChangeHandler = () => {
//
colorChange((prevColor) => (prevColor === "grey" ? "blue" : "grey"));
};
// Three, three.js
useEffect(() => {
// "Three" ,
if (!three.current) {
// "Three", three.js
three.current = new Three({
color,
rectSizes,
sceneSizes,
colorChangeHandler,
canvasContainer: threeRef.current,
});
}
}, [color]);
// Three
useEffect(() => {
if (three.current) {
// ,
three.current.rectColorChange(color);
}
}, [color]);
// canvas ( three.js)
return <div className="container" ref={threeRef} />;
};
export default ThreeContainer;
.
, , , .
.
, three.js React- - , . , , / . , , virtual dom React-. , react-three-fiber drei – React-.
:
import {useState} from "react";
import {Canvas} from "@react-three/fiber";
import {Plane, OrthographicCamera} from "@react-three/drei";
//
const sceneSizes = {width: 800, height: 500};
const rectSizes = {width: 200, height: 200};
const ThreeDrei = () => {
const [color, colorChange] = useState("blue"); //
// Handler ,
const colorChangeHandler = () => {
//
colorChange((prevColor) => (prevColor === "white" ? "blue" : "white"));
};
return (
<div className="container">
{/* , */}
<Canvas className="container" style={{...sceneSizes, background: "grey"}}>
{/* three.js, makeDefault,
, */}
<OrthographicCamera makeDefault position={[0, 0, 1]} />
<Plane
//
onClick={colorChangeHandler}
// , three.js
args={[rectSizes.width, rectSizes.height]}
>
{/* three.js,
attach */}
<meshBasicMaterial attach="material" color={color} />
</Plane>
</Canvas>
</div>
);
};
export default ThreeDrei;
, , . , , . , , .
three.js React-. , .
! , .