DAT.Globe = function(container, opts) {
var colorFn = opts.colorFn || function(x) {
var c = new THREE.Color();
c.setHSL( ( 0.6 - ( x * 0.5 ) ), 1.0, 0.5 );
var imgDir = opts.imgDir || '/globe/';
'texture': { type: 't', value: null }
'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
'vNormal = normalize( normalMatrix * normal );',
'uniform sampler2D texture;',
'vec3 diffuse = texture2D( texture, vUv ).xyz;',
'float intensity = 1.05 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) );',
'vec3 atmosphere = vec3( 1.0, 1.0, 1.0 ) * pow( intensity, 3.0 );',
'gl_FragColor = vec4( diffuse + atmosphere, 1.0 );',
'vNormal = normalize( normalMatrix * normal );',
'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
'float intensity = pow( 0.8 - dot( vNormal, vec3( 0, 0, 1.0 ) ), 12.0 );',
'gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * intensity;',
var camera, scene, renderer, w, h;
var mesh, atmosphere, point;
var mouse = { x: 0, y: 0 }, mouseOnDown = { x: 0, y: 0 };
var rotation = { x: 0, y: 0 },
target = { x: Math.PI*3/2, y: Math.PI / 6.0 },
targetOnDown = { x: 0, y: 0 };
var distance = 100000, distanceTarget = 100000;
var PI_HALF = Math.PI / 2;
container.style.color = '#fff';
container.style.font = '13px/20px Arial, sans-serif';
var shader, uniforms, material;
w = container.offsetWidth || window.innerWidth;
h = container.offsetHeight || window.innerHeight;
camera = new THREE.PerspectiveCamera(30, w / h, 1, 10000);
camera.position.z = distance;
scene = new THREE.Scene();
var geometry = new THREE.SphereGeometry(200, 40, 30);
shader = Shaders['earth'];
uniforms = THREE.UniformsUtils.clone(shader.uniforms);
uniforms['texture'].value = THREE.ImageUtils.loadTexture(imgDir+'world.jpg');
material = new THREE.ShaderMaterial({
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
mesh = new THREE.Mesh(geometry, material);
mesh.rotation.y = Math.PI;
shader = Shaders['atmosphere'];
uniforms = THREE.UniformsUtils.clone(shader.uniforms);
material = new THREE.ShaderMaterial({
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader,
blending: THREE.AdditiveBlending,
mesh = new THREE.Mesh(geometry, material);
mesh.scale.set( 1.1, 1.1, 1.1 );
geometry = new THREE.BoxGeometry(0.75, 0.75, 1);
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0,0,-0.5));
point = new THREE.Mesh(geometry);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.domElement.style.position = 'absolute';
container.appendChild(renderer.domElement);
container.addEventListener('mousedown', onMouseDown, false);
container.addEventListener('mousewheel', onMouseWheel, false);
document.addEventListener('keydown', onDocumentKeyDown, false);
window.addEventListener('resize', onWindowResize, false);
container.addEventListener('mouseover', function() {
container.addEventListener('mouseout', function() {
function addData(data, opts) {
var lat, lng, size, color, i, step, colorFnWrapper;
opts.animated = opts.animated || false;
this.is_animated = opts.animated;
opts.format = opts.format || 'magnitude'; // other option is 'legend'
if (opts.format === 'magnitude') {
colorFnWrapper = function(data, i) { return colorFn(data[i+2]); }
} else if (opts.format === 'legend') {
colorFnWrapper = function(data, i) { return colorFn(data[i+3]); }
throw('error: format not supported: '+opts.format);
if (this._baseGeometry === undefined) {
this._baseGeometry = new THREE.Geometry();
for (i = 0; i < data.length; i += step) {
color = colorFnWrapper(data,i);
addPoint(lat, lng, size, color, this._baseGeometry);
if(this._morphTargetId === undefined) {
this._morphTargetId += 1;
opts.name = opts.name || 'morphTarget'+this._morphTargetId;
var subgeo = new THREE.Geometry();
for (i = 0; i < data.length; i += step) {
color = colorFnWrapper(data,i);
addPoint(lat, lng, size, color, subgeo);
this._baseGeometry.morphTargets.push({'name': opts.name, vertices: subgeo.vertices});
this._baseGeometry = subgeo;
function createPoints() {
if (this._baseGeometry !== undefined) {
if (this.is_animated === false) {
this.points = new THREE.Mesh(this._baseGeometry, new THREE.MeshBasicMaterial({
vertexColors: THREE.FaceColors,
if (this._baseGeometry.morphTargets.length < 8) {
console.log('t l',this._baseGeometry.morphTargets.length);
var padding = 8-this._baseGeometry.morphTargets.length;
console.log('padding', padding);
for(var i=0; i<=padding; i++) {
console.log('padding',i);
this._baseGeometry.morphTargets.push({'name': 'morphPadding'+i, vertices: this._baseGeometry.vertices});
this.points = new THREE.Mesh(this._baseGeometry, new THREE.MeshBasicMaterial({
vertexColors: THREE.FaceColors,
this.points.name = "lines";
function removeAllPoints() {
scene.remove(scene.getObjectByName("lines"));
function addPoint(lat, lng, size, color, subgeo) {
var phi = (90 - lat) * Math.PI / 180;
var theta = (180 - lng) * Math.PI / 180;
point.position.x = 200 * Math.sin(phi) * Math.cos(theta);
point.position.y = 200 * Math.cos(phi);
point.position.z = 200 * Math.sin(phi) * Math.sin(theta);
point.lookAt(mesh.position);
point.scale.z = Math.max( size, 0.1 ); // avoid non-invertible matrix
for (var i = 0; i < point.geometry.faces.length; i++) {
point.geometry.faces[i].color = color;
if(point.matrixAutoUpdate){
subgeo.merge(point.geometry, point.matrix);
function onMouseDown(event) {
container.addEventListener('mousemove', onMouseMove, false);
container.addEventListener('mouseup', onMouseUp, false);
container.addEventListener('mouseout', onMouseOut, false);
mouseOnDown.x = - event.clientX;
mouseOnDown.y = event.clientY;
targetOnDown.x = target.x;
targetOnDown.y = target.y;
container.style.cursor = 'move';
function onMouseMove(event) {
mouse.x = - event.clientX;
var zoomDamp = distance/1000;
target.x = targetOnDown.x + (mouse.x - mouseOnDown.x) * 0.005 * zoomDamp;
target.y = targetOnDown.y + (mouse.y - mouseOnDown.y) * 0.005 * zoomDamp;
target.y = target.y > PI_HALF ? PI_HALF : target.y;
target.y = target.y < - PI_HALF ? - PI_HALF : target.y;
function onMouseUp(event) {
container.removeEventListener('mousemove', onMouseMove, false);
container.removeEventListener('mouseup', onMouseUp, false);
container.removeEventListener('mouseout', onMouseOut, false);
container.style.cursor = 'auto';
function onMouseOut(event) {
container.removeEventListener('mousemove', onMouseMove, false);
container.removeEventListener('mouseup', onMouseUp, false);
container.removeEventListener('mouseout', onMouseOut, false);
function onMouseWheel(event) {
zoom(event.wheelDeltaY * 0.3);
function onDocumentKeyDown(event) {
function onWindowResize( event ) {
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize( container.offsetWidth, container.offsetHeight );
distanceTarget = distanceTarget > 1000 ? 1000 : distanceTarget;
distanceTarget = distanceTarget < 350 ? 350 : distanceTarget;
requestAnimationFrame(animate);
rotation.x += (target.x - rotation.x) * 0.1;
rotation.y += (target.y - rotation.y) * 0.1;
distance += (distanceTarget - distance) * 0.3;
camera.position.x = distance * Math.sin(rotation.x) * Math.cos(rotation.y);
camera.position.y = distance * Math.sin(rotation.y);
camera.position.z = distance * Math.cos(rotation.x) * Math.cos(rotation.y);
camera.lookAt(mesh.position);
renderer.render(scene, camera);
this.__defineGetter__('time', function() {
this.__defineSetter__('time', function(t) {
var morphDict = this.points.morphTargetDictionary;
for(var k in morphDict) {
if(k.indexOf('morphPadding') < 0) {
validMorphs.push(morphDict[k]);
var l = validMorphs.length-1;
var index = Math.floor(scaledt);
for (i=0;i<validMorphs.length;i++) {
this.points.morphTargetInfluences[validMorphs[i]] = 0;
var lastIndex = index - 1;
var leftover = scaledt - index;
this.points.morphTargetInfluences[lastIndex] = 1 - leftover;
this.points.morphTargetInfluences[index] = leftover;
// Near the bottom of the code
this.removeAllPoints = removeAllPoints; // Add this line
this.createPoints = createPoints;
this.renderer = renderer;