demos relying on bounding boxes on text
This commit is contained in:
315
data/index.html
315
data/index.html
@@ -1423,10 +1423,323 @@ setTimeout( _ => {
|
||||
// spatial scoping
|
||||
// could show what is affected, and not, on the boundaries
|
||||
|
||||
// bounded valume
|
||||
// internal and external link following
|
||||
// internal e.g. ToC
|
||||
// external e.g. supported sources
|
||||
// ACM OA with PDF
|
||||
// arXiv
|
||||
// PmWiki
|
||||
|
||||
// bounded volume
|
||||
// see saved RSS filter as example
|
||||
// consider as showFile() parameter
|
||||
|
||||
// could blend q3_obbox_pinch (where content collide each other) and q3_bbox_pinch (on where to pinch)
|
||||
// could be easier to add finger tips to obb-collider
|
||||
// e.g AFRAME.scenes[0].setAttribute("bind-element-to-finger__collider", { hand: 'r_handMeshNode', finger: 'index-finger-tip', target: '#fingertipcollider' } )
|
||||
// then fingertipcollider as a 2cm2 box with el.setAttribute("obb-collider", true)
|
||||
// could then listen on that new element for events
|
||||
// el.addEventListener('obbcollisionstarted', evt => {
|
||||
// el.addEventListener('obbcollisionended', evt => {
|
||||
|
||||
// keyboard move could be done by pinching anywhere within the volume
|
||||
// AFRAME.scenes[0].addEventListener('emptypinch', evt => { ...containsPoint(evt.detail.position)
|
||||
|
||||
// try q3_obbox_grouping with q2_json_collaborations
|
||||
// group elements from loaded files within cubes
|
||||
|
||||
// should be able to show/hide within a cube
|
||||
// scale down?
|
||||
// cube in cube, first cube move other cube within it
|
||||
|
||||
if (username && username == "q3_alt_webdav") {
|
||||
let webdavClient = window.WebDAV.createClient( "https://192.168.0.206:8080/dav/",
|
||||
{ username: "fabien", password: "fabien" })
|
||||
// CORS failed, PROFIND and other problems, might want to check nginx configuration
|
||||
|
||||
// Get directory contents
|
||||
console.log( webdavClient.getDirectoryContents("/") )
|
||||
}
|
||||
|
||||
if (username && username == "q3_obbox_grouping") {
|
||||
const debugBoxClass = "debugbox"
|
||||
|
||||
window.newParent = function(el){
|
||||
if (!el.futureParent) return
|
||||
let parentPos = el.futureParent.getAttribute("position").clone()
|
||||
el.getAttribute("position").sub(parentPos)
|
||||
// takes the rotiation of the parent too... can be surprising
|
||||
el.object3D.parent = el.futureParent.object3D
|
||||
el.futureParent = null
|
||||
return el
|
||||
}
|
||||
|
||||
setTimeout( _ => {
|
||||
let snippetA = addNewNote("text nsippet A", "-.5 1 -.7")
|
||||
snippetA.id = username + '_snippedA'
|
||||
let snippetB = addNewNote("text snippet B", "0 1.5 -.7")
|
||||
let snippetC = addNewNote("snippet C", ".5 1 -.7")
|
||||
let elements = [snippetA, snippetB, snippetC]
|
||||
|
||||
let groupBoxEl = document.createElement("a-box")
|
||||
groupBoxEl.id = username + '_groupEl'
|
||||
groupBoxEl.setAttribute("position", "0 1.3 -1")
|
||||
groupBoxEl.setAttribute("width", .3)
|
||||
groupBoxEl.setAttribute("height", .3)
|
||||
groupBoxEl.setAttribute("depth", .3)
|
||||
groupBoxEl.setAttribute("wireframe", true )
|
||||
groupBoxEl.setAttribute("color", "pink" )
|
||||
groupBoxEl.setAttribute("target", "" )
|
||||
// should also in turn move all associated elements
|
||||
// could be onpicked/onreleased a la keyboard moving
|
||||
groupBoxEl.setAttribute("obb-collider", true)
|
||||
AFRAME.scenes[0].appendChild(groupBoxEl)
|
||||
let markedElements = []
|
||||
|
||||
// for testing only
|
||||
//setTimeout( _ => q3_obbox_grouping_snippedA.setAttribute("position", q3_obbox_grouping_groupEl.getAttribute("position") ) , 1000)
|
||||
//setTimeout( _ => q3_obbox_grouping_snippedA.setAttribute("position", "-.1 1.4 -1" ) , 1000)
|
||||
// works in 3D but not in XR... probably has to happen AFTER being released, not while entering
|
||||
|
||||
setTimeout( _ => {
|
||||
elements.map( el => {
|
||||
let bbox = new THREE.Box3().setFromObject(el.object3D);
|
||||
bbox.min.z -= .01
|
||||
bbox.max.z += .01
|
||||
// expand a bit forward and backward...
|
||||
|
||||
let boxEl = document.createElement("a-box")
|
||||
boxEl.setAttribute("width", bbox.max.x-bbox.min.x )
|
||||
boxEl.setAttribute("height", bbox.max.y-bbox.min.y )
|
||||
boxEl.setAttribute("depth", bbox.max.z-bbox.min.z )
|
||||
boxEl.setAttribute("position", (bbox.max.x-bbox.min.x)/2*10 + " 0 0" ) // parent has 1/10 scale
|
||||
boxEl.setAttribute("visible", false )
|
||||
boxEl.setAttribute("opacity", .3 )
|
||||
boxEl.setAttribute("scale", "10 10 10" ) // parent has 1/10 scale
|
||||
boxEl.classList.add(debugBoxClass)
|
||||
el.appendChild(boxEl)
|
||||
|
||||
boxEl.setAttribute("obb-collider", true)
|
||||
el.addEventListener('obbcollisionstarted', evt => {
|
||||
console.log( 'obbcollisionstarted', evt.detail ) // specifically evt.detail.withEl
|
||||
//evt.detail.withEl.parentEl.setAttribute("color", "pink")
|
||||
// might be the parent instead as here we attached the collider to the box instead
|
||||
//evt.detail.withEl.setAttribute("color", el.getAttribute("color"))
|
||||
el.setAttribute("color", evt.detail.withEl.getAttribute("color") )
|
||||
markedElements.push( el )
|
||||
|
||||
// become child of groupBoxEl only after being released
|
||||
el.futureParent = evt.detail.withEl
|
||||
el.setAttribute("onreleased", "newParent( selectedElements.at(-1).element )")
|
||||
el.setAttribute("onpicked", "selectedElements.at(-1).element.object3D.parent = AFRAME.scenes[0].object3D")
|
||||
// TODO have to leave before being able to parent back...
|
||||
})
|
||||
el.addEventListener('obbcollisionended', evt => {
|
||||
console.log( 'obbcollisionended', evt.detail )
|
||||
//evt.detail.withEl.parentEl.setAttribute("color", "white")
|
||||
el.setAttribute("color", "white")
|
||||
markedElements = markedElements.filter( t => t != el )
|
||||
el.futureParent = null
|
||||
})
|
||||
} )
|
||||
}, 900 )
|
||||
//AFRAME.scenes[0].setAttribute('obb-collider','showColliders:true')
|
||||
}, 500 )
|
||||
}
|
||||
|
||||
if (username && username == "q3_obbox_pinch") {
|
||||
const debugBoxClass = "debugbox"
|
||||
setTimeout( _ => {
|
||||
let snippetA = addNewNote("text nsippet A", "-.5 1 -.7")
|
||||
let snippetB = addNewNote("text snippet B", "0 1.5 -.7")
|
||||
let snippetC = addNewNote("snippet C", ".5 1 -.7")
|
||||
let elements = [snippetA, snippetB, snippetC]
|
||||
setTimeout( _ => {
|
||||
elements.map( el => {
|
||||
let bbox = new THREE.Box3().setFromObject(el.object3D);
|
||||
bbox.min.z -= .01
|
||||
bbox.max.z += .01
|
||||
// expand a bit forward and backward...
|
||||
|
||||
let boxEl = document.createElement("a-box")
|
||||
boxEl.setAttribute("width", bbox.max.x-bbox.min.x )
|
||||
boxEl.setAttribute("height", bbox.max.y-bbox.min.y )
|
||||
boxEl.setAttribute("depth", bbox.max.z-bbox.min.z )
|
||||
boxEl.setAttribute("position", (bbox.max.x-bbox.min.x)/2*10 + " 0 0" ) // parent has 1/10 scale
|
||||
//boxEl.setAttribute("wireframe", true )
|
||||
boxEl.setAttribute("visible", false )
|
||||
boxEl.setAttribute("opacity", .3 )
|
||||
boxEl.setAttribute("scale", "10 10 10" ) // parent has 1/10 scale
|
||||
boxEl.classList.add(debugBoxClass)
|
||||
el.appendChild(boxEl)
|
||||
|
||||
boxEl.setAttribute("obb-collider", true)
|
||||
el.addEventListener('obbcollisionstarted', evt => {
|
||||
console.log( evt.detail ) // specifically evt.detail.withEl
|
||||
evt.detail.withEl.parentEl.setAttribute("color", "pink")
|
||||
// might be the parent instead as here we attached the collider to the box instead
|
||||
})
|
||||
el.addEventListener('obbcollisionended', evt => {
|
||||
console.log( evt.detail )
|
||||
evt.detail.withEl.parentEl.setAttribute("color", "white")
|
||||
})
|
||||
} )
|
||||
}, 900 )
|
||||
//AFRAME.scenes[0].setAttribute('obb-collider','showColliders:true')
|
||||
let el = addNewNote('jxr applyToClass("debugbox", k => k.setAttribute("visible",!k.getAttribute("visible")))')
|
||||
el.setAttribute("annotation", "content:toggle debug box visibility")
|
||||
el.setAttribute("rotation", "90 0 0")
|
||||
jxrhighlight()
|
||||
}, 500 )
|
||||
}
|
||||
|
||||
if (username && username == "q3_bbox_pinch") {
|
||||
setTimeout( _ => {
|
||||
let snippetA = addNewNote("text nsippet A", "-.5 1 -.7")
|
||||
let snippetB = addNewNote("text snippet B", "0 1.5 -.7")
|
||||
let snippetC = addNewNote("snippet C", ".5 1 -.7")
|
||||
let elements = [snippetA, snippetB, snippetC]
|
||||
let bboxes = []
|
||||
setTimeout( _ => {
|
||||
elements.map( el => {
|
||||
el.removeAttribute("target") // does nothing
|
||||
targets = targets.filter( t => t != el ) // should update jxr-core accordingly, will do so after HT25
|
||||
let bbox = new THREE.Box3().setFromObject(el.object3D);
|
||||
// see instead https://threejs.org/docs/index.html?q=obb#examples/en/math/OBB
|
||||
// or higher level https://aframe.io/docs/1.7.0/components/obb-collider.html#main
|
||||
// probably does not work well with a-troika-text or adjusting BB depth
|
||||
// could try adding a box to it manually after loading then add obb-collider on that invisible box
|
||||
bbox.min.z -= .01
|
||||
bbox.max.z += .01
|
||||
// expand a bit forward and backward...
|
||||
bboxes.push( {bbox:bbox, element:el })
|
||||
const helper = new THREE.Box3Helper( bbox, 0xd3e3e5 )
|
||||
AFRAME.scenes[0].object3D.add( helper )
|
||||
} )
|
||||
}, 900 )
|
||||
AFRAME.scenes[0].addEventListener('emptypinch', evt => {
|
||||
console.log( evt.detail )
|
||||
bboxes.filter( b => b.bbox.containsPoint(evt.detail.position) ).map( b => {
|
||||
b.element.setAttribute("color", "pink")
|
||||
})
|
||||
});
|
||||
}, 500 )
|
||||
}
|
||||
|
||||
// see https://git.benetou.fr/utopiah/spasca-fot-sloan-q3/issues/4
|
||||
if (username && username == "q3_media_widget") {
|
||||
// consider
|
||||
// visible background as affordance to move around (a la brown rootEl cube in PDF unpacked)
|
||||
// seek via
|
||||
// onpicked : seek based on distance to initial position, showing current time and total time)
|
||||
// distance 0 = seek 0, 1m (probably way too far for most people but easier to test) = 100%
|
||||
// should be canceable too... so maybe under threshold (e.g. <.05m) do not even seek at all?
|
||||
// onreleased : reset command position to initial position then play()
|
||||
const testFileName = "Kaijuu.mp4"
|
||||
setTimeout( _ => {
|
||||
manuscript.setAttribute("visible", false)
|
||||
let videoEl = document.createElement("a-video")
|
||||
videoEl.setAttribute("width", 2 )
|
||||
//videoEl.setAttribute("src", testFileName)
|
||||
videoEl.setAttribute("src", "#videosrc")
|
||||
videoEl.setAttribute("position", "0 1.5 -1")
|
||||
AFRAME.scenes[0].appendChild(videoEl)
|
||||
let el = document.createElement("a-assets")
|
||||
AFRAME.scenes[0].appendChild(el)
|
||||
let elAsset = document.createElement("video")
|
||||
elAsset.id="videosrc"
|
||||
elAsset.src=testFileName
|
||||
el.appendChild(elAsset)
|
||||
|
||||
let widgetPlayEl = addNewNote("jxr document.getElementById('" + elAsset.id + "').play()", "0 2 -1")
|
||||
// does not work, might have to rely on component instead or play the src target
|
||||
widgetPlayEl.setAttribute("annotation", "content:play video")
|
||||
widgetPlayEl.setAttribute("rotation", "90 0 0")
|
||||
let widgetPauseEl = addNewNote("jxr document.getElementById('" + elAsset.id + "').pause()", "-0.5 2 -1")
|
||||
widgetPauseEl.setAttribute("annotation", "content:pause video")
|
||||
widgetPauseEl.setAttribute("rotation", "90 0 0")
|
||||
let widgetSeekEl = addNewNote("jxr document.getElementById('" + elAsset.id + "')", "-1 2 -1") // different way to interaction than play/pause
|
||||
widgetSeekEl.setAttribute("onpicked", "window.seeking=true")
|
||||
widgetSeekEl.setAttribute("onreleased", "window.seeking=false;let el=selectedElements.at(-1).element; el.setAttribute('position','-1 2 -1'); el.setAttribute('rotation','90 0 0')")
|
||||
widgetSeekEl.setAttribute("annotation", "content:seek video")
|
||||
widgetSeekEl.setAttribute("rotation", "90 0 0")
|
||||
// could be positioned below the media, typically where the timeline is
|
||||
jxrhighlight()
|
||||
}, 800) // should delay until ready
|
||||
window.seeking = false
|
||||
setInterval( _ => {
|
||||
if (!window.seeking) return
|
||||
let elAsset = document.getElementById("videosrc")
|
||||
let pos = new THREE.Vector3().copy({x:-1, y:2, z:-1})
|
||||
let dist = selectedElements.at(-1).element.getAttribute('position').distanceTo(pos)
|
||||
console.log( elAsset.duration , dist, elAsset.duration / (dist/10) )
|
||||
// elAsset.fastSeek( elAsset.duration / (dist/10) ) // get .duration but not get fastSeek(), Chromium limitation
|
||||
elAsset.currentTime = elAsset.duration / dist
|
||||
}, 100 )
|
||||
}
|
||||
|
||||
// see https://git.benetou.fr/utopiah/spasca-fot-sloan-q3/issues/3
|
||||
if (username && username == "q3_pdf_hidden_text") {
|
||||
// use pageAsTextViaXML() from filters/pdf_unpacked.xml.js but do not add new note
|
||||
const testFileName = "3648188.3675128"
|
||||
const testFileNamePDF = testFileName+ ".pdf"
|
||||
const testFileNameXML = "/saved/pdfxml/" + testFileName+ ".xml"
|
||||
const testFileNamePng = "/saved/pdfxml/" + testFileName + ".image-0.png"
|
||||
// needs a manual convert (to image) from 3648188.3675128.pdf
|
||||
// convert -density 150 3648188.3675128.pdf 3648188.3675128.image.png
|
||||
|
||||
setTimeout( _ => {
|
||||
manuscript.setAttribute("visible", false)
|
||||
let elImg = document.createElement("a-image")
|
||||
elImg.setAttribute("height", 29.7/21 ) // cm size of A4 for approximate ratio
|
||||
// display image
|
||||
elImg.setAttribute("src", testFileNamePng)
|
||||
elImg.setAttribute("position", "0.5 0.5 0") // requires small offset but might be related to scaling
|
||||
let rootEl = interactableOverlay( testFileNameXML )
|
||||
rootEl.appendChild(elImg)
|
||||
}, 800) // should delay until ready
|
||||
|
||||
// get coordinates from XML page from saved/pdfxml/3603163.3609031.xml
|
||||
function interactableOverlay(src){
|
||||
const scalingFactor = 1/1000*1.141// 1/1000
|
||||
if (!src) return
|
||||
let rootEl = document.createElement("a-entity")
|
||||
rootEl.id = "test_page_from_" + username
|
||||
rootEl.setAttribute("position", "-.5 1 -.5") // requires small offset but might be related to
|
||||
AFRAME.scenes[0].appendChild(rootEl)
|
||||
let sheetEl = document.createElement("a-box")
|
||||
sheetEl.setAttribute("height", 29.7/21 ) // cm size of A4 for approximate ratio
|
||||
sheetEl.setAttribute("depth", .01 )
|
||||
sheetEl.setAttribute("position", "0.5 0.5 -0.0051")
|
||||
rootEl.appendChild(sheetEl)
|
||||
let page = 0
|
||||
fetch( src ).then( r => r.text() ).then( txt => {
|
||||
const parser = new DOMParser();
|
||||
let doc = parser.parseFromString(txt, "application/xml")
|
||||
Array.from( doc.children[0].children[page].querySelectorAll("text") ).map( (l,n) => {
|
||||
let el = document.createElement("a-entity")
|
||||
el.setAttribute("target", "")
|
||||
el.setAttribute("scale", ".1 .1 .1") // used to make target sphere smaller
|
||||
el.id = "highlightimagefromxml_"+n
|
||||
let x = (l.attributes.left.value*scalingFactor) - .02
|
||||
let y = (1-l.attributes.top.value*scalingFactor) + .18
|
||||
let z = 0
|
||||
el.setAttribute("position", ""+x+" "+ y+ " " +z)
|
||||
el.setAttribute("onpicked", "let el = addNewNote('"+l.textContent+"', '0 0 0', '1 1 1'); el.setAttribute('color', 'black'); el.setAttribute('outline-width', 0); el.object3D.parent = selectedElements.at(-1).element.object3D")
|
||||
// instead append to the current element, break AFrame readability but quick to test
|
||||
el.setAttribute("onreleased", "console.log('"+l.textContent+"')")
|
||||
// 'live-selector-line'
|
||||
rootEl.appendChild(el)
|
||||
})
|
||||
setTimeout( _ => { makeAnchorsVisibleOnTargets() }, 500)
|
||||
setTimeout( _ => { Array.from( test_page_from_q3_pdf_hidden_text.querySelectorAll("a-sphere") ).map( el => el.setAttribute("color","#bbb")) }, 700)
|
||||
// should scale down
|
||||
})
|
||||
return rootEl
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (username && username == "q3_code_editing") {
|
||||
//showFile( "demo_hypertext2025.js" ) // javascript filter not existing, could consider txt.js instead
|
||||
file = "demo_hypertext2025.js"
|
||||
|
||||
Reference in New Issue
Block a user