<div id="container"></div>
<script src="https://cdn.rawgit.com/dataarts/webgl-globe/2d24ba30/globe/third-party/three.min.js"></script>
<!-- <script src="https://cdn.rawgit.com/dataarts/webgl-globe/2d24ba30/globe/globe.js"></script> -->
html {
height: 100%;
}
body {
margin: 0;
padding: 0;
height: 100%;
}
View Compiled
var DAT = DAT || {};
// blue 0x96ca6
// green 0x9de3cb
// green c.setHSL( 0.441, 0.56, 0.75 );
// blue c.setHSL( 0.558, 0.62, 0.75 );
DAT.Globe = function(container, opts) {
opts = opts || {};
var colorFn = opts.colorFn || function(x) {
var c = new THREE.Color();
c.setHSL(0.55 + (x / 2), 0.60, 0.75);
return c;
};
var Shaders = {
earth: {
uniforms: {
texture: { type: "t", value: null }
},
vertexShader: [
"varying vec3 vNormal;",
"varying vec2 vUv;",
"void main() {",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.05 );",
"vNormal = normalize( normalMatrix * normal );",
"vUv = uv;",
"}"
].join("\n"),
fragmentShader: [
"uniform sampler2D texture;",
"varying vec3 vNormal;",
"varying vec2 vUv;",
"void main() {",
"vec3 diffuse = texture2D( texture, vUv ).xyz;",
"float intensity = 1.05 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) );",
"vec3 atmosphere = vec3( 0, 1.0, 1.0 ) * pow( intensity, 3.0 );",
"gl_FragColor = vec4( diffuse + atmosphere, 0.3 );",
"}"
].join("\n")
},
atmosphere: {
uniforms: {},
vertexShader: [
"varying vec3 vNormal;",
"void main() {",
"vNormal = normalize( normalMatrix * normal );",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 0 );",
"}"
].join("\n"),
fragmentShader: [
"varying vec3 vNormal;",
"void main() {",
"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;",
"}"
].join("\n")
}
};
var camera, scene, renderer, w, h;
var mesh, atmosphere, point;
var overRenderer;
var curZoomSpeed = 0;
var zoomSpeed = 50;
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 = 1000000,
distanceTarget = 100000;
var padding = 40;
var PI_HALF = Math.PI / 2;
function init() {
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);
THREE.ImageUtils.crossOrigin = "";
uniforms["texture"].value = THREE.ImageUtils.loadTexture(
"http://cdn.rawgit.com/dataarts/webgl-globe/2d24ba30/globe/world.jpg"
);
material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader,
transparent: true
});
mesh = new THREE.Mesh(geometry, material);
mesh.rotation.y = Math.PI;
scene.add(mesh);
shader = Shaders["atmosphere"];
uniforms = THREE.UniformsUtils.clone(shader.uniforms);
material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader,
side: THREE.BackSide,
blending: THREE.AdditiveBlending,
transparent: true
});
mesh = new THREE.Mesh(geometry, material);
mesh.scale.set(1.1, 1.1, 1.1);
scene.add(mesh);
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.setSize(w, h);
renderer.setClearColor(0x111111, 1);
renderer.domElement.style.position = "absolute";
container.appendChild(renderer.domElement);
container.addEventListener("mousedown", onMouseDown, false);
document.addEventListener("keydown", onDocumentKeyDown, false);
window.addEventListener("resize", onWindowResize, false);
container.addEventListener(
"mouseover",
function() {
overRenderer = true;
},
false
);
container.addEventListener(
"mouseout",
function() {
overRenderer = false;
},
false
);
}
function addData(data, opts) {
var lat, lng, size, color, i, step, colorFnWrapper;
step = 3;
colorFnWrapper = function(data, i) {
return colorFn(data[i + 2]);
};
var subgeo = new THREE.Geometry();
for (i = 0; i < data.length; i += step) {
lat = data[i];
lng = data[i + 1];
color = colorFnWrapper(data, i);
size = data[i + 2];
size = size * 200;
addPoint(lat, lng, size, color, subgeo);
}
this._baseGeometry = subgeo;
}
// material texture
var mapFront = new THREE.Texture( generateTexture('front') ),
mapBack = new THREE.Texture( generateTexture('back') ),
mapLeft = new THREE.Texture( generateTexture('left') ),
mapRight = new THREE.Texture( generateTexture('right') ),
mapTop = new THREE.Texture( generateTexture('top') );
mapFront.needsUpdate = true;
mapBack.needsUpdate = true;
mapLeft.needsUpdate = true;
mapRight.needsUpdate = true;
mapTop.needsUpdate = true;
function createPoints() {
this.points = new THREE.Mesh(
this._baseGeometry,
new THREE.MeshFaceMaterial([
new THREE.MeshBasicMaterial({
map: mapLeft,
transparent: true,
vertexColors: THREE.FaceColors
}),
new THREE.MeshBasicMaterial({
map: mapRight,
transparent: true,
vertexColors: THREE.FaceColors
}),
new THREE.MeshBasicMaterial({
map: mapFront,
transparent: true,
vertexColors: THREE.FaceColors
}),
new THREE.MeshBasicMaterial({
map: mapBack,
transparent: true,
vertexColors: THREE.FaceColors
}),
// Bottom
new THREE.MeshBasicMaterial({
vertexColors: THREE.FaceColors
}),
// Top
new THREE.MeshBasicMaterial({
transparent: true,
alphaTest: 1
})
])
);
scene.add(this.points);
}
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
point.updateMatrix();
for (var i = 0; i < point.geometry.faces.length; i++) {
point.geometry.faces[i].color = color;
}
if (point.matrixAutoUpdate) {
point.updateMatrix();
}
subgeo.merge(point.geometry, point.matrix);
}
function onMouseDown(event) {
event.preventDefault();
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;
mouse.y = event.clientY;
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 onDocumentKeyDown(event) {
switch (event.keyCode) {
case 38:
zoom(100);
event.preventDefault();
break;
case 40:
zoom(-100);
event.preventDefault();
break;
}
}
function onWindowResize(event) {
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.offsetWidth, container.offsetHeight);
}
function zoom(delta) {
distanceTarget -= delta;
distanceTarget = distanceTarget > 1100 ? 1100 : distanceTarget;
distanceTarget = distanceTarget < 350 ? 350 : distanceTarget;
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
zoom(curZoomSpeed);
rotation.x += 0.005;
rotation.y += (target.y - rotation.y) * 0.1;
distance += (distanceTarget - distance) * 0.8;
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);
}
init();
this.animate = animate;
this.__defineGetter__("time", function() {
return this._time || 0;
});
this.__defineSetter__("time", function(t) {
var validMorphs = [];
var morphDict = this.points.morphTargetDictionary;
for (var k in morphDict) {
if (k.indexOf("morphPadding") < 0) {
validMorphs.push(morphDict[k]);
}
}
validMorphs.sort();
var l = validMorphs.length - 1;
var scaledt = t * l + 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;
if (lastIndex >= 0) {
this.points.morphTargetInfluences[lastIndex] = 1 - leftover;
}
this.points.morphTargetInfluences[index] = leftover;
this._time = t;
});
this.addData = addData;
this.createPoints = createPoints;
this.renderer = renderer;
this.scene = scene;
return this;
};
var container = document.getElementById("container");
var globe = new DAT.Globe(container);
var xhr = new XMLHttpRequest();
xhr.open(
"GET",
"https://cdn.rawgit.com/dataarts/webgl-globe/2d24ba30/globe/population909500.json",
true
);
xhr.onreadystatechange = function(e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
window.data = data;
for (i = 0; i < data.length; i++) {
globe.addData(data[i][1], {
format: "magnitude",
name: data[i][0],
animated: false
});
}
globe.createPoints();
globe.animate();
}
}
};
xhr.send(null);
function generateTexture(alt) {
var size = 16;
// create canvas
canvas = document.createElement( 'canvas' );
canvas.width = size;
canvas.height = size;
// get context
var context = canvas.getContext( '2d' );
// draw gradient
context.rect( 0, 0, size, size );
var gradient;
if (alt == 'front' || alt == 'back') {
gradient = context.createLinearGradient( 0, 0, 0, size );
} else {
gradient = context.createLinearGradient( 0, 0, size, 0 );
}
if (alt == 'front') {
gradient.addColorStop(0, 'transparent');
gradient.addColorStop(1, 'white');
} else if (alt == 'back') {
gradient.addColorStop(1, 'transparent');
gradient.addColorStop(0, 'white');
} else if (alt == 'left') {
gradient.addColorStop(1, 'transparent');
gradient.addColorStop(0, 'white');
} else if (alt == 'right') {
gradient.addColorStop(0, 'transparent');
gradient.addColorStop(1, 'white');
} else {
gradient.addColorStop(0, 'transparent');
gradient.addColorStop(1, 'white');
}
context.fillStyle = gradient;
context.fill();
return canvas;
}
This Pen doesn't use any external CSS resources.