interfaces updated
Before Width: | Height: | Size: 559 KiB |
Before Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 367 KiB |
Before Width: | Height: | Size: 24 KiB |
@ -0,0 +1,134 @@
|
|||||||
|
import { Ray } from '../math/Ray.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mrdoob / http://mrdoob.com/
|
||||||
|
* @author bhouston / http://clara.io/
|
||||||
|
* @author stephomi / http://stephaneginier.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Raycaster( origin, direction, near, far ) {
|
||||||
|
|
||||||
|
this.ray = new Ray( origin, direction );
|
||||||
|
// direction is assumed to be normalized (for accurate distance calculations)
|
||||||
|
|
||||||
|
this.near = near || 0;
|
||||||
|
this.far = far || Infinity;
|
||||||
|
|
||||||
|
this.params = {
|
||||||
|
Mesh: {},
|
||||||
|
Line: {},
|
||||||
|
LOD: {},
|
||||||
|
Points: { threshold: 1 },
|
||||||
|
Sprite: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperties( this.params, {
|
||||||
|
PointCloud: {
|
||||||
|
get: function () {
|
||||||
|
|
||||||
|
console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
|
||||||
|
return this.Points;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function ascSort( a, b ) {
|
||||||
|
|
||||||
|
return a.distance - b.distance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function intersectObject( object, raycaster, intersects, recursive ) {
|
||||||
|
|
||||||
|
if ( object.visible === false ) return;
|
||||||
|
|
||||||
|
object.raycast( raycaster, intersects );
|
||||||
|
|
||||||
|
if ( recursive === true ) {
|
||||||
|
|
||||||
|
var children = object.children;
|
||||||
|
|
||||||
|
for ( var i = 0, l = children.length; i < l; i ++ ) {
|
||||||
|
|
||||||
|
intersectObject( children[ i ], raycaster, intersects, true );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign( Raycaster.prototype, {
|
||||||
|
|
||||||
|
linePrecision: 1,
|
||||||
|
|
||||||
|
set: function ( origin, direction ) {
|
||||||
|
|
||||||
|
// direction is assumed to be normalized (for accurate distance calculations)
|
||||||
|
|
||||||
|
this.ray.set( origin, direction );
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
setFromCamera: function ( coords, camera ) {
|
||||||
|
|
||||||
|
if ( ( camera && camera.isPerspectiveCamera ) ) {
|
||||||
|
|
||||||
|
this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
|
||||||
|
this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
|
||||||
|
|
||||||
|
} else if ( ( camera && camera.isOrthographicCamera ) ) {
|
||||||
|
|
||||||
|
this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
|
||||||
|
this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
console.error( 'THREE.Raycaster: Unsupported camera type.' );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
intersectObject: function ( object, recursive, optionalTarget ) {
|
||||||
|
|
||||||
|
var intersects = optionalTarget || [];
|
||||||
|
|
||||||
|
intersectObject( object, this, intersects, recursive );
|
||||||
|
|
||||||
|
intersects.sort( ascSort );
|
||||||
|
|
||||||
|
return intersects;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
intersectObjects: function ( objects, recursive, optionalTarget ) {
|
||||||
|
|
||||||
|
var intersects = optionalTarget || [];
|
||||||
|
|
||||||
|
if ( Array.isArray( objects ) === false ) {
|
||||||
|
|
||||||
|
console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
|
||||||
|
return intersects;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( var i = 0, l = objects.length; i < l; i ++ ) {
|
||||||
|
|
||||||
|
intersectObject( objects[ i ], this, intersects, recursive );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
intersects.sort( ascSort );
|
||||||
|
|
||||||
|
return intersects;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
export { Raycaster };
|
@ -0,0 +1,81 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Collection</title>
|
||||||
|
<script>
|
||||||
|
var booktitles = [
|
||||||
|
{
|
||||||
|
title: "Mac OS X Leopard Edition",
|
||||||
|
id: "1",
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "The Qmail Handbook",
|
||||||
|
id: "2",
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Hardening Network Infrastructure: Bulletproof Your Systems Before You Are Hacked!",
|
||||||
|
id: "3",
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Cocoa Programming for Mac OS X Second Edition",
|
||||||
|
id: "4",
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "LDAP System Administration",
|
||||||
|
id: "5",
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ul>
|
||||||
|
<script>
|
||||||
|
for(i =0; i < booktitles.length;i++){
|
||||||
|
document.write('<h4>'+booktitles[i].title+'</h4>');
|
||||||
|
|
||||||
|
var myCoords = xyzGen(booktitles[i].title)
|
||||||
|
console.log("Coordinates of " + booktitles[i].title)
|
||||||
|
console.log("x : " + myCoords.x)
|
||||||
|
console.log("y : " + myCoords.y)
|
||||||
|
console.log("z : " + myCoords.z)
|
||||||
|
|
||||||
|
}
|
||||||
|
// console.log(booktitles);
|
||||||
|
|
||||||
|
var x,y,z
|
||||||
|
|
||||||
|
function xyzGen(string) {
|
||||||
|
let coords = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0,
|
||||||
|
}
|
||||||
|
string = string.split(' ')
|
||||||
|
|
||||||
|
for (var i = 0; i < 3; i++) {
|
||||||
|
for (c in string[i]) {
|
||||||
|
if (i == 0) {
|
||||||
|
coords.x += string[i].charCodeAt(c)
|
||||||
|
} else if (i == 1) {
|
||||||
|
coords.y += string[i].charCodeAt(c)
|
||||||
|
} else if (i == 2) {
|
||||||
|
coords.z += string[i].charCodeAt(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return coords
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,382 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>XPPL VOLUMETRIC CATALOGUE </title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Karla" rel="stylesheet">
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
cccccc;
|
||||||
|
font-family: 'Karla', sans-serif;
|
||||||
|
font-size:15px;
|
||||||
|
|
||||||
|
text-align:left;
|
||||||
|
background-color: #140b33;
|
||||||
|
margin: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#info {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px; width: 10%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #444b7c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-button {
|
||||||
|
padding: 7px 19px;
|
||||||
|
|
||||||
|
background-color: #aca4c1;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-title {
|
||||||
|
margin: 0px;
|
||||||
|
font-size: 16px;
|
||||||
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.21);
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-overlay {
|
||||||
|
background-color: rgba(20, 13, 50, 0.6);
|
||||||
|
}
|
||||||
|
.swal-modal {
|
||||||
|
background-color: rgba(172, 164, 193, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="info"><a target="_blank" rel="noopener">XPPL VOLUMETRIC CATALOGUE <br> <br> Feel free to move around and explore the content of the library by clicking on the volumetric shapes</div>
|
||||||
|
<div id="container"></div>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
|
||||||
|
|
||||||
|
<script src="three.min.js"></script>
|
||||||
|
<script src="OrbitControls.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
var category2color = new Object();
|
||||||
|
category2color["Technical"] = "#003d5d";
|
||||||
|
category2color["Science/History"] = "#f23d5d";
|
||||||
|
category2color["Media studies"] = "#8c3d5d";
|
||||||
|
category2color["Philosophy"] = "#723d5d";
|
||||||
|
category2color["Computer culture"] = "#423d5d";
|
||||||
|
category2color["Design / writing / publishing"] = "#ff0000";
|
||||||
|
category2color["Desk"] = "#09edff";
|
||||||
|
category2color["Art"] = "#ffedff";
|
||||||
|
category2color["Digital (Steve Trim 2 reading)"] = "#ffe1cc";
|
||||||
|
category2color["Media Studies (Femke Trim 3)"] = "#00e1cc";
|
||||||
|
category2color["Literature, Culture, Theory"] = "#00a1d4";
|
||||||
|
|
||||||
|
category2color["default"] = "#cdc1ec";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.clear();
|
||||||
|
|
||||||
|
const MAX_DISTANCE = 13000;
|
||||||
|
//
|
||||||
|
const MIN_DISTANCE = 200;
|
||||||
|
|
||||||
|
const MAX_SPHERE_RADIUS = 700;
|
||||||
|
|
||||||
|
var bookTitles;
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open('GET', 'export.json', true);
|
||||||
|
|
||||||
|
request.onload = function() {
|
||||||
|
if (request.status >= 200 && request.status < 400) {
|
||||||
|
var data = JSON.parse(request.responseText);
|
||||||
|
//bookTitles = data;
|
||||||
|
bookTitles = data.books[0];
|
||||||
|
|
||||||
|
bookTitles.forEach(function(book) {
|
||||||
|
book.type = "sphere";
|
||||||
|
console.log('BOOK:', book);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
console.log("got books", bookTitles)
|
||||||
|
// loaded data, start
|
||||||
|
init();
|
||||||
|
animate();
|
||||||
|
} else {
|
||||||
|
// We reached our target server, but it returned an error
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = function() {
|
||||||
|
// There was a connection error of some sort
|
||||||
|
};
|
||||||
|
|
||||||
|
request.send();
|
||||||
|
|
||||||
|
|
||||||
|
// --- threeJS --- //
|
||||||
|
var renderer, scene, camera, distance, raycaster, projector;
|
||||||
|
|
||||||
|
var container = document.getElementById('container');
|
||||||
|
var raycaster = new THREE.Raycaster(),INTERSECTED;
|
||||||
|
var mouse = new THREE.Vector2();
|
||||||
|
var distance = 400;
|
||||||
|
|
||||||
|
// -- basic initialization -- //
|
||||||
|
function init() {
|
||||||
|
renderer = new THREE.WebGLRenderer({
|
||||||
|
antialias: true
|
||||||
|
});
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
renderer.setClearColor(0x140b33, 1);
|
||||||
|
container.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.2, 25000);
|
||||||
|
controls = new THREE.OrbitControls(camera);
|
||||||
|
/*
|
||||||
|
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||||
|
controls.maxDistance = MAX_DISTANCE * 3;
|
||||||
|
controls.target = new THREE.Vector3(0, 0, 0);
|
||||||
|
controls.rotateSpeed = .2;
|
||||||
|
controls.enableDamping = true;
|
||||||
|
console.log(controls.enableDamping);
|
||||||
|
controls.dampingFactor = .15;
|
||||||
|
controls.panSpeed = .15;
|
||||||
|
controls.screenSpacePanning = true;*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
camera.position.set(100, 100, 2000);
|
||||||
|
controls.update();
|
||||||
|
scene.add(camera);
|
||||||
|
|
||||||
|
light = new THREE.PointLight(0xffffff, 1, 4000);
|
||||||
|
light.position.set(50, 0, 0);
|
||||||
|
light_two = new THREE.PointLight(0xffffff, 1, 4000);
|
||||||
|
light_two.position.set(-100, 800, 800);
|
||||||
|
lightAmbient = new THREE.AmbientLight(0x404040);
|
||||||
|
scene.add(light, light_two, lightAmbient);
|
||||||
|
|
||||||
|
// createSpheres();
|
||||||
|
|
||||||
|
createDiamond();
|
||||||
|
|
||||||
|
createSpace();
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', onMouseMove, false);
|
||||||
|
document.addEventListener('mousedown', onDocumentMouseDown, false);
|
||||||
|
window.addEventListener('resize', onWindowResize, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- diamonds -- //
|
||||||
|
|
||||||
|
|
||||||
|
function catInobject(obj, category){ //checks if category is in object, if so return corresponding color
|
||||||
|
if (obj.hasOwnProperty(category)) {
|
||||||
|
var color = obj[category];
|
||||||
|
} else { var color = obj["default"];
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDiamond() {
|
||||||
|
|
||||||
|
diamondsGroup = new THREE.Object3D();
|
||||||
|
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
bookTitles.forEach(function (book) {
|
||||||
|
var chosencolor = catInobject(category2color, book.category);
|
||||||
|
var sphere = new THREE.SphereGeometry(1, Math.random() * 100, Math.random() * 100);
|
||||||
|
var material = new THREE.MeshPhongMaterial({
|
||||||
|
color: chosencolor,//Math.random() * 0xff00000 - 0xff00000,
|
||||||
|
shading: THREE.FlatShading
|
||||||
|
});
|
||||||
|
var sphere = new THREE.Mesh(sphere, material);
|
||||||
|
sphere.position.x = Math.random() * -distance * 6;
|
||||||
|
sphere.position.y = Math.random() * -distance * 2;
|
||||||
|
sphere.position.z = Math.random() * distance * 3;
|
||||||
|
sphere.rotation.y = Math.random() * 2 * Math.PI;
|
||||||
|
sphere.scale.x = sphere.scale.y = sphere.scale.z = Math.random() * 50 + 10;
|
||||||
|
|
||||||
|
sphere.userData = book;
|
||||||
|
diamondsGroup.add(sphere);
|
||||||
|
|
||||||
|
})
|
||||||
|
diamondsGroup.position.x = 1400;
|
||||||
|
scene.add(diamondsGroup);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- dots on the back -- //
|
||||||
|
function createSpace() {
|
||||||
|
|
||||||
|
dots = new THREE.Object3D();
|
||||||
|
|
||||||
|
for (var i = 0; i < 1000; i++) {
|
||||||
|
var circleGeometry = new THREE.SphereGeometry(2, Math.random() * 5, Math.random() * 5);
|
||||||
|
var color;
|
||||||
|
if (Math.round(Math.random()) === 0)
|
||||||
|
color = new THREE.Color('#003d5d');
|
||||||
|
else
|
||||||
|
//color = new THREE.Color('#f23d5d');
|
||||||
|
color = new THREE.Color('#4f2939');
|
||||||
|
|
||||||
|
var material = new THREE.MeshBasicMaterial({
|
||||||
|
color: color
|
||||||
|
});
|
||||||
|
material.flatShading = true;
|
||||||
|
|
||||||
|
//var material = new THREE.MeshBasicMaterial({
|
||||||
|
//color : new THREE.Color(Math.floor(Math.random() * 1) === 1),
|
||||||
|
//color : new THREE.Color(Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 0),
|
||||||
|
//shading: THREE.FlatShading,
|
||||||
|
//})
|
||||||
|
var circle = new THREE.Mesh(circleGeometry, material);
|
||||||
|
material.side = THREE.DoubleSide;
|
||||||
|
|
||||||
|
circle.position.x = Math.random() * -distance * 50;
|
||||||
|
circle.position.y = Math.random() * -distance * 8;
|
||||||
|
circle.position.z = Math.random() * distance * 5;
|
||||||
|
circle.rotation.y = Math.random() * 2 * Math.PI;
|
||||||
|
circle.scale.x = circle.scale.y = circle.scale.z = Math.random() * 6 + 5;
|
||||||
|
dots.add(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
dots.position.x = 14000;
|
||||||
|
dots.position.y = 1500;
|
||||||
|
dots.position.z = -4000;
|
||||||
|
dots.rotation.y = Math.PI * 600;
|
||||||
|
dots.rotation.z = Math.PI * 500;
|
||||||
|
|
||||||
|
scene.add(dots);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -- events -- //
|
||||||
|
function onMouseMove(event) {
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
mouseX = event.clientX - window.innerWidth / 2;
|
||||||
|
mouseY = event.clientY - window.innerHeight / 2;
|
||||||
|
camera.position.x += (mouseX - camera.position.x) * 0.01;
|
||||||
|
controls.update();
|
||||||
|
camera.position.y += (mouseY - camera.position.y) * 0.01;
|
||||||
|
controls.update();
|
||||||
|
camera.lookAt(scene.position);
|
||||||
|
controls.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
function onDocumentMouseDown(event) {
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
var intersects = raycaster.intersectObjects(diamondsGroup.children);
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
var book = intersects[0].object.userData;
|
||||||
|
console.log("click", book);
|
||||||
|
//alert("book" + book.title);
|
||||||
|
|
||||||
|
//swal(book.title + book.authors);
|
||||||
|
|
||||||
|
swal(book.title + " \n " + " " + book.authors[0].author_name + " \n" + book.category, {
|
||||||
|
button: {
|
||||||
|
text: "Open",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}). then (function() {
|
||||||
|
window.location = "/books/"+book.id
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function onDocumentMouseWheel( event ) {
|
||||||
|
|
||||||
|
fov -= event.wheelDeltaY * 0.05;
|
||||||
|
camera.projectionMatrix = THREE.Matrix4.makePerspective( fov, window.innerWidth / window.innerHeight, 1, 1100 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onWindowResize() {
|
||||||
|
camera.aspect = window.innerWidth / window.innerHeight;
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
controls.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- //
|
||||||
|
function animate() {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
controls.update();
|
||||||
|
render();
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- render all -- //
|
||||||
|
function render() {
|
||||||
|
|
||||||
|
var timer = 0.00001 * Date.now();
|
||||||
|
|
||||||
|
for (var i = 0, l = diamondsGroup.children.length; i < l; i++) {
|
||||||
|
var object = diamondsGroup.children[i];
|
||||||
|
object.position.y = 500 * Math.cos(timer + i);
|
||||||
|
object.rotation.y += Math.PI / 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the picking ray with the camera and mouse position
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
// calculate objects intersecting the picking ray
|
||||||
|
var intersects = raycaster.intersectObjects(diamondsGroup.children);
|
||||||
|
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
if (INTERSECTED != intersects[0].object) {
|
||||||
|
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||||
|
INTERSECTED = intersects[0].object;
|
||||||
|
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
|
||||||
|
INTERSECTED.material.emissive.setHex(Math.random() * 0xff00000 - 0xff00000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||||
|
INTERSECTED = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- run functions -- //
|
||||||
|
//init();
|
||||||
|
//animate();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,458 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>XPPL VOLUMETRIC CATALOGUE </title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Karla" rel="stylesheet">
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
cccccc;
|
||||||
|
font-family: 'Karla', sans-serif;
|
||||||
|
font-size:15px;
|
||||||
|
|
||||||
|
text-align:left;
|
||||||
|
background-color: #140b33;
|
||||||
|
margin: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#info {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px; width: 10%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #444b7c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-button {
|
||||||
|
padding: 7px 19px;
|
||||||
|
|
||||||
|
background-color: #aca4c1;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-title {
|
||||||
|
margin: 0px;
|
||||||
|
font-size: 16px;
|
||||||
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.21);
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-overlay {
|
||||||
|
background-color: rgba(20, 13, 50, 0.6);
|
||||||
|
}
|
||||||
|
.swal-modal {
|
||||||
|
background-color: rgba(172, 164, 193, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="container"></div>
|
||||||
|
<canvas id="viewer"></canvas>
|
||||||
|
<script src="https://rawgit.com/mrdoob/three.js/dev/build/three.min.js"></script>
|
||||||
|
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js"></script>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
var category2color = new Object();
|
||||||
|
category2color["Technical"] = "#003d5d";
|
||||||
|
category2color["Science/History"] = "#f23d5d";
|
||||||
|
category2color["Media studies"] = "#8c3d5d";
|
||||||
|
category2color["Philosophy"] = "#723d5d";
|
||||||
|
category2color["Computer culture"] = "#423d5d";
|
||||||
|
category2color["Design / writing / publishing"] = "#ff0000";
|
||||||
|
category2color["Desk"] = "#09edff";
|
||||||
|
category2color["Art"] = "#ffedff";
|
||||||
|
category2color["Digital (Steve Trim 2 reading)"] = "#ffe1cc";
|
||||||
|
category2color["Media Studies (Femke Trim 3)"] = "#00e1cc";
|
||||||
|
category2color["Literature, Culture, Theory"] = "#00a1d4";
|
||||||
|
|
||||||
|
category2color["default"] = "#cdc1ec";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.clear();
|
||||||
|
|
||||||
|
const MAX_DISTANCE = 1000;
|
||||||
|
//
|
||||||
|
const MIN_DISTANCE = 200;
|
||||||
|
|
||||||
|
const MAX_SPHERE_RADIUS = 700;
|
||||||
|
|
||||||
|
var bookTitles;
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open('GET', 'export.json', true);
|
||||||
|
|
||||||
|
request.onload = function() {
|
||||||
|
if (request.status >= 200 && request.status < 400) {
|
||||||
|
var data = JSON.parse(request.responseText);
|
||||||
|
//bookTitles = data;
|
||||||
|
bookTitles = data.books[0];
|
||||||
|
|
||||||
|
bookTitles.forEach(function(book) {
|
||||||
|
book.type = "sphere";
|
||||||
|
console.log('BOOK:', book);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
console.log("got books", bookTitles)
|
||||||
|
// loaded data, start
|
||||||
|
init();
|
||||||
|
animate();
|
||||||
|
} else {
|
||||||
|
// We reached our target server, but it returned an error
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = function() {
|
||||||
|
// There was a connection error of some sort
|
||||||
|
};
|
||||||
|
|
||||||
|
request.send();
|
||||||
|
|
||||||
|
|
||||||
|
// --- threeJS --- //
|
||||||
|
var renderer, scene, camera, distance, raycaster, projector;
|
||||||
|
|
||||||
|
var container = document.getElementById('container');
|
||||||
|
var raycaster = new THREE.Raycaster(),INTERSECTED;
|
||||||
|
var mouse = new THREE.Vector2();
|
||||||
|
var distance = 600;
|
||||||
|
|
||||||
|
// -- basic initialization -- //
|
||||||
|
function init() {
|
||||||
|
renderer = new THREE.WebGLRenderer({
|
||||||
|
antialias: true
|
||||||
|
});
|
||||||
|
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
renderer.setClearColor(0x140b33, 1);
|
||||||
|
container.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 300000);
|
||||||
|
// controls = new THREE.OrbitControls(camera);
|
||||||
|
//camera.position.set(1, 1, -5);
|
||||||
|
camera.position.set(MAX_DISTANCE/2, MAX_DISTANCE/20, MAX_DISTANCE/20);
|
||||||
|
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||||
|
// controls.maxDistance = MAX_DISTANCE * 3;
|
||||||
|
controls.target = new THREE.Vector3(0, 0, 0);
|
||||||
|
controls.rotateSpeed = .2;
|
||||||
|
controls.enableDamping = true;
|
||||||
|
console.log(controls.enableDamping);
|
||||||
|
controls.dampingFactor = .15;
|
||||||
|
controls.panSpeed = .15;
|
||||||
|
controls.screenSpacePanning = true;
|
||||||
|
// to disable zoom
|
||||||
|
controls.enableZoom = true;
|
||||||
|
// to disable rotation
|
||||||
|
controls.enableRotate = true;
|
||||||
|
// to disable pan
|
||||||
|
controls.enablePan = true;
|
||||||
|
scene.add(camera);
|
||||||
|
|
||||||
|
//camera.position.set(-150, 10, 1);
|
||||||
|
//controls.update();
|
||||||
|
// scene.add(camera);
|
||||||
|
/*
|
||||||
|
light = new THREE.PointLight(0xffffff, 1, 4000);
|
||||||
|
light.position.set(50, 0, 0);
|
||||||
|
light_two = new THREE.PointLight(0xffffff, 1, 4000);
|
||||||
|
light_two.position.set(-100, 800, 800);
|
||||||
|
lightAmbient = new THREE.AmbientLight(0x404040);
|
||||||
|
scene.add(light, light_two, lightAmbient);*/
|
||||||
|
|
||||||
|
// createSpheres();
|
||||||
|
|
||||||
|
scene.add(new THREE.DirectionalLight(0xffffff));
|
||||||
|
scene.add(new THREE.AmbientLight(0x222222));
|
||||||
|
|
||||||
|
renderer.setPixelRatio(window.devicePixelRatio);
|
||||||
|
|
||||||
|
let viewer = document.querySelector('#viewer');
|
||||||
|
viewer.parentNode.replaceChild(renderer.domElement, viewer);
|
||||||
|
|
||||||
|
createDiamond();
|
||||||
|
|
||||||
|
createSpace();
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', onMouseMove, false);
|
||||||
|
document.addEventListener('mousedown', onDocumentMouseDown, false);
|
||||||
|
window.addEventListener('resize', onWindowResize, false);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- diamonds -- //
|
||||||
|
|
||||||
|
|
||||||
|
function catInobject(obj, category){ //checks if category is in object, if so return corresponding color
|
||||||
|
if (obj.hasOwnProperty(category)) {
|
||||||
|
var color = obj[category];
|
||||||
|
} else { var color = obj["default"];
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDiamond() {
|
||||||
|
|
||||||
|
diamondsGroup = new THREE.Object3D();
|
||||||
|
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
bookTitles.forEach(function (book) {
|
||||||
|
var chosencolor = catInobject(category2color, book.category);
|
||||||
|
var sphere = new THREE.SphereGeometry(50, Math.random() * 1, Math.random() * 1);
|
||||||
|
var material = new THREE.MeshPhongMaterial({
|
||||||
|
color: chosencolor,//Math.random() * 0xff00000 - 0xff00000,
|
||||||
|
shading: THREE.FlatShading
|
||||||
|
});
|
||||||
|
var sphere = new THREE.Mesh(sphere, material);
|
||||||
|
sphere.position.x = get_x(book.title) * Math.random() * 100 - 1000;
|
||||||
|
sphere.position.z = get_z(book.category) * Math.random() * 100 - 1000;
|
||||||
|
sphere.rotation.y =get_y(book.fileformat) * Math.random() * 100 - 1000;
|
||||||
|
//sphere.scale.x = sphere.scale.y = sphere.scale.z = Math.random() * 50 + 10;
|
||||||
|
sphere.scale.x = sphere.scale.y = sphere.scale.z = get_size(book.title);
|
||||||
|
|
||||||
|
sphere.userData = book;
|
||||||
|
diamondsGroup.add(sphere);
|
||||||
|
|
||||||
|
})
|
||||||
|
diamondsGroup.position.x = 500;
|
||||||
|
scene.add(diamondsGroup);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function get_size(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_x(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
function get_y(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
function get_z(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- dots on the back -- //
|
||||||
|
function createSpace() {
|
||||||
|
|
||||||
|
let dots = new THREE.Object3D();
|
||||||
|
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
let circleGeometry = new THREE.SphereGeometry(2, Math.random() * 5, Math.random() * 5);
|
||||||
|
let color;
|
||||||
|
if (Math.round(Math.random()) === 0)
|
||||||
|
color = new THREE.Color('#003d5d');
|
||||||
|
else
|
||||||
|
//color = new THREE.Color('#f23d5d');
|
||||||
|
color = new THREE.Color('#4f2939');
|
||||||
|
|
||||||
|
let material = new THREE.MeshPhongMaterial({
|
||||||
|
color: color
|
||||||
|
//side: THREE.DoubleSide
|
||||||
|
});
|
||||||
|
|
||||||
|
material.flatShading = true;
|
||||||
|
|
||||||
|
//var material = new THREE.MeshBasicMaterial({
|
||||||
|
//color : new THREE.Color(Math.floor(Math.random() * 1) === 1),
|
||||||
|
//color : new THREE.Color(Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 0),
|
||||||
|
//shading: THREE.FlatShading,
|
||||||
|
//})
|
||||||
|
var circle = new THREE.Mesh(circleGeometry, material);
|
||||||
|
material.side = THREE.DoubleSide;
|
||||||
|
|
||||||
|
circle.position.x = Math.random() * -distance * 50;
|
||||||
|
circle.position.y = Math.random() * -distance * 8;
|
||||||
|
circle.position.z = Math.random() * distance * 5;
|
||||||
|
circle.rotation.y = Math.random() * 2 * Math.PI;
|
||||||
|
circle.scale.x = circle.scale.y = circle.scale.z = Math.random() * 6 + 5;
|
||||||
|
dots.add(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
dots.position.x = 14000;
|
||||||
|
dots.position.y = 1500;
|
||||||
|
dots.position.z = -4000;
|
||||||
|
dots.rotation.y = Math.PI * 600;
|
||||||
|
dots.rotation.z = Math.PI * 500;
|
||||||
|
|
||||||
|
scene.add(dots);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* let circle = new THREE.Mesh(circleGeometry, material);
|
||||||
|
|
||||||
|
let direction = getRandomVector().normalize();
|
||||||
|
let minDistance = MAX_DISTANCE * 8;
|
||||||
|
let maxDistance = minDistance + 0.5;
|
||||||
|
direction.multiplyScalar(Math.random() * (maxDistance - minDistance) + minDistance);
|
||||||
|
|
||||||
|
circle.position.add(direction);
|
||||||
|
|
||||||
|
dots.add(circle);
|
||||||
|
}
|
||||||
|
scene.add(dots);
|
||||||
|
} */
|
||||||
|
|
||||||
|
function getRandomVector(max_distance) {
|
||||||
|
if (max_distance === undefined)
|
||||||
|
max_distance = 1;
|
||||||
|
return new THREE.Vector3(getRandom(max_distance), getRandom(max_distance), getRandom(max_distance));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandom(max_distance) {
|
||||||
|
let random = Math.random() * max_distance;
|
||||||
|
random *= Math.floor(Math.random() * 2) === 1 ? 1 : -1;
|
||||||
|
return random;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -- events -- //
|
||||||
|
function onMouseMove(event) {
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
mouseX = event.clientX - window.innerWidth / 2 ;
|
||||||
|
mouseY = event.clientY - window.innerHeight / 2 ;
|
||||||
|
camera.position.x += (mouseX - camera.position.x) * 0.01;
|
||||||
|
camera.position.y += (mouseY - camera.position.y) * 0.01;
|
||||||
|
camera.lookAt(scene.position);
|
||||||
|
};
|
||||||
|
|
||||||
|
function onDocumentMouseDown(event) {
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
var intersects = raycaster.intersectObjects(diamondsGroup.children);
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
var book = intersects[0].object.userData;
|
||||||
|
console.log("click", book);
|
||||||
|
//alert("book" + book.title);
|
||||||
|
|
||||||
|
//swal(book.title + book.authors);
|
||||||
|
|
||||||
|
swal(book.title + " \n " + " " + book.authors[0].author_name + " \n" + book.category, {
|
||||||
|
button: {
|
||||||
|
text: "Open",
|
||||||
|
}
|
||||||
|
}).then (function(){
|
||||||
|
window.location = "/books/"+book.id
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function onDocumentMouseWheel( event ) {
|
||||||
|
|
||||||
|
fov -= event.wheelDeltaY * 0.05;
|
||||||
|
camera.projectionMatrix = THREE.Matrix4.makePerspective( fov, window.innerWidth / window.innerHeight, 1, 1100 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onWindowResize() {
|
||||||
|
camera.aspect = window.innerWidth / window.innerHeight;
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
controls.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- //
|
||||||
|
function animate() {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
controls.update();
|
||||||
|
render();
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- render all -- //
|
||||||
|
function render() {
|
||||||
|
|
||||||
|
var timer = 0.00001 * Date.now();
|
||||||
|
|
||||||
|
for (var i = 0, l = diamondsGroup.children.length; i < l; i++) {
|
||||||
|
var object = diamondsGroup.children[i];
|
||||||
|
object.position.y = 500 * Math.cos(timer + i);
|
||||||
|
object.rotation.y += Math.PI / 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the picking ray with the camera and mouse position
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
// calculate objects intersecting the picking ray
|
||||||
|
var intersects = raycaster.intersectObjects(diamondsGroup.children);
|
||||||
|
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
if (INTERSECTED != intersects[0].object) {
|
||||||
|
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||||
|
INTERSECTED = intersects[0].object;
|
||||||
|
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
|
||||||
|
INTERSECTED.material.emissive.setHex(Math.random() * 0xff00000 - 0xff00000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||||
|
INTERSECTED = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- run functions -- //
|
||||||
|
//init();
|
||||||
|
//animate();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,459 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>XPPL VOLUMETRIC CATALOGUE </title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Karla" rel="stylesheet">
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
cccccc;
|
||||||
|
font-family: 'Karla', sans-serif;
|
||||||
|
font-size:15px;
|
||||||
|
|
||||||
|
text-align:left;
|
||||||
|
background-color: #140b33;
|
||||||
|
margin: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#info {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px; width: 10%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #444b7c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-button {
|
||||||
|
padding: 7px 19px;
|
||||||
|
|
||||||
|
background-color: #aca4c1;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-title {
|
||||||
|
margin: 0px;
|
||||||
|
font-size: 16px;
|
||||||
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.21);
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-overlay {
|
||||||
|
background-color: rgba(20, 13, 50, 0.6);
|
||||||
|
}
|
||||||
|
.swal-modal {
|
||||||
|
background-color: rgba(172, 164, 193, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="info"><a target="_blank" rel="noopener">XPPL VOLUMETRIC CATALOGUE <br> <br> Feel free to move around and explore the content of the library by clicking on the volumetric shapes</div>
|
||||||
|
<div id="container"></div>
|
||||||
|
<canvas id="viewer"></canvas>
|
||||||
|
<script src="https://rawgit.com/mrdoob/three.js/dev/build/three.min.js"></script>
|
||||||
|
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js"></script>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
var category2color = new Object();
|
||||||
|
category2color["Technical"] = "#003d5d";
|
||||||
|
category2color["Science/History"] = "#f23d5d";
|
||||||
|
category2color["Media studies"] = "#8c3d5d";
|
||||||
|
category2color["Philosophy"] = "#723d5d";
|
||||||
|
category2color["Computer culture"] = "#423d5d";
|
||||||
|
category2color["Design / writing / publishing"] = "#ff0000";
|
||||||
|
category2color["Desk"] = "#09edff";
|
||||||
|
category2color["Art"] = "#ffedff";
|
||||||
|
category2color["Digital (Steve Trim 2 reading)"] = "#ffe1cc";
|
||||||
|
category2color["Media Studies (Femke Trim 3)"] = "#00e1cc";
|
||||||
|
category2color["Literature, Culture, Theory"] = "#00a1d4";
|
||||||
|
|
||||||
|
category2color["default"] = "#cdc1ec";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.clear();
|
||||||
|
|
||||||
|
const MAX_DISTANCE = 1000;
|
||||||
|
//
|
||||||
|
const MIN_DISTANCE = 200;
|
||||||
|
|
||||||
|
const MAX_SPHERE_RADIUS = 700;
|
||||||
|
|
||||||
|
var bookTitles;
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open('GET', 'export.json', true);
|
||||||
|
|
||||||
|
request.onload = function() {
|
||||||
|
if (request.status >= 200 && request.status < 400) {
|
||||||
|
var data = JSON.parse(request.responseText);
|
||||||
|
//bookTitles = data;
|
||||||
|
bookTitles = data.books[0];
|
||||||
|
|
||||||
|
bookTitles.forEach(function(book) {
|
||||||
|
book.type = "sphere";
|
||||||
|
console.log('BOOK:', book);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
console.log("got books", bookTitles)
|
||||||
|
// loaded data, start
|
||||||
|
init();
|
||||||
|
animate();
|
||||||
|
} else {
|
||||||
|
// We reached our target server, but it returned an error
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = function() {
|
||||||
|
// There was a connection error of some sort
|
||||||
|
};
|
||||||
|
|
||||||
|
request.send();
|
||||||
|
|
||||||
|
|
||||||
|
// --- threeJS --- //
|
||||||
|
var renderer, scene, camera, distance, raycaster, projector;
|
||||||
|
|
||||||
|
var container = document.getElementById('container');
|
||||||
|
var raycaster = new THREE.Raycaster(),INTERSECTED;
|
||||||
|
var mouse = new THREE.Vector2();
|
||||||
|
var distance = 600;
|
||||||
|
|
||||||
|
// -- basic initialization -- //
|
||||||
|
function init() {
|
||||||
|
renderer = new THREE.WebGLRenderer({
|
||||||
|
antialias: true
|
||||||
|
});
|
||||||
|
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
renderer.setClearColor(0x140b33, 1);
|
||||||
|
container.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 300000);
|
||||||
|
// controls = new THREE.OrbitControls(camera);
|
||||||
|
//camera.position.set(1, 1, -5);
|
||||||
|
camera.position.set(MAX_DISTANCE/2, MAX_DISTANCE/20, MAX_DISTANCE/20);
|
||||||
|
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||||
|
// controls.maxDistance = MAX_DISTANCE * 3;
|
||||||
|
controls.target = new THREE.Vector3(0, 0, 0);
|
||||||
|
controls.rotateSpeed = .2;
|
||||||
|
controls.enableDamping = true;
|
||||||
|
console.log(controls.enableDamping);
|
||||||
|
controls.dampingFactor = .15;
|
||||||
|
controls.panSpeed = .15;
|
||||||
|
controls.screenSpacePanning = true;
|
||||||
|
// to disable zoom
|
||||||
|
controls.enableZoom = true;
|
||||||
|
// to disable rotation
|
||||||
|
controls.enableRotate = true;
|
||||||
|
// to disable pan
|
||||||
|
controls.enablePan = true;
|
||||||
|
scene.add(camera);
|
||||||
|
|
||||||
|
//camera.position.set(-150, 10, 1);
|
||||||
|
//controls.update();
|
||||||
|
// scene.add(camera);
|
||||||
|
|
||||||
|
light = new THREE.PointLight(0x404040);
|
||||||
|
light.position.set(50, 0, 0);
|
||||||
|
scene.add(light);
|
||||||
|
/* light_two = new THREE.PointLight(0xffffff, 1, 4000);
|
||||||
|
light_two.position.set(-100, 800, 800);
|
||||||
|
lightAmbient = new THREE.AmbientLight(0x404040);
|
||||||
|
scene.add(light, light_two, lightAmbient);*/
|
||||||
|
|
||||||
|
// createSpheres();
|
||||||
|
|
||||||
|
scene.add(new THREE.DirectionalLight(0xffffff));
|
||||||
|
scene.add(new THREE.AmbientLight(0x222222));
|
||||||
|
|
||||||
|
renderer.setPixelRatio(window.devicePixelRatio);
|
||||||
|
|
||||||
|
let viewer = document.querySelector('#viewer');
|
||||||
|
viewer.parentNode.replaceChild(renderer.domElement, viewer);
|
||||||
|
|
||||||
|
createDiamond();
|
||||||
|
|
||||||
|
createSpace();
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', onMouseMove, false);
|
||||||
|
document.addEventListener('mousedown', onDocumentMouseDown, false);
|
||||||
|
window.addEventListener('resize', onWindowResize, false);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- diamonds -- //
|
||||||
|
|
||||||
|
|
||||||
|
function catInobject(obj, category){ //checks if category is in object, if so return corresponding color
|
||||||
|
if (obj.hasOwnProperty(category)) {
|
||||||
|
var color = obj[category];
|
||||||
|
} else { var color = obj["default"];
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDiamond() {
|
||||||
|
|
||||||
|
diamondsGroup = new THREE.Object3D();
|
||||||
|
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
bookTitles.forEach(function (book) {
|
||||||
|
var chosencolor = catInobject(category2color, book.category);
|
||||||
|
var sphere = new THREE.SphereGeometry(1.3, Math.random() * 50, Math.random() * 50);
|
||||||
|
var material = new THREE.MeshPhongMaterial({
|
||||||
|
color: chosencolor,//Math.random() * 0xff00000 - 0xff00000,
|
||||||
|
shading: THREE.FlatShading
|
||||||
|
});
|
||||||
|
var sphere = new THREE.Mesh(sphere, material);
|
||||||
|
sphere.position.x = get_x(book.title) * Math.random() * 100 - 1000;
|
||||||
|
sphere.position.z = get_z(book.category) * Math.random() * 100 - 1000;
|
||||||
|
sphere.rotation.y =get_y(book.fileformat) * Math.random() * 100 - 1000;
|
||||||
|
//sphere.scale.x = sphere.scale.y = sphere.scale.z = Math.random() * 50 + 10;
|
||||||
|
sphere.scale.x = sphere.scale.y = sphere.scale.z = get_size(book.title);
|
||||||
|
|
||||||
|
sphere.userData = book;
|
||||||
|
diamondsGroup.add(sphere);
|
||||||
|
|
||||||
|
})
|
||||||
|
diamondsGroup.position.x = 500;
|
||||||
|
scene.add(diamondsGroup);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function get_size(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_x(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
function get_y(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
function get_z(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- dots on the back -- //
|
||||||
|
function createSpace() {
|
||||||
|
|
||||||
|
let dots = new THREE.Object3D();
|
||||||
|
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
let circleGeometry = new THREE.SphereGeometry(2, Math.random() * 5, Math.random() * 5);
|
||||||
|
let color;
|
||||||
|
if (Math.round(Math.random()) === 0)
|
||||||
|
color = new THREE.Color('#003d5d');
|
||||||
|
else
|
||||||
|
//color = new THREE.Color('#f23d5d');
|
||||||
|
color = new THREE.Color('#f23d5d');
|
||||||
|
|
||||||
|
let material = new THREE.MeshPhongMaterial({
|
||||||
|
color: color
|
||||||
|
//side: THREE.DoubleSide
|
||||||
|
});
|
||||||
|
|
||||||
|
material.flatShading = true;
|
||||||
|
|
||||||
|
//var material = new THREE.MeshBasicMaterial({
|
||||||
|
//color : new THREE.Color(Math.floor(Math.random() * 1) === 1),
|
||||||
|
//color : new THREE.Color(Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 0),
|
||||||
|
//shading: THREE.FlatShading,
|
||||||
|
//})
|
||||||
|
var circle = new THREE.Mesh(circleGeometry, material);
|
||||||
|
material.side = THREE.DoubleSide;
|
||||||
|
|
||||||
|
circle.position.x = Math.random() * -distance * 100;
|
||||||
|
circle.position.y = Math.random() * -distance * 8;
|
||||||
|
circle.position.z = Math.random() * distance * 5;
|
||||||
|
circle.rotation.y = Math.random() * 2 * Math.PI;
|
||||||
|
circle.scale.x = circle.scale.y = circle.scale.z = Math.random() * 6 + 5;
|
||||||
|
dots.add(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
dots.position.x = 14000;
|
||||||
|
dots.position.y = 1500;
|
||||||
|
dots.position.z = 4000;
|
||||||
|
dots.rotation.y = Math.PI * 600;
|
||||||
|
dots.rotation.z = Math.PI * 500;
|
||||||
|
|
||||||
|
scene.add(dots);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* let circle = new THREE.Mesh(circleGeometry, material);
|
||||||
|
|
||||||
|
let direction = getRandomVector().normalize();
|
||||||
|
let minDistance = MAX_DISTANCE * 8;
|
||||||
|
let maxDistance = minDistance + 0.5;
|
||||||
|
direction.multiplyScalar(Math.random() * (maxDistance - minDistance) + minDistance);
|
||||||
|
|
||||||
|
circle.position.add(direction);
|
||||||
|
|
||||||
|
dots.add(circle);
|
||||||
|
}
|
||||||
|
scene.add(dots);
|
||||||
|
} */
|
||||||
|
|
||||||
|
function getRandomVector(max_distance) {
|
||||||
|
if (max_distance === undefined)
|
||||||
|
max_distance = 1;
|
||||||
|
return new THREE.Vector3(getRandom(max_distance), getRandom(max_distance), getRandom(max_distance));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandom(max_distance) {
|
||||||
|
let random = Math.random() * max_distance;
|
||||||
|
random *= Math.floor(Math.random() * 2) === 1 ? 1 : -1;
|
||||||
|
return random;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -- events -- //
|
||||||
|
function onMouseMove(event) {
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
mouseX = event.clientX - window.innerWidth / 2 ;
|
||||||
|
mouseY = event.clientY - window.innerHeight / 2 ;
|
||||||
|
camera.position.x += (mouseX - camera.position.x) * 0.01;
|
||||||
|
camera.position.y += (mouseY - camera.position.y) * 0.01;
|
||||||
|
camera.lookAt(scene.position);
|
||||||
|
};
|
||||||
|
|
||||||
|
function onDocumentMouseDown(event) {
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
var intersects = raycaster.intersectObjects(diamondsGroup.children);
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
var book = intersects[0].object.userData;
|
||||||
|
console.log("click", book);
|
||||||
|
//alert("book" + book.title);
|
||||||
|
|
||||||
|
//swal(book.title + book.authors);
|
||||||
|
|
||||||
|
swal(book.title + " \n " + " " + book.authors[0].author_name + " \n" + book.category, {
|
||||||
|
button: {
|
||||||
|
text: "Open",
|
||||||
|
}
|
||||||
|
}).then (function(){
|
||||||
|
window.location = "/books/"+book.id
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function onDocumentMouseWheel( event ) {
|
||||||
|
|
||||||
|
fov -= event.wheelDeltaY * 0.05;
|
||||||
|
camera.projectionMatrix = THREE.Matrix4.makePerspective( fov, window.innerWidth / window.innerHeight, 1, 1100 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onWindowResize() {
|
||||||
|
camera.aspect = window.innerWidth / window.innerHeight;
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
controls.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- //
|
||||||
|
function animate() {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
controls.update();
|
||||||
|
render();
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- render all -- //
|
||||||
|
function render() {
|
||||||
|
|
||||||
|
var timer = 0.00001 * Date.now();
|
||||||
|
|
||||||
|
for (var i = 0, l = diamondsGroup.children.length; i < l; i++) {
|
||||||
|
var object = diamondsGroup.children[i];
|
||||||
|
object.position.y = 500 * Math.cos(timer + i);
|
||||||
|
object.rotation.y += Math.PI / 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the picking ray with the camera and mouse position
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
// calculate objects intersecting the picking ray
|
||||||
|
var intersects = raycaster.intersectObjects(diamondsGroup.children);
|
||||||
|
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
if (INTERSECTED != intersects[0].object) {
|
||||||
|
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||||
|
INTERSECTED = intersects[0].object;
|
||||||
|
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
|
||||||
|
INTERSECTED.material.emissive.setHex(Math.random() * 0xff00000 - 0xff00000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||||
|
INTERSECTED = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- run functions -- //
|
||||||
|
//init();
|
||||||
|
//animate();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,474 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>XPPL VOLUMETRIC CATALOGUE </title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Karla" rel="stylesheet">
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
|
||||||
|
font-family: 'Karla', sans-serif;
|
||||||
|
font-size:15px;
|
||||||
|
|
||||||
|
text-align:left;
|
||||||
|
background: #140b33;
|
||||||
|
margin: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#info {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px; width: 10%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #444b7c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-button {
|
||||||
|
padding: 7px 19px;
|
||||||
|
|
||||||
|
background-color: #aca4c1;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-title {
|
||||||
|
margin: 0px;
|
||||||
|
font-size: 16px;
|
||||||
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.21);
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-overlay {
|
||||||
|
background-color: rgba(20, 13, 50, 0.6);
|
||||||
|
}
|
||||||
|
.swal-modal {
|
||||||
|
background-color: rgba(172, 164, 193, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="info"><a href ="/">back to library</a> <br><br><a target="_blank" rel="noopener"> <b> <font size="5"> XPPL VOLUMETRIC CATALOGUE </font> </b> <br> <br> Feel free to move around and explore the content of the library by clicking on the volumetric shapes</div>
|
||||||
|
<div id="container"></div>
|
||||||
|
<canvas id="viewer"></canvas>
|
||||||
|
<script src="https://rawgit.com/mrdoob/three.js/dev/build/three.min.js"></script>
|
||||||
|
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js"></script>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
var category2color = new Object();
|
||||||
|
category2color["Technical"] = "#003d5d";
|
||||||
|
category2color["Science/History"] = "#f23d5d";
|
||||||
|
category2color["Media studies"] = "#8c3d5d";
|
||||||
|
category2color["Philosophy"] = "#723d5d";
|
||||||
|
category2color["Computer culture"] = "#423d5d";
|
||||||
|
category2color["Design / writing / publishing"] = "#ff0000";
|
||||||
|
category2color["Desk"] = "#09edff";
|
||||||
|
category2color["Art"] = "#ffedff";
|
||||||
|
category2color["Digital (Steve Trim 2 reading)"] = "#ffe1cc";
|
||||||
|
category2color["Media Studies (Femke Trim 3)"] = "#00e1cc";
|
||||||
|
category2color["Literature, Culture, Theory"] = "#00a1d4";
|
||||||
|
|
||||||
|
category2color["default"] = "#cdc1ec";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.clear();
|
||||||
|
|
||||||
|
const MAX_DISTANCE = 1000;
|
||||||
|
//
|
||||||
|
const MIN_DISTANCE = 200;
|
||||||
|
|
||||||
|
const MAX_SPHERE_RADIUS = 700;
|
||||||
|
|
||||||
|
var bookTitles;
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open('GET', '/api/books', true);
|
||||||
|
|
||||||
|
request.onload = function() {
|
||||||
|
if (request.status >= 200 && request.status < 400) {
|
||||||
|
var data = JSON.parse(request.responseText);
|
||||||
|
//bookTitles = data;
|
||||||
|
bookTitles = data.books;
|
||||||
|
|
||||||
|
bookTitles.forEach(function(book) {
|
||||||
|
book.type = "sphere";
|
||||||
|
console.log('BOOK:', book);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
console.log("got books", bookTitles)
|
||||||
|
// loaded data, start
|
||||||
|
init();
|
||||||
|
animate();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// We reached our target server, but it returned an error
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = function() {
|
||||||
|
// There was a connection error of some sort
|
||||||
|
};
|
||||||
|
|
||||||
|
request.send();
|
||||||
|
|
||||||
|
|
||||||
|
// --- threeJS --- //
|
||||||
|
var renderer, scene, camera, distance, raycaster, projector;
|
||||||
|
|
||||||
|
var container = document.getElementById('container');
|
||||||
|
var raycaster = new THREE.Raycaster(),INTERSECTED;
|
||||||
|
var mouse = new THREE.Vector2();
|
||||||
|
var distance = 600;
|
||||||
|
|
||||||
|
// -- basic initialization -- //
|
||||||
|
function init() {
|
||||||
|
renderer = new THREE.WebGLRenderer({
|
||||||
|
antialias: true
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
renderer.setClearColor(0x140b33, 1);
|
||||||
|
//renderer.setClearColor(0xFF00FF, 1.0);
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
container.appendChild(renderer.domElement);
|
||||||
|
renderer.clear();
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 300000);
|
||||||
|
// controls = new THREE.OrbitControls(camera);
|
||||||
|
//camera.position.set(1, 1, -5);
|
||||||
|
camera.position.set(MAX_DISTANCE/2, MAX_DISTANCE/20, MAX_DISTANCE/20);
|
||||||
|
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||||
|
// controls.maxDistance = MAX_DISTANCE * 3;
|
||||||
|
controls.target = new THREE.Vector3(0, 0, 0);
|
||||||
|
controls.rotateSpeed = .2;
|
||||||
|
controls.enableDamping = true;
|
||||||
|
console.log(controls.enableDamping);
|
||||||
|
controls.dampingFactor = .15;
|
||||||
|
controls.panSpeed = .15;
|
||||||
|
controls.screenSpacePanning = true;
|
||||||
|
// to disable zoom
|
||||||
|
controls.enableZoom = true;
|
||||||
|
// to disable rotation
|
||||||
|
controls.enableRotate = true;
|
||||||
|
// to disable pan
|
||||||
|
controls.enablePan = true;
|
||||||
|
scene.add(camera);
|
||||||
|
|
||||||
|
//camera.position.set(-150, 10, 1);
|
||||||
|
//controls.update();
|
||||||
|
// scene.add(camera);
|
||||||
|
|
||||||
|
light = new THREE.PointLight(0x404040);
|
||||||
|
light.position.set(50, 0, 0);
|
||||||
|
scene.add(light);
|
||||||
|
/* light_two = new THREE.PointLight(0xffffff, 1, 4000);
|
||||||
|
light_two.position.set(-100, 800, 800);
|
||||||
|
lightAmbient = new THREE.AmbientLight(0x404040);
|
||||||
|
scene.add(light, light_two, lightAmbient);*/
|
||||||
|
|
||||||
|
// createSpheres();
|
||||||
|
scene.add(new THREE.DirectionalLight(0xffffff));
|
||||||
|
scene.add(new THREE.AmbientLight(0x222222));
|
||||||
|
|
||||||
|
renderer.setPixelRatio(window.devicePixelRatio);
|
||||||
|
renderer.clear();
|
||||||
|
|
||||||
|
let viewer = document.querySelector('#viewer');
|
||||||
|
viewer.parentNode.replaceChild(renderer.domElement, viewer);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
|
||||||
|
createDiamond();
|
||||||
|
createSpace();
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', onMouseMove, false);
|
||||||
|
document.addEventListener('mousedown', onDocumentMouseDown, false);
|
||||||
|
window.addEventListener('resize', onWindowResize, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- diamonds -- //
|
||||||
|
|
||||||
|
|
||||||
|
function catInobject(obj, category){ //checks if category is in object, if so return corresponding color
|
||||||
|
if (obj.hasOwnProperty(category)) {
|
||||||
|
var color = obj[category];
|
||||||
|
} else { var color = obj["default"];
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDiamond() {
|
||||||
|
|
||||||
|
diamondsGroup = new THREE.Object3D();
|
||||||
|
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
bookTitles.forEach(function (book) {
|
||||||
|
var chosencolor = catInobject(category2color, book.category);
|
||||||
|
var sphere = new THREE.SphereGeometry(1.3, Math.random() * 50, Math.random() * 50);
|
||||||
|
var material = new THREE.MeshPhongMaterial({
|
||||||
|
color: chosencolor,//Math.random() * 0xff00000 - 0xff00000,
|
||||||
|
shading: THREE.FlatShading
|
||||||
|
});
|
||||||
|
var sphere = new THREE.Mesh(sphere, material);
|
||||||
|
sphere.position.x = get_x(book.title) * Math.random() * 100 - 1000;
|
||||||
|
sphere.position.z = get_z(book.category) * Math.random() * 100 - 1000;
|
||||||
|
sphere.rotation.y =get_y(book.fileformat) * Math.random() * 100 - 1000;
|
||||||
|
//sphere.scale.x = sphere.scale.y = sphere.scale.z = Math.random() * 50 + 10;
|
||||||
|
sphere.scale.x = sphere.scale.y = sphere.scale.z = get_size(book.title);
|
||||||
|
|
||||||
|
sphere.userData = book;
|
||||||
|
diamondsGroup.add(sphere);
|
||||||
|
|
||||||
|
})
|
||||||
|
diamondsGroup.position.x = 500;
|
||||||
|
scene.add(diamondsGroup);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function get_size(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_x(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
function get_y(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
function get_z(title){
|
||||||
|
radius = 0;
|
||||||
|
for (var i = 0; i < title.length; i++) {
|
||||||
|
radius = radius + title.charCodeAt(i)
|
||||||
|
}
|
||||||
|
console.log(radius)
|
||||||
|
return radius/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- dots on the back -- //
|
||||||
|
function createSpace() {
|
||||||
|
|
||||||
|
let dots = new THREE.Object3D();
|
||||||
|
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
let circleGeometry = new THREE.SphereGeometry(2, Math.random() * 5, Math.random() * 5);
|
||||||
|
let color;
|
||||||
|
if (Math.round(Math.random()) === 0)
|
||||||
|
color = new THREE.Color('#003d5d');
|
||||||
|
else
|
||||||
|
//color = new THREE.Color('#f23d5d');
|
||||||
|
color = new THREE.Color('#f23d5d');
|
||||||
|
|
||||||
|
let material = new THREE.MeshPhongMaterial({
|
||||||
|
color: color
|
||||||
|
//side: THREE.DoubleSide
|
||||||
|
});
|
||||||
|
|
||||||
|
material.flatShading = true;
|
||||||
|
|
||||||
|
//var material = new THREE.MeshBasicMaterial({
|
||||||
|
//color : new THREE.Color(Math.floor(Math.random() * 1) === 1),
|
||||||
|
//color : new THREE.Color(Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 0),
|
||||||
|
//shading: THREE.FlatShading,
|
||||||
|
//})
|
||||||
|
|
||||||
|
|
||||||
|
var circle = new THREE.Mesh(circleGeometry, material);
|
||||||
|
material.side = THREE.DoubleSide;
|
||||||
|
|
||||||
|
circle.position.x = Math.random() * -distance * 100;
|
||||||
|
circle.position.y = Math.random() * -distance * 8;
|
||||||
|
circle.position.z = Math.random() * distance * 5;
|
||||||
|
circle.rotation.y = Math.random() * 2 * Math.PI;
|
||||||
|
circle.scale.x = circle.scale.y = circle.scale.z = Math.random() * 8 + 5;
|
||||||
|
dots.add(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
dots.position.x = 14000;
|
||||||
|
dots.position.y = 1500;
|
||||||
|
dots.position.z = 4000;
|
||||||
|
dots.rotation.y = Math.PI * 600;
|
||||||
|
dots.rotation.z = Math.PI * 500;
|
||||||
|
|
||||||
|
scene.add(dots);
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
let circle = new THREE.Mesh(circleGeometry, material);
|
||||||
|
|
||||||
|
let direction = getRandomVector().normalize();
|
||||||
|
let minDistance = MAX_DISTANCE * 8;
|
||||||
|
let maxDistance = minDistance + 0.5;
|
||||||
|
direction.multiplyScalar(Math.random() * (maxDistance - minDistance) + minDistance);
|
||||||
|
|
||||||
|
circle.position.add(direction);
|
||||||
|
|
||||||
|
dots.add(circle);
|
||||||
|
}
|
||||||
|
scene.add(dots);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
function getRandomVector(max_distance) {
|
||||||
|
if (max_distance === undefined)
|
||||||
|
max_distance = 1;
|
||||||
|
return new THREE.Vector3(getRandom(max_distance), getRandom(max_distance), getRandom(max_distance));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandom(max_distance) {
|
||||||
|
let random = Math.random() * max_distance;
|
||||||
|
random *= Math.floor(Math.random() * 2) === 1 ? 1 : -1;
|
||||||
|
return random;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -- events -- //
|
||||||
|
function onMouseMove(event) {
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
mouseX = event.clientX - window.innerWidth / 2 ;
|
||||||
|
mouseY = event.clientY - window.innerHeight / 2 ;
|
||||||
|
//camera.position.x += (mouseX - camera.position.x) * 0.01;
|
||||||
|
//camera.position.y += (mouseY - camera.position.y) * 0.01;
|
||||||
|
// camera.lookAt(scene.position);
|
||||||
|
};
|
||||||
|
|
||||||
|
function onDocumentMouseDown(event) {
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
var intersects = raycaster.intersectObjects(diamondsGroup.children);
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
var book = intersects[0].object.userData;
|
||||||
|
console.log("click", book);
|
||||||
|
//alert("book" + book.title);
|
||||||
|
|
||||||
|
//swal(book.title + book.authors);
|
||||||
|
|
||||||
|
|
||||||
|
swal(book.title + " \n " + " " + book.authors.map(function(x){return x.author_name}).join(", ") + " \n" + book.category, {
|
||||||
|
buttons: ["return", "open" ],
|
||||||
|
}).then (function(button){
|
||||||
|
console.log("button", button)
|
||||||
|
if (button) {
|
||||||
|
window.location = "/books/"+book.id
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function onDocumentMouseWheel( event ) {
|
||||||
|
|
||||||
|
fov -= event.wheelDeltaY * 0.05;
|
||||||
|
camera.projectionMatrix = THREE.Matrix4.makePerspective( fov, window.innerWidth / window.innerHeight, 1, 1100 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onWindowResize() {
|
||||||
|
camera.aspect = window.innerWidth / window.innerHeight;
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
controls.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- //
|
||||||
|
function animate() {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
controls.update();
|
||||||
|
render();
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- render all -- //
|
||||||
|
function render() {
|
||||||
|
|
||||||
|
var timer = 0.00001 * Date.now();
|
||||||
|
|
||||||
|
for (var i = 0, l = diamondsGroup.children.length; i < l; i++) {
|
||||||
|
var object = diamondsGroup.children[i];
|
||||||
|
object.position.y = 500 * Math.cos(timer + i);
|
||||||
|
object.rotation.y += Math.PI / 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the picking ray with the camera and mouse position
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
// calculate objects intersecting the picking ray
|
||||||
|
var intersects = raycaster.intersectObjects(diamondsGroup.children);
|
||||||
|
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
if (INTERSECTED != intersects[0].object) {
|
||||||
|
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||||
|
INTERSECTED = intersects[0].object;
|
||||||
|
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
|
||||||
|
INTERSECTED.material.emissive.setHex(Math.random() * 0xff00000 - 0xff00000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||||
|
INTERSECTED = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- run functions -- //
|
||||||
|
//init();
|
||||||
|
//animate();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|