css3d_molecules.html 11.0 KB
Newer Older
A
alteredq 已提交
1 2 3
<!DOCTYPE html>
<html>
	<head>
M
Mr.doob 已提交
4
		<title>three.js css3d - molecules</title>
A
alteredq 已提交
5 6
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
M
Mr.doob 已提交
7
		<link type="text/css" rel="stylesheet" href="main.css">
A
alteredq 已提交
8 9
		<style>
			body {
10
				background-color: #050505;
M
Mr.doob 已提交
11
				background: radial-gradient(ellipse at center,  rgba(43,45,48,1) 0%,rgba(0,0,0,1) 100%);
A
alteredq 已提交
12 13
			}

M
Mr.doob 已提交
14
			#topmenu {
A
alteredq 已提交
15
				position: absolute;
M
Mr.doob 已提交
16
				top: 50px;
A
alteredq 已提交
17
				width: 100%;
M
Mr.doob 已提交
18 19
				padding: 10px;
				box-sizing: border-box;
A
alteredq 已提交
20 21 22 23 24 25 26
				text-align: center;
			}

			#menu {
				position: absolute;
				bottom: 20px;
				width: 100%;
M
Mr.doob 已提交
27 28
				padding: 10px;
				box-sizing: border-box;
A
alteredq 已提交
29
				text-align: center;
30 31
			}

A
alteredq 已提交
32 33
			button {
				color: rgb(255,255,255);
M
Mr.doob 已提交
34
				background: rgb(255,255,255,0.1);
A
alteredq 已提交
35 36
				border: 0px;
				padding: 5px 10px;
M
Mr.doob 已提交
37 38
				margin: 2px;
				font-size: 14px;
A
alteredq 已提交
39 40
				cursor: pointer;
			}
M
Mr.doob 已提交
41 42 43 44 45 46 47 48 49

				button:hover {
					background-color: rgba(0,255,255,0.5);
				}

				button:active {
					color: #000000;
					background-color: rgba(0,255,255,1);
				}
A
alteredq 已提交
50 51 52 53

			.bond {
				width: 5px;
				height: 10px;
54
				background: #eee;
A
alteredq 已提交
55 56
				display: block;
			}
A
alteredq 已提交
57 58 59 60
		</style>
	</head>
	<body>
		<div id="container"></div>
M
Mr.doob 已提交
61
		<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> css3d - molecules</div>
62
		<div id="topmenu">
M
Mr.doob 已提交
63
			<button id="b_a">Atoms</button><button id="b_b">Bonds</button><button id="b_ab">Atoms + Bonds</button>
64
		</div>
A
alteredq 已提交
65 66
		<div id="menu"></div>

67
		<script type="module">
68

M
Mr.doob 已提交
69
			import * as THREE from '../build/three.module.js';
70 71 72 73 74

			import { TrackballControls } from './jsm/controls/TrackballControls.js';
			import { PDBLoader } from './jsm/loaders/PDBLoader.js';
			import { CSS3DRenderer, CSS3DObject, CSS3DSprite } from './jsm/renderers/CSS3DRenderer.js';

A
alteredq 已提交
75 76
			var camera, scene, renderer;
			var controls;
77
			var root;
A
alteredq 已提交
78 79

			var objects = [];
M
Mr.doob 已提交
80 81 82 83 84
			var tmpVec1 = new THREE.Vector3();
			var tmpVec2 = new THREE.Vector3();
			var tmpVec3 = new THREE.Vector3();
			var tmpVec4 = new THREE.Vector3();
			var offset = new THREE.Vector3();
A
alteredq 已提交
85

86 87
			var visualizationType = 2;

A
alteredq 已提交
88
			var MOLECULES = {
M
Mr.doob 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
				"Ethanol": "ethanol.pdb",
				"Aspirin": "aspirin.pdb",
				"Caffeine": "caffeine.pdb",
				"Nicotine": "nicotine.pdb",
				"LSD": "lsd.pdb",
				"Cocaine": "cocaine.pdb",
				"Cholesterol": "cholesterol.pdb",
				"Lycopene": "lycopene.pdb",
				"Glucose": "glucose.pdb",
				"Aluminium oxide": "Al2O3.pdb",
				"Cubane": "cubane.pdb",
				"Copper": "cu.pdb",
				"Fluorite": "caf2.pdb",
				"Salt": "nacl.pdb",
				"YBCO superconductor": "ybco.pdb",
				"Buckyball": "buckyball.pdb",
				//"Diamond": "diamond.pdb",
				"Graphite": "graphite.pdb"
A
alteredq 已提交
107 108
			};

109
			var loader = new PDBLoader();
A
alteredq 已提交
110 111 112 113 114 115 116 117 118 119
			var colorSpriteMap = {};
			var baseSprite = document.createElement( 'img' );

			var menu = document.getElementById( "menu" );

			init();
			animate();

			function init() {

M
Mr.doob 已提交
120
				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 5000 );
121
				camera.position.z = 1500;
A
alteredq 已提交
122

M
Mr.doob 已提交
123
				scene = new THREE.Scene();
A
alteredq 已提交
124

M
Mr.doob 已提交
125
				root = new THREE.Object3D();
126 127
				scene.add( root );

A
alteredq 已提交
128 129
				//

130
				renderer = new CSS3DRenderer();
A
alteredq 已提交
131 132 133 134 135
				renderer.setSize( window.innerWidth, window.innerHeight );
				document.getElementById( 'container' ).appendChild( renderer.domElement );

				//

136
				controls = new TrackballControls( camera, renderer.domElement );
A
alteredq 已提交
137 138 139 140 141 142 143
				controls.rotateSpeed = 0.5;

				//

				baseSprite.onload = function () {

					loadMolecule( "models/molecules/caffeine.pdb" );
144
					createMenu();
A
alteredq 已提交
145 146 147 148 149 150 151 152 153 154 155 156 157

				};

				baseSprite.src = 'textures/sprites/ball.png';

				//

				window.addEventListener( 'resize', onWindowResize, false );

			}

			//

158
			function generateButtonCallback( url ) {
A
alteredq 已提交
159

L
Lewy Blue 已提交
160
				return function () {
A
alteredq 已提交
161

162
					loadMolecule( url );
A
alteredq 已提交
163

L
Lewy Blue 已提交
164
				};
A
alteredq 已提交
165

166
			}
A
alteredq 已提交
167

168
			function createMenu() {
A
alteredq 已提交
169

170
				for ( var m in MOLECULES ) {
A
alteredq 已提交
171

172 173 174
					var button = document.createElement( 'button' );
					button.innerHTML = m;
					menu.appendChild( button );
A
alteredq 已提交
175

L
Lewy Blue 已提交
176
					var url = "models/molecules/" + MOLECULES[ m ];
A
alteredq 已提交
177

178
					button.addEventListener( 'click', generateButtonCallback( url ), false );
A
alteredq 已提交
179 180 181

				}

182 183 184 185
				var b_a = document.getElementById( "b_a" );
				var b_b = document.getElementById( "b_b" );
				var b_ab = document.getElementById( "b_ab" );

L
Lewy Blue 已提交
186 187
				b_a.addEventListener( 'click', function () {

L
Lewy Blue 已提交
188 189
					visualizationType = 0;
					showAtoms();
L
Lewy Blue 已提交
190 191 192 193

				} );
				b_b.addEventListener( 'click', function () {

L
Lewy Blue 已提交
194 195
					visualizationType = 1;
					showBonds();
L
Lewy Blue 已提交
196 197 198 199

				} );
				b_ab.addEventListener( 'click', function () {

L
Lewy Blue 已提交
200 201
					visualizationType = 2;
					showAtomsBonds();
L
Lewy Blue 已提交
202 203

				} );
204 205 206 207 208 209 210 211 212 213 214

			}

			//

			function showAtoms() {

				for ( var i = 0; i < objects.length; i ++ ) {

					var object = objects[ i ];

215
					if ( object instanceof CSS3DSprite ) {
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

						object.element.style.display = "";
						object.visible = true;

					} else {

						object.element.style.display = "none";
						object.visible = false;

					}

				}

			}

			function showBonds() {

				for ( var i = 0; i < objects.length; i ++ ) {

					var object = objects[ i ];

237
					if ( object instanceof CSS3DSprite ) {
238 239 240 241 242 243 244

						object.element.style.display = "none";
						object.visible = false;

					} else {

						object.element.style.display = "";
245
						object.element.style.height = object.userData.bondLengthFull;
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
						object.visible = true;

					}

				}

			}

			function showAtomsBonds() {

				for ( var i = 0; i < objects.length; i ++ ) {

					var object = objects[ i ];

					object.element.style.display = "";
					object.visible = true;

263
					if ( ! ( object instanceof CSS3DSprite ) ) {
264

265
						object.element.style.height = object.userData.bondLengthShort;
266 267 268 269 270

					}

				}

A
alteredq 已提交
271 272
			}

273 274
			//

M
Mr.doob 已提交
275
			function colorify( ctx, width, height, color ) {
A
alteredq 已提交
276

M
Mr.doob 已提交
277
				var r = color.r, g = color.g, b = color.b;
A
alteredq 已提交
278 279 280 281

				var imageData = ctx.getImageData( 0, 0, width, height );
				var data = imageData.data;

M
Mr.doob 已提交
282
				for ( var i = 0, l = data.length; i < l; i += 4 ) {
A
alteredq 已提交
283

M
Mr.doob 已提交
284 285 286
					data[ i + 0 ] *= r;
					data[ i + 1 ] *= g;
					data[ i + 2 ] *= b;
A
alteredq 已提交
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316

				}

				ctx.putImageData( imageData, 0, 0 );

			}

			function imageToCanvas( image ) {

				var width = image.width;
				var height = image.height;

				var canvas = document.createElement( 'canvas' );

				canvas.width = width;
				canvas.height = height;

				var context = canvas.getContext( '2d' );
				context.drawImage( image, 0, 0, width, height );

				return canvas;

			}

			//

			function loadMolecule( url ) {

				for ( var i = 0; i < objects.length; i ++ ) {

A
alteredq 已提交
317 318
					var object = objects[ i ];
					object.parent.remove( object );
319

A
alteredq 已提交
320 321 322 323
				}

				objects = [];

M
Mugen87 已提交
324
				loader.load( url, function ( pdb ) {
A
alteredq 已提交
325

M
Mugen87 已提交
326 327 328 329
					var geometryAtoms = pdb.geometryAtoms;
					var geometryBonds = pdb.geometryBonds;
					var json = pdb.json;

M
Mugen87 已提交
330 331 332 333
					geometryAtoms.computeBoundingBox();
					geometryAtoms.boundingBox.getCenter( offset ).negate();

					geometryAtoms.translate( offset.x, offset.y, offset.z );
334
					geometryBonds.translate( offset.x, offset.y, offset.z );
A
alteredq 已提交
335

M
Mugen87 已提交
336 337
					var positions = geometryAtoms.getAttribute( 'position' );
					var colors = geometryAtoms.getAttribute( 'color' );
M
Mugen87 已提交
338

M
Mr.doob 已提交
339 340
					var position = new THREE.Vector3();
					var color = new THREE.Color();
M
Mugen87 已提交
341 342 343 344 345 346 347 348 349 350

					for ( var i = 0; i < positions.count; i ++ ) {

						position.x = positions.getX( i );
						position.y = positions.getY( i );
						position.z = positions.getZ( i );

						color.r = colors.getX( i );
						color.g = colors.getY( i );
						color.b = colors.getZ( i );
A
alteredq 已提交
351

M
Mugen87 已提交
352 353
						var atom = json.atoms[ i ];
						var element = atom[ 4 ];
A
alteredq 已提交
354

355
						if ( ! colorSpriteMap[ element ] ) {
A
alteredq 已提交
356 357 358 359

							var canvas = imageToCanvas( baseSprite );
							var context = canvas.getContext( '2d' );

M
Mr.doob 已提交
360
							colorify( context, canvas.width, canvas.height, color );
A
alteredq 已提交
361 362 363 364 365 366 367

							var dataUrl = canvas.toDataURL();

							colorSpriteMap[ element ] = dataUrl;

						}

368
						var colorSprite = colorSpriteMap[ element ];
A
alteredq 已提交
369 370 371 372

						var atom = document.createElement( 'img' );
						atom.src = colorSprite;

373
						var object = new CSS3DSprite( atom );
A
alteredq 已提交
374
						object.position.copy( position );
A
alteredq 已提交
375
						object.position.multiplyScalar( 75 );
376 377 378 379

						object.matrixAutoUpdate = false;
						object.updateMatrix();

380
						root.add( object );
A
alteredq 已提交
381 382 383 384 385

						objects.push( object );

					}

M
Mugen87 已提交
386
					positions = geometryBonds.getAttribute( 'position' );
A
alteredq 已提交
387

M
Mr.doob 已提交
388 389
					var start = new THREE.Vector3();
					var end = new THREE.Vector3();
M
Mugen87 已提交
390 391 392 393 394 395 396 397 398 399

					for ( var i = 0; i < positions.count; i += 2 ) {

						start.x = positions.getX( i );
						start.y = positions.getY( i );
						start.z = positions.getZ( i );

						end.x = positions.getX( i + 1 );
						end.y = positions.getY( i + 1 );
						end.z = positions.getZ( i + 1 );
A
alteredq 已提交
400 401 402 403

						start.multiplyScalar( 75 );
						end.multiplyScalar( 75 );

404
						tmpVec1.subVectors( end, start );
A
alteredq 已提交
405 406 407 408 409 410 411 412
						var bondLength = tmpVec1.length() - 50;

						//

						var bond = document.createElement( 'div' );
						bond.className = "bond";
						bond.style.height = bondLength + "px";

413
						var object = new CSS3DObject( bond );
A
alteredq 已提交
414
						object.position.copy( start );
415
						object.position.lerp( end, 0.5 );
A
alteredq 已提交
416

417 418
						object.userData.bondLengthShort = bondLength + "px";
						object.userData.bondLengthFull = ( bondLength + 55 ) + "px";
419

A
alteredq 已提交
420 421
						//

422
						var axis = tmpVec2.set( 0, 1, 0 ).cross( tmpVec1 );
A
alteredq 已提交
423 424
						var radians = Math.acos( tmpVec3.set( 0, 1, 0 ).dot( tmpVec4.copy( tmpVec1 ).normalize() ) );

M
Mr.doob 已提交
425
						var objMatrix = new THREE.Matrix4().makeRotationAxis( axis.normalize(), radians );
A
alteredq 已提交
426
						object.matrix = objMatrix;
W
WestLangley 已提交
427
						object.quaternion.setFromRotationMatrix( object.matrix );
A
alteredq 已提交
428

429 430 431
						object.matrixAutoUpdate = false;
						object.updateMatrix();

A
alteredq 已提交
432 433 434 435 436 437 438 439 440 441
						root.add( object );

						objects.push( object );

						//

						var bond = document.createElement( 'div' );
						bond.className = "bond";
						bond.style.height = bondLength + "px";

M
Mr.doob 已提交
442
						var joint = new THREE.Object3D( bond );
A
alteredq 已提交
443
						joint.position.copy( start );
444
						joint.position.lerp( end, 0.5 );
A
alteredq 已提交
445 446

						joint.matrix.copy( objMatrix );
W
WestLangley 已提交
447
						joint.quaternion.setFromRotationMatrix( joint.matrix );
A
alteredq 已提交
448

449 450 451
						joint.matrixAutoUpdate = false;
						joint.updateMatrix();

452
						var object = new CSS3DObject( bond );
L
Lewy Blue 已提交
453
						object.rotation.y = Math.PI / 2;
A
alteredq 已提交
454

455 456 457
						object.matrixAutoUpdate = false;
						object.updateMatrix();

458 459
						object.userData.bondLengthShort = bondLength + "px";
						object.userData.bondLengthFull = ( bondLength + 55 ) + "px";
460

461
						object.userData.joint = joint;
462

A
alteredq 已提交
463 464 465 466 467 468 469 470 471
						joint.add( object );
						root.add( joint );

						objects.push( object );

					}

					//console.log( "CSS3DObjects:", objects.length );

472 473
					switch ( visualizationType ) {

L
Lewy Blue 已提交
474 475 476 477 478 479 480 481 482
						case 0:
							showAtoms();
							break;
						case 1:
							showBonds();
							break;
						case 2:
							showAtomsBonds();
							break;
483 484 485

					}

A
alteredq 已提交
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
				} );


			}

			//

			function onWindowResize() {

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

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

			}

			function animate() {

				requestAnimationFrame( animate );
				controls.update();

507 508 509 510 511 512 513
				var time = Date.now() * 0.0004;

				root.rotation.x = time;
				root.rotation.y = time * 0.7;

				render();

A
alteredq 已提交
514 515 516 517 518 519 520 521 522 523 524 525
			}

			function render() {

				renderer.render( scene, camera );

			}

    </script>
  </body>

</html>