I get that this has probably been answered somewhere 100 times, or that this is knowledge that comes to those who bleed for it through trial and error, so this isn't being asked out of sheer negligence.
I understand how to create a R3F component with a function returning JSX code.
I understand how to create R3F groups and meshes, as well as how to add meshes to the group.
I understand how to do this in Three js and R3f independently.
I DON'T understand how the heck you can dynamically do this...
What I'm stubbornly trying to do is create a bar graph that contains a background plane and individual bars. There will be text later and tics and all the fun jazz once I can figure this basic hicth stuff out. I currently have a working component that generates the background called 'BackgroundGen':
2dBackgroundGen.jsx
import * as THREE from 'three';
function BackgroundGen({state, props, win, bg}) {
let path = ''
path = new THREE.Shape([
new THREE.Vector3(bg.background.x.start, bg.background.y.start, bg.background.z),
new THREE.Vector3(bg.background.x.stop, bg.background.y.start,bg.background.z),
new THREE.Vector3(bg.background.x.stop, bg.background.y.stop,bg.background.z),
new THREE.Vector3(bg.background.x.start, bg.background.y.stop,bg.background.z)])
bg.geometry = new THREE.ShapeGeometry(path)
bg.material = new THREE.MeshToonMaterial( { color: props.bg.color} );
bg.mesh = new THREE.Mesh(bg.geometry,bg.material)
console.log(`bg.mesh is: `)
console.log(`bg.mesh is: `)
console.log(`bg.mesh is: `)
console.log(bg.mesh)
return(
<mesh material = {bg.material} geometry = {bg.geometry}/>
)
}
export default BackgroundGen
I have a component that does NOT work called BarGen:
2dBarGen.jsx
import * as THREE from 'three';
function BarGen({state, props, bg})
{
console.log(`DURING BARGEN props is:`)
//console.log(props.bars.color)
let bar = []
let barMeshGroup = []
let bShapeGroup = []
let bGeometryGroup = []
let bMaterialGroup = []
let testGroup = []
let innerGap = 0
let xoffset = bg.background.x.start + ((props.bg.x.sidePadding + props.bg.x.borderSize) * state.viewport.width)
/*
console.log(`bg.background.x.start is: ${bg.background.x.start}`)
console.log(`props.bg.x.sidePadding is: ${props.bg.x.sidePadding}`)
console.log(`props.bg.x.borderSize is: ${props.bg.x.borderSize}`)
console.log(`state.viewport.width is: ${state.viewport.width}`)
console.log(`sum of props.bg.x.sidePadding + props.bg.x.borderSize is: ${props.bg.x.sidePadding + props.bg.x.borderSize}`)
console.log(`product of (props.bg.x.sidePadding + props.bg.x.borderSize) * state.viewport.width is: ${(props.bg.x.sidePadding + props.bg.x.borderSize) * state.viewport.width}`)
console.log(`sum of bg.background.x.start + (props.bg.x.sidePadding + props.bg.x.borderSize) * state.viewport.width is: ${bg.background.x.start + (props.bg.x.sidePadding + props.bg.x.borderSize) * state.viewport.width}`)
*/
if (props.bars.length > 1)
{
innerGap = props.bg.x.innerGap * props.bars.length * state.viewport.width
}
else
{
innerGap = 0
}
for(let i = 0; i<props.bars.length; i++)
{
bar[i] = {shape:0,geometry:0,material:0,x:{finalWidth:0,start:0, stop: 0}, y:{start:0, stop:0}, z:10}
//console.log(`i is: ${i}`)
bar[i].x.finalWidth = Math.abs(
(
(
bg.background.x.stop
-bg.background.x.start
)
-(
bg.background.x.borderSize
* 2
)
-innerGap
-(
(
props.bg.x.sidePadding
* 2
)
* state.viewport.width
)
)
/props.bars.length
)
//console.log(`bar[i].x.finalWidth is: ${bar[i].x.finalWidth}`)
if(i == 0)
{
bar[i].x.start = xoffset
//console.log(`initial bar[${i}].x.start: ${bar[i].x.start}`)
bar[i].x.stop = bar[i].x.start + bar[i].x.finalWidth
bar[i].y.start = bg.background.y.start + bg.background.y.borderSize + (props.bg.y.sidePadding*state.viewport.height)
bar[i].y.stop = bg.background.y.stop - bg.background.y.borderSize - ((props.bg.y.sidePadding + props.bg.header.y.size)*state.viewport.height)
}
else
{
//note the ONLY things that have been viewport corrected are bar.x.finalWdith, xoffset and bg.background objects
bar[i].x.start = xoffset + (bar[i].x.finalWidth*i) + (i*props.bg.x.innerGap*state.viewport.width)
/*
console.log(`BAR[${i}] CALC START:`)
console.log(`xoffset + (bar[i].x.finalWidth*i): ${xoffset + (bar[i].x.finalWidth*i)}`)
console.log(`i*props.bg.x.innerGap*state.viewport.width: ${(i*props.bg.x.innerGap*state.viewport.width)}`)
console.log(`BAR[${i}].x CALC STOP:`)
*/
bar[i].x.stop = bar[i].x.start + bar[i].x.finalWidth
bar[i].y.start = bg.background.y.start + bg.background.y.borderSize + (props.bg.y.sidePadding*state.viewport.height)
/*
console.log(`bar[${i}].y.start CALC START`)
console.log(`bar[${i}].y.start CALC START`)
console.log(`bar[${i}].y.start CALC START`)
console.log(`bg.background.y.start is: ${bg.background.y.start}`)
console.log(`bg.background.y.borderSize is: ${bg.background.y.borderSize}`)
console.log(`props.bg.y.sidePadding is: ${props.bg.y.sidePadding}`)
console.log(`state.viewport.height is: ${state.viewport.height}`)
console.log(`bg.background.y.start + bg.background.y.borderSize is: ${bg.background.y.start + bg.background.y.borderSize}`)
console.log(`props.bg.y.sidePadding*state.viewport.height is: ${props.bg.y.sidePadding*state.viewport.height}`)
console.log(`bg.background.y.start + bg.background.y.borderSize + (props.bg.y.sidePadding*state.viewport.height) is: ${bg.background.y.start + bg.background.y.borderSize + (props.bg.y.sidePadding*state.viewport.height)}`)
console.log(`bar[${i}].y.start CALC STOP`)
console.log(`bar[${i}].y.start CALC STOP`)
console.log(`bar[${i}].y.start CALC STOP`)
*/
bar[i].y.stop = bg.background.y.stop - bg.background.y.borderSize - ((props.bg.y.sidePadding + props.bg.header.y.size)*state.viewport.height)
}
console.log(`bar[${i}].x.start is ${bar[i].x.start}`)
console.log(`bar[${i}].x.stop is ${bar[i].x.stop}`)
console.log(`bar[${i}].y.start is ${bar[i].y.start}`)
console.log(`bar[${i}].y.stop is ${bar[i].y.stop}`)
bar[i].shape = new THREE.Shape
(
[
new THREE.Vector3(bar[i].x.start, bar[i].y.start, bar[i].z),
new THREE.Vector3(bar[i].x.stop, bar[i].y.start,bar[i].z),
new THREE.Vector3(bar[i].x.stop, bar[i].y.stop,bar[i].z),
new THREE.Vector3(bar[i].x.start, bar[i].y.stop,bar[i].z)
]
)
//bar[i].geometry = new THREE.ShapeGeometry(bar[i].shape)
bar[i].material = new THREE.MeshToonMaterial( { color: 0x300030} )
//barMeshGroup[i] = new THREE.Mesh(bar[i].geometry, bar[i].material)
//bShapeGroup[i] = bar[i].shape
//bShapeGroup[i] = bar[i].shape
//bMaterialGroup[i] = bar[i].material
//bGeometryGroup[i] = bar[i].geometry
testGroup[i] = {shape:bar[i].shape, material:bar[i].material}
}
//const bShapeMap = bShapeGroup.map(shape, i)
//const bMaterialMap = bMaterialGroup.map(material,i)
//const bGeometryMap = bGeometryGroup.map(geometry,i)
//const bMeshGroup = barMeshGroup.map(meshinst,i)
//testGroup is an array of objects[shape:,material:] that I'd like to use to dynamically create meshes when BarGen executs.
return(testGroup.map((meshobj,i) => <mesh key={i} geometry={meshobj.shape} material={meshobj.material}/> ))
}
export default BarGen
And I have an application component that utilizes both BackgroundGen and BarGen for rendering.
App.jsx
import './App.css'
import { Canvas} from '@react-three/fiber'
import { Stats } from './common/Stats'
import TwoDBG from './common/2dBarGraph'
function BackGround()
{/*List of properties for bgInfo
color: in hex format 0xff0000
header:
text: the title of this bar graph
y:
size: the size in y of this header pane within the background plane
x:
borderSize: the percentage of the background plane the border on the left and right sides (of the background plane) is going to take. This will be scaled to the viewport size later
innerGap: the percentage of the background plane between bargraph bar meshes. Placed here to prevent future misuse of changing this value on a per-bar basis in the barGen component
sidePadding: the percentage of the background plane between the side borders and the outer edges of the bars generated for this bargraph (to be generated in a seperate component called barGen)
size: the 'x' percentage of the viewport (or available space within the browser from the users perspective when ran, will likely need to be updated with event 'onWindowChange' (actual event name probably differs) at a later time)
y:
borderSize: the percentage of the background plane the border on the top and bottom sides (of the background plane) is going to take
sidePadding: the percentage of the background plane between the top and bottom borders and the outer edges of the bars generated for this bargraph (to be generated in a seperate component called barGen)
size: the 'y' percentage of the viewport (or available space within the browser from the users perspective when ran), will likely need to be updated with event 'onWindowChange' (actual event name probably differs) at a later time)
*/
let bgdetails = {
bg: {color:0x300030,header:{text:'',y:{size:.1}},x:{borderSize:.05, innerGap: .05, sidePadding: .05, size:.2},y:{borderSize:.05,sidePadding: .05, size:.6}},
bars: [{color:0x50FF0f, min:0, max:100, num:1, units:'$', title:"MaterialsCost"},{color:0x50FF0f, min:0, max:100, num:2, units:'$', title:"MaterialsCost"}] //stack position to be added later if you want to stack bars
}
return (
<Canvas>
<Stats />
<TwoDBG {...bgdetails}/>
</Canvas>
)
}
function App() {
return (
<>
<BackGround/>
</>
)
}
export default App
Can someone please help me understand how to dynamically generate and return meshes in the BarGen component? It seems like the array map function has been utilized for this from other people, but I'm running into a thick wall of not understanding what is and is not allowed for generating JSX return statements with respect to what React Three Fiber can tolerate.
At the end of the day, I plan on using these components for generating a bargraph with a number of bars based on how many initial inputs the data source provides.
Thank you!
I described everything I was trying in the above statement along with all the source files utilized.
So, realized that not many folks are answering questions in the react-three-fiber tag..
Kept beating my head against the wall and FINALLY got this working:
App.jsx
2dBarGraph.jsx
2dBackground.jsx
2dBarGen.jsx