PageSourceSearch

https://grabosky.net/js/globe.js

js grabosky.net collected 2026-10-07 18:30:26 UTC 11,966 bytes, 416 lines download raw bytes

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.