<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.min.js"></script>
<script src="particle-label.js"></script>
<script src="script.js"></script>
</head>
<body>
</body>
</html>
// change this Boolean to swap between Mesh and Sprite
var USE_SPRITE = true;
var theta = 0;
var radiusCamera = 4000;
var particleLabel;
var hoverSprite;
var scene;
var renderer;
var raycaster;
var mouse;
var userMouse;
var spriteGroup;
function create3d() {
mouse = new THREE.Vector2();
userMouse = new THREE.Vector2();
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
raycaster = new THREE.Raycaster();
renderer.autoClear = true;
renderer.setClearColor( 0x111111 );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 4000;
camera.position.y = 1000;
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
}
function createSprites() {
var o;
var m;
var radius = 500;
var a = 250 / ( Math.PI * 2 );
var pi2 = Math.PI * 2;
var r;
var total;
var scale;
spriteGroup = new THREE.Object3D();
for ( var i = 0; i < 250; i++ ) {
total = Math.floor(Math.random() * 1000);
if ( USE_SPRITE ) {
// using SpriteMaterial / Sprite
m = new THREE.SpriteMaterial( { color: 0xff0000 } );
o = new THREE.Sprite( m );
} else {
// using MeshBasicMaterial / Material
m = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
o = new THREE.Mesh(new THREE.PlaneGeometry( 1, 1, 1 ), m );
}
r = ( radius * Math.random() );
a = Math.random() * pi2;
o.position.x = Math.sin( a ) * r * 2;
o.position.z = Math.cos( a ) * r; // z
o.position.y = Math.sqrt( total ) * 25 + Math.random() * 200 + 50; // y
o.position.round();
o.userData.title = '#' + i;
scale = total / 10;
o.scale.set( scale, scale, 1 );
spriteGroup.add( o );
}
scene.add( spriteGroup );
}
function render() {
requestAnimationFrame(render);
theta += 0.05;
camera.position.x = radiusCamera * Math.sin( THREE.Math.degToRad( theta ) );
camera.position.z = radiusCamera * Math.cos( THREE.Math.degToRad( theta ) );
camera.lookAt( scene.position );
camera.updateMatrixWorld();
raycastSprites();
renderer.render( scene, camera );
}
function raycastSprites() {
raycaster.setFromCamera( mouse, camera );
intersects = raycaster.intersectObjects( spriteGroup.children );
if ( intersects.length > 0 ) {
// get the first object.
showLabel( intersects[ 0 ].object, userMouse.x, userMouse.y );
} else {
particleLabel.hide();
hoverSprite = null;
}
}
function onMouseMove( event ) {
event.preventDefault();
userMouse.x = event.clientX;
userMouse.y = event.clientY;
// normalize between -1 and +1
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;
isMouseMoving = true;
}
function showLabel( object, x, y ) {
if (!object) return;
if ( hoverSprite !== object && object.visible ) {
hoverSprite = object;
particleLabel.setText(hoverSprite.userData.title);
particleLabel.show();
}
particleLabel.setPos( x, y );
}
window.onload = function () {
create3d();
createSprites();
particleLabel = new ParticleLabel();
renderer.domElement.addEventListener('mousemove', onMouseMove, false);
render();
};
/* Styles go here */
html,
body,
canvas,
div {
margin: 0;
padding: 0;
border: 0;
}
.label {
font-size: 1.25em;
z-index: 100;
position: absolute;
background: #333;
color: #fff;
padding: 10px;
-moz-transform: translatez(1px);
-ms-transform: translatez(1px);
-o-transform: translatez(1px);
-webkit-transform: translatez(1px);
transform: translatez(1px);
-khtml-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.label .label-number {
font-size: 24px;
margin-right: 10px;
}
(function (){
'use strict';
var ParticleLabel = function () {
this.container = document.createElement( 'div' );
this.container.className = 'label';
this.container.style.display = 'none';
document.body.appendChild( this.container );
};
ParticleLabel.prototype = {
setText: function ( text, countArea ) {
this.container.innerHTML = '<span class="label-number">' + text + '</span>';
},
setPos: function ( x, y ) {
this.container.style.top = ( y - 80 ) + 'px';
this.container.style.left = x + 'px';
},
hide: function () {
this.container.style.display = 'none';
},
show: function () {
this.container.style.display = 'block';
}
};
window.ParticleLabel = ParticleLabel;
}());