I have two lists of data on the screen, one on the left and one on the right, I'm trying to show the relationship between the two lists. The lists should look somewhat like the ones in the middle of this image. This image is from this webpage https://react-three-fiber-website-playground.vercel.app/ but this has been done in D3 I can see. I need to do the same in Three.js, ideally react-three-fiber. Would bezier curves help? Is there a proper name for this type of data visualization?
Just to show the current lines are drawing nicely based upon the example code given in answer here.
As an option, use CubicBezierCurve
and bend PlaneGeometry
in accordance to the curve:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three@0.133.1";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
camera.lookAt(scene.position);
let renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(innerWidth, innerHeight);
renderer.setClearColor(0x202020);
document.body.appendChild(renderer.domElement);
let basePoints = [ // start, end points
new THREE.Vector3(-2, -3),
new THREE.Vector3(2, 3)
];
let pathPoints = [
basePoints[0],
new THREE.Vector2().addVectors(basePoints[0], basePoints[1]).multiplyScalar(0.5).setY(basePoints[0].y),
new THREE.Vector2().addVectors(basePoints[0], basePoints[1]).multiplyScalar(0.5).setY(basePoints[1].y),
basePoints[1]
]
let curve = new THREE.CubicBezierCurve(pathPoints[0], pathPoints[1], pathPoints[2], pathPoints[3]);
let resultPoints = curve.getSpacedPoints(50);
let line = new THREE.Line(new THREE.BufferGeometry().setFromPoints(resultPoints), new THREE.LineBasicMaterial({
color: "yellow"
}));
scene.add(line);
let width = [1, 3]; // start, end
let g = new THREE.PlaneGeometry(1, 1, 50, 1);
let pos = g.attributes.position;
for (let i = 0; i <= 50; i++) {
let lrp = THREE.MathUtils.lerp(width[0], width[1], i / 50);
pos.setXYZ(
i, resultPoints[i].x, resultPoints[i].y + lrp * 0.5 * Math.sign(pos.getY(i)), 0
);
pos.setXYZ(
i + 51, resultPoints[i].x, resultPoints[i].y + lrp * 0.5 * Math.sign(pos.getY(i + 51)), 0
)
}
let m = new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
});
let o = new THREE.Mesh(g, m);
scene.add(o);
window.addEventListener("resize", onResize);
renderer.setAnimationLoop(_ => {
renderer.render(scene, camera);
})
function onResize(event) {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
}
</script>