Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions examples/css2d_label.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
const MOON_RADIUS = 0.27;

camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 200 );
camera.position.set( 10, 5, 20 );
camera.position.set( 5, 2, 10 );
camera.layers.enableAll();

scene = new THREE.Scene();
Expand Down Expand Up @@ -127,43 +127,49 @@
earthDiv.className = 'label';
earthDiv.textContent = 'Earth';
earthDiv.style.backgroundColor = 'transparent';
earthDiv.style.border = "1px solid white";

const earthLabel = new CSS2DObject( earthDiv );
earthLabel.position.set( 1.5 * EARTH_RADIUS, 0, 0 );
earthLabel.center.set( 0, 1 );
earthLabel.center.set( 0, 1 ); // lower-left
earth.add( earthLabel );
earthLabel.layers.set( 0 );
earthLabel.rotationAngle = Math.PI / 8;

const earthMassDiv = document.createElement( 'div' );
earthMassDiv.className = 'label';
earthMassDiv.textContent = '5.97237e24 kg';
earthMassDiv.style.backgroundColor = 'transparent';
earthMassDiv.style.border = "1px solid white";

const earthMassLabel = new CSS2DObject( earthMassDiv );
earthMassLabel.position.set( 1.5 * EARTH_RADIUS, 0, 0 );
earthMassLabel.center.set( 0, 0 );
earthMassLabel.center.set( 0, 0 ); // upper-left
earth.add( earthMassLabel );
earthMassLabel.layers.set( 1 );
earthMassLabel.rotationAngle = - Math.PI / 8;

const moonDiv = document.createElement( 'div' );
moonDiv.className = 'label';
moonDiv.textContent = 'Moon';
moonDiv.style.backgroundColor = 'transparent';
moonDiv.style.border = "1px solid white";

const moonLabel = new CSS2DObject( moonDiv );
moonLabel.position.set( 1.5 * MOON_RADIUS, 0, 0 );
moonLabel.center.set( 0, 1 );
moonLabel.center.set( 0, 1 ); // lower-left
moon.add( moonLabel );
moonLabel.layers.set( 0 );

const moonMassDiv = document.createElement( 'div' );
moonMassDiv.className = 'label';
moonMassDiv.textContent = '7.342e22 kg';
moonMassDiv.style.backgroundColor = 'transparent';
moonMassDiv.style.border = "1px solid white";

const moonMassLabel = new CSS2DObject( moonMassDiv );
moonMassLabel.position.set( 1.5 * MOON_RADIUS, 0, 0 );
moonMassLabel.center.set( 0, 0 );
moonMassLabel.center.set( 0, 0 ); // upper-left
moon.add( moonMassLabel );
moonMassLabel.layers.set( 1 );

Expand Down
31 changes: 26 additions & 5 deletions examples/jsm/renderers/CSS2DRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,23 @@ class CSS2DObject extends Object3D {
this.element.setAttribute( 'draggable', false );

/**
* The 3D objects center point.
* `( 0, 0 )` is the lower left, `( 1, 1 )` is the top right.
* The object's anchor point, and the point around which the object rotates.
* A value of `(0.5, 0.5)` corresponds to the midpoint of the object. A value
* of `(0, 0)` corresponds to the upper left corner of the object.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not change the implementation of the "center" API. (0, 0) was always the upper-left, not the lower-left, in this renderer.

The upper-left/lower-left convention is not consistent in three.js, and perhaps it would be advisable to agree to a convention going forward.

*
* @type {Vector2}
* @default (0.5,0.5)
*/
this.center = new Vector2( 0.5, 0.5 );

/**
* The object's angle of rotation, counterclockwise, in radians.
*
* @type {number}
* @default 0
*/
this.rotationAngle = 0;
Copy link
Copy Markdown
Collaborator Author

@WestLangley WestLangley Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't use rotation for the name. CSS3DRenderer uses rotation2D.


this.addEventListener( 'removed', function () {

this.traverse( function ( object ) {
Expand Down Expand Up @@ -97,8 +106,7 @@ const _a = new Vector3();
const _b = new Vector3();

/**
* This renderer is a simplified version of {@link CSS3DRenderer}. The only transformation that is
* supported is translation.
* This renderer is a simplified version of {@link CSS3DRenderer}.
*
* The renderer is very useful if you want to combine HTML based labels with 3D objects. Here too,
* the respective DOM elements are wrapped into an instance of {@link CSS2DObject} and added to the
Expand Down Expand Up @@ -235,7 +243,20 @@ class CSS2DRenderer {

object.onBeforeRender( _this, scene, camera );

element.style.transform = 'translate(' + ( - 100 * object.center.x ) + '%,' + ( - 100 * object.center.y ) + '%)' + 'translate(' + ( _vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - _vector.y * _heightHalf + _heightHalf ) + 'px)';
// pivot point
const cx = 100 * object.center.x;
const cy = 100 * object.center.y;
element.style.transformOrigin = `${cx}% ${cy}%`;

// angle of rotation, counter-clockwise convention
const angle = - object.rotationAngle;

// coordinates
const tx = _vector.x * _widthHalf + _widthHalf;
const ty = -_vector.y * _heightHalf + _heightHalf;

// transform
element.style.transform = `translate(${-cx}%, ${-cy}%) translate(${tx}px, ${ty}px) rotate(${angle}rad)`;

if ( element.parentNode !== domElement ) {

Expand Down
Loading