Files
AR-Menu/AR Menu/Needle/MenuScene/node_modules/three-mesh-ui/examples/dev__justification.js
2025-11-30 08:35:03 +02:00

434 lines
11 KiB
JavaScript

import * as THREE from 'three';
import { VRButton } from 'three/examples/jsm/webxr/VRButton.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { BoxLineGeometry } from 'three/examples/jsm/geometries/BoxLineGeometry.js';
import Stats from 'three/examples/jsm/libs/stats.module.js';
import ThreeMeshUI, { FontLibrary } from 'three-mesh-ui';
import MSDFNormalMaterial from 'three-mesh-ui/examples/materials/msdf/MSDFNormalMaterial';
import ROBOTO_ADJUSTMENT from 'three-mesh-ui/examples/assets/fonts/msdf/roboto/adjustment';
const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;
let container, justifyInRow, justifyInColumn;
const DIM_HIGH = 1.6;
const MIN_HIGH = 1.1;
const DIM_LOW = 0.25;
const justificationLegend = [
{ id: 'start', color: 0xff9900 },
{ id: 'end', color: 0xff0099 },
{ id: 'center', color: 0x00ff99 },
{ id: "space-between", color: 0x99ff00 },
{ id: "space-around", color: 0x9900ff },
{ id: "space-evenly", color: 0x0099ff }
];
let scene, camera, renderer, controls, stats;
// Using `ThreeMeshUI.FontLibrary.prepare( fontFamily, [...fontFamily] )
// We can ensure any fontFamily passed in that function and theirs variants are properly loaded and setup
FontLibrary.prepare(
FontLibrary
// Registering a fontFamily called "Roboto", the name is up to us.
.addFontFamily("Roboto")
// On the fontFamily added, lets add a variant
// a font variant usually requires 4 parameters
.addVariant(
// The weight of the variant '100'|'200'|'300'|'400'|'600'|'700'|'800'|'900'
// LIGHTER NORMAL BOLD BOLDER
"400",
// The style of the variant 'normal'|'italic'|'oblique'|'oblique(x deg)'
"normal",
// The json definition of the msdf font 'urlToLoad'|loadedObject
"./assets/fonts/msdf/roboto/regular.json",
// The texture of the msdf font 'urlToLoad'|Texture
"./assets/fonts/msdf/roboto/regular.png"
)
// Registering additional variants
.addVariant("700", "italic", "./assets/fonts/msdf/roboto/bold-italic.json", "./assets/fonts/msdf/roboto/bold-italic.png" )
.addVariant("700", "normal", "./assets/fonts/msdf/roboto/bold.json", "./assets/fonts/msdf/roboto/bold.png" )
.addVariant("400", "italic", "./assets/fonts/msdf/roboto/italic.json", "./assets/fonts/msdf/roboto/italic.png" )
// FontLibrary.prepare() returns a Promise, we can therefore add a callback to be executed when all files are loaded
).then( () => {
// Once font are registered, we can get the font family
const RobotoFamily = FontLibrary.getFontFamily("Roboto");
// And then retrieve a fontVariant defined in this Family
const RobotoRegular = RobotoFamily.getVariant('400','normal');
// Having font variant allows us to perform some modifications
// 1. Adjustments
// If you look closely the `Getting started - Basic Setup` you may have noticed that :
// - the `h` character is slightly below the baseline
// This can be adjusted per fontVariant
RobotoRegular.adjustTypographicGlyphs( {
// 'h' character must change some of its properties defined in the json
h: {
// the yoffset property should be 2 (instead of 4 in the json)
yoffset: 2
}
} );
// Once adjusted, any three-mesh-ui Text using this font variant will use the adjusted properties
// 1. Material
// Instead of assigning custom materials to Text one by one
// We can assign a Material(class) to a font variant (Here the bold one)
RobotoFamily.getVariant('700','normal').fontMaterial = MSDFNormalMaterial;
// Once set, any three-mesh-ui Text using this font variant will use the defined material
// We may encounter the following lines in other examples,
// they are adjusting font variants to display a nice baseline
RobotoFamily.getVariant('700','normal').adjustTypographicGlyphs( ROBOTO_ADJUSTMENT );
RobotoFamily.getVariant('700','italic').adjustTypographicGlyphs( ROBOTO_ADJUSTMENT );
RobotoFamily.getVariant('400','italic').adjustTypographicGlyphs( ROBOTO_ADJUSTMENT );
// Now that the font are loaded and adjusted,
init();
});
window.addEventListener( 'resize', onWindowResize );
//
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x505050 );
camera = new THREE.PerspectiveCamera( 60, WIDTH / HEIGHT, 0.1, 100 );
renderer = new THREE.WebGLRenderer( {
antialias: true
} );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( WIDTH, HEIGHT );
renderer.xr.enabled = true;
document.body.appendChild( VRButton.createButton( renderer ) );
document.body.appendChild( renderer.domElement );
stats = new Stats();
document.body.appendChild( stats.dom );
controls = new OrbitControls( camera, renderer.domElement );
camera.position.set( 0, 1.6, 0 );
controls.target = new THREE.Vector3( 0, 1, -1.8 );
controls.update();
// ROOM
const room = new THREE.LineSegments(
new BoxLineGeometry( 6, 6, 6, 10, 10, 10 ).translate( 0, 3, 0 ),
new THREE.LineBasicMaterial( { color: 0x808080 } )
);
scene.add( room );
// TEXT PANEL
makeTitlePanel();
justifyInRow = makeTextPanel( 'column' );
window.rootBlock = justifyInRow;
justifyInColumn = makeTextPanel( 'row' );
justifyInRow.position.x = -0.75;
justifyInRow.scale.setScalar( 0.75 );
justifyInColumn.position.x = 0.75;
justifyInColumn.scale.setScalar( 0.75 );
//
renderer.setAnimationLoop( loop );
}
function makeTextPanel( flexDirection ) {
container = new ThreeMeshUI.Block( {
height: DIM_HIGH + 0.2,
width: DIM_HIGH + 0.2,
flexDirection: flexDirection,
justifyContent: 'center',
backgroundOpacity: 1,
backgroundColor: new THREE.Color( 'grey' ),
overflow: 'hidden',
fontFamily: "Roboto"
} );
container.position.set( 0, 1, -1.8 );
container.rotation.x = - 0.55;
scene.add( container );
for ( let i = 0; i < justificationLegend.length; i ++ ) {
const color = new THREE.Color( justificationLegend[ i ].color );
const id = justificationLegend[ i ].id;
const panel = buildJustifiedPanel( id, color, flexDirection === 'column' ? 'row' : 'column' );
container.add( panel );
}
return container;
}
function buildJustifiedPanel( id, color, flexDirection ) {
const panel = new ThreeMeshUI.Block( {
width: flexDirection === 'row' ? DIM_HIGH : DIM_LOW,
height: flexDirection === 'row' ? DIM_LOW : DIM_HIGH,
flexDirection: flexDirection,
justifyContent: id,
backgroundOpacity: 0.3,
backgroundColor: 0xff9900,
padding: 0.01,
margin: 0.01,
offset:0.0001
} );
container.add( panel );
const letters = 'ABCDEF';
const step = 0xFFFFFF / 5;
for ( let i = 0; i < 5; i ++ ) {
const blockText = new ThreeMeshUI.Block( {
margin: 0.01,
borderRadius: 0.05,
backgroundColor: color,
justifyContent: 'center',
alignItems: 'center',
borderWidth: '0 0 0.01 0',
borderColor: Math.floor( step * (5-i) ),
offset:0.001,
visible: i !== 2,
} );
if( i === 0 ) {
blockText.set({ width:0.125, height:0.125 });
}
panel.add( blockText );
const text = new ThreeMeshUI.Text( {
textAlign: 'center',
alignItems : 'center',
lineHeight: 1,
width: 0.125,
height: 0.125,
textContent: letters[ i ],
} );
blockText.add( text );
}
return panel;
}
function makeTitlePanel(){
const panel = new ThreeMeshUI.Text( {
width: DIM_HIGH * 1.85,
height: 0.15,
padding: 0.05,
flexDirection: 'row',
justifyContent: 'center',
textAlign: 'center',
backgroundOpacity: 0.6,
fontSize: 0.1,
fontFamily: "Roboto"
} );
for ( let i = 0; i < justificationLegend.length; i ++ ) {
const color = new THREE.Color( justificationLegend[ i ].color );
const id = justificationLegend[ i ].id;
panel.add(
new ThreeMeshUI.Inline( {
textContent: id + " ",
color: color
} )
);
}
panel.scale.setScalar( 0.86 );
panel.position.set( 0, 1.8, -2.1 );
scene.add( panel );
}
// handles resizing the renderer when the viewport is resized
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
let isInverted = false;
setInterval( () => {
isInverted = ! isInverted;
for ( let i = 1; i < justifyInRow.children.length; i ++ ) {
justifyInRow.children[ i ].set( { flexDirection:isInverted ? 'row-reverse' : 'row' } );
}
for ( let i = 1; i < justifyInColumn.children.length; i ++ ) {
justifyInColumn.children[ i ].set( { flexDirection:isInverted ? 'column-reverse' : 'column' } );
}
}, 2500 );
let alignMode = 1;
const aligns = [ 'start', 'center', 'end', 'stretch'];
setInterval( () => {
alignMode += 1;
alignMode = alignMode >= aligns.length ? 0 : alignMode;
const mode = aligns[alignMode];
for ( let i = 1; i < justifyInRow.children.length; i ++ ) {
justifyInRow.children[ i ].set( { alignItems: mode } );
}
for ( let i = 1; i < justifyInColumn.children.length; i ++ ) {
justifyInColumn.children[ i ].set( { alignItems: mode } );
}
}, 1000 );
// let sizeMode = 1;
// const sizes = [ 0.125, 0.175, 0.225, 0.295 ];
//
// setInterval( () => {
//
// sizeMode += 1;
// sizeMode = sizeMode >= sizes.length ? 0 : sizeMode;
//
// const mode = sizes[ sizeMode ];
//
// for ( let i = 1; i < justifyInRow.children.length; i ++ ) {
//
// for ( let j = 1; j < justifyInRow.children[ i ].children.length; j ++ ) {
//
// justifyInRow.children[ i ].children[ j ].set( { width: mode } );
//
// }
//
// }
//
// for ( let i = 1; i < justifyInColumn.children.length; i ++ ) {
//
// for ( let j = 1; j < justifyInColumn.children[ i ].children.length; j ++ ) {
//
// justifyInColumn.children[ i ].children[ j ].set( { height:mode } );
//
// }
// }
//
// }, 3000 );
// let childAlignMode = 1;
// const childAligns = [ 'center', 'stretch' ];
//
// setInterval( () => {
//
// childAlignMode += 1;
// childAlignMode = childAlignMode >= childAligns.length ? 0 : childAlignMode;
//
// const mode = childAligns[ childAlignMode ];
//
// for ( let i = 1; i < justifyInRow.children.length; i ++ ) {
//
// for ( let j = 1; j < justifyInRow.children[ i ].children.length; j ++ ) {
//
// justifyInRow.children[ i ].children[ j ].set( { alignItems: mode } );
//
// }
//
// }
//
// for ( let i = 1; i < justifyInColumn.children.length; i ++ ) {
//
// for ( let j = 1; j < justifyInColumn.children[ i ].children.length; j ++ ) {
//
// justifyInColumn.children[ i ].children[ j ].set( { alignItems:mode } );
//
// }
// }
//
// }, 500 );
let currentBigSize = DIM_HIGH;
let currentSpeed = - 0.005;
function loop() {
currentBigSize += currentSpeed;
if ( currentBigSize >= DIM_HIGH ) {
currentBigSize = DIM_HIGH;
currentSpeed *= - 1;
} else if ( currentBigSize <= MIN_HIGH ) {
currentBigSize = MIN_HIGH;
currentSpeed *= -1;
}
for ( let i = 1; i < justifyInRow.children.length; i ++ ) {
justifyInRow.children[ i ].set( { width: currentBigSize } );
}
for ( let i = 1; i < justifyInColumn.children.length; i ++ ) {
justifyInColumn.children[ i ].set( { height: currentBigSize } );
}
// Don't forget, ThreeMeshUI must be updated manually.
// This has been introduced in version 3.0.0 in order
// to improve performance
ThreeMeshUI.update();
controls.update();
renderer.render( scene, camera );
stats.update();
}