updated parser: added root-operator / + test & cleanup

This commit is contained in:
Leon van Kammen 2023-06-22 08:48:52 +02:00
parent e3cf693fa7
commit 5584d22e25
11 changed files with 291 additions and 305 deletions

View File

@ -239,7 +239,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.EMBEDDED | xrfragment_XRF.PROMPT;
if(value.length == 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
if(value.length == 0 && key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR);
v.validate(key);
resultMap[key] = v;
@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isClass = new EReg("^[-]?class$","");
this.isRoot = new EReg("^/","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
this.q = { };
@ -350,15 +350,15 @@ xrfragment_Query.prototype = {
}
return;
} else {
if(_gthis.isRoot.match(k)) {
str = HxOverrides.substr(k,1,null);
filter["root"] = true;
} else if(filter["root"] == true) {
Reflect.deleteField(filter,"root");
}
filter["id"] = _gthis.isExclude.match(str) ? false : true;
var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str;
q[key] = filter;
filter["root"] = _gthis.isRoot.match(str);
if(_gthis.isExclude.match(str)) {
str = HxOverrides.substr(str,1,null);
}
if(_gthis.isRoot.match(str)) {
str = HxOverrides.substr(str,1,null);
}
q[str] = filter;
}
};
var _g = 0;
@ -663,6 +663,7 @@ xrf.addEventListener = function(eventName, callback) {
};
xrf.emit = function(eventName, data){
if( typeof data != 'object' ) throw 'emit() requires passing objects'
return xrf.emit.promise(eventName,data)
}
@ -884,11 +885,13 @@ xrf.eval = function( url, model, flags ){ // evaluate fragments in url
model = model || xrf.model
let { THREE, camera } = xrf
let frag = xrf.URI.parse( url, flags || xrf.XRF.NAVIGATOR )
for ( let k in frag ){
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts)
.then( () => xrf.eval.fragment(k,opts) )
}
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts)
.then( () => {
for ( let k in frag ){
xrf.eval.fragment(k,opts)
}
})
}
xrf.eval.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) inside mesh of model
@ -946,15 +949,15 @@ xrf.add = (object) => {
xrf.navigator = {}
xrf.navigator.to = (url,event) => {
xrf.navigator.to = (url,flags) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
return new Promise( (resolve,reject) => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
console.log("xrfragment: navigating to "+url)
console.log(url)
if( !file || xrf.model.file == file ){ // we're already loaded
document.location.hash = `#${hash}` // just update the hash
xrf.eval( url, xrf.model ) // and eval local URI XR fragments
xrf.eval( url, xrf.model, flags ) // and eval local URI XR fragments
return resolve(xrf.model)
}
@ -968,10 +971,13 @@ xrf.navigator.to = (url,event) => {
loader.load( file, function(model){
model.file = file
xrf.add( model.scene )
// only change url when loading *another* file
if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.model = model
xrf.eval( '#', model ) // execute the default projection '#' (if exist)
xrf.eval( url, model ) // and eval URI XR fragments
xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.eval( '#', model ) // execute the default projection '#' (if exist)
xrf.eval( url, model ) // and eval URI XR fragments
if( !hash.match(/pos=/) )
xrf.eval( '#pos=0,0,0' ) // set default position if not specified
resolve(model)
})
})
@ -980,7 +986,7 @@ xrf.navigator.to = (url,event) => {
xrf.navigator.init = () => {
if( xrf.navigator.init.inited ) return
window.addEventListener('popstate', function (event){
xrf.navigator.to( document.location.search.substr(1) + document.location.hash, event)
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
})
xrf.navigator.material = {
selection: new xrf.THREE.LineBasicMaterial({color:0xFF00FF,linewidth:2})
@ -988,6 +994,12 @@ xrf.navigator.init = () => {
xrf.navigator.init.inited = true
}
xrf.navigator.updateHash = (hash) => {
if( hash == document.location.hash || hash.match(/\|/) ) return // skip unnecesary pushState triggers
document.location.hash = hash
xrf.emit('updateHash', {hash} )
}
xrf.navigator.pushState = (file,hash) => {
if( file == document.location.search.substr(1) ) return // page is in its default state
window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` )
@ -995,36 +1007,12 @@ xrf.navigator.pushState = (file,hash) => {
xrf.frag.env = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts
let env = mesh.getObjectByName(v.string)
if( !env ) return console.warn("xrf.env "+v.string+" not found")
env.material.map.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = env.material.map
//scene.texture = env.material.map
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 2;
// apply to meshes *DISABLED* renderer.environment does this
const maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
setTimeout( () => {
scene.traverse( (mesh) => {
//if (mesh.material && mesh.material.map && mesh.material.metalness == 1.0) {
// mesh.material = new THREE.MeshBasicMaterial({ map: mesh.material.map });
// mesh.material.dithering = true
// mesh.material.map.anisotropy = maxAnisotropy;
// mesh.material.needsUpdate = true;
//}
//if (mesh.material && mesh.material.metalness == 1.0 ){
// mesh.material = new THREE.MeshBasicMaterial({
// color:0xffffff,
// emissive: mesh.material.map,
// envMap: env.material.map,
// side: THREE.DoubleSide,
// flatShading: true
// })
// mesh.material.needsUpdate = true
// //mesh.material.envMap = env.material.map;
// //mesh.material.envMap.intensity = 5;
// //mesh.material.needsUpdate = true;
//}
});
},500)
console.log(` └ applied image '${v.string}' as environment map`)
}
/**
@ -1122,10 +1110,8 @@ xrf.frag.href = function(v, opts){
xrf
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
.then( () => {
if( v.string[0] == '#' && v.string.match(/(\||#q)/) ){ // apply modifications to scene *TODO* decide on queries...
console.log("ja")
xrf.eval( v.string, xrf.model, xrf.XRF.PV_OVERRIDE )
}else xrf.navigator.to(v.string) // or let's surf to HREF!
const flags = v.string[0] == '#' && v.string.match(/(\||#q)/) ? xrf.XRF.PV_OVERRIDE : undefined
xrf.navigator.to(v.string,flags) // or let's surf to HREF!
})
}
@ -1173,7 +1159,6 @@ xrf.frag.href = function(v, opts){
*/
xrf.frag.pos = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ setting camera position to "+v.string)
if( !frag.q ){
camera.position.x = v.x
@ -1181,18 +1166,15 @@ xrf.frag.pos = function(v, opts){
camera.position.z = v.z
}
}
const doPredefinedView = (opts) => {
const updatePredefinedView = (opts) => {
let {frag,scene} = opts
const selectionOfInterest = (frag,scene,mesh) => {
let id = frag.string
if(!id) return id // important: ignore empty strings
if( mesh.selection ){
scene.remove(mesh.selection)
delete mesh.selection
}
if( mesh.selection ) return mesh
// Selection of Interest if predefined_view matches object name
if( id == mesh.name || id.substr(1) == mesh.userData.class ){
if( mesh.visible && (id == mesh.name || id.substr(1) == mesh.userData.class) ){
xrf.emit('selection',{...opts,frag})
.then( () => {
const margin = 1.2
@ -1212,39 +1194,51 @@ const doPredefinedView = (opts) => {
if( !id ) return // prevent empty matches
if( mesh.userData[`#${id}`] ){ // get alias
frag = xrf.URI.parse( mesh.userData[`#${id}`], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED )
for ( let k in frag ){
let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('predefinedView',{...opts,frag})
.then( () => xrf.eval.fragment(k,opts) )
}
xrf.emit('predefinedView',{...opts,frag})
.then( () => {
for ( let k in frag ){
let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.eval.fragment(k,opts)
}
})
}
}
const traverseScene = (v,scene) => {
let remove = []
if( !scene ) return
scene.traverse( (mesh) => {
remove.push( selectionOfInterest( v, scene, mesh ) )
predefinedView( v , scene, mesh )
})
remove.filter( (e) => e ).map( (mesh) => {
scene.remove(mesh.selection)
delete mesh.selection
})
}
let pviews = []
for ( let i in frag ) {
let v = frag[i]
if( v.is( xrf.XRF.PV_EXECUTE ) ){
if( v.args ) v = v.args[ xrf.roundrobin(v,xrf.model) ]
// wait for nested instances to arrive at the scene
setTimeout( () => {
if( !scene ) return
scene.traverse( (mesh) => {
selectionOfInterest( v, scene, mesh )
predefinedView( v , scene, mesh )
})
},100)
}
setTimeout( () => traverseScene(v,scene), 100 )
console.dir(v)
if( v.string ) pviews.push(v.string)
}else if( v.is( xrf.XRF.NAVIGATOR ) ) pviews.push(`${i}=${v.string}`)
}
if( pviews.length ) xrf.navigator.updateHash( pviews.join("&") )
}
// when predefined view occurs in url changes
xrf.addEventListener('eval', doPredefinedView )
xrf.addEventListener('eval', updatePredefinedView )
// clicking href url with predefined view
xrf.addEventListener('href', (opts) => {
if( !opts.click || opts.xrf.string[0] != '#' ) return
let frag = xrf.URI.parse( opts.xrf.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED )
doPredefinedView({frag,scene:xrf.scene})
updatePredefinedView({frag,scene:xrf.scene,href:opts.xrf})
})
//let updateUrl = (opts) => {
@ -1295,6 +1289,7 @@ xrf.frag.q = function(v, opts){
let isMeshId = q[i].id != undefined
let isMeshClass = q[i].class != undefined
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId && !isMeshClass
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
if( isMeshId && i == mesh.name ) mesh.visible = q[i].id
if( isMeshClass && i == mesh.userData.class ) mesh.visible = q[i].class
if( isMeshProperty && mesh.userData[i] ) mesh.visible = (new xrf.Query(frag.q.string)).testProperty(i,mesh.userData[i])
@ -1338,18 +1333,20 @@ xrf.frag.src = function(v, opts){
console.log(" └ inserting "+i+" (srcScene)")
srcScene.position.set(0,0,0)
srcScene.rotation.set(0,0,0)
// add interactive elements (href's e.g.)
srcScene.add( xrf.interactive.clone() )
srcScene.traverse( (m) => {
if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion
xrf.eval.mesh(m,{scene,recursive:true})
m.name = mesh.name+"."+m.name // prefix meshname so predefined views don't affect objectnames anymore
m.isSRC = true
})
console.dir(xrf)
if( srcScene.visible ) src.add( srcScene )
}
src.position.copy( mesh.position )
src.rotation.copy( mesh.rotation )
src.scale.copy( mesh.scale )
mesh.add(src)
console.dir(opts)
if( !opts.recursive ) mesh.material.visible = false // lets hide the preview object because deleting disables animations+nested objs
},10)
}
@ -1360,6 +1357,9 @@ window.AFRAME.registerComponent('xrf', {
init: function () {
if( !AFRAME.XRF ) this.initXRFragments()
if( this.data ){
if( document.location.search || document.location.hash.length > 1 ){ // override url
this.data = `${document.location.search.substr(1)}${document.location.hash}`
}
AFRAME.XRF.navigator.to(this.data)
.then( (model) => {
let gets = [ ...document.querySelectorAll('[xrf-get]') ]

20
dist/xrfragment.js vendored
View File

@ -239,7 +239,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.EMBEDDED | xrfragment_XRF.PROMPT;
if(value.length == 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
if(value.length == 0 && key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR);
v.validate(key);
resultMap[key] = v;
@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isClass = new EReg("^[-]?class$","");
this.isRoot = new EReg("^/","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
this.q = { };
@ -350,15 +350,15 @@ xrfragment_Query.prototype = {
}
return;
} else {
if(_gthis.isRoot.match(k)) {
str = HxOverrides.substr(k,1,null);
filter["root"] = true;
} else if(filter["root"] == true) {
Reflect.deleteField(filter,"root");
}
filter["id"] = _gthis.isExclude.match(str) ? false : true;
var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str;
q[key] = filter;
filter["root"] = _gthis.isRoot.match(str);
if(_gthis.isExclude.match(str)) {
str = HxOverrides.substr(str,1,null);
}
if(_gthis.isRoot.match(str)) {
str = HxOverrides.substr(str,1,null);
}
q[str] = filter;
}
};
var _g = 0;

54
dist/xrfragment.lua vendored
View File

@ -1546,7 +1546,7 @@ __xrfragment_Parser.parse = function(key,value,resultMap)
else
Frag_h.session = value1;
end;
if ((__lua_lib_luautf8_Utf8.len(value) == 0) and (Frag_h[key] == nil)) then
if (((__lua_lib_luautf8_Utf8.len(value) == 0) and (__lua_lib_luautf8_Utf8.len(key) > 0)) and (Frag_h[key] == nil)) then
local v = __xrfragment_XRF.new(key, _hx_bit.bor(__xrfragment_XRF.PV_EXECUTE,__xrfragment_XRF.NAVIGATOR));
v:validate(key);
resultMap[key] = v;
@ -1633,7 +1633,7 @@ end
__xrfragment_Query.super = function(self,str)
self.isNumber = EReg.new("^[0-9\\.]+$", "");
self.isClass = EReg.new("^[-]?class$", "");
self.isRoot = EReg.new("^/", "");
self.isRoot = EReg.new("^[-]?/", "");
self.isExclude = EReg.new("^-", "");
self.isProp = EReg.new("^.*:[><=!]?", "");
self.q = _hx_e();
@ -1889,29 +1889,6 @@ __xrfragment_Query.prototype.parse = function(self,str,recurse)
end;
do return end;
else
if (_gthis.isRoot:match(k)) then
local pos = 1;
local len = nil;
if ((len == nil) or (len > (pos + __lua_lib_luautf8_Utf8.len(k)))) then
len = __lua_lib_luautf8_Utf8.len(k);
else
if (len < 0) then
len = __lua_lib_luautf8_Utf8.len(k) + len;
end;
end;
if (pos < 0) then
pos = __lua_lib_luautf8_Utf8.len(k) + pos;
end;
if (pos < 0) then
pos = 0;
end;
str = __lua_lib_luautf8_Utf8.sub(k, pos + 1, pos + len);
filter.root = true;
else
if (Reflect.field(filter, "root") == true) then
Reflect.deleteField(filter, "root");
end;
end;
local value = (function()
local _hx_7
if (_gthis.isExclude:match(str)) then
@ -1920,7 +1897,8 @@ __xrfragment_Query.prototype.parse = function(self,str,recurse)
return _hx_7
end )();
filter.id = value;
local key;
local value = _gthis.isRoot:match(str);
filter.root = value;
if (_gthis.isExclude:match(str)) then
local pos = 1;
local len = nil;
@ -1937,11 +1915,27 @@ __xrfragment_Query.prototype.parse = function(self,str,recurse)
if (pos < 0) then
pos = 0;
end;
key = __lua_lib_luautf8_Utf8.sub(str, pos + 1, pos + len);
else
key = str;
str = __lua_lib_luautf8_Utf8.sub(str, pos + 1, pos + len);
end;
q[key] = filter;
if (_gthis.isRoot:match(str)) then
local pos = 1;
local len = nil;
if ((len == nil) or (len > (pos + __lua_lib_luautf8_Utf8.len(str)))) then
len = __lua_lib_luautf8_Utf8.len(str);
else
if (len < 0) then
len = __lua_lib_luautf8_Utf8.len(str) + len;
end;
end;
if (pos < 0) then
pos = __lua_lib_luautf8_Utf8.len(str) + pos;
end;
if (pos < 0) then
pos = 0;
end;
str = __lua_lib_luautf8_Utf8.sub(str, pos + 1, pos + len);
end;
q[str] = filter;
end;
end;
local _g = 0;

View File

@ -239,7 +239,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.EMBEDDED | xrfragment_XRF.PROMPT;
if(value.length == 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
if(value.length == 0 && key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR);
v.validate(key);
resultMap[key] = v;
@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isClass = new EReg("^[-]?class$","");
this.isRoot = new EReg("^/","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
this.q = { };
@ -350,15 +350,15 @@ xrfragment_Query.prototype = {
}
return;
} else {
if(_gthis.isRoot.match(k)) {
str = HxOverrides.substr(k,1,null);
filter["root"] = true;
} else if(filter["root"] == true) {
Reflect.deleteField(filter,"root");
}
filter["id"] = _gthis.isExclude.match(str) ? false : true;
var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str;
q[key] = filter;
filter["root"] = _gthis.isRoot.match(str);
if(_gthis.isExclude.match(str)) {
str = HxOverrides.substr(str,1,null);
}
if(_gthis.isRoot.match(str)) {
str = HxOverrides.substr(str,1,null);
}
q[str] = filter;
}
};
var _g = 0;

24
dist/xrfragment.py vendored
View File

@ -1316,7 +1316,7 @@ class xrfragment_Parser:
Frag.h["unit"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["description"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["session"] = (((((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.EMBEDDED) | xrfragment_XRF.PROMPT)
if ((len(value) == 0) and (not (key in Frag.h))):
if (((len(value) == 0) and ((len(key) > 0))) and (not (key in Frag.h))):
v = xrfragment_XRF(key,(xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR))
v.validate(key)
setattr(resultMap,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),v)
@ -1345,7 +1345,7 @@ class xrfragment_Query:
def __init__(self,_hx_str):
self.isNumber = EReg("^[0-9\\.]+$","")
self.isClass = EReg("^[-]?class$","")
self.isRoot = EReg("^/","")
self.isRoot = EReg("^[-]?/","")
self.isExclude = EReg("^-","")
self.isProp = EReg("^.*:[><=!]?","")
self.q = _hx_AnonObject({})
@ -1432,21 +1432,23 @@ class xrfragment_Query:
setattr(q,(("_hx_" + k) if ((k in python_Boot.keywords)) else (("_hx_" + k) if (((((len(k) > 2) and ((ord(k[0]) == 95))) and ((ord(k[1]) == 95))) and ((ord(k[(len(k) - 1)]) != 95)))) else k)),_hx_filter)
return
else:
_this = _gthis.isRoot
_this.matchObj = python_lib_Re.search(_this.pattern,k)
if (_this.matchObj is not None):
_hx_str = HxString.substr(k,1,None)
setattr(_hx_filter,(("_hx_" + "root") if (("root" in python_Boot.keywords)) else (("_hx_" + "root") if (((((len("root") > 2) and ((ord("root"[0]) == 95))) and ((ord("root"[1]) == 95))) and ((ord("root"[(len("root") - 1)]) != 95)))) else "root")),True)
elif (Reflect.field(_hx_filter,"root") == True):
Reflect.deleteField(_hx_filter,"root")
_this = _gthis.isExclude
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
value = (False if ((_this.matchObj is not None)) else True)
setattr(_hx_filter,(("_hx_" + "id") if (("id" in python_Boot.keywords)) else (("_hx_" + "id") if (((((len("id") > 2) and ((ord("id"[0]) == 95))) and ((ord("id"[1]) == 95))) and ((ord("id"[(len("id") - 1)]) != 95)))) else "id")),value)
_this = _gthis.isRoot
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
value = (_this.matchObj is not None)
setattr(_hx_filter,(("_hx_" + "root") if (("root" in python_Boot.keywords)) else (("_hx_" + "root") if (((((len("root") > 2) and ((ord("root"[0]) == 95))) and ((ord("root"[1]) == 95))) and ((ord("root"[(len("root") - 1)]) != 95)))) else "root")),value)
_this = _gthis.isExclude
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
key = (HxString.substr(_hx_str,1,None) if ((_this.matchObj is not None)) else _hx_str)
setattr(q,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),_hx_filter)
if (_this.matchObj is not None):
_hx_str = HxString.substr(_hx_str,1,None)
_this = _gthis.isRoot
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
_hx_str = HxString.substr(_hx_str,1,None)
setattr(q,(("_hx_" + _hx_str) if ((_hx_str in python_Boot.keywords)) else (("_hx_" + _hx_str) if (((((len(_hx_str) > 2) and ((ord(_hx_str[0]) == 95))) and ((ord(_hx_str[1]) == 95))) and ((ord(_hx_str[(len(_hx_str) - 1)]) != 95)))) else _hx_str)),_hx_filter)
process = _hx_local_0
_g = 0
_g1 = len(token)

View File

@ -239,7 +239,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.EMBEDDED | xrfragment_XRF.PROMPT;
if(value.length == 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
if(value.length == 0 && key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR);
v.validate(key);
resultMap[key] = v;
@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isClass = new EReg("^[-]?class$","");
this.isRoot = new EReg("^/","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
this.q = { };
@ -350,15 +350,15 @@ xrfragment_Query.prototype = {
}
return;
} else {
if(_gthis.isRoot.match(k)) {
str = HxOverrides.substr(k,1,null);
filter["root"] = true;
} else if(filter["root"] == true) {
Reflect.deleteField(filter,"root");
}
filter["id"] = _gthis.isExclude.match(str) ? false : true;
var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str;
q[key] = filter;
filter["root"] = _gthis.isRoot.match(str);
if(_gthis.isExclude.match(str)) {
str = HxOverrides.substr(str,1,null);
}
if(_gthis.isRoot.match(str)) {
str = HxOverrides.substr(str,1,null);
}
q[str] = filter;
}
};
var _g = 0;
@ -663,6 +663,7 @@ xrf.addEventListener = function(eventName, callback) {
};
xrf.emit = function(eventName, data){
if( typeof data != 'object' ) throw 'emit() requires passing objects'
return xrf.emit.promise(eventName,data)
}
@ -884,11 +885,13 @@ xrf.eval = function( url, model, flags ){ // evaluate fragments in url
model = model || xrf.model
let { THREE, camera } = xrf
let frag = xrf.URI.parse( url, flags || xrf.XRF.NAVIGATOR )
for ( let k in frag ){
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts)
.then( () => xrf.eval.fragment(k,opts) )
}
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts)
.then( () => {
for ( let k in frag ){
xrf.eval.fragment(k,opts)
}
})
}
xrf.eval.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) inside mesh of model
@ -946,15 +949,15 @@ xrf.add = (object) => {
xrf.navigator = {}
xrf.navigator.to = (url,event) => {
xrf.navigator.to = (url,flags) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
return new Promise( (resolve,reject) => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
console.log("xrfragment: navigating to "+url)
console.log(url)
if( !file || xrf.model.file == file ){ // we're already loaded
document.location.hash = `#${hash}` // just update the hash
xrf.eval( url, xrf.model ) // and eval local URI XR fragments
xrf.eval( url, xrf.model, flags ) // and eval local URI XR fragments
return resolve(xrf.model)
}
@ -968,10 +971,13 @@ xrf.navigator.to = (url,event) => {
loader.load( file, function(model){
model.file = file
xrf.add( model.scene )
// only change url when loading *another* file
if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.model = model
xrf.eval( '#', model ) // execute the default projection '#' (if exist)
xrf.eval( url, model ) // and eval URI XR fragments
xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.eval( '#', model ) // execute the default projection '#' (if exist)
xrf.eval( url, model ) // and eval URI XR fragments
if( !hash.match(/pos=/) )
xrf.eval( '#pos=0,0,0' ) // set default position if not specified
resolve(model)
})
})
@ -980,7 +986,7 @@ xrf.navigator.to = (url,event) => {
xrf.navigator.init = () => {
if( xrf.navigator.init.inited ) return
window.addEventListener('popstate', function (event){
xrf.navigator.to( document.location.search.substr(1) + document.location.hash, event)
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
})
xrf.navigator.material = {
selection: new xrf.THREE.LineBasicMaterial({color:0xFF00FF,linewidth:2})
@ -988,6 +994,12 @@ xrf.navigator.init = () => {
xrf.navigator.init.inited = true
}
xrf.navigator.updateHash = (hash) => {
if( hash == document.location.hash || hash.match(/\|/) ) return // skip unnecesary pushState triggers
document.location.hash = hash
xrf.emit('updateHash', {hash} )
}
xrf.navigator.pushState = (file,hash) => {
if( file == document.location.search.substr(1) ) return // page is in its default state
window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` )
@ -995,36 +1007,12 @@ xrf.navigator.pushState = (file,hash) => {
xrf.frag.env = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts
let env = mesh.getObjectByName(v.string)
if( !env ) return console.warn("xrf.env "+v.string+" not found")
env.material.map.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = env.material.map
//scene.texture = env.material.map
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 2;
// apply to meshes *DISABLED* renderer.environment does this
const maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
setTimeout( () => {
scene.traverse( (mesh) => {
//if (mesh.material && mesh.material.map && mesh.material.metalness == 1.0) {
// mesh.material = new THREE.MeshBasicMaterial({ map: mesh.material.map });
// mesh.material.dithering = true
// mesh.material.map.anisotropy = maxAnisotropy;
// mesh.material.needsUpdate = true;
//}
//if (mesh.material && mesh.material.metalness == 1.0 ){
// mesh.material = new THREE.MeshBasicMaterial({
// color:0xffffff,
// emissive: mesh.material.map,
// envMap: env.material.map,
// side: THREE.DoubleSide,
// flatShading: true
// })
// mesh.material.needsUpdate = true
// //mesh.material.envMap = env.material.map;
// //mesh.material.envMap.intensity = 5;
// //mesh.material.needsUpdate = true;
//}
});
},500)
console.log(` └ applied image '${v.string}' as environment map`)
}
/**
@ -1122,10 +1110,8 @@ xrf.frag.href = function(v, opts){
xrf
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
.then( () => {
if( v.string[0] == '#' && v.string.match(/(\||#q)/) ){ // apply modifications to scene *TODO* decide on queries...
console.log("ja")
xrf.eval( v.string, xrf.model, xrf.XRF.PV_OVERRIDE )
}else xrf.navigator.to(v.string) // or let's surf to HREF!
const flags = v.string[0] == '#' && v.string.match(/(\||#q)/) ? xrf.XRF.PV_OVERRIDE : undefined
xrf.navigator.to(v.string,flags) // or let's surf to HREF!
})
}
@ -1173,7 +1159,6 @@ xrf.frag.href = function(v, opts){
*/
xrf.frag.pos = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ setting camera position to "+v.string)
if( !frag.q ){
camera.position.x = v.x
@ -1181,18 +1166,15 @@ xrf.frag.pos = function(v, opts){
camera.position.z = v.z
}
}
const doPredefinedView = (opts) => {
const updatePredefinedView = (opts) => {
let {frag,scene} = opts
const selectionOfInterest = (frag,scene,mesh) => {
let id = frag.string
if(!id) return id // important: ignore empty strings
if( mesh.selection ){
scene.remove(mesh.selection)
delete mesh.selection
}
if( mesh.selection ) return mesh
// Selection of Interest if predefined_view matches object name
if( id == mesh.name || id.substr(1) == mesh.userData.class ){
if( mesh.visible && (id == mesh.name || id.substr(1) == mesh.userData.class) ){
xrf.emit('selection',{...opts,frag})
.then( () => {
const margin = 1.2
@ -1212,39 +1194,51 @@ const doPredefinedView = (opts) => {
if( !id ) return // prevent empty matches
if( mesh.userData[`#${id}`] ){ // get alias
frag = xrf.URI.parse( mesh.userData[`#${id}`], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED )
for ( let k in frag ){
let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('predefinedView',{...opts,frag})
.then( () => xrf.eval.fragment(k,opts) )
}
xrf.emit('predefinedView',{...opts,frag})
.then( () => {
for ( let k in frag ){
let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.eval.fragment(k,opts)
}
})
}
}
const traverseScene = (v,scene) => {
let remove = []
if( !scene ) return
scene.traverse( (mesh) => {
remove.push( selectionOfInterest( v, scene, mesh ) )
predefinedView( v , scene, mesh )
})
remove.filter( (e) => e ).map( (mesh) => {
scene.remove(mesh.selection)
delete mesh.selection
})
}
let pviews = []
for ( let i in frag ) {
let v = frag[i]
if( v.is( xrf.XRF.PV_EXECUTE ) ){
if( v.args ) v = v.args[ xrf.roundrobin(v,xrf.model) ]
// wait for nested instances to arrive at the scene
setTimeout( () => {
if( !scene ) return
scene.traverse( (mesh) => {
selectionOfInterest( v, scene, mesh )
predefinedView( v , scene, mesh )
})
},100)
}
setTimeout( () => traverseScene(v,scene), 100 )
console.dir(v)
if( v.string ) pviews.push(v.string)
}else if( v.is( xrf.XRF.NAVIGATOR ) ) pviews.push(`${i}=${v.string}`)
}
if( pviews.length ) xrf.navigator.updateHash( pviews.join("&") )
}
// when predefined view occurs in url changes
xrf.addEventListener('eval', doPredefinedView )
xrf.addEventListener('eval', updatePredefinedView )
// clicking href url with predefined view
xrf.addEventListener('href', (opts) => {
if( !opts.click || opts.xrf.string[0] != '#' ) return
let frag = xrf.URI.parse( opts.xrf.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED )
doPredefinedView({frag,scene:xrf.scene})
updatePredefinedView({frag,scene:xrf.scene,href:opts.xrf})
})
//let updateUrl = (opts) => {
@ -1295,6 +1289,7 @@ xrf.frag.q = function(v, opts){
let isMeshId = q[i].id != undefined
let isMeshClass = q[i].class != undefined
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId && !isMeshClass
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
if( isMeshId && i == mesh.name ) mesh.visible = q[i].id
if( isMeshClass && i == mesh.userData.class ) mesh.visible = q[i].class
if( isMeshProperty && mesh.userData[i] ) mesh.visible = (new xrf.Query(frag.q.string)).testProperty(i,mesh.userData[i])
@ -1338,18 +1333,20 @@ xrf.frag.src = function(v, opts){
console.log(" └ inserting "+i+" (srcScene)")
srcScene.position.set(0,0,0)
srcScene.rotation.set(0,0,0)
// add interactive elements (href's e.g.)
srcScene.add( xrf.interactive.clone() )
srcScene.traverse( (m) => {
if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion
xrf.eval.mesh(m,{scene,recursive:true})
m.name = mesh.name+"."+m.name // prefix meshname so predefined views don't affect objectnames anymore
m.isSRC = true
})
console.dir(xrf)
if( srcScene.visible ) src.add( srcScene )
}
src.position.copy( mesh.position )
src.rotation.copy( mesh.rotation )
src.scale.copy( mesh.scale )
mesh.add(src)
console.dir(opts)
if( !opts.recursive ) mesh.material.visible = false // lets hide the preview object because deleting disables animations+nested objs
},10)
}

View File

@ -239,7 +239,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.EMBEDDED | xrfragment_XRF.PROMPT;
if(value.length == 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
if(value.length == 0 && key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR);
v.validate(key);
resultMap[key] = v;
@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isClass = new EReg("^[-]?class$","");
this.isRoot = new EReg("^/","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
this.q = { };
@ -350,15 +350,15 @@ xrfragment_Query.prototype = {
}
return;
} else {
if(_gthis.isRoot.match(k)) {
str = HxOverrides.substr(k,1,null);
filter["root"] = true;
} else if(filter["root"] == true) {
Reflect.deleteField(filter,"root");
}
filter["id"] = _gthis.isExclude.match(str) ? false : true;
var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str;
q[key] = filter;
filter["root"] = _gthis.isRoot.match(str);
if(_gthis.isExclude.match(str)) {
str = HxOverrides.substr(str,1,null);
}
if(_gthis.isRoot.match(str)) {
str = HxOverrides.substr(str,1,null);
}
q[str] = filter;
}
};
var _g = 0;
@ -663,6 +663,7 @@ xrf.addEventListener = function(eventName, callback) {
};
xrf.emit = function(eventName, data){
if( typeof data != 'object' ) throw 'emit() requires passing objects'
return xrf.emit.promise(eventName,data)
}
@ -884,11 +885,13 @@ xrf.eval = function( url, model, flags ){ // evaluate fragments in url
model = model || xrf.model
let { THREE, camera } = xrf
let frag = xrf.URI.parse( url, flags || xrf.XRF.NAVIGATOR )
for ( let k in frag ){
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts)
.then( () => xrf.eval.fragment(k,opts) )
}
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts)
.then( () => {
for ( let k in frag ){
xrf.eval.fragment(k,opts)
}
})
}
xrf.eval.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) inside mesh of model
@ -946,15 +949,15 @@ xrf.add = (object) => {
xrf.navigator = {}
xrf.navigator.to = (url,event) => {
xrf.navigator.to = (url,flags) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
return new Promise( (resolve,reject) => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
console.log("xrfragment: navigating to "+url)
console.log(url)
if( !file || xrf.model.file == file ){ // we're already loaded
document.location.hash = `#${hash}` // just update the hash
xrf.eval( url, xrf.model ) // and eval local URI XR fragments
xrf.eval( url, xrf.model, flags ) // and eval local URI XR fragments
return resolve(xrf.model)
}
@ -968,10 +971,13 @@ xrf.navigator.to = (url,event) => {
loader.load( file, function(model){
model.file = file
xrf.add( model.scene )
// only change url when loading *another* file
if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.model = model
xrf.eval( '#', model ) // execute the default projection '#' (if exist)
xrf.eval( url, model ) // and eval URI XR fragments
xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.eval( '#', model ) // execute the default projection '#' (if exist)
xrf.eval( url, model ) // and eval URI XR fragments
if( !hash.match(/pos=/) )
xrf.eval( '#pos=0,0,0' ) // set default position if not specified
resolve(model)
})
})
@ -980,7 +986,7 @@ xrf.navigator.to = (url,event) => {
xrf.navigator.init = () => {
if( xrf.navigator.init.inited ) return
window.addEventListener('popstate', function (event){
xrf.navigator.to( document.location.search.substr(1) + document.location.hash, event)
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
})
xrf.navigator.material = {
selection: new xrf.THREE.LineBasicMaterial({color:0xFF00FF,linewidth:2})
@ -988,6 +994,12 @@ xrf.navigator.init = () => {
xrf.navigator.init.inited = true
}
xrf.navigator.updateHash = (hash) => {
if( hash == document.location.hash || hash.match(/\|/) ) return // skip unnecesary pushState triggers
document.location.hash = hash
xrf.emit('updateHash', {hash} )
}
xrf.navigator.pushState = (file,hash) => {
if( file == document.location.search.substr(1) ) return // page is in its default state
window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` )
@ -995,36 +1007,12 @@ xrf.navigator.pushState = (file,hash) => {
xrf.frag.env = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts
let env = mesh.getObjectByName(v.string)
if( !env ) return console.warn("xrf.env "+v.string+" not found")
env.material.map.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = env.material.map
//scene.texture = env.material.map
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 2;
// apply to meshes *DISABLED* renderer.environment does this
const maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
setTimeout( () => {
scene.traverse( (mesh) => {
//if (mesh.material && mesh.material.map && mesh.material.metalness == 1.0) {
// mesh.material = new THREE.MeshBasicMaterial({ map: mesh.material.map });
// mesh.material.dithering = true
// mesh.material.map.anisotropy = maxAnisotropy;
// mesh.material.needsUpdate = true;
//}
//if (mesh.material && mesh.material.metalness == 1.0 ){
// mesh.material = new THREE.MeshBasicMaterial({
// color:0xffffff,
// emissive: mesh.material.map,
// envMap: env.material.map,
// side: THREE.DoubleSide,
// flatShading: true
// })
// mesh.material.needsUpdate = true
// //mesh.material.envMap = env.material.map;
// //mesh.material.envMap.intensity = 5;
// //mesh.material.needsUpdate = true;
//}
});
},500)
console.log(` └ applied image '${v.string}' as environment map`)
}
/**
@ -1122,10 +1110,8 @@ xrf.frag.href = function(v, opts){
xrf
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
.then( () => {
if( v.string[0] == '#' && v.string.match(/(\||#q)/) ){ // apply modifications to scene *TODO* decide on queries...
console.log("ja")
xrf.eval( v.string, xrf.model, xrf.XRF.PV_OVERRIDE )
}else xrf.navigator.to(v.string) // or let's surf to HREF!
const flags = v.string[0] == '#' && v.string.match(/(\||#q)/) ? xrf.XRF.PV_OVERRIDE : undefined
xrf.navigator.to(v.string,flags) // or let's surf to HREF!
})
}
@ -1173,7 +1159,6 @@ xrf.frag.href = function(v, opts){
*/
xrf.frag.pos = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ setting camera position to "+v.string)
if( !frag.q ){
camera.position.x = v.x
@ -1181,18 +1166,15 @@ xrf.frag.pos = function(v, opts){
camera.position.z = v.z
}
}
const doPredefinedView = (opts) => {
const updatePredefinedView = (opts) => {
let {frag,scene} = opts
const selectionOfInterest = (frag,scene,mesh) => {
let id = frag.string
if(!id) return id // important: ignore empty strings
if( mesh.selection ){
scene.remove(mesh.selection)
delete mesh.selection
}
if( mesh.selection ) return mesh
// Selection of Interest if predefined_view matches object name
if( id == mesh.name || id.substr(1) == mesh.userData.class ){
if( mesh.visible && (id == mesh.name || id.substr(1) == mesh.userData.class) ){
xrf.emit('selection',{...opts,frag})
.then( () => {
const margin = 1.2
@ -1212,39 +1194,51 @@ const doPredefinedView = (opts) => {
if( !id ) return // prevent empty matches
if( mesh.userData[`#${id}`] ){ // get alias
frag = xrf.URI.parse( mesh.userData[`#${id}`], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED )
for ( let k in frag ){
let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('predefinedView',{...opts,frag})
.then( () => xrf.eval.fragment(k,opts) )
}
xrf.emit('predefinedView',{...opts,frag})
.then( () => {
for ( let k in frag ){
let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.eval.fragment(k,opts)
}
})
}
}
const traverseScene = (v,scene) => {
let remove = []
if( !scene ) return
scene.traverse( (mesh) => {
remove.push( selectionOfInterest( v, scene, mesh ) )
predefinedView( v , scene, mesh )
})
remove.filter( (e) => e ).map( (mesh) => {
scene.remove(mesh.selection)
delete mesh.selection
})
}
let pviews = []
for ( let i in frag ) {
let v = frag[i]
if( v.is( xrf.XRF.PV_EXECUTE ) ){
if( v.args ) v = v.args[ xrf.roundrobin(v,xrf.model) ]
// wait for nested instances to arrive at the scene
setTimeout( () => {
if( !scene ) return
scene.traverse( (mesh) => {
selectionOfInterest( v, scene, mesh )
predefinedView( v , scene, mesh )
})
},100)
}
setTimeout( () => traverseScene(v,scene), 100 )
console.dir(v)
if( v.string ) pviews.push(v.string)
}else if( v.is( xrf.XRF.NAVIGATOR ) ) pviews.push(`${i}=${v.string}`)
}
if( pviews.length ) xrf.navigator.updateHash( pviews.join("&") )
}
// when predefined view occurs in url changes
xrf.addEventListener('eval', doPredefinedView )
xrf.addEventListener('eval', updatePredefinedView )
// clicking href url with predefined view
xrf.addEventListener('href', (opts) => {
if( !opts.click || opts.xrf.string[0] != '#' ) return
let frag = xrf.URI.parse( opts.xrf.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED )
doPredefinedView({frag,scene:xrf.scene})
updatePredefinedView({frag,scene:xrf.scene,href:opts.xrf})
})
//let updateUrl = (opts) => {
@ -1295,6 +1289,7 @@ xrf.frag.q = function(v, opts){
let isMeshId = q[i].id != undefined
let isMeshClass = q[i].class != undefined
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId && !isMeshClass
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
if( isMeshId && i == mesh.name ) mesh.visible = q[i].id
if( isMeshClass && i == mesh.userData.class ) mesh.visible = q[i].class
if( isMeshProperty && mesh.userData[i] ) mesh.visible = (new xrf.Query(frag.q.string)).testProperty(i,mesh.userData[i])
@ -1338,18 +1333,20 @@ xrf.frag.src = function(v, opts){
console.log(" └ inserting "+i+" (srcScene)")
srcScene.position.set(0,0,0)
srcScene.rotation.set(0,0,0)
// add interactive elements (href's e.g.)
srcScene.add( xrf.interactive.clone() )
srcScene.traverse( (m) => {
if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion
xrf.eval.mesh(m,{scene,recursive:true})
m.name = mesh.name+"."+m.name // prefix meshname so predefined views don't affect objectnames anymore
m.isSRC = true
})
console.dir(xrf)
if( srcScene.visible ) src.add( srcScene )
}
src.position.copy( mesh.position )
src.rotation.copy( mesh.rotation )
src.scale.copy( mesh.scale )
mesh.add(src)
console.dir(opts)
if( !opts.recursive ) mesh.material.visible = false // lets hide the preview object because deleting disables animations+nested objs
},10)
}

View File

@ -44,10 +44,7 @@ class Test {
if( item.expect.fn == "equal.xy" ) valid = equalXY(res,item);
if( item.expect.fn == "equal.xyz" ) valid = equalXYZ(res,item);
if( item.expect.fn == "equal.multi" ) valid = equalMulti(res, item);
if( item.expect.fn == "testQueryRoot" ){
if( !item.expect.out ) valid = !q.get()[ item.expect.input[0] ].root;
else valid = item.expect.out == q.get()[ item.expect.input[0] ].root;
}
if( item.expect.fn == "testQueryRoot" ) valid = item.expect.out == q.get()[ item.expect.input[0] ].root;
var ok:String = valid ? "[ ] " : "[ ] ";
trace( ok + item.fn + ": '" + item.data + "'" + (item.label ? " (" + (item.label?item.label:item.expect.fn) +")" : ""));
if( !valid ) errors += 1;

View File

@ -61,7 +61,7 @@ class Parser {
*/
// dynamic fragments cases: predefined views & assign/binds
if( value.length == 0 && !Frag.exists(key) ){
if( value.length == 0 && key.length > 0 && !Frag.exists(key) ){
var v:XRF = new XRF(key, XRF.PV_EXECUTE | XRF.NAVIGATOR );
v.validate(key); // will fail but will parse multiple args for us (separated by |)
resultMap.set(key, v );

View File

@ -44,7 +44,7 @@ class Query {
private var q:haxe.DynamicAccess<Dynamic> = {};
private var isProp:EReg = ~/^.*:[><=!]?/;
private var isExclude:EReg = ~/^-/;
private var isRoot:EReg = ~/^\//;
private var isRoot:EReg = ~/^[-]?\//;
private var isClass:EReg = ~/^[-]?class$/;
private var isNumber:EReg = ~/^[0-9\.]+$/;
@ -104,12 +104,11 @@ class Query {
}
return;
}else{ // id
if( isRoot.match(k) ){
str = k.substr(1); // convert "/foo" to "foo"
filter[ "root" ] = true;
}else if( filter[ "root" ] == true ) filter.remove("root"); // undo root-only
filter[ "id" ] = isExclude.match(str) ? false: true;
q.set( (isExclude.match(str) ? str.substr(1) : str ) ,filter );
filter[ "id" ] = isExclude.match(str) ? false: true;
filter[ "root" ] = isRoot.match(str) ? true: false;
if( isExclude.match(str) ) str = str.substr(1); // convert '-foo' into 'foo'
if( isRoot.match(str) ) str = str.substr(1); // convert '/foo' into 'foo'
q.set( str ,filter );
}
}
for( i in 0...token.length ) process( expandAliases(token[i]) );

View File

@ -18,10 +18,10 @@ class XRF {
public static var QUERY_OPERATOR:Int = 4; // fragment will be applied to result of queryselecto
public static var PROMPT:Int = 8; // ask user whether this fragment value can be changed
public static var ROUNDROBIN:Int = 16; // evaluation of this (multi) value can be roundrobined
public static var NAVIGATOR:Int = 32; // fragment can be overridden by (manual) browser URI change
public static var EMBEDDED:Int = 64; // fragment can be overridden by an embedded URL
public static var PV_OVERRIDE:Int = 128; // fragment can be overridden when specified in predefined view value
public static var PV_EXECUTE:Int = 256; // fragment can be overridden by (manual) browser URI change
public static var NAVIGATOR:Int = 32; // fragment can be overridden by (manual) browser URI change
public static var EMBEDDED:Int = 64; // fragment can be overridden by an embedded URL
public static var PV_OVERRIDE:Int = 128; // embedded fragment can be overridden when specified in predefined view value
public static var PV_EXECUTE:Int = 256; // predefined view
// high-level value-types (powers of 2)
public static var T_COLOR:Int = 8192;