mirror of
https://github.com/leaders-of-digital-9-task/3d-viewer.git
synced 2024-12-04 23:13:44 +03:00
add all
This commit is contained in:
commit
f1dc8e5de7
15
index.html
Normal file
15
index.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script src="/stl_viewer/stl_viewer.min.js"></script>
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="stl_cont"></div>
|
||||||
|
|
||||||
|
<script src="index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
15
index.js
Normal file
15
index.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
var stl_viewer=new StlViewer(document.getElementById("stl_cont"), { models: [ {
|
||||||
|
id:0,
|
||||||
|
filename:"https://storage.googleapis.com/ucloud-v3/ccab50f18fb14c91ccca300a.stl",
|
||||||
|
opacity: 0.5
|
||||||
|
} ] });
|
||||||
|
stl_viewer.set_opacity(0, 0.5)
|
||||||
|
|
||||||
|
window.onmessage = (e) => {
|
||||||
|
console.log(e)
|
||||||
|
if (e.data.type == 'setUrl') {
|
||||||
|
stl_viewer.remove_model(0)
|
||||||
|
stl_viewer.add_model({id:0, filename:e.data.data, opacity: 0.5})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
1158
stl_viewer/CanvasRenderer.js
Normal file
1158
stl_viewer/CanvasRenderer.js
Normal file
File diff suppressed because it is too large
Load Diff
625
stl_viewer/OrbitControls.js
Normal file
625
stl_viewer/OrbitControls.js
Normal file
|
@ -0,0 +1,625 @@
|
||||||
|
/**
|
||||||
|
* @author qiao / https://github.com/qiao
|
||||||
|
* @author mrdoob / http://mrdoob.com
|
||||||
|
* @author alteredq / http://alteredqualia.com/
|
||||||
|
* @author WestLangley / http://github.com/WestLangley
|
||||||
|
* @author erich666 / http://erichaines.com
|
||||||
|
*/
|
||||||
|
/*global THREE, console */
|
||||||
|
|
||||||
|
// This set of controls performs orbiting, dollying (zooming), and panning. It maintains
|
||||||
|
// the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
|
||||||
|
// supported.
|
||||||
|
//
|
||||||
|
// Orbit - left mouse / touch: one finger move
|
||||||
|
// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
|
||||||
|
// Pan - right mouse, or arrow keys / touch: three finter swipe
|
||||||
|
//
|
||||||
|
// This is a drop-in replacement for (most) TrackballControls used in examples.
|
||||||
|
// That is, include this js file and wherever you see:
|
||||||
|
// controls = new THREE.TrackballControls( camera );
|
||||||
|
// controls.target.z = 150;
|
||||||
|
// Simple substitute "OrbitControls" and the control should work as-is.
|
||||||
|
|
||||||
|
THREE.OrbitControls = function ( object, domElement ) {
|
||||||
|
|
||||||
|
this.object = object;
|
||||||
|
this.domElement = ( domElement !== undefined ) ? domElement : document;
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// Set to false to disable this control
|
||||||
|
this.enabled = true;
|
||||||
|
|
||||||
|
// "target" sets the location of focus, where the control orbits around
|
||||||
|
// and where it pans with respect to.
|
||||||
|
this.target = new THREE.Vector3();
|
||||||
|
|
||||||
|
// center is old, deprecated; use "target" instead
|
||||||
|
this.center = this.target;
|
||||||
|
|
||||||
|
// This option actually enables dollying in and out; left as "zoom" for
|
||||||
|
// backwards compatibility
|
||||||
|
this.noZoom = false;
|
||||||
|
this.zoomSpeed = 1.0;
|
||||||
|
|
||||||
|
// Limits to how far you can dolly in and out
|
||||||
|
this.minDistance = 0;
|
||||||
|
this.maxDistance = Infinity;
|
||||||
|
|
||||||
|
// Set to true to disable this control
|
||||||
|
this.noRotate = false;
|
||||||
|
this.rotateSpeed = 1.0;
|
||||||
|
|
||||||
|
// Set to true to disable this control
|
||||||
|
this.noPan = false;
|
||||||
|
this.keyPanSpeed = 7.0; // pixels moved per arrow key push
|
||||||
|
|
||||||
|
// Set to true to automatically rotate around the target
|
||||||
|
this.autoRotate = false;
|
||||||
|
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
|
||||||
|
|
||||||
|
// How far you can orbit vertically, upper and lower limits.
|
||||||
|
// Range is 0 to Math.PI radians.
|
||||||
|
this.minPolarAngle = 0; // radians
|
||||||
|
this.maxPolarAngle = Math.PI; // radians
|
||||||
|
|
||||||
|
// Set to true to disable use of the keys
|
||||||
|
this.noKeys = false;
|
||||||
|
|
||||||
|
// The four arrow keys
|
||||||
|
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// internals
|
||||||
|
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
var EPS = 0.000001;
|
||||||
|
|
||||||
|
var rotateStart = new THREE.Vector2();
|
||||||
|
var rotateEnd = new THREE.Vector2();
|
||||||
|
var rotateDelta = new THREE.Vector2();
|
||||||
|
|
||||||
|
var panStart = new THREE.Vector2();
|
||||||
|
var panEnd = new THREE.Vector2();
|
||||||
|
var panDelta = new THREE.Vector2();
|
||||||
|
var panOffset = new THREE.Vector3();
|
||||||
|
|
||||||
|
var offset = new THREE.Vector3();
|
||||||
|
|
||||||
|
var dollyStart = new THREE.Vector2();
|
||||||
|
var dollyEnd = new THREE.Vector2();
|
||||||
|
var dollyDelta = new THREE.Vector2();
|
||||||
|
|
||||||
|
var phiDelta = 0;
|
||||||
|
var thetaDelta = 0;
|
||||||
|
var scale = 1;
|
||||||
|
var pan = new THREE.Vector3();
|
||||||
|
|
||||||
|
var lastPosition = new THREE.Vector3();
|
||||||
|
|
||||||
|
var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
|
||||||
|
|
||||||
|
var state = STATE.NONE;
|
||||||
|
|
||||||
|
// for reset
|
||||||
|
|
||||||
|
this.target0 = this.target.clone();
|
||||||
|
this.position0 = this.object.position.clone();
|
||||||
|
|
||||||
|
// events
|
||||||
|
|
||||||
|
var changeEvent = { type: 'change' };
|
||||||
|
var startEvent = { type: 'start'};
|
||||||
|
var endEvent = { type: 'end'};
|
||||||
|
|
||||||
|
this.rotateLeft = function ( angle ) {
|
||||||
|
|
||||||
|
if ( angle === undefined ) {
|
||||||
|
|
||||||
|
angle = getAutoRotationAngle();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
thetaDelta -= angle;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.rotateUp = function ( angle ) {
|
||||||
|
|
||||||
|
if ( angle === undefined ) {
|
||||||
|
|
||||||
|
angle = getAutoRotationAngle();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
phiDelta -= angle;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// pass in distance in world space to move left
|
||||||
|
this.panLeft = function ( distance ) {
|
||||||
|
|
||||||
|
var te = this.object.matrix.elements;
|
||||||
|
|
||||||
|
// get X column of matrix
|
||||||
|
panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
|
||||||
|
panOffset.multiplyScalar( - distance );
|
||||||
|
|
||||||
|
pan.add( panOffset );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// pass in distance in world space to move up
|
||||||
|
this.panUp = function ( distance ) {
|
||||||
|
|
||||||
|
var te = this.object.matrix.elements;
|
||||||
|
|
||||||
|
// get Y column of matrix
|
||||||
|
panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
|
||||||
|
panOffset.multiplyScalar( distance );
|
||||||
|
|
||||||
|
pan.add( panOffset );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// pass in x,y of change desired in pixel space,
|
||||||
|
// right and down are positive
|
||||||
|
this.pan = function ( deltaX, deltaY ) {
|
||||||
|
|
||||||
|
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
|
||||||
|
|
||||||
|
if ( scope.object.fov !== undefined ) {
|
||||||
|
|
||||||
|
// perspective
|
||||||
|
var position = scope.object.position;
|
||||||
|
var offset = position.clone().sub( scope.target );
|
||||||
|
var targetDistance = offset.length();
|
||||||
|
|
||||||
|
// half of the fov is center to top of screen
|
||||||
|
targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
|
||||||
|
|
||||||
|
// we actually don't use screenWidth, since perspective camera is fixed to screen height
|
||||||
|
scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
|
||||||
|
scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
|
||||||
|
|
||||||
|
} else if ( scope.object.top !== undefined ) {
|
||||||
|
|
||||||
|
// orthographic
|
||||||
|
scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
|
||||||
|
scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// camera neither orthographic or perspective
|
||||||
|
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dollyIn = function ( dollyScale ) {
|
||||||
|
|
||||||
|
if ( dollyScale === undefined ) {
|
||||||
|
|
||||||
|
dollyScale = getZoomScale();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
scale /= dollyScale;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dollyOut = function ( dollyScale ) {
|
||||||
|
|
||||||
|
if ( dollyScale === undefined ) {
|
||||||
|
|
||||||
|
dollyScale = getZoomScale();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
scale *= dollyScale;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.update = function () {
|
||||||
|
|
||||||
|
var position = this.object.position;
|
||||||
|
|
||||||
|
offset.copy( position ).sub( this.target );
|
||||||
|
|
||||||
|
// angle from z-axis around y-axis
|
||||||
|
|
||||||
|
var theta = Math.atan2( offset.x, offset.z );
|
||||||
|
|
||||||
|
// angle from y-axis
|
||||||
|
|
||||||
|
var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
|
||||||
|
|
||||||
|
if ( this.autoRotate ) {
|
||||||
|
|
||||||
|
this.rotateLeft( getAutoRotationAngle() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
theta += thetaDelta;
|
||||||
|
phi += phiDelta;
|
||||||
|
|
||||||
|
// restrict phi to be between desired limits
|
||||||
|
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
|
||||||
|
|
||||||
|
// restrict phi to be betwee EPS and PI-EPS
|
||||||
|
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
|
||||||
|
|
||||||
|
var radius = offset.length() * scale;
|
||||||
|
|
||||||
|
// restrict radius to be between desired limits
|
||||||
|
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
|
||||||
|
|
||||||
|
// move target to panned location
|
||||||
|
this.target.add( pan );
|
||||||
|
|
||||||
|
offset.x = radius * Math.sin( phi ) * Math.sin( theta );
|
||||||
|
offset.y = radius * Math.cos( phi );
|
||||||
|
offset.z = radius * Math.sin( phi ) * Math.cos( theta );
|
||||||
|
|
||||||
|
position.copy( this.target ).add( offset );
|
||||||
|
|
||||||
|
this.object.lookAt( this.target );
|
||||||
|
|
||||||
|
thetaDelta = 0;
|
||||||
|
phiDelta = 0;
|
||||||
|
scale = 1;
|
||||||
|
pan.set( 0, 0, 0 );
|
||||||
|
|
||||||
|
if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
|
||||||
|
|
||||||
|
this.dispatchEvent( changeEvent );
|
||||||
|
|
||||||
|
lastPosition.copy( this.object.position );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.reset = function () {
|
||||||
|
|
||||||
|
state = STATE.NONE;
|
||||||
|
|
||||||
|
this.target.copy( this.target0 );
|
||||||
|
//this.object.position.copy( this.position0 );
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function getAutoRotationAngle() {
|
||||||
|
|
||||||
|
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function getZoomScale() {
|
||||||
|
|
||||||
|
return Math.pow( 0.95, scope.zoomSpeed );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseDown( event ) {
|
||||||
|
|
||||||
|
if ( scope.enabled === false ) return;
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if ( event.button === 0 ) {
|
||||||
|
if ( scope.noRotate === true ) return;
|
||||||
|
|
||||||
|
state = STATE.ROTATE;
|
||||||
|
|
||||||
|
rotateStart.set( event.clientX, event.clientY );
|
||||||
|
|
||||||
|
} else if ( event.button === 1 ) {
|
||||||
|
if ( scope.noZoom === true ) return;
|
||||||
|
|
||||||
|
state = STATE.DOLLY;
|
||||||
|
|
||||||
|
dollyStart.set( event.clientX, event.clientY );
|
||||||
|
|
||||||
|
} else if ( event.button === 2 ) {
|
||||||
|
if ( scope.noPan === true ) return;
|
||||||
|
|
||||||
|
state = STATE.PAN;
|
||||||
|
|
||||||
|
panStart.set( event.clientX, event.clientY );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.domElement.addEventListener( 'mousemove', onMouseMove, false );
|
||||||
|
scope.domElement.addEventListener( 'mouseup', onMouseUp, false );
|
||||||
|
scope.dispatchEvent( startEvent );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseMove( event ) {
|
||||||
|
|
||||||
|
if ( scope.enabled === false ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
|
||||||
|
|
||||||
|
if ( state === STATE.ROTATE ) {
|
||||||
|
|
||||||
|
if ( scope.noRotate === true ) return;
|
||||||
|
|
||||||
|
rotateEnd.set( event.clientX, event.clientY );
|
||||||
|
rotateDelta.subVectors( rotateEnd, rotateStart );
|
||||||
|
|
||||||
|
// rotating across whole screen goes 360 degrees around
|
||||||
|
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
|
||||||
|
|
||||||
|
// rotating up and down along whole screen attempts to go 360, but limited to 180
|
||||||
|
scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
|
||||||
|
|
||||||
|
rotateStart.copy( rotateEnd );
|
||||||
|
|
||||||
|
} else if ( state === STATE.DOLLY ) {
|
||||||
|
|
||||||
|
if ( scope.noZoom === true ) return;
|
||||||
|
|
||||||
|
dollyEnd.set( event.clientX, event.clientY );
|
||||||
|
dollyDelta.subVectors( dollyEnd, dollyStart );
|
||||||
|
|
||||||
|
if ( dollyDelta.y > 0 ) {
|
||||||
|
|
||||||
|
scope.dollyIn();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
scope.dollyOut();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dollyStart.copy( dollyEnd );
|
||||||
|
|
||||||
|
} else if ( state === STATE.PAN ) {
|
||||||
|
|
||||||
|
if ( scope.noPan === true ) return;
|
||||||
|
|
||||||
|
panEnd.set( event.clientX, event.clientY );
|
||||||
|
panDelta.subVectors( panEnd, panStart );
|
||||||
|
|
||||||
|
scope.pan( panDelta.x, panDelta.y );
|
||||||
|
|
||||||
|
panStart.copy( panEnd );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseUp( /* event */ ) {
|
||||||
|
|
||||||
|
if ( scope.enabled === false ) return;
|
||||||
|
|
||||||
|
scope.domElement.removeEventListener( 'mousemove', onMouseMove, false );
|
||||||
|
scope.domElement.removeEventListener( 'mouseup', onMouseUp, false );
|
||||||
|
scope.dispatchEvent( endEvent );
|
||||||
|
state = STATE.NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseWheel( event ) {
|
||||||
|
|
||||||
|
if ( scope.enabled === false || scope.noZoom === true ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var delta = 0;
|
||||||
|
|
||||||
|
if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
|
||||||
|
|
||||||
|
delta = event.wheelDelta;
|
||||||
|
|
||||||
|
} else if ( event.detail !== undefined ) { // Firefox
|
||||||
|
|
||||||
|
delta = - event.detail;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( delta > 0 ) {
|
||||||
|
|
||||||
|
scope.dollyOut();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
scope.dollyIn();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.update();
|
||||||
|
scope.dispatchEvent( startEvent );
|
||||||
|
scope.dispatchEvent( endEvent );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown( event ) {
|
||||||
|
|
||||||
|
if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
|
||||||
|
|
||||||
|
switch ( event.keyCode ) {
|
||||||
|
|
||||||
|
case scope.keys.UP:
|
||||||
|
scope.pan( 0, scope.keyPanSpeed );
|
||||||
|
scope.update();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case scope.keys.BOTTOM:
|
||||||
|
scope.pan( 0, - scope.keyPanSpeed );
|
||||||
|
scope.update();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case scope.keys.LEFT:
|
||||||
|
scope.pan( scope.keyPanSpeed, 0 );
|
||||||
|
scope.update();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case scope.keys.RIGHT:
|
||||||
|
scope.pan( - scope.keyPanSpeed, 0 );
|
||||||
|
scope.update();
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchstart( event ) {
|
||||||
|
|
||||||
|
if ( scope.enabled === false ) return;
|
||||||
|
|
||||||
|
switch ( event.touches.length ) {
|
||||||
|
|
||||||
|
case 1: // one-fingered touch: rotate
|
||||||
|
|
||||||
|
if ( scope.noRotate === true ) return;
|
||||||
|
|
||||||
|
state = STATE.TOUCH_ROTATE;
|
||||||
|
|
||||||
|
rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // two-fingered touch: dolly
|
||||||
|
|
||||||
|
if ( scope.noZoom === true ) return;
|
||||||
|
|
||||||
|
state = STATE.TOUCH_DOLLY;
|
||||||
|
|
||||||
|
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
||||||
|
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
||||||
|
var distance = Math.sqrt( dx * dx + dy * dy );
|
||||||
|
dollyStart.set( 0, distance );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // three-fingered touch: pan
|
||||||
|
|
||||||
|
if ( scope.noPan === true ) return;
|
||||||
|
|
||||||
|
state = STATE.TOUCH_PAN;
|
||||||
|
|
||||||
|
panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
state = STATE.NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.dispatchEvent( startEvent );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchmove( event ) {
|
||||||
|
|
||||||
|
if ( scope.enabled === false ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
|
||||||
|
|
||||||
|
switch ( event.touches.length ) {
|
||||||
|
|
||||||
|
case 1: // one-fingered touch: rotate
|
||||||
|
|
||||||
|
if ( scope.noRotate === true ) return;
|
||||||
|
if ( state !== STATE.TOUCH_ROTATE ) return;
|
||||||
|
|
||||||
|
rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||||
|
rotateDelta.subVectors( rotateEnd, rotateStart );
|
||||||
|
|
||||||
|
// rotating across whole screen goes 360 degrees around
|
||||||
|
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
|
||||||
|
// rotating up and down along whole screen attempts to go 360, but limited to 180
|
||||||
|
scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
|
||||||
|
|
||||||
|
rotateStart.copy( rotateEnd );
|
||||||
|
|
||||||
|
scope.update();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // two-fingered touch: dolly
|
||||||
|
|
||||||
|
if ( scope.noZoom === true ) return;
|
||||||
|
if ( state !== STATE.TOUCH_DOLLY ) return;
|
||||||
|
|
||||||
|
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
||||||
|
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
||||||
|
var distance = Math.sqrt( dx * dx + dy * dy );
|
||||||
|
|
||||||
|
dollyEnd.set( 0, distance );
|
||||||
|
dollyDelta.subVectors( dollyEnd, dollyStart );
|
||||||
|
|
||||||
|
if ( dollyDelta.y > 0 ) {
|
||||||
|
|
||||||
|
scope.dollyOut();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
scope.dollyIn();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dollyStart.copy( dollyEnd );
|
||||||
|
|
||||||
|
scope.update();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // three-fingered touch: pan
|
||||||
|
|
||||||
|
if ( scope.noPan === true ) return;
|
||||||
|
if ( state !== STATE.TOUCH_PAN ) return;
|
||||||
|
|
||||||
|
panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||||
|
panDelta.subVectors( panEnd, panStart );
|
||||||
|
|
||||||
|
scope.pan( panDelta.x, panDelta.y );
|
||||||
|
|
||||||
|
panStart.copy( panEnd );
|
||||||
|
|
||||||
|
scope.update();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
state = STATE.NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchend( /* event */ ) {
|
||||||
|
|
||||||
|
if ( scope.enabled === false ) return;
|
||||||
|
|
||||||
|
scope.dispatchEvent( endEvent );
|
||||||
|
state = STATE.NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
|
||||||
|
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
|
||||||
|
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
|
||||||
|
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
|
||||||
|
|
||||||
|
this.domElement.addEventListener( 'touchstart', touchstart, false );
|
||||||
|
this.domElement.addEventListener( 'touchend', touchend, false );
|
||||||
|
this.domElement.addEventListener( 'touchmove', touchmove, false );
|
||||||
|
|
||||||
|
window.addEventListener( 'keydown', onKeyDown, false );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
|
1028
stl_viewer/Projector.js
Normal file
1028
stl_viewer/Projector.js
Normal file
File diff suppressed because it is too large
Load Diff
619
stl_viewer/TrackballControls.js
Normal file
619
stl_viewer/TrackballControls.js
Normal file
|
@ -0,0 +1,619 @@
|
||||||
|
/**
|
||||||
|
* @author Eberhard Graether / http://egraether.com/
|
||||||
|
* @author Mark Lundin / http://mark-lundin.com
|
||||||
|
* @author Simone Manini / http://daron1337.github.io
|
||||||
|
* @author Luca Antiga / http://lantiga.github.io
|
||||||
|
*/
|
||||||
|
|
||||||
|
THREE.TrackballControls = function ( object, domElement ) {
|
||||||
|
|
||||||
|
var _this = this;
|
||||||
|
var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };
|
||||||
|
|
||||||
|
this.object = object;
|
||||||
|
this.domElement = ( domElement !== undefined ) ? domElement : document;
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
this.enabled = true;
|
||||||
|
|
||||||
|
this.screen = { left: 0, top: 0, width: 0, height: 0 };
|
||||||
|
|
||||||
|
this.rotateSpeed = 1.0;
|
||||||
|
this.zoomSpeed = 1.2;
|
||||||
|
this.panSpeed = 0.3;
|
||||||
|
|
||||||
|
this.noRotate = false;
|
||||||
|
this.noZoom = false;
|
||||||
|
this.noPan = false;
|
||||||
|
|
||||||
|
this.staticMoving = false;
|
||||||
|
this.dynamicDampingFactor = 0.2;
|
||||||
|
|
||||||
|
this.minDistance = 0;
|
||||||
|
this.maxDistance = Infinity;
|
||||||
|
|
||||||
|
this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
|
||||||
|
|
||||||
|
// internals
|
||||||
|
|
||||||
|
this.target = new THREE.Vector3();
|
||||||
|
|
||||||
|
var EPS = 0.000001;
|
||||||
|
|
||||||
|
var lastPosition = new THREE.Vector3();
|
||||||
|
|
||||||
|
var _state = STATE.NONE,
|
||||||
|
_prevState = STATE.NONE,
|
||||||
|
|
||||||
|
_eye = new THREE.Vector3(),
|
||||||
|
|
||||||
|
_movePrev = new THREE.Vector2(),
|
||||||
|
_moveCurr = new THREE.Vector2(),
|
||||||
|
|
||||||
|
_lastAxis = new THREE.Vector3(),
|
||||||
|
_lastAngle = 0,
|
||||||
|
|
||||||
|
_zoomStart = new THREE.Vector2(),
|
||||||
|
_zoomEnd = new THREE.Vector2(),
|
||||||
|
|
||||||
|
_touchZoomDistanceStart = 0,
|
||||||
|
_touchZoomDistanceEnd = 0,
|
||||||
|
|
||||||
|
_panStart = new THREE.Vector2(),
|
||||||
|
_panEnd = new THREE.Vector2();
|
||||||
|
|
||||||
|
// for reset
|
||||||
|
|
||||||
|
this.target0 = this.target.clone();
|
||||||
|
this.position0 = this.object.position.clone();
|
||||||
|
this.up0 = this.object.up.clone();
|
||||||
|
|
||||||
|
// events
|
||||||
|
|
||||||
|
var changeEvent = { type: 'change' };
|
||||||
|
var startEvent = { type: 'start' };
|
||||||
|
var endEvent = { type: 'end' };
|
||||||
|
|
||||||
|
|
||||||
|
// methods
|
||||||
|
|
||||||
|
this.handleResize = function () {
|
||||||
|
|
||||||
|
if ( this.domElement === document ) {
|
||||||
|
|
||||||
|
this.screen.left = 0;
|
||||||
|
this.screen.top = 0;
|
||||||
|
this.screen.width = window.innerWidth;
|
||||||
|
this.screen.height = window.innerHeight;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var box = this.domElement.getBoundingClientRect();
|
||||||
|
// adjustments come from similar code in the jquery offset() function
|
||||||
|
var d = this.domElement.ownerDocument.documentElement;
|
||||||
|
this.screen.left = box.left + window.pageXOffset - d.clientLeft;
|
||||||
|
this.screen.top = box.top + window.pageYOffset - d.clientTop;
|
||||||
|
this.screen.width = box.width;
|
||||||
|
this.screen.height = box.height;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
var getMouseOnScreen = ( function () {
|
||||||
|
|
||||||
|
var vector = new THREE.Vector2();
|
||||||
|
|
||||||
|
return function getMouseOnScreen( pageX, pageY ) {
|
||||||
|
|
||||||
|
vector.set(
|
||||||
|
( pageX - _this.screen.left ) / _this.screen.width,
|
||||||
|
( pageY - _this.screen.top ) / _this.screen.height
|
||||||
|
);
|
||||||
|
|
||||||
|
return vector;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}() );
|
||||||
|
|
||||||
|
var getMouseOnCircle = ( function () {
|
||||||
|
|
||||||
|
var vector = new THREE.Vector2();
|
||||||
|
|
||||||
|
return function getMouseOnCircle( pageX, pageY ) {
|
||||||
|
|
||||||
|
vector.set(
|
||||||
|
( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ),
|
||||||
|
( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional
|
||||||
|
);
|
||||||
|
|
||||||
|
return vector;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}() );
|
||||||
|
|
||||||
|
this.rotateCamera = ( function () {
|
||||||
|
|
||||||
|
var axis = new THREE.Vector3(),
|
||||||
|
quaternion = new THREE.Quaternion(),
|
||||||
|
eyeDirection = new THREE.Vector3(),
|
||||||
|
objectUpDirection = new THREE.Vector3(),
|
||||||
|
objectSidewaysDirection = new THREE.Vector3(),
|
||||||
|
moveDirection = new THREE.Vector3(),
|
||||||
|
angle;
|
||||||
|
|
||||||
|
return function rotateCamera() {
|
||||||
|
|
||||||
|
moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 );
|
||||||
|
angle = moveDirection.length();
|
||||||
|
|
||||||
|
if ( angle ) {
|
||||||
|
|
||||||
|
_eye.copy( _this.object.position ).sub( _this.target );
|
||||||
|
|
||||||
|
eyeDirection.copy( _eye ).normalize();
|
||||||
|
objectUpDirection.copy( _this.object.up ).normalize();
|
||||||
|
objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize();
|
||||||
|
|
||||||
|
objectUpDirection.setLength( _moveCurr.y - _movePrev.y );
|
||||||
|
objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x );
|
||||||
|
|
||||||
|
moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) );
|
||||||
|
|
||||||
|
axis.crossVectors( moveDirection, _eye ).normalize();
|
||||||
|
|
||||||
|
angle *= _this.rotateSpeed;
|
||||||
|
quaternion.setFromAxisAngle( axis, angle );
|
||||||
|
|
||||||
|
_eye.applyQuaternion( quaternion );
|
||||||
|
_this.object.up.applyQuaternion( quaternion );
|
||||||
|
|
||||||
|
_lastAxis.copy( axis );
|
||||||
|
_lastAngle = angle;
|
||||||
|
|
||||||
|
} else if ( ! _this.staticMoving && _lastAngle ) {
|
||||||
|
|
||||||
|
_lastAngle *= Math.sqrt( 1.0 - _this.dynamicDampingFactor );
|
||||||
|
_eye.copy( _this.object.position ).sub( _this.target );
|
||||||
|
quaternion.setFromAxisAngle( _lastAxis, _lastAngle );
|
||||||
|
_eye.applyQuaternion( quaternion );
|
||||||
|
_this.object.up.applyQuaternion( quaternion );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_movePrev.copy( _moveCurr );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}() );
|
||||||
|
|
||||||
|
|
||||||
|
this.zoomCamera = function () {
|
||||||
|
|
||||||
|
var factor;
|
||||||
|
|
||||||
|
if ( _state === STATE.TOUCH_ZOOM_PAN ) {
|
||||||
|
|
||||||
|
factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
|
||||||
|
_touchZoomDistanceStart = _touchZoomDistanceEnd;
|
||||||
|
_eye.multiplyScalar( factor );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;
|
||||||
|
|
||||||
|
if ( factor !== 1.0 && factor > 0.0 ) {
|
||||||
|
|
||||||
|
_eye.multiplyScalar( factor );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _this.staticMoving ) {
|
||||||
|
|
||||||
|
_zoomStart.copy( _zoomEnd );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.panCamera = ( function () {
|
||||||
|
|
||||||
|
var mouseChange = new THREE.Vector2(),
|
||||||
|
objectUp = new THREE.Vector3(),
|
||||||
|
pan = new THREE.Vector3();
|
||||||
|
|
||||||
|
return function panCamera() {
|
||||||
|
|
||||||
|
mouseChange.copy( _panEnd ).sub( _panStart );
|
||||||
|
|
||||||
|
if ( mouseChange.lengthSq() ) {
|
||||||
|
|
||||||
|
mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );
|
||||||
|
|
||||||
|
pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x );
|
||||||
|
pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) );
|
||||||
|
|
||||||
|
_this.object.position.add( pan );
|
||||||
|
_this.target.add( pan );
|
||||||
|
|
||||||
|
if ( _this.staticMoving ) {
|
||||||
|
|
||||||
|
_panStart.copy( _panEnd );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}() );
|
||||||
|
|
||||||
|
this.checkDistances = function () {
|
||||||
|
|
||||||
|
if ( ! _this.noZoom || ! _this.noPan ) {
|
||||||
|
|
||||||
|
if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {
|
||||||
|
|
||||||
|
_this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );
|
||||||
|
_zoomStart.copy( _zoomEnd );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {
|
||||||
|
|
||||||
|
_this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );
|
||||||
|
_zoomStart.copy( _zoomEnd );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.update = function () {
|
||||||
|
|
||||||
|
_eye.subVectors( _this.object.position, _this.target );
|
||||||
|
|
||||||
|
if ( ! _this.noRotate ) {
|
||||||
|
|
||||||
|
_this.rotateCamera();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! _this.noZoom ) {
|
||||||
|
|
||||||
|
_this.zoomCamera();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! _this.noPan ) {
|
||||||
|
|
||||||
|
_this.panCamera();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.object.position.addVectors( _this.target, _eye );
|
||||||
|
|
||||||
|
_this.checkDistances();
|
||||||
|
|
||||||
|
_this.object.lookAt( _this.target );
|
||||||
|
|
||||||
|
if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) {
|
||||||
|
|
||||||
|
_this.dispatchEvent( changeEvent );
|
||||||
|
|
||||||
|
lastPosition.copy( _this.object.position );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.reset = function () {
|
||||||
|
|
||||||
|
_state = STATE.NONE;
|
||||||
|
_prevState = STATE.NONE;
|
||||||
|
|
||||||
|
_this.target.copy( _this.target0 );
|
||||||
|
_this.object.position.copy( _this.position0 );
|
||||||
|
_this.object.up.copy( _this.up0 );
|
||||||
|
|
||||||
|
_eye.subVectors( _this.object.position, _this.target );
|
||||||
|
|
||||||
|
_this.object.lookAt( _this.target );
|
||||||
|
|
||||||
|
_this.dispatchEvent( changeEvent );
|
||||||
|
|
||||||
|
lastPosition.copy( _this.object.position );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// listeners
|
||||||
|
|
||||||
|
function keydown( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
window.removeEventListener( 'keydown', keydown );
|
||||||
|
|
||||||
|
_prevState = _state;
|
||||||
|
|
||||||
|
if ( _state !== STATE.NONE ) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate ) {
|
||||||
|
|
||||||
|
_state = STATE.ROTATE;
|
||||||
|
|
||||||
|
} else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom ) {
|
||||||
|
|
||||||
|
_state = STATE.ZOOM;
|
||||||
|
|
||||||
|
} else if ( event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan ) {
|
||||||
|
|
||||||
|
_state = STATE.PAN;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyup( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
_state = _prevState;
|
||||||
|
|
||||||
|
window.addEventListener( 'keydown', keydown, false );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousedown( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if ( _state === STATE.NONE ) {
|
||||||
|
|
||||||
|
_state = event.button;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _state === STATE.ROTATE && ! _this.noRotate ) {
|
||||||
|
|
||||||
|
_moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
|
||||||
|
_movePrev.copy( _moveCurr );
|
||||||
|
|
||||||
|
} else if ( _state === STATE.ZOOM && ! _this.noZoom ) {
|
||||||
|
|
||||||
|
_zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
|
||||||
|
_zoomEnd.copy( _zoomStart );
|
||||||
|
|
||||||
|
} else if ( _state === STATE.PAN && ! _this.noPan ) {
|
||||||
|
|
||||||
|
_panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
|
||||||
|
_panEnd.copy( _panStart );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener( 'mousemove', mousemove, false );
|
||||||
|
document.addEventListener( 'mouseup', mouseup, false );
|
||||||
|
|
||||||
|
_this.dispatchEvent( startEvent );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousemove( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if ( _state === STATE.ROTATE && ! _this.noRotate ) {
|
||||||
|
|
||||||
|
_movePrev.copy( _moveCurr );
|
||||||
|
_moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
|
||||||
|
|
||||||
|
} else if ( _state === STATE.ZOOM && ! _this.noZoom ) {
|
||||||
|
|
||||||
|
_zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
|
||||||
|
|
||||||
|
} else if ( _state === STATE.PAN && ! _this.noPan ) {
|
||||||
|
|
||||||
|
_panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseup( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
_state = STATE.NONE;
|
||||||
|
|
||||||
|
document.removeEventListener( 'mousemove', mousemove );
|
||||||
|
document.removeEventListener( 'mouseup', mouseup );
|
||||||
|
_this.dispatchEvent( endEvent );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousewheel( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
if ( _this.noZoom === true ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
switch ( event.deltaMode ) {
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Zoom in pages
|
||||||
|
_zoomStart.y -= event.deltaY * 0.025;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Zoom in lines
|
||||||
|
_zoomStart.y -= event.deltaY * 0.01;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// undefined, 0, assume pixels
|
||||||
|
_zoomStart.y -= event.deltaY * 0.00025;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.dispatchEvent( startEvent );
|
||||||
|
_this.dispatchEvent( endEvent );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchstart( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
switch ( event.touches.length ) {
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
_state = STATE.TOUCH_ROTATE;
|
||||||
|
_moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
|
||||||
|
_movePrev.copy( _moveCurr );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // 2 or more
|
||||||
|
_state = STATE.TOUCH_ZOOM_PAN;
|
||||||
|
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
||||||
|
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
||||||
|
_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
|
||||||
|
|
||||||
|
var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
|
||||||
|
var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
|
||||||
|
_panStart.copy( getMouseOnScreen( x, y ) );
|
||||||
|
_panEnd.copy( _panStart );
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.dispatchEvent( startEvent );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchmove( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
switch ( event.touches.length ) {
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
_movePrev.copy( _moveCurr );
|
||||||
|
_moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // 2 or more
|
||||||
|
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
||||||
|
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
||||||
|
_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );
|
||||||
|
|
||||||
|
var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
|
||||||
|
var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
|
||||||
|
_panEnd.copy( getMouseOnScreen( x, y ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchend( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
switch ( event.touches.length ) {
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
_state = STATE.NONE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
_state = STATE.TOUCH_ROTATE;
|
||||||
|
_moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
|
||||||
|
_movePrev.copy( _moveCurr );
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.dispatchEvent( endEvent );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function contextmenu( event ) {
|
||||||
|
|
||||||
|
if ( _this.enabled === false ) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispose = function () {
|
||||||
|
|
||||||
|
this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
|
||||||
|
this.domElement.removeEventListener( 'mousedown', mousedown, false );
|
||||||
|
this.domElement.removeEventListener( 'wheel', mousewheel, false );
|
||||||
|
|
||||||
|
this.domElement.removeEventListener( 'touchstart', touchstart, false );
|
||||||
|
this.domElement.removeEventListener( 'touchend', touchend, false );
|
||||||
|
this.domElement.removeEventListener( 'touchmove', touchmove, false );
|
||||||
|
|
||||||
|
document.removeEventListener( 'mousemove', mousemove, false );
|
||||||
|
document.removeEventListener( 'mouseup', mouseup, false );
|
||||||
|
|
||||||
|
window.removeEventListener( 'keydown', keydown, false );
|
||||||
|
window.removeEventListener( 'keyup', keyup, false );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.domElement.addEventListener( 'contextmenu', contextmenu, false );
|
||||||
|
this.domElement.addEventListener( 'mousedown', mousedown, false );
|
||||||
|
this.domElement.addEventListener( 'wheel', mousewheel, false );
|
||||||
|
|
||||||
|
this.domElement.addEventListener( 'touchstart', touchstart, false );
|
||||||
|
this.domElement.addEventListener( 'touchend', touchend, false );
|
||||||
|
this.domElement.addEventListener( 'touchmove', touchmove, false );
|
||||||
|
|
||||||
|
window.addEventListener( 'keydown', keydown, false );
|
||||||
|
window.addEventListener( 'keyup', keyup, false );
|
||||||
|
|
||||||
|
this.handleResize();
|
||||||
|
|
||||||
|
// force an update at start
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
|
||||||
|
THREE.TrackballControls.prototype.constructor = THREE.TrackballControls;
|
48
stl_viewer/ie_polyfills.js
Normal file
48
stl_viewer/ie_polyfills.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
if (!String.prototype.repeat) {
|
||||||
|
String.prototype.repeat = function(count) {
|
||||||
|
'use strict';
|
||||||
|
if (this == null) {
|
||||||
|
throw new TypeError('can\'t convert ' + this + ' to object');
|
||||||
|
}
|
||||||
|
var str = '' + this;
|
||||||
|
count = +count;
|
||||||
|
if (count != count) {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
if (count < 0) {
|
||||||
|
throw new RangeError('repeat count must be non-negative');
|
||||||
|
}
|
||||||
|
if (count == Infinity) {
|
||||||
|
throw new RangeError('repeat count must be less than infinity');
|
||||||
|
}
|
||||||
|
count = Math.floor(count);
|
||||||
|
if (str.length == 0 || count == 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
// Ensuring count is a 31-bit integer allows us to heavily optimize the
|
||||||
|
// main part. But anyway, most current (August 2014) browsers can't handle
|
||||||
|
// strings 1 << 28 chars or longer, so:
|
||||||
|
if (str.length * count >= 1 << 28) {
|
||||||
|
throw new RangeError('repeat count must not overflow maximum string size');
|
||||||
|
}
|
||||||
|
var rpt = '';
|
||||||
|
for (;;) {
|
||||||
|
if ((count & 1) == 1) {
|
||||||
|
rpt += str;
|
||||||
|
}
|
||||||
|
count >>>= 1;
|
||||||
|
if (count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str += str;
|
||||||
|
}
|
||||||
|
// Could we try:
|
||||||
|
// return Array(count + 1).join(this);
|
||||||
|
return rpt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
'use strict';(function(e){function r(b){var a=b.charCodeAt(0),c=1114112,d=0,n=b.length|0,g="";switch(a>>>4){case 12:case 13:c=(a&31)<<6|b.charCodeAt(1)&63;d=128>c?0:2;break;case 14:c=(a&15)<<12|(b.charCodeAt(1)&63)<<6|b.charCodeAt(2)&63;d=2048>c?0:3;break;case 15:30===a>>>3&&(c=(a&7)<<18|(b.charCodeAt(1)&63)<<12|(b.charCodeAt(2)&63)<<6|b.charCodeAt(3),d=65536>c?0:4)}d&&(n<d?d=0:65536>c?g=f(c):1114112>c?(c=c-65664|0,g=f((c>>>10)+55296|0,(c&1023)+56320|0)):d=0);for(;d<n;d=d+1|0)g+="\ufffd";return g}
|
||||||
|
function p(){}function t(b){var a=b.charCodeAt(0)|0;if(55296<=a&&56319>=a)if(b=b.charCodeAt(1)|0,56320<=b&&57343>=b){if(a=(a<<10)+b-56613888|0,65535<a)return f(240|a>>>18,128|a>>>12&63,128|a>>>6&63,128|a&63)}else a=65533;return 2047>=a?f(192|a>>>6,128|a&63):f(224|a>>>12,128|a>>>6&63,128|a&63)}function q(){}var f=String.fromCharCode,l={}.toString,h=e.SharedArrayBuffer,u=h?l.call(h):"",k=e.Uint8Array,m=k||Array,v=l.call((k?ArrayBuffer:m).prototype);h=q.prototype;var w=e.TextEncoder;p.prototype.decode=
|
||||||
|
function(b){var a=b&&b.buffer||b,c=l.call(a);if(c!==v&&c!==u&&void 0!==b)throw TypeError("Failed to execute 'decode' on 'TextDecoder': The provided value is not of type '(ArrayBuffer or ArrayBufferView)'");b=k?new m(a):a;a="";c=0;for(var d=b.length|0;c<d;c=c+32768|0)a+=f.apply(0,b[k?"subarray":"slice"](c,c+32768|0));return a.replace(/[\xc0-\xff][\x80-\xbf]+|[\x80-\xff]/g,r)};e.TextDecoder||(e.TextDecoder=p);h.encode=function(b){b=void 0===b?"":(""+b).replace(/[\x80-\uD7ff\uDC00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]?/g,
|
||||||
|
t);for(var a=b.length|0,c=new m(a),d=0;d<a;d=d+1|0)c[d]=b.charCodeAt(d);return c};w||(e.TextEncoder=q)})(""+void 0==typeof global?""+void 0==typeof self?this:self:global);//AnonyCo
|
2
stl_viewer/load_stl.min.js
vendored
Normal file
2
stl_viewer/load_stl.min.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
//=========== Stl Viewer v1.13, by Omri Rips, Viewstl.com, July 2021 ; admin@viewstl.com ===========
|
||||||
|
importScripts("parser.min.js"),MSG_DATA=0,MSG_LOAD=1,MSG_ERROR=2,MSG_STL_LOADED=3,MSG_LOAD_IN_PROGRESS=4;var filename=null,local_file=null,load_from_blob_or_ab=null,x=0,y=0,z=0,model_id=-1,get_progress=!1,jszip_path="jszip.min.js";function isNumeric(a){return!isNaN(parseFloat(a))&&isFinite(a)}function send_error(a){postMessage({msg_type:MSG_ERROR,data:a})}function download_from_local(a){download_from_local_xhr(a)}function download_from_local_xhr(a){var e=new XMLHttpRequest;get_progress&&(e.onprogress=function(a){postMessage({msg_type:MSG_LOAD_IN_PROGRESS,id:model_id,loaded:a.loaded,total:a.total})}),e.onreadystatechange=function(a){4==e.readyState&&200==e.status&&after_file_load(e.response)},e.open("GET",a,!0),e.responseType="arraybuffer",e.send(null)}function after_file_load(a){if(a)try{parse_3d_file(filename,a,after_file_parse,jszip_path)}catch(a){send_error("Error parsing the file")}else send_error("no data")}function after_file_parse(a){"string"!=typeof a?postMessage({msg_type:MSG_STL_LOADED,vertices:a.vertices,faces:a.faces,colors:a.colors}):send_error(a)}function read_file(a){var e=new FileReader;e.onerror=function(a){var e="";switch(a.target.error.code){case a.target.error.NOT_FOUND_ERR:e="File not found";break;case a.target.error.NOT_READABLE_ERR:e="Can't read file - too large?";break;case a.target.error.ABORT_ERR:e="Read operation aborted";break;case a.target.error.SECURITY_ERR:e="File is locked";break;case a.target.error.ENCODING_ERR:e="File too large";break;default:e="Error reading file"}send_error(e)},e.onprogress=function(a){postMessage({msg_type:MSG_LOAD_IN_PROGRESS,id:model_id,loaded:a.loaded,total:a.total})},e.onload=function(a){after_file_load(a.target.result)},e.readAsArrayBuffer(a)}self.addEventListener("message",function(a){switch(a.data.msg_type){case MSG_DATA:if(!a.data.data){send_error("no data");break}if(!a.data.data.filename&&!a.data.data.local_file){send_error("no file");break}a.data.jszip_path&&(jszip_path=a.data.jszip_path),a.data.data.local_file?(filename=a.data.data.local_file.name?a.data.data.local_file.name:a.data.data.filename,local_file=a.data.data.local_file?a.data.data.local_file:null):a.data.data.filename&&(filename=a.data.data.filename),a.data.data.x&&isNumeric(a.data.data.x)&&(x=a.data.data.x),a.data.data.y&&isNumeric(a.data.data.y)&&(y=a.data.data.y),a.data.data.y&&isNumeric(a.data.data.z)&&(z=a.data.data.z),load_from_blob_or_ab=null,a.data.load_from_blob_or_ab&&(load_from_blob_or_ab=a.data.load_from_blob_or_ab),model_id=a.data.data.id?a.data.data.id:-1,get_progress=!!a.data.get_progress&&a.data.get_progress;break;case MSG_LOAD:load_from_blob_or_ab?load_from_blob_or_ab instanceof ArrayBuffer?after_file_load(load_from_blob_or_ab):read_file(load_from_blob_or_ab):local_file?read_file(local_file):filename&&download_from_local(filename);break;default:console.log("invalid msg: "+a.data.msg_type)}});
|
2
stl_viewer/parser.min.js
vendored
Normal file
2
stl_viewer/parser.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
37
stl_viewer/readme.txt
Normal file
37
stl_viewer/readme.txt
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
Stl Viewer v1.13, July 2021
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Installation:
|
||||||
|
-------------
|
||||||
|
upload those files into your web server:
|
||||||
|
stl_viewer.min.js
|
||||||
|
parser.min.js
|
||||||
|
load_stl.min.js
|
||||||
|
webgl_detector.js
|
||||||
|
CanvasRenderer.js
|
||||||
|
OrbitControls.js
|
||||||
|
TrackballControls.js
|
||||||
|
Projector.js
|
||||||
|
three.min.js
|
||||||
|
ie_polyfills.js (optional)
|
||||||
|
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
------
|
||||||
|
At the html body:
|
||||||
|
|
||||||
|
<script src="stl_viewer.min.js"></script>
|
||||||
|
<div id="stl_cont"></div>
|
||||||
|
<script>
|
||||||
|
var stl_viewer=new StlViewer(document.getElementById("stl_cont"), { models: [ {id:0, filename:"mystl.stl"} ] });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Documentation & License details:
|
||||||
|
--------------------------------
|
||||||
|
https://www.viewstl.com/plugin/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
by Omri Rips, Viewstl.com
|
2
stl_viewer/stl_viewer.min.js
vendored
Normal file
2
stl_viewer/stl_viewer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
stl_viewer/three.min.js
vendored
Normal file
2
stl_viewer/three.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
54
stl_viewer/webgl_detector.js
Normal file
54
stl_viewer/webgl_detector.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
var webgl_Detector = {
|
||||||
|
|
||||||
|
canvas: !! window.CanvasRenderingContext2D,
|
||||||
|
webgl: ( function () { try { var canvas = document.createElement( 'canvas' ); return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )(),
|
||||||
|
workers: !! window.Worker,
|
||||||
|
fileapi: window.File && window.FileReader && window.FileList && window.Blob,
|
||||||
|
|
||||||
|
getWebGLErrorMessage: function () {
|
||||||
|
|
||||||
|
var element = document.createElement( 'div' );
|
||||||
|
element.id = 'webgl-error-message';
|
||||||
|
element.style.fontFamily = 'monospace';
|
||||||
|
element.style.fontSize = '13px';
|
||||||
|
element.style.fontWeight = 'normal';
|
||||||
|
element.style.textAlign = 'center';
|
||||||
|
element.style.background = '#fff';
|
||||||
|
element.style.color = '#000';
|
||||||
|
element.style.padding = '1.5em';
|
||||||
|
element.style.width = '400px';
|
||||||
|
element.style.margin = '5em auto 0';
|
||||||
|
|
||||||
|
if ( ! this.webgl ) {
|
||||||
|
|
||||||
|
element.innerHTML = window.WebGLRenderingContext ? [
|
||||||
|
'Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br />',
|
||||||
|
'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
|
||||||
|
].join( '\n' ) : [
|
||||||
|
'Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br/>',
|
||||||
|
'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
|
||||||
|
].join( '\n' );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
addGetWebGLMessage: function ( parameters ) {
|
||||||
|
|
||||||
|
var parent, id, element;
|
||||||
|
|
||||||
|
parameters = parameters || {};
|
||||||
|
|
||||||
|
parent = parameters.parent !== undefined ? parameters.parent : document.body;
|
||||||
|
id = parameters.id !== undefined ? parameters.id : 'oldie';
|
||||||
|
|
||||||
|
element = Detector.getWebGLErrorMessage();
|
||||||
|
element.id = id;
|
||||||
|
|
||||||
|
parent.appendChild( element );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user