commit
a479cb8abc
@ -0,0 +1,111 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<!-- Required meta tags --> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<!-- Bootstrap CSS --> |
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> |
||||
<link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet"> |
||||
|
||||
<script src="setup/upload/server/php/files/usersdb.js"></script> |
||||
<script src="https://aframe.io/releases/1.0.0/aframe.min.js"></script> |
||||
</head> |
||||
<style> |
||||
body { background-color: transparent; } |
||||
|
||||
#email, #sms { |
||||
font-size: xx-large; |
||||
} |
||||
</style> |
||||
|
||||
<body> |
||||
|
||||
<img src="setup/productlogo.png"> |
||||
|
||||
<h3>flat viewer by category sorted by position</h3> |
||||
|
||||
<div id="spacesholder">Your spaces: |
||||
<ul id="spaces"></ul> |
||||
</div> |
||||
|
||||
<div>Already have an account? <span onclick="login()" style="text-decoration: underline;">Log-in</span> |
||||
<form> |
||||
<div id="login" style="display:none"><input id="useremail"/> |
||||
<button style="margin-top:2px;" type="button" onclick="loginViaEmail()" id="loginemail" class="btn btn-lg btn-primary btn-block">Login</button> |
||||
</div> |
||||
</form> |
||||
<div style="display:none" id="nouser">User not found. Double check your email address then contact fabien@iterative-explorations.com</a></div> |
||||
</div> |
||||
|
||||
<script> |
||||
const urlParams = new URLSearchParams(window.location.search); |
||||
const email = urlParams.get('email'); |
||||
if (email) loginViaEmail() |
||||
|
||||
var uploadedURL = "setup/upload/server/php/files/"; |
||||
var images = [] |
||||
var url = "/" |
||||
var urlParameters = "?customimages=" |
||||
var userspace |
||||
|
||||
function login(){ |
||||
document.querySelector("#login").style.display = "block" |
||||
} |
||||
|
||||
function findCategory(image){ |
||||
if (!userspace) return |
||||
console.log(image.filename) |
||||
var imagePos = new THREE.Vector3(); |
||||
imagePos.copy ( AFRAME.utils.coordinates.parse(image.position) ) |
||||
|
||||
var closest |
||||
var smallestDistance = 1000 |
||||
for (var category of userspace.categories){ |
||||
var categoryPos = new THREE.Vector3(); |
||||
categoryPos.copy ( AFRAME.utils.coordinates.parse(category.position) ) |
||||
var distance = categoryPos.distanceTo( imagePos ) |
||||
if (distance < smallestDistance){ |
||||
smallestDistance = distance |
||||
closest = category.label |
||||
} |
||||
console.log(distance, category.label) |
||||
} |
||||
|
||||
return closest |
||||
} |
||||
|
||||
function loginViaEmail(){ |
||||
var path = "setup/" |
||||
if (!email) |
||||
email = document.querySelector("#useremail").value |
||||
userspace = database[email] |
||||
if (!userspace){ |
||||
document.querySelector("#nouser").style.display = "block" |
||||
return |
||||
} |
||||
|
||||
document.querySelector("#spacesholder").style.display = "block" |
||||
var spaces = document.querySelector("#spaces") |
||||
var space = document.createElement("li") |
||||
var spacelink = document.createElement("a") |
||||
var images = userspace.files |
||||
spacelink.href = url + urlParameters |
||||
spacelink.target = "_blank" |
||||
spacelink.innerHTML = userspace.last_login |
||||
space.appendChild(spacelink) |
||||
for (var image of images){ |
||||
urlParameters += image.filename + "," |
||||
space.innerHTML += path + image.filename + " " + findCategory( image ) |
||||
} |
||||
console.log(space) |
||||
spaces.appendChild(space) |
||||
console.log("userspace", userspace) |
||||
} |
||||
</script> |
||||
|
||||
<h3 style="position:absolute; bottom:0px; right:0px;">A product by <a href="https://iterative-explorations.com"><img width="200px" src="https://iterative-explorations.com/logo.svg"></a>.</h3> |
||||
|
||||
</body> |
||||
</html> |
@ -0,0 +1,150 @@ |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<title>Think + Relax space by Iterative Explorations</title> |
||||
<script src="https://aframe.io/releases/1.0.0/aframe.min.js"></script> |
||||
<script src="https://rawgit.com/feiss/aframe-environment-component/master/dist/aframe-environment-component.min.js"></script> |
||||
<script src="https://cdn.rawgit.com/donmccurdy/aframe-extras/v4.1.2/dist/aframe-extras.min.js"></script> |
||||
<script src="https://unpkg.com/super-hands@3.0.0/dist/super-hands.min.js"></script> |
||||
<script src="pimvrhelpers.js"></script> |
||||
</head> |
||||
<script> |
||||
// could add an in VR edit mode for the categories, to position them, name them, etc |
||||
// should be mostly for adjustments |
||||
var timer = AFRAME.utils.getUrlParameter('timer') |
||||
if (!timer) timer = 300 //5min |
||||
|
||||
function saveNewItemsPosition(){ |
||||
var selector = ".notes"; |
||||
var pos = "" |
||||
document.querySelectorAll(selector).forEach( |
||||
e => pos += "\n" + AFRAME.utils.coordinates.stringify( e.getAttribute("position") ) |
||||
) |
||||
pimvrSaveRemote("WeWorkTest", pos) // from pimvrhelpers.js |
||||
// should be saved by username by space |
||||
// could be pointed at from the database file (thus having multiple storages) |
||||
} |
||||
|
||||
AFRAME.registerComponent("watch", { |
||||
init: function() { |
||||
document.querySelector("#timer").setAttribute("text","value:"+timer) |
||||
this.tick = AFRAME.utils.throttleTick(this.tick, 1000, this); |
||||
// details https://aframe.io/docs/1.0.0/core/utils.html#aframe-utils-throttle-function-minimuminterval-optionalcontext |
||||
}, |
||||
|
||||
tick: function (t, dt) { |
||||
var time = Number( document.querySelector("#timer").getAttribute("text").value ) |
||||
time-- |
||||
document.querySelector("#timer").setAttribute("text","value:"+(time)) |
||||
}, |
||||
}) |
||||
|
||||
AFRAME.registerComponent("relaxing-introduction", { |
||||
init: function() { |
||||
// get in flow state |
||||
// for now controlled just with AFrame animation |
||||
// cf https://aframe.io/docs/1.0.0/components/animation.html |
||||
|
||||
setTimeout(function(){ |
||||
for (var note of document.querySelectorAll(".notes")){ note.emit("fadein") } |
||||
}, 10 * 1000) // arbitrary 10s, should be instead after the introduction is finished |
||||
} |
||||
}) |
||||
|
||||
AFRAME.registerComponent("decompression-conclusion", { |
||||
init: function() { |
||||
// cf PoC at 2017 W3C web authoring workshop with Roland Dubois |
||||
setTimeout(function(){ |
||||
var intructions = document.querySelector("#instructions") |
||||
instructions.setAttribute("position", "-1 1.5 -1") // assumes the user is roughtly centered... could force on camera instead |
||||
instructions.setAttribute("text", "value", "Your session will end soon\n\nVisit https://learnWebVR.xyz/flat.html\n\nto work outside of VR.") |
||||
instructions.setAttribute("opacity", "1") // could be animated instead |
||||
|
||||
console.log("X min voice over and notes fade-out with contextual information (time, weather, etc)") |
||||
|
||||
document.querySelector("[environment]").setAttribute("environment", "preset:checkerboard") |
||||
}, timer * 1000); |
||||
|
||||
} |
||||
}) |
||||
|
||||
AFRAME.registerComponent("environment-by-url", { |
||||
schema: {}, |
||||
init: function() { |
||||
var environment = AFRAME.utils.getUrlParameter('environment') |
||||
if (environment) document.querySelector("[environment]").setAttribute("environment", "preset:" + environment) |
||||
} |
||||
}) |
||||
|
||||
AFRAME.registerComponent("photo-importer", { |
||||
schema: {}, |
||||
init: function() { |
||||
var baseURL = "setup/" |
||||
var images = AFRAME.utils.getUrlParameter('customimages').split(','); |
||||
if (images.length == 1) window.location = baseURL; // no images? must be configured first |
||||
// could also display a tutorial instead |
||||
var i=1 |
||||
for (var image of images){ |
||||
if (image){ |
||||
var id = "placeholder"+i |
||||
var placeholder = document.querySelector("#"+id) |
||||
if (!placeholder){ |
||||
// TODO somehow not interactable anymore?! |
||||
// had a similar silly issue before but can't recall how I fixed it :( |
||||
// something basic about entities or hierarchy... |
||||
placeholder = document.createElement("a-box") |
||||
placeholder.id = id |
||||
placeholder.setAttribute("material", "shader:flat") |
||||
placeholder.setAttribute("hoverable", "") |
||||
placeholder.setAttribute("grabbable", "") |
||||
placeholder.setAttribute("draggable", "") |
||||
placeholder.setAttribute("dropppable", "") |
||||
// somehow does appear visually correct but are NOT interactable! |
||||
placeholder.setAttribute("position", "" + i/1.5-1.5 + " 1.5 -0.7") |
||||
placeholder.setAttribute("scale", "0.5 0.3 0.01") |
||||
// assume 1 * 1.5 photo ratio (landscape) |
||||
AFRAME.scenes[0].appendChild(placeholder) |
||||
} |
||||
placeholder.className += "notes" |
||||
placeholder.setAttribute("opacity", "0") |
||||
placeholder.setAttribute("animation", "property: components.material.material.opacity; to: 1; dur: 1500; easing: linear; startEvents: fadein;") |
||||
placeholder.setAttribute("src", baseURL+image) |
||||
i++ |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
|
||||
|
||||
</script> |
||||
<body> |
||||
<a-scene photo-importer environment-by-url relaxing-introduction decompression-conclusion> |
||||
<a-entity environment="preset: forest;"></a-entity> |
||||
|
||||
<a-entity sphere-collider="objects: a-box" super-hands hand-controls="left"></a-entity> |
||||
<a-entity sphere-collider="objects: a-box" super-hands hand-controls="right"></a-entity> |
||||
|
||||
<!-- could be wrist watch as I've done via Twitter years ago --> |
||||
<a-text watch id="timer" rotation="180 0 180" position="0 1 2" value="time"></a-text> |
||||
|
||||
<a-text id="instructions" position="-1 1.5 -0.65" value="welcome to your\n\nthink+relax space" opacity="0" |
||||
animation__fadein="property: components.text.material.uniforms.opacity.value; to: 0.99; dur: 1500; easing: linear" |
||||
animation__fadeout="property: components.text.material.uniforms.opacity.value; to: 0.01; dur: 1500; easing: linear; startEvents: fadeout;" |
||||
animation__leave="property: object3D.position.z; to: -100; dur: 15000; easing: linear; delay: 2500;" |
||||
></a-text> |
||||
|
||||
|
||||
<a-text rotation="-20 20 0" position="-2 0.2 -2" scale="1 1 1" value="waiting"></a-text> |
||||
<a-box material="wireframe:true" color="orange" position="-2 1 -2" scale="2 2 2"></a-box> |
||||
<a-text rotation="-20 0 0" position=" 0 0.2 -2" scale="1 1 1" value="in progress"></a-text> |
||||
<a-box material="wireframe:true" color="red" position="0 1 -2" scale="2 2 2"></a-box> |
||||
<a-text rotation="-20 -20 0" position=" 2 0.2 -2" scale="1 1 1" value="completed"></a-text> |
||||
<a-box material="wireframe:true" color="green" position="2 1 -2" scale="2 2 2"></a-box> |
||||
|
||||
<a-box material="shader:flat" id="placeholder1" hoverable grabbable stretchable draggable dropppable position="0.5 1.5 -0.5" scale="0.5 0.3 0.01"></a-box> |
||||
<a-box material="shader:flat" id="placeholder2" hoverable grabbable stretchable draggable dropppable position="0 1.9 -0.7" scale="0.5 0.3 0.01"></a-box> |
||||
<a-box material="shader:flat" id="placeholder3" hoverable grabbable stretchable draggable dropppable position="-0.5 1.5 -0.7" scale="0.5 0.3 0.01"></a-box> |
||||
<!-- somehow creating dynamically fails... even though it did (!) work at some point (but wasn't saved via git)--> |
||||
<!-- until then will rely on a pool of objects --> |
||||
|
||||
</a-scene> |
||||
</body> |
@ -0,0 +1,187 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<!-- Required meta tags --> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<!-- Bootstrap CSS --> |
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> |
||||
<link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet"> |
||||
|
||||
<script src="clipboard.min.js"></script> |
||||
<script src="upload/server/php/files/usersdb.js"></script> |
||||
</head> |
||||
<style> |
||||
body { background-color: transparent; } |
||||
|
||||
#email, #sms { |
||||
font-size: xx-large; |
||||
} |
||||
</style> |
||||
|
||||
<body> |
||||
|
||||
<img src="productlogo.png"> |
||||
|
||||
<script> |
||||
var tickMark = "✔"; |
||||
var uploadedURL = "upload/server/php/files/"; |
||||
var images = [] |
||||
var url = "/" |
||||
var urlParameters = "?customimages=" |
||||
|
||||
function generateURL(){ |
||||
//var url = "https://learnwebvr.xyz/importer.html" |
||||
for (var image of images){ |
||||
urlParameters += image + "," |
||||
} |
||||
console.log ("URL", urlParameters ); |
||||
|
||||
var encodedURL = url + urlParameters |
||||
|
||||
encodedURL += "&environment=" + document.querySelector("#environment").value |
||||
document.querySelector("#link").href = encodedURL |
||||
document.querySelector("#copyBtn").setAttribute("data-clipboard-text", encodedURL) |
||||
document.querySelector("#generateURL").style.display = "block" |
||||
|
||||
document.querySelector("#email").href = "mailto:?&subject=session&body=" + encodeURIComponent( encodedURL ) |
||||
// tested on iPhone 6S and Pixel2 and desktop |
||||
|
||||
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) { |
||||
} |
||||
else { |
||||
document.querySelector("#copydiv").className = "cold-md-6" |
||||
document.querySelector("#emaildiv").className = "cold-md-6" |
||||
} |
||||
} |
||||
</script> |
||||
<div class="container"> |
||||
|
||||
<form class="form-signin"> |
||||
|
||||
Environment: |
||||
<select id="environment"> |
||||
<option name="contact">contact</option> |
||||
<option name="egypt">egypt</option> |
||||
<option name="checkerboard">checkerboard</option> |
||||
<option name="forest" selected="selected">forest</option> |
||||
<option name="goaland">goaland</option> |
||||
<option name="yavapai">yavapai</option> |
||||
<option name="goldmine">goldmine</option> |
||||
<option name="threetowers">threetowers</option> |
||||
<option name="poison">poison</option> |
||||
<option name="arches">arches</option> |
||||
<option name="tron">tron</option> |
||||
<option name="japan">japan</option> |
||||
<option name="dream">dream</option> |
||||
<option name="volcano">volcano</option> |
||||
<option name="starry">starry</option> |
||||
<option name="osiris">osiris</option> |
||||
</select> |
||||
|
||||
<button style="margin-top:2px;" type="button" onclick="unhide('#fileupload2');" class="btn btn-primary btn-block">Upload your office photos<br/>(post-its, white board, etc)</button> |
||||
|
||||
No content available? Try <a target="_blank" href="https://learnwebvr.xyz/?customimages=upload/server/php/files/photo6035074301452988871.jpg,upload/server/php/files/photo6035074301452988870.jpg,upload/server/php/files/IMG_6496 (1).jpg"> this example instead</a>! |
||||
|
||||
<input style="display:none;" id="fileupload2" type="file" name="files[]" data-url="upload/server/php/" multiple> |
||||
<div style="display:none;" id="fileuploaded2">Files uploaded: </div> |
||||
<div style="opacity:0.7;" id="uploadrate"></div> |
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> |
||||
<script src="upload/js/vendor/jquery.ui.widget.js"></script> |
||||
<script src="upload/js/jquery.iframe-transport.js"></script> |
||||
<script src="upload/js/jquery.fileupload.js"></script> |
||||
<script> |
||||
|
||||
function unhide( element ){ |
||||
document.querySelector(element).style.display = "block"; |
||||
} |
||||
|
||||
$(function () { |
||||
|
||||
$('#fileupload2').fileupload({ |
||||
dataType: 'json', |
||||
done: function (e, data) { |
||||
$.each(data.result.files, function (index, file) { |
||||
var imageURL = uploadedURL + (file.name) |
||||
images.push(imageURL) |
||||
var uploaded = document.querySelector("#fileuploaded2"); |
||||
uploaded.style.display = "block"; |
||||
uploaded.innerHTML += tickMark; |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
}); |
||||
</script> |
||||
|
||||
<button style="margin-top:2px;" type="button" onclick="generateURL()" id="generate-simulation" class="btn btn-lg btn-primary btn-block">Generate your<br/>relax+think space</button> |
||||
</form> |
||||
</div> |
||||
|
||||
<div id="generateURL" style="display:none; text-align:center;" class="container"> |
||||
<div class="container"> |
||||
<a id="link" target="_blank" href=""><button type="button" class="btn btn-lg btn-primary btn-block">Launch relax+think space</button></a> |
||||
</div> |
||||
<br/> |
||||
<div class="container"> |
||||
<div class="row"> |
||||
<div class="col-md-4" id="copydiv"> |
||||
<button class="btn" data-clipboard-text="" id="copyBtn">Copy to clipboard</button> |
||||
<script> |
||||
new Clipboard('.btn'); |
||||
</script> |
||||
</div> |
||||
<div class="col-md-4" id="emaildiv"> |
||||
<a id="email" href="" target="_blank">email link</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<script> |
||||
function login(){ |
||||
document.querySelector("#login").style.display = "block" |
||||
} |
||||
function loginViaEmail(){ |
||||
var email = document.querySelector("#useremail").value |
||||
var userspace = database[email] |
||||
if (!userspace){ |
||||
document.querySelector("#nouser").style.display = "block" |
||||
return |
||||
} |
||||
|
||||
document.querySelector("#spacesholder").style.display = "block" |
||||
var spaces = document.querySelector("#spaces") |
||||
var space = document.createElement("li") |
||||
var spacelink = document.createElement("a") |
||||
var images = userspace.files |
||||
for (var image of images){ |
||||
urlParameters += image.filename + "," |
||||
} |
||||
spacelink.href = url + urlParameters |
||||
spacelink.target = "_blank" |
||||
spacelink.innerHTML = userspace.last_login |
||||
space.appendChild(spacelink) |
||||
console.log(space) |
||||
spaces.appendChild(space) |
||||
console.log("userspace", userspace) |
||||
} |
||||
</script> |
||||
|
||||
<div>Already have an account? <span onclick="login()" style="text-decoration: underline;">Log-in</span> |
||||
<form> |
||||
<div id="login" style="display:none"><input id="useremail"/> |
||||
<button style="margin-top:2px;" type="button" onclick="loginViaEmail()" id="loginemail" class="btn btn-lg btn-primary btn-block">Login</button> |
||||
</div> |
||||
</form> |
||||
<div style="display:none" id="nouser">User not found. Double check your email address then contact fabien@iterative-explorations.com</a></div> |
||||
<div style="display:none" id="spacesholder">Your spaces: |
||||
<ul id="spaces"></ul> |
||||
</div> |
||||
</div> |
||||
|
||||
<h3 style="position:absolute; bottom:0px; right:0px;">A product by <a href="https://iterative-explorations.com"><img width="200px" src="https://iterative-explorations.com/logo.svg"></a>.</h3> |
||||
|
||||
</body> |
||||
</html> |
@ -0,0 +1,18 @@ |
||||
var database = { |
||||
"fabien@benetou.fr" : { |
||||
"username": "fabien", |
||||
"password": "test", |
||||
"last_login": 1576749381516, |
||||
"environment": "forest", |
||||
"files" : [ |
||||
{ "position": "-2 1 -2", "filename" : "upload/server/php/files/C1C4E2F7-865A-4DB4-9274-1EA69B6C4A7E.jpeg" }, |
||||
{ "position": "0 1 -2", "filename" : "upload/server/php/files/4A21A76C-F375-4884-9040-BC51A24057A6.jpeg" }, |
||||
{ "position": "2 1 -2", "filename" : "upload/server/php/files/2CD9932F-891C-4BA5-BDDA-A3B39B39CF09.jpeg" } |
||||
], |
||||
"categories" : [ |
||||
{ "position": "-2 1 -2", "color" : "orange", "label" : "waiting" }, |
||||
{ "position": "0 1 -2", "color" : "red", "label" : "in progress" }, |
||||
{ "position": "2 1 -2", "color" : "green", "label" : "completed" } |
||||
] |
||||
} |
||||
} |
Loading…
Reference in new issue