Du WebGL couplé à Nmap, inspiré par 3JS/3D CSS voici ce que ça donne
Cet outil permet depuis un serveur Linux/Unix de faire une cartographie de premier niveau (un seul masque).
Pour utiliser ce script, il vous faut nmap, un accès à la fonction PHP exec, PHP (donc) et un serveur Apache et pour finir un navigateur compatible.
La table normalement des éléments du tableau de Mendeleiev sont remplacé par la liste des adresses IP scanné et de leur ports ouverts.
Résultat plutôt sympa, mais très perfectible.
0x01. INDEX.PHP
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <title>Network Scanner - WebGL</title> <link rel='stylesheet' type='text/css' href='style.css' /> </head> <body> <script src="./3js/three.min.js"></script> <script src="./3js/tween.min.js"></script> <script src="./3js/TrackballControls.js"></script> <script src="./3js/CSS3DRenderer.js"></script> <div id="container"></div> <div id="menu"> <button id="table">TABLE</button> <button id="sphere">SPHERE</button> <button id="helix">HELIX</button> <button id="grid">GRID</button> </div> <script> <? include("table.php"); /* Generated table with network and scanned ports */ ?> <? include("cinematics.js"); /* Camera/3D effects */ ?> </script> </body> </html>
0x02. TABLE.PHP
/* Table for scanned network */ var table = [ <?php function pingnet($net) { $cmd = 'nmap -v -sn -n -T5 '.$net; $cmd .='|grep report|awk \\'{ print $7" : "$5 }\\''; $cmd .='|sed \\'s/down\\] : /0:/g;s/^ : /1:/1\\''; $cmd .='|tr "\\n" ","'; @exec( $cmd , $ret ); $ret = split(",",$ret[0]); return( $ret ); } function scanport($host) { $cmd = 'nmap -n -F -Pn '.$host.'|grep "open"|cut -d"/" -f1|tr "\\n" ","'; @exec( $cmd , $ret ); return( $ret[0] ); } // Not secured, dev version, only in local. $ret = pingnet($_GET["net"]); // For each alive/dead host, store in an array foreach( $ret as $host ) { $state = split(":",$host); if( isset($state[1]) ) { $host = $state[1]; } if( $ret[0] == 1 ) { $test_hosts[ $host ] = $state[0]; } else { $test_hosts[ $host ] = $state[0]; } } $j=0; $i=0; foreach( $test_hosts as $host => $value ) { if( $value == 1 ) { $ports=scanport($host); $i++; // Fill screen in width if( $i == 32 ) { // 5 cells : IP address width $j+=5; $i=0; } echo '"'.$host.'", "", "'.$ports.'", '.$j.', '.$i.','; } } ?> ];
0x03. CINEMATICS.JS
var camera, scene, renderer; var controls; var objects = []; var targets = { table: [], sphere: [], helix: [], grid: [] }; init(); animate(); function init() { camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 ); camera.position.z = 3000; scene = new THREE.Scene(); // table for ( var i = 0; i < table.length; i += 5 ) { var element = document.createElement( 'div' ); element.className = 'element'; element.style.backgroundColor = 'rgba(0,127,127,' + ( Math.random() * 0.5 + 0.25 ) + ')'; var number = document.createElement( 'div' ); number.className = 'number'; number.textContent = (i/5) + 1; element.appendChild( number ); var symbol = document.createElement( 'div' ); symbol.className = 'symbol'; symbol.textContent = table[ i ]; element.appendChild( symbol ); var details = document.createElement( 'div' ); details.className = 'details'; details.innerHTML = table[ i + 1 ] + '<br>' + table[ i + 2 ]; element.appendChild( details ); var object = new THREE.CSS3DObject( element ); object.position.x = Math.random() * 4000 - 2000; object.position.y = Math.random() * 4000 - 2000; object.position.z = Math.random() * 4000 - 2000; scene.add( object ); objects.push( object ); // var object = new THREE.Object3D(); object.position.x = ( table[ i + 3 ] * 140 ) - 1330; object.position.y = - ( table[ i + 4 ] * 180 ) + 990; targets.table.push( object ); } // sphere var vector = new THREE.Vector3(); for ( var i = 0, l = objects.length; i < l; i ++ ) { var phi = Math.acos( -1 + ( 2 * i ) / l ); var theta = Math.sqrt( l * Math.PI ) * phi; var object = new THREE.Object3D(); object.position.x = 800 * Math.cos( theta ) * Math.sin( phi ); object.position.y = 800 * Math.sin( theta ) * Math.sin( phi ); object.position.z = 800 * Math.cos( phi ); vector.copy( object.position ).multiplyScalar( 2 ); object.lookAt( vector ); targets.sphere.push( object ); } // helix var vector = new THREE.Vector3(); for ( var i = 0, l = objects.length; i < l; i ++ ) { var phi = i * 0.175 + Math.PI; var object = new THREE.Object3D(); object.position.x = 900 * Math.sin( phi ); object.position.y = - ( i * 8 ) + 450; object.position.z = 900 * Math.cos( phi ); vector.x = object.position.x * 2; vector.y = object.position.y; vector.z = object.position.z * 2; object.lookAt( vector ); targets.helix.push( object ); } // grid for ( var i = 0; i < objects.length; i ++ ) { var object = new THREE.Object3D(); object.position.x = ( ( i % 5 ) * 400 ) - 800; object.position.y = ( - ( Math.floor( i / 5 ) % 5 ) * 400 ) + 800; object.position.z = ( Math.floor( i / 25 ) ) * 1000 - 2000; targets.grid.push( object ); } // renderer = new THREE.CSS3DRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.domElement.style.position = 'absolute'; document.getElementById( 'container' ).appendChild( renderer.domElement ); // controls = new THREE.TrackballControls( camera, renderer.domElement ); controls.rotateSpeed = 0.5; controls.minDistance = 500; controls.maxDistance = 6000; controls.addEventListener( 'change', render ); var button = document.getElementById( 'table' ); button.addEventListener( 'click', function ( event ) { transform( targets.table, 2000 ); }, false ); var button = document.getElementById( 'sphere' ); button.addEventListener( 'click', function ( event ) { transform( targets.sphere, 2000 ); }, false ); var button = document.getElementById( 'helix' ); button.addEventListener( 'click', function ( event ) { transform( targets.helix, 2000 ); }, false ); var button = document.getElementById( 'grid' ); button.addEventListener( 'click', function ( event ) { transform( targets.grid, 2000 ); }, false ); transform( targets.table, 5000 ); // window.addEventListener( 'resize', onWindowResize, false ); } function transform( targets, duration ) { TWEEN.removeAll(); for ( var i = 0; i < objects.length; i ++ ) { var object = objects[ i ]; var target = targets[ i ]; new TWEEN.Tween( object.position ) .to( { x: target.position.x, y: target.position.y, z: target.position.z }, Math.random() * duration + duration ) .easing( TWEEN.Easing.Exponential.InOut ) .start(); new TWEEN.Tween( object.rotation ) .to( { x: target.rotation.x, y: target.rotation.y, z: target.rotation.z }, Math.random() * duration + duration ) .easing( TWEEN.Easing.Exponential.InOut ) .start(); } new TWEEN.Tween( this ) .to( {}, duration * 2 ) .onUpdate( render ) .start(); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); render(); } function animate() { requestAnimationFrame( animate ); TWEEN.update(); controls.update(); } function render() { renderer.render( scene, camera ); }
0x04. STYLE.CSS
html, body { height: 100%; } body { background-color: #000000; margin: 0; font-family: Helvetica, sans-serif;; overflow: hidden; } a { color: #ffffff; } #info { position: absolute; width: 100%; color: #ffffff; padding: 5px; font-family: Monospace; font-size: 13px; font-weight: bold; text-align: center; z-index: 1; } #menu { position: absolute; bottom: 20px; width: 100%; text-align: center; } .element { width: 480px; height: 160px; /* box-shadow: 0px 0px 12px rgba(0,100,255,0.5); */ border: 1px solid rgb(127,100,255); text-align: center; cursor: default; font-size: 60px; } .element:hover { width: 960px; height: 320px; /* box-shadow: 0px 0px 12px rgba(0,255,255); */ border: 3px solid rgb(255,255,255); font-size: 72px; } .element .number { position: absolute; top: 20px; right: 20px; font-size: 12px; color: rgba(129,129,255,0.75); } .element .symbol { position: absolute; top: 40px; left: 0px; right: 0px; font-size: 60px; font-weight: bold; color: rgba(255,255,255,0.75); text-shadow: 0 0 10px rgba(0,255,255,0.95); } .element .details { position: absolute; bottom: 13px; left: 0px; right: 0px; font-size: 36px; color: rgba(127,255,255,0.75); } button { color: rgba(127,100,255,0.75); background: transparent; outline: 1px solid rgba(127,255,255,0.75); border: 0px; padding: 5px 10px; cursor: pointer; } button:hover { background-color: rgba(0,255,255,0.5); } button:active { color: #000000; background-color: rgba(0,255,255,0.75); }
0x05. CSS3DRENDERER.JS
/** * Based on http://www.emagix.net/academic/mscs-project/item/camera-sync-with-css3-and-webgl-threejs * @author mrdoob / http://mrdoob.com/ */ THREE.CSS3DObject = function ( element ) { THREE.Object3D.call( this ); this.element = element; this.element.style.position = 'absolute'; this.addEventListener( 'removed', function ( event ) { if ( this.element.parentNode !== null ) { this.element.parentNode.removeChild( this.element ); } } ); }; THREE.CSS3DObject.prototype = Object.create( THREE.Object3D.prototype ); THREE.CSS3DSprite = function ( element ) { THREE.CSS3DObject.call( this, element ); }; THREE.CSS3DSprite.prototype = Object.create( THREE.CSS3DObject.prototype ); // THREE.CSS3DRenderer = function () { console.log( 'THREE.CSS3DRenderer', THREE.REVISION ); var _width, _height; var _widthHalf, _heightHalf; var matrix = new THREE.Matrix4(); var cache = { camera: { fov: 0, style: '' }, objects: {} }; var domElement = document.createElement( 'div' ); domElement.style.overflow = 'hidden'; domElement.style.WebkitTransformStyle = 'preserve-3d'; domElement.style.MozTransformStyle = 'preserve-3d'; domElement.style.oTransformStyle = 'preserve-3d'; domElement.style.transformStyle = 'preserve-3d'; this.domElement = domElement; var cameraElement = document.createElement( 'div' ); cameraElement.style.WebkitTransformStyle = 'preserve-3d'; cameraElement.style.MozTransformStyle = 'preserve-3d'; cameraElement.style.oTransformStyle = 'preserve-3d'; cameraElement.style.transformStyle = 'preserve-3d'; domElement.appendChild( cameraElement ); this.setClearColor = function () { }; this.setSize = function ( width, height ) { _width = width; _height = height; _widthHalf = _width / 2; _heightHalf = _height / 2; domElement.style.width = width + 'px'; domElement.style.height = height + 'px'; cameraElement.style.width = width + 'px'; cameraElement.style.height = height + 'px'; }; var epsilon = function ( value ) { return Math.abs( value ) < 0.000001 ? 0 : value; }; var getCameraCSSMatrix = function ( matrix ) { var elements = matrix.elements; return 'matrix3d(' + epsilon( elements[ 0 ] ) + ',' + epsilon( - elements[ 1 ] ) + ',' + epsilon( elements[ 2 ] ) + ',' + epsilon( elements[ 3 ] ) + ',' + epsilon( elements[ 4 ] ) + ',' + epsilon( - elements[ 5 ] ) + ',' + epsilon( elements[ 6 ] ) + ',' + epsilon( elements[ 7 ] ) + ',' + epsilon( elements[ 8 ] ) + ',' + epsilon( - elements[ 9 ] ) + ',' + epsilon( elements[ 10 ] ) + ',' + epsilon( elements[ 11 ] ) + ',' + epsilon( elements[ 12 ] ) + ',' + epsilon( - elements[ 13 ] ) + ',' + epsilon( elements[ 14 ] ) + ',' + epsilon( elements[ 15 ] ) + ')'; }; var getObjectCSSMatrix = function ( matrix ) { var elements = matrix.elements; return 'translate3d(-50%,-50%,0) matrix3d(' + epsilon( elements[ 0 ] ) + ',' + epsilon( elements[ 1 ] ) + ',' + epsilon( elements[ 2 ] ) + ',' + epsilon( elements[ 3 ] ) + ',' + epsilon( - elements[ 4 ] ) + ',' + epsilon( - elements[ 5 ] ) + ',' + epsilon( - elements[ 6 ] ) + ',' + epsilon( - elements[ 7 ] ) + ',' + epsilon( elements[ 8 ] ) + ',' + epsilon( elements[ 9 ] ) + ',' + epsilon( elements[ 10 ] ) + ',' + epsilon( elements[ 11 ] ) + ',' + epsilon( elements[ 12 ] ) + ',' + epsilon( elements[ 13 ] ) + ',' + epsilon( elements[ 14 ] ) + ',' + epsilon( elements[ 15 ] ) + ')'; }; var renderObject = function ( object, camera ) { if ( object instanceof THREE.CSS3DObject ) { var style; if ( object instanceof THREE.CSS3DSprite ) { // http://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/ matrix.copy( camera.matrixWorldInverse ); matrix.transpose(); matrix.copyPosition( object.matrixWorld ); matrix.scale( object.scale ); matrix.elements[ 3 ] = 0; matrix.elements[ 7 ] = 0; matrix.elements[ 11 ] = 0; matrix.elements[ 15 ] = 1; style = getObjectCSSMatrix( matrix ); } else { style = getObjectCSSMatrix( object.matrixWorld ); } var element = object.element; var cachedStyle = cache.objects[ object.id ]; if ( cachedStyle === undefined || cachedStyle !== style ) { element.style.WebkitTransform = style; element.style.MozTransform = style; element.style.oTransform = style; element.style.transform = style; cache.objects[ object.id ] = style; } if ( element.parentNode !== cameraElement ) { cameraElement.appendChild( element ); } } for ( var i = 0, l = object.children.length; i < l; i ++ ) { renderObject( object.children[ i ], camera ); } }; this.render = function ( scene, camera ) { var fov = 0.5 / Math.tan( THREE.Math.degToRad( camera.fov * 0.5 ) ) * _height; if ( cache.camera.fov !== fov ) { domElement.style.WebkitPerspective = fov + "px"; domElement.style.MozPerspective = fov + "px"; domElement.style.oPerspective = fov + "px"; domElement.style.perspective = fov + "px"; cache.camera.fov = fov; } scene.updateMatrixWorld(); if ( camera.parent === undefined ) camera.updateMatrixWorld(); camera.matrixWorldInverse.getInverse( camera.matrixWorld ); var style = "translate3d(0,0," + fov + "px)" + getCameraCSSMatrix( camera.matrixWorldInverse ) + " translate3d(" + _widthHalf + "px," + _heightHalf + "px, 0)"; if ( cache.camera.style !== style ) { cameraElement.style.WebkitTransform = style; cameraElement.style.MozTransform = style; cameraElement.style.oTransform = style; cameraElement.style.transform = style; cache.camera.style = style; } renderObject( scene, camera ); }; };
0x06. THREE.MIN.JS
0x07. TRACKBALLCONTROLS.JS
/** * @author Eberhard Graether / http://egraether.com/ * @author Mark Lundin / http://mark-lundin.com */ 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.noRoll = 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(), _rotateStart = new THREE.Vector3(), _rotateEnd = new THREE.Vector3(), _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 ( pageX, pageY ) { vector.set( ( pageX - _this.screen.left ) / _this.screen.width, ( pageY - _this.screen.top ) / _this.screen.height ); return vector; }; }() ); var getMouseProjectionOnBall = ( function () { var vector = new THREE.Vector3(); var objectUp = new THREE.Vector3(); var mouseOnBall = new THREE.Vector3(); return function ( pageX, pageY ) { mouseOnBall.set( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5), ( _this.screen.height * 0.5 + _this.screen.top - pageY ) / (_this.screen.height*.5), 0.0 ); var length = mouseOnBall.length(); if ( _this.noRoll ) { if ( length < Math.SQRT1_2 ) { mouseOnBall.z = Math.sqrt( 1.0 - length*length ); } else { mouseOnBall.z = .5 / length; } } else if ( length > 1.0 ) { mouseOnBall.normalize(); } else { mouseOnBall.z = Math.sqrt( 1.0 - length * length ); } _eye.copy( _this.object.position ).sub( _this.target ); vector.copy( _this.object.up ).setLength( mouseOnBall.y ) vector.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) ); vector.add( _eye.setLength( mouseOnBall.z ) ); return vector; }; }() ); this.rotateCamera = (function(){ var axis = new THREE.Vector3(), quaternion = new THREE.Quaternion(); return function () { var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() ); if ( angle ) { axis.crossVectors( _rotateStart, _rotateEnd ).normalize(); angle *= _this.rotateSpeed; quaternion.setFromAxisAngle( axis, -angle ); _eye.applyQuaternion( quaternion ); _this.object.up.applyQuaternion( quaternion ); _rotateEnd.applyQuaternion( quaternion ); if ( _this.staticMoving ) { _rotateStart.copy( _rotateEnd ); } else { quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) ); _rotateStart.applyQuaternion( quaternion ); } } } }()); this.zoomCamera = function () { if ( _state === STATE.TOUCH_ZOOM_PAN ) { var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; _touchZoomDistanceStart = _touchZoomDistanceEnd; _eye.multiplyScalar( factor ); } else { var 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 () { 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 ) ); } if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); } } }; 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 ) { _rotateStart.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) ); _rotateEnd.copy( _rotateStart ); } 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 ) { _rotateEnd.copy( getMouseProjectionOnBall( 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(); var delta = 0; if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 delta = event.wheelDelta / 40; } else if ( event.detail ) { // Firefox delta = - event.detail / 3; } _zoomStart.y += delta * 0.01; _this.dispatchEvent( startEvent ); _this.dispatchEvent( endEvent ); } function touchstart( event ) { if ( _this.enabled === false ) return; switch ( event.touches.length ) { case 1: _state = STATE.TOUCH_ROTATE; _rotateStart.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); _rotateEnd.copy( _rotateStart ); break; case 2: _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; default: _state = STATE.NONE; } _this.dispatchEvent( startEvent ); } function touchmove( event ) { if ( _this.enabled === false ) return; event.preventDefault(); event.stopPropagation(); switch ( event.touches.length ) { case 1: _rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); break; case 2: 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; default: _state = STATE.NONE; } } function touchend( event ) { if ( _this.enabled === false ) return; switch ( event.touches.length ) { case 1: _rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); _rotateStart.copy( _rotateEnd ); break; case 2: _touchZoomDistanceStart = _touchZoomDistanceEnd = 0; 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 ) ); _panStart.copy( _panEnd ); break; } _state = STATE.NONE; _this.dispatchEvent( endEvent ); } this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); this.domElement.addEventListener( 'mousedown', mousedown, false ); this.domElement.addEventListener( 'mousewheel', mousewheel, false ); this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox 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 );
0x08. TWEEN.MIN.JS
0x09. DEMO
=> Écrit par : Nicolas & Anté, le 19 août 2014