1/** 2 * dat.globe Javascript WebGL Globe Toolkit 3 * https://github.com/dataarts/webgl-globe 4 * 5 * Copyright 2011 Data Arts Team, Google Creative Lab 6 * 7 * Licensed under the Apache License, Version 2.0 (the 'License'); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 */ 13 14var DAT = DAT || {}; 15 16DAT.Globe = function(container, opts) { 17 opts = opts || {}; 18 19 var colorFn = opts.colorFn || function(x) { 20 var c = new THREE.Color(); 21 c.setHSL( ( 0.6 - ( x * 0.5 ) ), 1.0, 0.5 ); 22 return c; 23 }; 24 var imgDir = opts.imgDir || '/globe/'; 25 26 var Shaders = { 27 'earth' : { 28 uniforms: { 29 'texture': { type: 't', value: null } 30 }, 31 vertexShader: [ 32 'varying vec3 vNormal;', 33 'varying vec2 vUv;', 34 'void main() {', 35 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', 36 'vNormal = normalize( normalMatrix * normal );', 37 'vUv = uv;', 38 '}' 39 ].join('\n'), 40 fragmentShader: [ 41 'uniform sampler2D texture;', 42 'varying vec3 vNormal;', 43 'varying vec2 vUv;', 44 'void main() {', 45 'vec3 diffuse = texture2D( texture, vUv ).xyz;', 46 'float intensity = 1.05 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) );', 47 'vec3 atmosphere = vec3( 1.0, 1.0, 1.0 ) * pow( intensity, 3.0 );', 48 'gl_FragColor = vec4( diffuse + atmosphere, 1.0 );', 49 '}' 50 ].join('\n') 51 }, 52 'atmosphere' : { 53 uniforms: {}, 54 vertexShader: [ 55 'varying vec3 vNormal;', 56 'void main() {', 57 'vNormal = normalize( normalMatrix * normal );', 58 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', 59 '}' 60 ].join('\n'), 61 fragmentShader: [ 62 'varying vec3 vNormal;', 63 'void main() {', 64 'float intensity = pow( 0.8 - dot( vNormal, vec3( 0, 0, 1.0 ) ), 12.0 );', 65 'gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * intensity;', 66 '}' 67 ].join('\n') 68 } 69 }; 70 71 var camera, scene, renderer, w, h; 72 var mesh, atmosphere, point; 73 74 var overRenderer; 75 76 var curZoomSpeed = 0; 77 var zoomSpeed = 50; 78 79 var mouse = { x: 0, y: 0 }, mouseOnDown = { x: 0, y: 0 }; 80 var rotation = { x: 0, y: 0 }, 81 target = { x: Math.PI*3/2, y: Math.PI / 6.0 }, 82 targetOnDown = { x: 0, y: 0 }; 83 84 var distance = 100000, distanceTarget = 100000; 85 var padding = 40; 86 var PI_HALF = Math.PI / 2; 87 88 function init() { 89 90 container.style.color = '#fff'; 91 container.style.font = '13px/20px Arial, sans-serif'; 92 93 var shader, uniforms, material; 94 w = container.offsetWidth || window.innerWidth; 95 h = container.offsetHeight || window.innerHeight; 96 97 camera = new THREE.PerspectiveCamera(30, w / h, 1, 10000); 98 camera.position.z = distance; 99 100 scene = new THREE.Scene(); 101 102 var geometry = new THREE.SphereGeometry(200, 40, 30); 103 104 shader = Shaders['earth']; 105 uniforms = THREE.UniformsUtils.clone(shader.uniforms); 106 107 uniforms['texture'].value = THREE.ImageUtils.loadTexture(imgDir+'world.jpg'); 108 109 material = new THREE.ShaderMaterial({ 110 111 uniforms: uniforms, 112 vertexShader: shader.vertexShader, 113 fragmentShader: shader.fragmentShader 114 115 }); 116 117 mesh = new THREE.Mesh(geometry, material); 118 mesh.rotation.y = Math.PI; 119 scene.add(mesh); 120 121 shader = Shaders['atmosphere']; 122 uniforms = THREE.UniformsUtils.clone(shader.uniforms); 123 124 material = new THREE.ShaderMaterial({ 125 126 uniforms: uniforms, 127 vertexShader: shader.vertexShader, 128 fragmentShader: shader.fragmentShader, 129 side: THREE.BackSide, 130 blending: THREE.AdditiveBlending, 131 transparent: true 132 133 }); 134 135 mesh = new THREE.Mesh(geometry, material); 136 mesh.scale.set( 1.1, 1.1, 1.1 ); 137 scene.add(mesh); 138 139 geometry = new THREE.BoxGeometry(0.75, 0.75, 1); 140 geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0,0,-0.5)); 141 142 point = new THREE.Mesh(geometry); 143 144 renderer = new THREE.WebGLRenderer({antialias: true}); 145 renderer.setSize(w, h); 146 147 renderer.domElement.style.position = 'absolute'; 148 149 container.appendChild(renderer.domElement); 150 151 container.addEventListener('mousedown', onMouseDown, false); 152 153 container.addEventListener('mousewheel', onMouseWheel, false); 154 155 document.addEventListener('keydown', onDocumentKeyDown, false); 156 157 window.addEventListener('resize', onWindowResize, false); 158 159 container.addEventListener('mouseover', function() { 160 overRenderer = true; 161 }, false); 162 163 container.addEventListener('mouseout', function() { 164 overRenderer = false;
165 }, false); 166 } 167 168 function addData(data, opts) { 169 var lat, lng, size, color, i, step, colorFnWrapper; 170 171 opts.animated = opts.animated || false; 172 this.is_animated = opts.animated; 173 opts.format = opts.format || 'magnitude'; // other option is 'legend' 174 if (opts.format === 'magnitude') { 175 step = 3; 176 colorFnWrapper = function(data, i) { return colorFn(data[i+2]); } 177 } else if (opts.format === 'legend') { 178 step = 4; 179 colorFnWrapper = function(data, i) { return colorFn(data[i+3]); } 180 } else { 181 throw('error: format not supported: '+opts.format); 182 } 183 184 if (opts.animated) { 185 if (this._baseGeometry === undefined) { 186 this._baseGeometry = new THREE.Geometry(); 187 for (i = 0; i < data.length; i += step) { 188 lat = data[i]; 189 lng = data[i + 1]; 190// size = data[i + 2]; 191 color = colorFnWrapper(data,i); 192 size = 0; 193 addPoint(lat, lng, size, color, this._baseGeometry); 194 } 195 } 196 if(this._morphTargetId === undefined) { 197 this._morphTargetId = 0; 198 } else { 199 this._morphTargetId += 1; 200 } 201 opts.name = opts.name || 'morphTarget'+this._morphTargetId; 202 } 203 var subgeo = new THREE.Geometry(); 204 for (i = 0; i < data.length; i += step) { 205 lat = data[i]; 206 lng = data[i + 1]; 207 color = colorFnWrapper(data,i); 208 size = data[i + 2]; 209 size = size*200; 210 addPoint(lat, lng, size, color, subgeo); 211 } 212 if (opts.animated) { 213 this._baseGeometry.morphTargets.push({'name': opts.name, vertices: subgeo.vertices}); 214 } else { 215 this._baseGeometry = subgeo; 216 } 217 218 }; 219 220 function createPoints() { 221 if (this._baseGeometry !== undefined) { 222 if (this.is_animated === false) { 223 this.points = new THREE.Mesh(this._baseGeometry, new THREE.MeshBasicMaterial({ 224 color: 0xffffff, 225 vertexColors: THREE.FaceColors, 226 morphTargets: false 227 })); 228 } else { 229 if (this._baseGeometry.morphTargets.length < 8) { 230 console.log('t l',this._baseGeometry.morphTargets.length); 231 var padding = 8-this._baseGeometry.morphTargets.length; 232 console.log('padding', padding); 233 for(var i=0; i<=padding; i++) { 234 console.log('padding',i); 235 this._baseGeometry.morphTargets.push({'name': 'morphPadding'+i, vertices: this._baseGeometry.vertices}); 236 } 237 } 238 this.points = new THREE.Mesh(this._baseGeometry, new THREE.MeshBasicMaterial({ 239 color: 0xffffff, 240 vertexColors: THREE.FaceColors, 241 morphTargets: true 242 })); 243 } 244 scene.add(this.points); 245 } 246 } 247 248 function addPoint(lat, lng, size, color, subgeo) { 249 250 var phi = (90 - lat) * Math.PI / 180; 251 var theta = (180 - lng) * Math.PI / 180; 252 253 point.position.x = 200 * Math.sin(phi) * Math.cos(theta); 254 point.position.y = 200 * Math.cos(phi); 255 point.position.z = 200 * Math.sin(phi) * Math.sin(theta); 256 257 point.lookAt(mesh.position); 258 259 point.scale.z = Math.max( size, 0.1 ); // avoid non-invertible matrix 260 point.updateMatrix(); 261 262 for (var i = 0; i < point.geometry.faces.length; i++) { 263 264 point.geometry.faces[i].color = color; 265 266 } 267 if(point.matrixAutoUpdate){ 268 point.updateMatrix(); 269 } 270 subgeo.merge(point.geometry, point.matrix); 271 } 272 273 function onMouseDown(event) { 274 event.preventDefault(); 275 276 container.addEventListener('mousemove', onMouseMove, false); 277 container.addEventListener('mouseup', onMouseUp, false); 278 container.addEventListener('mouseout', onMouseOut, false); 279 280 mouseOnDown.x = - event.clientX; 281 mouseOnDown.y = event.clientY; 282 283 targetOnDown.x = target.x; 284 targetOnDown.y = target.y; 285 286 container.style.cursor = 'move'; 287 } 288 289 function onMouseMove(event) { 290 mouse.x = - event.clientX; 291 mouse.y = event.clientY; 292 293 var zoomDamp = distance/1000; 294 295 target.x = targetOnDown.x + (mouse.x - mouseOnDown.x) * 0.005 * zoomDamp; 296 target.y = targetOnDown.y + (mouse.y - mouseOnDown.y) * 0.005 * zoomDamp; 297 298 target.y = target.y > PI_HALF ? PI_HALF : target.y; 299 target.y = target.y < - PI_HALF ? - PI_HALF : target.y; 300 } 301 302 function onMouseUp(event) { 303 container.removeEventListener('mousemove', onMouseMove, false); 304 container.removeEventListener('mouseup', onMouseUp, false); 305 container.removeEventListener('mouseout', onMouseOut, false); 306 container.style.cursor = 'auto'; 307 } 308 309 function onMouseOut(event) { 310 container.removeEventListener('mousemove', onMouseMove, false); 311 container.removeEventListener('mouseup', onMouseUp, false); 312 container.removeEventListener('mouseout', onMouseOut, false); 313 } 314 315 function onMouseWheel(event) { 316 event.preventDefault();
317 if (overRenderer) { 318 zoom(event.wheelDeltaY * 0.3); 319 } 320 return false; 321 } 322 323 function onDocumentKeyDown(event) { 324 switch (event.keyCode) { 325 case 38: 326 zoom(100); 327 event.preventDefault(); 328 break; 329 case 40: 330 zoom(-100); 331 event.preventDefault(); 332 break; 333 } 334 } 335 336 function onWindowResize( event ) { 337 camera.aspect = container.offsetWidth / container.offsetHeight; 338 camera.updateProjectionMatrix(); 339 renderer.setSize( container.offsetWidth, container.offsetHeight ); 340 } 341 342 function zoom(delta) { 343 distanceTarget -= delta; 344 distanceTarget = distanceTarget > 1000 ? 1000 : distanceTarget; 345 distanceTarget = distanceTarget < 350 ? 350 : distanceTarget; 346 } 347 348 function animate() { 349 requestAnimationFrame(animate); 350 render(); 351 } 352 353 function render() { 354 zoom(curZoomSpeed); 355 356 rotation.x += (target.x - rotation.x) * 0.1; 357 rotation.y += (target.y - rotation.y) * 0.1; 358 distance += (distanceTarget - distance) * 0.3; 359 360 camera.position.x = distance * Math.sin(rotation.x) * Math.cos(rotation.y); 361 camera.position.y = distance * Math.sin(rotation.y); 362 camera.position.z = distance * Math.cos(rotation.x) * Math.cos(rotation.y); 363 364 camera.lookAt(mesh.position); 365 366 renderer.render(scene, camera); 367 } 368 369 function grabTurn(val) { 370 371 var zoomDamp = distance/1000; 372 373 target.x = target.x + val * 0.005 * zoomDamp; 374 } 375 376 init(); 377 this.animate = animate; 378 379 380 this.__defineGetter__('time', function() { 381 return this._time || 0; 382 }); 383 384 this.__defineSetter__('time', function(t) { 385 var validMorphs = []; 386 var morphDict = this.points.morphTargetDictionary; 387 for(var k in morphDict) { 388 if(k.indexOf('morphPadding') < 0) { 389 validMorphs.push(morphDict[k]); 390 } 391 } 392 validMorphs.sort(); 393 var l = validMorphs.length-1; 394 var scaledt = t*l+1; 395 var index = Math.floor(scaledt); 396 for (i=0;i<validMorphs.length;i++) { 397 this.points.morphTargetInfluences[validMorphs[i]] = 0; 398 } 399 var lastIndex = index - 1; 400 var leftover = scaledt - index; 401 if (lastIndex >= 0) { 402 this.points.morphTargetInfluences[lastIndex] = 1 - leftover; 403 } 404 this.points.morphTargetInfluences[index] = leftover; 405 this._time = t; 406 }); 407 408 this.addData = addData; 409 this.createPoints = createPoints; 410 this.renderer = renderer; 411 this.scene = scene; 412 this.grabTurn = grabTurn; 413 414 return this; 415 416};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.