您的位置:首页 > Web前端

THREE.js 第一部分 canvas_ascii_effect.html 内容分析

2017-09-29 14:17 399 查看
因为之后会用到图表插件开发,需要用到THREE.js D3.js ECharts。

D3部分因为已经开发了几个插件部分,个人觉得难点在于数据的预处理与结构的变换,不同于从数据库中的SELECT出的数据部分,可能更多的是需要配合D3.json等接口数据处理的格式,整合数据。

ECharts部分的图表开发,相对于会更加的简练。

THREE.js 感觉不太适用于通用的图表展示,本身是一个实时渲染的过程,个人感觉之后的发展方向会向简单动画部分或者片头去展示,或者是更加高大上的图表,抽象图表部分。

贴代码:

var container, stats;

var camera, controls, scene, renderer;
var effect;

var sphere, plane;

//获取js当前运行的事件
var start = Date.now();

//初始化 属于惯用方法
init();
//动画操作 属于惯用方法
animate();

function init() {

//窗口的大小
var width = window.innerWidth || 2;
var height = window.innerHeight || 2;

//创建div部分 属于惯用方法
container = document.createElement( 'div' );
document.body.appendChild( container );

var info = document.createElement( 'div' );
//样式部分
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to change the view';
container.appendChild( info );

//镜头部分
camera = new THREE.PerspectiveCamera( 70, width / height, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;

//控制器部分
controls = new THREE.TrackballControls( camera );

//场景部分
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf0f0f0 );

//灯光效果,点光源
var light = new THREE.PointLight( 0xffffff );
light.position.set( 500, 500, 500 );
scene.add( light );

//光源颜色,光强度
var light = new THREE.PointLight( 0xffffff, 0.25 );
light.position.set( - 500, - 500, - 500 );
scene.add( light );

//几何 形状 球体 这种材质对光照有反应,用于创建暗淡的不发光的物体
sphere = new THREE.Mesh( new THREE.SphereGeometry( 200, 20, 10 ), new THREE.MeshLambertMaterial() );
scene.add( sphere );

//几何 形状 平面骨架 对光照无感,给几何体一种简单的颜色或显示线框
plane = new THREE.Mesh( new THREE.PlaneBufferGeometry( 400, 400 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0 } ) );
plane.position.y = - 200;
plane.rotation.x = - Math.PI / 2;
scene.add( plane );

//渲染
renderer = new THREE.CanvasRenderer();
renderer.setSize( width, height );
container.appendChild( renderer.domElement );

effect = new THREE.AsciiEffect( renderer );
effect.setSize( width, height );
container.appendChild( effect.domElement );

stats = new Stats();
container.appendChild( stats.dom );

//添加事件监听
window.addEventListener( 'resize', onWindowResize, false );

}

//页面调整大小,可以理解为鼠标滚轮变化
function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

renderer.setSize( window.innerWidth, window.innerHeight );
effect.setSize( window.innerWidth, window.innerHeight );

}

//动画部分
function animate() {
//固定格式
requestAnimationFrame( animate );

stats.begin();
render();
stats.end();

}

//渲染操作
function render() {

var timer = Date.now() - start;

sphere.position.y = Math.abs( Math.sin( timer * 0.002 ) ) * 150;
sphere.rotation.x = timer * 0.0003;
sphere.rotation.z = timer * 0.0002;

controls.update();

effect.render( scene, camera );

}代码部分添加了部分注释。
采取一步步的分析的过程:

1.针对引用的TrackballControls看一下源码部分

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;

}

};

this.handleEvent = function ( event ) {

if ( typeof this[ event.type ] == 'function' ) {

this[ event.type ]( event );

}

};

//鼠标在屏幕上的处理
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;

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;

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.st
989b
opPropagation();

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();

};整个js中主要的作用是写定了事件处理部分,是整个页面的核心处理模块。
2.主要的难点就在于事件的处理与内容的渲染render,至于camera,scene,light部分,知道是什么内容和含义即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  THREE.JS