JSFiddle - React, Tailwind, and code Playground
HTML
<!-- Right click to change the pivot point -->
<!DOCTYPE html>
<html>
<head>
<title>Rotation and Scale</title>
<meta name='viewport' content='initial-scale=1.0,width=device-width'>
</head>
<body>
<canvas id='scene'></canvas>
<div class='ctrls'>
<div class='ctrl-item' id='scale'>Scale</div>
<div class='ctrl-item active' id='rotate'>Rotate</div>
</div>
<script src='https://threejs.org/build/three.min.js'></script>
</body>
</html>
CSS
body {
padding: 0;
margin: 0;
font-family: arial;
font-size: 16px;
user-select: none;
}
#scene {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.ctrls {
position: absolute;
top: 0;
left: 0;
display: flex;
flex-direction: row;
padding: 10px;
}
.ctrl-item {
border-radius: 1.55em;
padding: 0.45em 0.85em;
margin: 0 5px;
color: #666;
background: #fff;
font-weight: 700;
transition: all 0.2s ease-in;
cursor: pointer;
}
.ctrl-item:active, .active {
box-shadow: 0 0.11em 0.11em #ccc inset;
color: #03a9f4;
}
JavaScript
var renderer = new THREE.WebGLRenderer( {
alpha: true,
antialias: true,
canvas: document.getElementById( 'scene' )
} );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x333333 );
var scene = new THREE.Scene();
var frustumSize = 10;
var aspect = window.innerWidth / window.innerHeight;
var camera = new THREE.OrthographicCamera( -frustumSize * aspect, frustumSize * aspect, frustumSize, -frustumSize, 0, 10 );
var geometry = new THREE.PlaneGeometry( 5, 5 );
var material = new THREE.MeshBasicMaterial( { color: 'gold', side: THREE.DoubleSide } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.x = 0;
scene.add( mesh );
// universal back plane
var _plane = new THREE.Mesh( new THREE.PlaneGeometry( 10000, 10000 ), undefined );
var gizmoGeometry = new THREE.PlaneGeometry( 1, 1 );
var gizmoMaterial = new THREE.MeshBasicMaterial( { color: 'silver' } )
var gizmo = new THREE.Mesh( gizmoGeometry, gizmoMaterial );
gizmo.position.x = -4;
mesh.add( gizmo );
var pivotGeometry = new THREE.PlaneGeometry( 1, 1 );
var pivotMaterial = new THREE.MeshBasicMaterial( { color: 'black' } )
var pivot = new THREE.Mesh( pivotGeometry, pivotMaterial );
mesh.add( pivot );
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var pointStart = new THREE.Vector3();
var pointEnd = new THREE.Vector3();
var canRotate = false;
var canScale = false;
document.oncontextmenu = function() { return false; }
var isRightMouseBtnDown = false;
function setPivot() {
mesh.pivot.x = mouse.x * frustumSize * aspect;
mesh.pivot.y = mouse.y * frustumSize;
pivot.position.copy( mesh.pivot );
}
function onMouseDown( evt ) {
mouse.set( 2.0 * evt.clientX / window.innerWidth - 1.0, -2.0 * evt.clientY / window.innerHeight + 1.0 );
raycaster.setFromCamera( mouse, camera );
if ( evt.button === 2 ) {
isRightMouseBtnDown = true;
setPivot();
}
var intersects = raycaster.intersectObject( gizmo )[ 0 ];
if...