I’m creating a network diagram. I have a line that connects two objects and I’m also aligning objects (network interface labels) on that line.
In the scene I’m using drag controls for my object (network routers) and no other controls are configured for the scene.
When dragging the routers I have the points in the line updating and while updating the network interface label positions manually. The issue is the labels positions flip depending on where a node is dragged as seen in the video. Here is the code to update label postions.
I’ve tried to group the line and the labels but i think since I’m only updating the line points and not positions, the label wont move as a group with the line.
As a test I assign drag controls to the line and labels as group and they move as one. Per my design I only want the routers being dragged.
Countless hours and I’m running out of ideas. I think the solution maybe something i don’t understand about three.js yet.
So you have a line in 3D space and you want to position another 3D object (label) above the line at a certain point, counting from one end of the line towards the other as, say, a percentage of the line’s length?
I have the labels positioned as i want , its just when i drag the object in a certain direction you can see the labels flip/rotate depending on the direction. This would make my scene or network topology inaccurate .
As far as complexity, I would love any advice on placing the labels on the lines with less code. They aren’t exactly where I want them as I would like them center on the line. -----[–g0/1–]----. I’ve have a a lot of code for this project but this seems to be my roadblock.
I don’t know how you make labels (I would write text on 2D canvas and then used it as a texture for Point geometry, so your labels always face the camera).
Apart from that here is a simple example of objects tracing start, end and middle points of a line:
Here is how the line and labels is created. This code is executed in two possible ways. With imported data from the backend it creates the scene dynamically, or when someone is creating a diagram using eventListeners for ctrl + leftClick. If 2 devices are selected it creates the line between the two objects.
The labels are always front facing, and for the scene i don’t have any controls configured other than dragControls. This is by design
export const setLinkLabels = (linkLabelOne, linkLabelTwo, line) => {
const center = line.geometry.boundingBox.getCenter(line.geometry.boundingSphere.center)
line.geometry.boundingBox.copy(line.geometry.boundingBox).applyMatrix4(line.matrixWorld)
const dir = line.geometry.boundingBox.max.clone().sub(center).normalize().multiplyScalar(.85)
const dirTwo = line.geometry.boundingBox.min.clone().sub(center).normalize().multiplyScalar(.85)
linkLabelOne.position.set(center.clone().add(dirTwo).x, center.clone().add(dirTwo).y, 0)
linkLabelTwo.position.set(center.clone().add(dir).x, center.clone().add(dir).y, 0)
}
export const canvas = (labelText) => {
const canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;
const ctx = canvas.getContext("2d");
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.strokeStyle = "black";
ctx.lineWidth = 8;
ctx.strokeText(labelText, 128, 46);
ctx.fillText(labelText, 128, 46);
return canvas
}
const createLabel = (labelText) => {
const createCanvas = canvas(labelText)
const texture = new THREE.Texture(createCanvas);
texture.needsUpdate = true;
const spriteMat = new THREE.SpriteMaterial({map: texture});
return new THREE.Sprite(spriteMat)
}
const addLink = (operation) => {
//multiselect.current is the to objects that the line connects. It also has the label text which is applied to canvas
const linkLabelOne = createLabel(multiSelect.current[0].interface)
const linkLabelTwo = createLabel(multiSelect.current[1].interface)
const points = [];
points.push(multiSelect.current[0].position);
points.push(multiSelect.current[1].position);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({color: 0xffffff, depthTest: false});
const line = new THREE.Line(geometry, material);
line.links = {from: multiSelect.current[0].uuid, to: multiSelect.current[1].uuid}
line.renderOrder = 0
line.geometry.attributes.position.needsUpdate = true;
line.geometry.computeBoundingBox();
line.geometry.computeBoundingSphere();
line.add(linkLabelOne)
line.add(linkLabelTwo)
setLinkLabels(linkLabelOne, linkLabelTwo, line)
scene.current.add(line);
}
In the last fiddle labels go boom0 - boom1 - boom2, when the line flips horizontally, they go boom2 - boom1 - boom0, so labels follow the line ends, as they should, do they not?
I added back the cubes that mark different ends of the line and the middle:
If you want labels to be on the line, that’s how you could it, if you want them to reposition somehow on top of that, then they are not on the line, that’s a different task.
I created a fiddle to simulate the action. Unfortunately I could not get dragControls imported. I was still able to simulate the action shown in my video and it looks like it works properly. Let me review my code to see if i can get it to work,