|
|
|
@ -18,34 +18,46 @@ AFRAME.registerComponent('startfunctions', { |
|
|
|
|
init: function(){ |
|
|
|
|
|
|
|
|
|
let newEl = document.createElement('a-entity') |
|
|
|
|
newEl.setAttribute('instruction-coffee-machine', '') |
|
|
|
|
newEl.setAttribute('instruction-machine', '') |
|
|
|
|
AFRAME.scenes[0].appendChild(newEl) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
//___________________________________________________________________________________________________________________________________ |
|
|
|
|
AFRAME.registerComponent('instruction-coffee-machine', { |
|
|
|
|
// once done, equivalent for |
|
|
|
|
AFRAME.registerComponent('instruction-machine', { |
|
|
|
|
// other content next, ideally combinable |
|
|
|
|
// tournevie metal workshop |
|
|
|
|
// laser cutter at the EP |
|
|
|
|
// todo |
|
|
|
|
// describe the target task, e.g "Make extra long coffee (on PicoBarista)" |
|
|
|
|
// 3D model of target object to align efficiently |
|
|
|
|
// list the steps then iterate over them : |
|
|
|
|
// highlight, e.g via arrow pointer, the next element to interact with |
|
|
|
|
// confirm that the instruction was properly conducted |
|
|
|
|
// optionally allow to |
|
|
|
|
// rollback 1 step |
|
|
|
|
// restart from scratch |
|
|
|
|
// adjust bounding box |
|
|
|
|
// port a much simplified version, i.e no 6DoF or hand tracking, to Monocle/Frame |
|
|
|
|
// probably text only then, so only the load from wiki sequential instructions part |
|
|
|
|
// todo |
|
|
|
|
// visual timeline and where we are on it, e.g 1/4 steps |
|
|
|
|
// a la Lego instruction, i.e horizontal bar with dot on current position |
|
|
|
|
// could use a cylinder and a moving sphere |
|
|
|
|
// could be helpful to persist once position is ok, after step 1 then |
|
|
|
|
// https://aframe.io/docs/1.5.0/components/anchored.html |
|
|
|
|
// timeout for increasingly explicit feedback |
|
|
|
|
// jump to specific step via hash to better discussion |
|
|
|
|
// port a text version, i.e no 6DoF or hand tracking, to Monocle/Frame |
|
|
|
|
// adapt from wiki sequential instructions part, possibly with some images |
|
|
|
|
// consider https://threejs.org/docs/?q=grid#api/en/helpers/GridHelper too |
|
|
|
|
|
|
|
|
|
init: function(){ |
|
|
|
|
|
|
|
|
|
// shortcut to navigate through steps, 2D only |
|
|
|
|
onwheel = (event) => { |
|
|
|
|
event.deltaY < 0 ? |
|
|
|
|
document.querySelector("["+generatorName+"]").emit('previousStep') |
|
|
|
|
// does not yet exist |
|
|
|
|
: document.querySelector("["+generatorName+"]").emit('nextStep') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let generatorName = this.attrName |
|
|
|
|
const idSuffix = "_framing_box" |
|
|
|
|
let el = this.el |
|
|
|
|
this.scale = 1/10 |
|
|
|
|
this.steps = ["pick the grey box and align it with your coffee machine", "press button A", "press button B"] |
|
|
|
|
this.steps = ["pick the grey box and align it with your 3D printer", "press change filament button", "remove the filament spool"] |
|
|
|
|
// symplistic, could instead be a directed graph of named nodes, each with optionally multiple outgoing edges |
|
|
|
|
this.buttonSuffix = "_step_button" |
|
|
|
|
this.endOfInstructions = "You have finished the instructions. Feel free to reset and try again." |
|
|
|
|
const confirmationStep = "Done" // could also consider a "done" area, moving the text there |
|
|
|
|
let newEl = document.createElement('a-box') |
|
|
|
|
newEl.setAttribute("scale", ""+this.scale+" "+this.scale+" "+this.scale) |
|
|
|
@ -62,9 +74,47 @@ AFRAME.registerComponent('instruction-coffee-machine', { |
|
|
|
|
newEl.id = generatorName+idSuffix |
|
|
|
|
el.appendChild(newEl) |
|
|
|
|
|
|
|
|
|
let timelinegEl = document.createElement('a-cylinder') |
|
|
|
|
timelinegEl.setAttribute("height", "1") |
|
|
|
|
timelinegEl.setAttribute("radius", ".1") |
|
|
|
|
timelinegEl.setAttribute("color", "white") |
|
|
|
|
timelinegEl.setAttribute("rotation", "90 0 0") |
|
|
|
|
timelinegEl.setAttribute("position", "0.1 0.1 0.5") |
|
|
|
|
timelinegEl.setAttribute("visible","false") |
|
|
|
|
timelinegEl.classList.add( generatorName ) |
|
|
|
|
timelinegEl.id = generatorName+"_timeline" |
|
|
|
|
//newEl.appendChild(timelinegEl) |
|
|
|
|
|
|
|
|
|
let buttonEl = document.createElement('a-box') |
|
|
|
|
buttonEl.setAttribute("scale", ".2 .1 .1") |
|
|
|
|
buttonEl.setAttribute("wireframe", "true") |
|
|
|
|
buttonEl.setAttribute("color", "red") |
|
|
|
|
buttonEl.setAttribute("position", "0.1 0.1 0.5") |
|
|
|
|
buttonEl.setAttribute("target","true") |
|
|
|
|
buttonEl.setAttribute("visible","false") |
|
|
|
|
buttonEl.classList.add( generatorName ) |
|
|
|
|
buttonEl.classList.add( generatorName+this.buttonSuffix) |
|
|
|
|
buttonEl.id = generatorName+this.buttonSuffix+"_1" |
|
|
|
|
newEl.appendChild(buttonEl) |
|
|
|
|
this.addArrow([-4.5, 0, 0], buttonEl) |
|
|
|
|
|
|
|
|
|
buttonEl = document.createElement('a-cylinder') |
|
|
|
|
buttonEl.setAttribute("scale", ".5 .5 .5") |
|
|
|
|
buttonEl.setAttribute("wireframe", "true") |
|
|
|
|
buttonEl.setAttribute("color", "blue") |
|
|
|
|
buttonEl.setAttribute("rotation", "90 0 0") |
|
|
|
|
buttonEl.setAttribute("position", "0 0 -0.5") |
|
|
|
|
buttonEl.setAttribute("target", "true") |
|
|
|
|
buttonEl.setAttribute("visible","false") |
|
|
|
|
buttonEl.classList.add( generatorName ) |
|
|
|
|
buttonEl.classList.add( generatorName+this.buttonSuffix) |
|
|
|
|
buttonEl.id = generatorName+this.buttonSuffix+"_2" |
|
|
|
|
newEl.appendChild(buttonEl) |
|
|
|
|
this.addArrow([-4.5, 0, 0], buttonEl) |
|
|
|
|
let n = addNewNote("jxr qs #"+newEl.id+" sa rotation 0", "0.5 0.9 -.5") |
|
|
|
|
n.setAttribute("rotation", "90 0 0") |
|
|
|
|
n.setAttribute("annotation", "content: snap") |
|
|
|
|
|
|
|
|
|
let actions = [ |
|
|
|
|
"translateX(.1)", "translateX(-.1)", "translateY(.1)", "translateY(-.1)", "translateZ(.1)", "translateZ(-.1)", |
|
|
|
|
"rotateX(-.1)", "rotateX(.1)", "rotateY(.1)", "rotateY(-.1)", "rotateZ(.1)", "rotateZ(-.1)", |
|
|
|
@ -72,13 +122,21 @@ AFRAME.registerComponent('instruction-coffee-machine', { |
|
|
|
|
actions.reverse().map( (a,i) => { |
|
|
|
|
let n = addNewNote("jxr qs #"+newEl.id+" .object3D."+a, ".5 "+(1+i/20)+" -.5") |
|
|
|
|
n.setAttribute("rotation", "90 0 0") |
|
|
|
|
n.setAttribute("annotation", "content: "+a) |
|
|
|
|
n.setAttribute("annotation", "content: "+a.replace(/xxx/,'')) |
|
|
|
|
}) |
|
|
|
|
el.appendChild(newEl) |
|
|
|
|
|
|
|
|
|
n = addNewNote("jxr qs #"+newEl.id+" .emit('nextStep')" , "0 1.1 -.5") |
|
|
|
|
n.setAttribute("rotation", "90 0 0") |
|
|
|
|
n.setAttribute("annotation", "content: confirm/reset") |
|
|
|
|
n.setAttribute("annotation", "content: confirm") |
|
|
|
|
|
|
|
|
|
n = addNewNote("jxr qs #"+newEl.id+" .emit('previousStep')" , "0 1.0 -.5") |
|
|
|
|
n.setAttribute("rotation", "90 0 0") |
|
|
|
|
n.setAttribute("annotation", "content: go backward") |
|
|
|
|
|
|
|
|
|
n = addNewNote("jxr qs #"+newEl.id+" .emit('reset')" , "0 0.8 -.5") |
|
|
|
|
n.setAttribute("rotation", "90 0 0") |
|
|
|
|
n.setAttribute("annotation", "content: restart") |
|
|
|
|
|
|
|
|
|
this.currentInstructionStep = 0 |
|
|
|
|
this.currentInstruction = addNewNote(this.steps[this.currentInstructionStep], "-.3 1.2 -.5") |
|
|
|
@ -88,11 +146,41 @@ AFRAME.registerComponent('instruction-coffee-machine', { |
|
|
|
|
reset: function (evt) { |
|
|
|
|
console.log(this.attrName, 'component was resetted!'); |
|
|
|
|
let generatorName = this.attrName |
|
|
|
|
this.currentInstructionStep=-1 |
|
|
|
|
document.querySelector("["+generatorName+"]").emit('nextStep') |
|
|
|
|
}, |
|
|
|
|
nextStep: function (evt) { |
|
|
|
|
this.currentInstruction.setAttribute("value",this.steps[++this.currentInstructionStep]) |
|
|
|
|
let generatorName = this.attrName |
|
|
|
|
if (this.currentInstructionStep<this.steps.length-1){ |
|
|
|
|
this.currentInstruction.setAttribute("value",this.steps[++this.currentInstructionStep]) |
|
|
|
|
Array.from( document.querySelectorAll( "."+generatorName+this.buttonSuffix) ).map( el => el.setAttribute("visible", "false" ) ) |
|
|
|
|
document.getElementById( generatorName+this.buttonSuffix +"_"+this.currentInstructionStep )?.setAttribute("visible", "true" ) |
|
|
|
|
} else { |
|
|
|
|
this.currentInstruction.setAttribute("value", this.endOfInstructions) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
previousStep: function (evt) { |
|
|
|
|
let generatorName = this.attrName |
|
|
|
|
if (this.currentInstructionStep>0){ |
|
|
|
|
this.currentInstruction.setAttribute("value",this.steps[--this.currentInstructionStep]) |
|
|
|
|
Array.from( document.querySelectorAll( "."+generatorName+this.buttonSuffix) ).map( el => el.setAttribute("visible", "false" ) ) |
|
|
|
|
document.getElementById( generatorName+this.buttonSuffix +"_"+this.currentInstructionStep )?.setAttribute("visible", "true" ) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
addArrow: function(relativePosition, parentEl, color=0xffff00){ |
|
|
|
|
const dir = new THREE.Vector3( 1, 0, 0 ) |
|
|
|
|
|
|
|
|
|
//normalize the direction vector (convert to vector of length 1) |
|
|
|
|
dir.normalize() |
|
|
|
|
|
|
|
|
|
const origin = new THREE.Vector3( ...relativePosition ) |
|
|
|
|
const length = 4 |
|
|
|
|
const hex = color |
|
|
|
|
|
|
|
|
|
const arrowHelper = new THREE.ArrowHelper( dir, origin, length, hex ) |
|
|
|
|
parentEl.object3D.add( arrowHelper ) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
function cloneTarget(target){ |
|
|
|
|