Skip to content

Instantly share code, notes, and snippets.

@scoaband
Created December 20, 2018 07:32
Show Gist options
  • Select an option

  • Save scoaband/36670440c65f16283eb6063427a4eaf7 to your computer and use it in GitHub Desktop.

Select an option

Save scoaband/36670440c65f16283eb6063427a4eaf7 to your computer and use it in GitHub Desktop.
WebGL data visualization
<div id="content">
<!-- canas -->
<div id="paint"></div>
<!-- text -->
<div id="wrapper">
<div class="flex">
<div id="controls">
<button class="one">Business class</button>
<button class="two">Ahead of wing</button>
<button class="three">Over the wing</button>
<button class="four">Rear cabin</button>
<label class="option">360 view<input type="checkbox" id="myCheck"></label>
</div>
<section id="text">
<h1>Survival rates in commercial jet crashes, by seat position.</h1>
<p>According to an analysis of all commercial jet crashes in the United States since 1971, In 11 of the 20 crashes that involved both fatalities and survivors, <span class="high">rear passengers had a 69% chance of survival</span> than those compared to a less favorable <span>49%</span> in business class. </p>
<small>source: <br>
<a href="https://www.statista.com/chart/9805/which-plane-seats-are-safest/" target="_blank">Statista</a><br>
<a href="https://www.popularmechanics.com/flight/a1918/4219452/" target="_blank">Popular Mechanics</a></small>
</section>
</div>
</div><!-- /text -->
</div>
<!-- numbers -->
<canvas id="number" width="100%" height="100%"></canvas>
<canvas id="number2" width="100%" height="100%"></canvas>
<canvas id="number3" width="100%" height="100%"></canvas>
<canvas id="number4" width="100%" height="100%"></canvas>
<script src="https://threejs.org/build/three.min.js"></script>
<script src='https://threejs.org/examples/js/controls/OrbitControls.js'></script>
<script src="https://threejs.org/examples/js/loaders/deprecated/LegacyJSONLoader.js"></script>
<script src="https://threejs.org/examples/js/controls/DeviceOrientationControls.js"></script>
<script src="https://threejs.org/examples/js/effects/StereoEffect.js"></script>
<script src="https://threejs.org/examples/js/libs/tween.min.js"></script>
//===================================================== canvas
var container = document.getElementById('paint');
var renderer = new THREE.WebGLRenderer({antialiase:true});
container.appendChild(renderer.domElement);
renderer.setSize(container.getBoundingClientRect().width, container.getBoundingClientRect().height);
renderer.setClearColor(0x151515, 1);
//===================================================== camera
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, container.getBoundingClientRect().width / container.getBoundingClientRect().height, 1, 10000);
//===================================================== resize
window.addEventListener("resize", function() {
let width = container.getBoundingClientRect().width;
let height = container.getBoundingClientRect().height;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
//===================================================== camera
var plane = new THREE.GridHelper(150, 50);
plane.material.color = new THREE.Color('gray');
scene.add(plane);
//===================================================== controls
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
controls.maxPolarAngle = Math.PI / 2.1;
//===================================================== add Light
var light = new THREE.DirectionalLight(0xefefff, 1.5);
light.position.set(1, 1, 1).normalize();
scene.add(light);
var light = new THREE.DirectionalLight(0xffefef, 1.5);
light.position.set(-1, -1, -1).normalize();
scene.add(light);
//===================================================== add blue light on the seats
var light = new THREE.DirectionalLight(new THREE.Color("blue"), 1.5);
light.position.set(0, 200, 100);
light.castShadow = true;
light.shadow.camera.top = 280;
light.shadow.camera.bottom = -200;
light.shadow.camera.left = -200;
light.shadow.camera.right = 200;
scene.add(light);
//==================================================== Add obj
loader = new THREE.LegacyJSONLoader();
loader.load('https://raw.githubusercontent.com/baronwatts/models/master/airplane2.js', function(geometry, materials) {
var matt = new THREE.MeshPhongMaterial({
vertexColors: THREE.FaceColors,
side: THREE.DoubleSide,
wireframe: true,
transparent: true,
opacity: .085
});
var obj = new THREE.Mesh(geometry, matt);
obj.scale.set(.5, .5, .5);
obj.rotateY(-Math.PI);
obj.receiveShadow = true;
obj.castShadow = true;
scene.add(obj);
});
//===================================================== seating rows
var row = new THREE.Group();
row.rotateY(Math.PI);
row.position.y = 5;
row.position.z = -3.75;
row.translateX(20);
scene.add(row);
loader = new THREE.LegacyJSONLoader();
loader.load('https://raw.githubusercontent.com/baronwatts/models/master/seats.js', function(geometry, materials) {
var matt = new THREE.MeshLambertMaterial({
vertexColors: THREE.FaceColors,
color: new THREE.Color('#888'),
side: THREE.DoubleSide
});
for (var i = 0; i < 30; i++) {
for (var j = 0; j < 2; j++) {
var obj2 = new THREE.Mesh(geometry, matt);
obj2.scale.set(3, 3, 3);
obj2.rotateY(Math.PI / 2);
obj2.position.z = -3 * j;
obj2.position.x = -1.25 * i;
obj2.receiveShadow = true;
obj2.castShadow = true;
row.add(obj2);
}
}
});
//==================================================== number
var canvas = document.getElementById("number");
var ctx = canvas.getContext("2d");
var x = 32;
var y = 32;
var radius = 30;
var startAngle = 0;
var endAngle = Math.PI * 2;
ctx.fillStyle = "rgba(0, 0, 0, 0)";
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.fill();
ctx.fillStyle = "#ccc";
ctx.font = "bold 32px Roboto Condensed";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("56%", x, y);
var numberTexture = new THREE.CanvasTexture(document.querySelector("#number"));
var spriteMaterial = new THREE.SpriteMaterial({
map: numberTexture,
alphaTest: 0.5,
transparent: true,
depthTest: false,
depthWrite: false
});
sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(0, 10, 0);
sprite.scale.set(2, 2, 2);
scene.add(sprite);
//==================================================== number
var canvas2 = document.getElementById("number2");
var ctx = canvas2.getContext("2d");
ctx.fillStyle = "#ccc";
ctx.font = "bold 32px Roboto Condensed";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("56%", x, y);
var numberTexture = new THREE.CanvasTexture(document.querySelector("#number2"));
var spriteMaterial = new THREE.SpriteMaterial({
map: numberTexture,
alphaTest: 0.5,
transparent: true,
depthTest: false,
depthWrite: false
});
sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(-10, 10, 0);
sprite.scale.set(2, 2, 2);
scene.add(sprite);
//==================================================== number
var canvas2 = document.getElementById("number4");
var ctx = canvas2.getContext("2d");
ctx.fillStyle = "gray";
ctx.font = "bold 32px Roboto Condensed";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("49%", x, y);
var numberTexture = new THREE.CanvasTexture(document.querySelector("#number4"));
var spriteMaterial = new THREE.SpriteMaterial({
map: numberTexture,
alphaTest: 0.5,
transparent: true,
depthTest: false,
depthWrite: false
});
sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(-18, 10, 0);
sprite.scale.set(2, 2, 2);
scene.add(sprite);
//==================================================== number
var canvas2 = document.getElementById("number3");
var ctx = canvas2.getContext("2d");
ctx.fillStyle = "#3fe687";
ctx.font = "bold 32px Roboto Condensed";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("69%", x, y);
var numberTexture = new THREE.CanvasTexture(document.querySelector("#number3"));
var spriteMaterial = new THREE.SpriteMaterial({
map: numberTexture,
alphaTest: 0.5,
transparent: true,
depthTest: false,
depthWrite: false
});
sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(15, 10, 0);
sprite.scale.set(2, 2, 2);
scene.add(sprite);
//===================================================== Circle path for the camera
var segmentCount = 10;
var radius = 50;
var xyzArray = new Array(segmentCount)
.fill(null)
.map(
(d, i) =>
new THREE.Vector3(
/*x*/
Math.cos(i / segmentCount * Math.PI * 2) * radius,
/*y*/
5,
/*z*/
Math.sin(i / segmentCount * Math.PI * 2) * radius
)
);
var curve = new THREE.CatmullRomCurve3(xyzArray);
curve.closed = true;
var g2 = new THREE.Geometry();
g2.vertices = curve.getPoints(50);
var m2 = new THREE.LineBasicMaterial({
color: new THREE.Color("skyblue")
});
var curveObject = new THREE.Line(g2, m2);
//scene.add(curveObject);
//===================================================== buttons
let button1 = document.querySelector('.one');
button1.addEventListener('click', function() {
zoom(-30, 10, 5);
});
let button2 = document.querySelector('.two');
button2.addEventListener('click', function() {
zoom(-20, 10, 20)
});
let button3 = document.querySelector('.three');
button3.addEventListener('click', function() {
zoom(5, 10, 30);
});
let button4 = document.querySelector('.four');
button4.addEventListener('click', function() {
zoom(30, 10, 5);
});
function zoom(x, y, z) {
var from = {
x: camera.position.x,
y: camera.position.y,
z: camera.position.z
};
var to = {
x: x,
y: y,
z: z
};
var tween = new TWEEN.Tween(from)
.to(to, 900)
.easing(TWEEN.Easing.Quadratic.Out)
.onUpdate(function() {
camera.position.set(this.x, this.y, this.z);
camera.lookAt(new THREE.Vector3(0, 0, 0));
})
.onComplete(function() {
camera.lookAt(new THREE.Vector3(0, 0, 0));
})
.start();
};
//===================================================== animate
spline = curve;
camPosIndex = 0;
clock = new THREE.Clock();
function animate() {
TWEEN.update();
camPosIndex++;
if (camPosIndex > 1000) {
camPosIndex = 0;
}
let camPos = spline.getPoint(camPosIndex / 1000); //move camera x,y,z
let camRot = spline.getTangent(camPosIndex / 1000); //rotates camera x,y,z
//move camera on path
if (document.getElementById("myCheck").checked == true) {
camera.position.set(camPos.x, camPos.y, camPos.z + 5);
camera.lookAt(new THREE.Vector3(0, 0, 0));
} else {
camera.position.set(camera.position.x, camera.position.y, camera.position.z);
camera.lookAt(new THREE.Vector3(0, 0, 0));
}
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
zoom(1, 10, 40);
@import url("https://fonts.googleapis.com/css?family=Roboto+Condensed|Playfair+Display:700i|Didact+Gothic");
html,
body {
background: black;
font-family: monospace;
font-family: "Roboto", sans-serif;
margin: 0;
padding: 0;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
h1 {
font-family: "Roboto Condensed", "Helvetica Neue", Helvetica, Arial,
sans-serif;
font-size: 40px;
line-height: 1;
}
h3 {
font-weight: lighter;
}
section {
color: white;
padding: 50px 25px;
}
p {
color: rgba(255, 255, 255, 0.5);
}
a {
color: white;
}
span {
font-weight: bold;
font-size: 20px;
}
span.high {
color: #3fe687;
}
canvas[id*="number"] {
position: absolute;
z-index: -1;
}
button {
flex: 1;
}
button,
label {
background: none;
border: none;
text-align: center;
padding: 5px 10px;
margin: 5px;
border: 1px solid white;
color: white;
font-size: 13px;
}
button:hover,
label:hover{
cursor:pointer;
}
#controls {
position: fixed;
width: 100%;
top: 300px;
left: 0;
background: black;
display: flex;
-webkit-display: flex;
}
#content {
color: white;
background: #151515;
}
#paint {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 300px;
margin: auto;
z-index: 100;
}
#wrapper {
position: relative;
top: 300px;
background: black;
}
@media (min-width: 1200px) {
section {
padding: 25px;
pointer-events: initial;
max-width: 275px;
width: 100%;
}
#paint {
width: 100%;
height: 100%;
margin: 0;
top: 0;
left: 0;
}
#wrapper {
width: 100%;
height: 100%;
z-index: 100;
top: 0;
background: none;
position: relative;
}
.flex {
display: flex;
-webkit-display: flex;
justify-content: space-between;
-webkit-justify-content: space-between;
align-items: flex-end;
-webkit-align-items: flex-end;
flex-direction: row-reverse;
-webkit-flex-direction: row-reverse;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
pointer-events: none;
/*background: red;*/
}
#controls {
position: relative;
top: 0;
left: 0;
background: none;
pointer-events: initial;
width: auto;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment