question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Asking for advice on manage three.js with React and data-driven rendering possibility in react-three-fiber

See original GitHub issue

Hi, thanks for sharing react-three-fiber with developers! I got really a lot thoughts in how to manage three.js application with React from this project.

Currently, I’m going to make a series of data visualization tutorials from scratch, and I also created a repository in GitHub call glmaps. In a word, glmaps is a project full of bunch of earth and map visualization examples based on three.js and deck.gl, as well as some tutorials for visualization beginners, in which I realized a small three.js application manager, too.

The manager I created is quite simple, but can cover the basic needs, such as Curve Animation, I may ask you for advice in better coding, that is how will you organize the codes if you need to realize it.

1. The background and question description

I created a globe with three.js, in which I have a visualization type named “Curve Animation”(Something like arc animation from origin to destination). I handle this requirement with dividing it into two parts currently.

  1. Manage three.js scene with React (with Hooks, Hooks is really good!)
  2. Animate Curve with setRange and force it update

1.1 Manage three.js

My idea is quite simple, I provide a three.js wrapper for react developers (I know it lacks a lot of reactive things):

const ThreeCube = (props) => {
  useEffect(() => {
    if (!data.length) return () => {};

    const [cleanFunc] = threeEntryPoint({
      ...props
    });

    return () => {
      cleanFunc();
    };
  });

  return (
    <canvas 
      id={id}
    />
  );
};

in which developers can handle his three.js application just like write plain JavaScript. In which threeEntryPoint is entry point for SceneManager, and the later is a function which can handle the whole three.js application lifecycle.

const threeEntryPoint = ({id, ...otherProps}) => {
  const canvas = document.getElementById(id);
  const sceneManager = SceneManager.getInstance(canvas, otherProps);
  raf = null;
  
  function bindEventListeners() {
    window.addEventListener ("resize", resizeCanvas);

    resizeCanvas();
  }
  resizeCanvas = function() {
    // ...
  }
  const render = () => {
    // ...
  }

  bindEventListeners();
  render();

  const cleanFunc = () => {
    const gl = canvas.getContext('webgl');
    gl.clearColor(1.0, 1.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    window.removeEventListener("resize", resizeCanvas);
    cancelAnimationFrame(raf);
    SceneManager.destroyInstance();
  }

  return [cleanFunc];
}

1.2 Animate Curve

Definition of Curve (the orange lines in the picture): Curve is actually THREE.Line made with THREE.BufferGeometry (so I can control which part of this line be rendered to the scene, with the help of setRange method)

The structure of my scene is:

  • Put multiple Curve (which is THREE.Line) in THREE.Mesh code
  • Put the THREE.BufferGeometry used in Curve in an array (suppose it’s named curveMesh) code
  • Put THREE.Mesh in THREE.Group, and put THREE.Group in THREE.Scene code

and then when I need to update the Curve, I get the array and manipulate it like this:

curveMesh.children.forEach((path) => {
  path.geometry.setDrawRange(index, 20);
  path.geometry.attributes.position.needsUpdate = true;
})

and then back to the title of this issue (sorry for that, but I think only in this way I can express my thoughts completely…).

2. How to make data-driven render possible with react-three-fiber

I wonder how can I do it with react-three-fiber if I want to realize the above animation? According to README, I think I may code it in this way possibly:

import { Canvas } from 'react-three-fiber'

function App(props) {
  const {curvesData = []} = props;
  return (
    <Canvas>
      <group>
        <mesh
          geometry={new THREE.BoxGeometry(1, 1, 1)}
          material={new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true })}
        >
			{curvesData.map((curve) => {
				<line
	          	  geometry={new THREE.BufferGeometry()}
	  			  // MY THOUGHTS
				  onUpdate={(instance) => instance.setDrawRange(SOMETHING, SOMETHING, etc)}
		        />
			})}
		</mesh>
      </group>
    </Canvas>
  )
}

but how can I insert setDrawRange method, I’m not sure whether it’s right to put it inside a onUpdate callback?

And another question is that what’s your consideration in designing the API of react-three-fiber? Since I find you may want developers provide objects like geometry manually, rather than a data-driven API like D3?

The way D3 handle it:

d3.select("body")
  .selectAll("p")
  .data([4, 8, 15, 16, 23, 42])
  .enter().append("p")
    .text(function(d) { return "I’m number " + d + "!"; });

I supposed react-three-fiber may do it like this (if it’s good to do it in this way):

import { Canvas } from 'react-three-fiber'

function App() {
  return (
    <Canvas>
      <group>
        <mesh
          geometry={new THREE.BoxGeometry(1, 1, 1)}
          material={new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true })}
          data={data}
		  customRender={(item, index, instance) => {
			// instance: the object itself
			// item: current data item, equals to data[index]
			// index: current data item index
			
			// customized logic here
		  }}
        />
      </group>
    </Canvas>
  )
}

Thanks for your sharing, again! react-three-fiber is really awesome!

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
drcmdacommented, Feb 27, 2019

1

The first is possible:

<Canvas render={({ gl, canvas, scene, camera ) => {
  gl.render(scene, camera)
}}>

You don’t need the resize event, it auto adjusts with a resize observer, meaning that it can even respond to changes if it isn’t fullscreen.

2

You still have full access. I realize that in some situations pure declarative support is probably not possible since three has so many access functions. A good way could be to break these up into small, contained components instead.

const ref = useRef()
useEffect(() => {
  ref.current.children.forEach((path) => {
    path.geometry.setDrawRange(index, 20);
    path.geometry.attributes.position.needsUpdate = true;
  })
})
return <mesh ref={ref} />
0reactions
hijiangtaocommented, Mar 1, 2019

Thanks for sharing your thoughts!

Read more comments on GitHub >

github_iconTop Results From Across the Web

A Dive Into React And Three.js Using react-three-fiber
react -three-fiber is a powerful Three.js renderer that helps render 3D models and animations for React and its native applications.
Read more >
3D Data Visualization with React and Three.js - Medium
In this post, I'll go over how to create something similar to what I did using React, Three.js, and react-three-fiber as the magical...
Read more >
Building with React and Three.js using React Three Fiber
What's up, everyone! Hope you are all having a great week so far :) In this episode, we are going to work on...
Read more >
I wish I knew this before using React Three Fiber - YouTube
Sometimes the best way to understand a library like React Three Fiber is to compare it to the original 3D web library, Three....
Read more >
THREE JS computeBoundingBox - Stack Overflow
i am working on this react project, its using threeJs objects, i upgraded the version of threeJs and this part of the code...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Hashnode Post

No results found