<!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>