Public
Edited
May 7, 2023
Insert cell
Insert cell
x3dschema = await fetch ('https://gist.githubusercontent.com/andreasplesch/eb344010e0d292bca6181dfaf115b43e/raw/9f0465f106086b44ba1301f11a6ed1099bf5e2a4/x3d-3.3-JSONSchema-AP.json').then (r => r.json())
Insert cell
allNodes = Object.keys(x3dschema.definitions["-allNodes"].items.properties)
Insert cell
x3dschema.definitions['@geoSystem']

Insert cell
getChildrenNodes = function (name) {
const n = [];
let p;
for ( p in x3dschema.definitions[name]?.properties) {
if (! p.startsWith("@")) { //not attributes
const v = x3dschema.definitions[name].properties[p];
if (p.startsWith("-")) {
let children=[];
if ( v.properties ) {
children = Object.keys( v.properties ); // node fields
}
if ( v.items ) {
children = Object.keys( v.items.properties ); // node fields
}
else { // ref
const path = v['$ref']?.split('/');
if (path) {
const nfield = x3dschema.definitions[path.slice(-1)];
if (nfield.properties) { //SFNode
children = Object.keys(nfield.properties);
}
if (nfield.items) { //MFNode
children = Object.keys(nfield.items.properties);
}
}
}
n.push(...children);
}
else {
if (! (v.type && v.type === 'string')) n.push(p); //statement objects
}
}
}
return n.filter( n => n !== "#comment" )
}
Insert cell
getChildrenNodes('Scene')
Insert cell
x3dschema.definitions.Scene.properties['-children']
Insert cell
# xml from spec
Insert cell
allAttr= new DOMParser().parseFromString(xml, 'text/xml')
Insert cell
allXMLNodes = allAttr.children[0].children
Insert cell
attr2Obj = function(node){ let result={}; node.getAttributeNames().forEach( (a) => { result[a]=[node.getAttribute(a)] } ); return result }
Insert cell
attr2Obj(allXMLNodes[6])
Insert cell
Insert cell
getAttributeEnums = function( nodeName, attributeName ) {
let enums = [];
let attributes = x3dschema.definitions[nodeName]?.properties;
let attribute = attributes && attributes['@' + attributeName];
if ( attribute && attribute.enum ) enums = attribute.enum;
if ( attribute && attribute.items && attribute.items.enum ) enums = attribute.items.enum.map( s => `"${s}"` )
return enums
}
Insert cell
tags = {
let t = {};
[...allXMLNodes].forEach( (n) => {
let nodeName = n.localName;
let allAttr = attr2Obj(n);
for ( let attr in allAttr ) {
let enums = getAttributeEnums(nodeName, attr);
allAttr[attr].push( ...enums ); // add to keep default on top
}
t[n.localName]={attrs: allAttr, children: getChildrenNodes(n.localName)} });
return t }
Insert cell
hints = JSON.stringify(tags)
Insert cell
Insert cell
x3duom4 = fetch("https://gist.githubusercontent.com/andreasplesch/1ab4d9635cefda4eeb9ec797553c4ece/raw/cc44ae567c08389e184814e6be6509547a07aa80/X3dUnifiedObjectModel-4.0.xml").then((response) => response.text()).then( (t) => new DOMParser().parseFromString(t, 'text/xml'))
Insert cell
ConcreteNodes = x3duom4.querySelector('ConcreteNodes')
Insert cell
concreteNodes = [...x3duom4.querySelector('ConcreteNodes').querySelectorAll('ConcreteNode')]
Insert cell
concreteNodes.map( n => n.getAttribute('name') )
Insert cell
concreteNodes.map( n => [...n.querySelectorAll('[acceptableNodeTypes]')].map( f => resolveAcceptable(f.getAttribute('acceptableNodeTypes'))))
Insert cell
abstractNodes = [...x3duom4.querySelector('AbstractNodeTypes').querySelectorAll('AbstractNodeType')]
Insert cell
abstractObjects = [...x3duom4.querySelector('AbstractObjectTypes').querySelectorAll('AbstractObjectType')]
Insert cell
nodeTypes='X3DGroupingNode'
Insert cell
resolveAcceptable = function (typeNames) {
let resolved = []
resolved = typeNames.split("|")
resolved = resolved.map( t => {
if ( t.startsWith('X3D' ) ) {
let basedOn = concreteNodes.filter( n => n.querySelectorAll(`[baseType=${t}]`).length ) ;
let subNTypes = abstractNodes.filter( n => n.querySelectorAll(`[baseType=${t}]`).length );
//recursive subTypes ?
return [...basedOn].map( n => n.getAttribute('name'));
}
return t
})
return resolved.flat()
}
Insert cell
resolveAcceptable(nodeTypes)
Insert cell
Math.min(...[...concreteNodes].map( n => n.querySelectorAll('[acceptableNodeTypes]').length - n.querySelectorAll('[type$="FNode"]').length))
Insert cell
## enums
Insert cell
hintNode = "FontStyle"
Insert cell
hintField = "family"
Insert cell
x3domhints[hintNode].attrs[hintField]
Insert cell
[...x3duom4.querySelector(`[name=${hintNode}] [name=${hintField}]`).querySelectorAll('enumeration')].map( e => e.getAttribute('value'))
Insert cell
x3domhints[hintNode].attrs[hintField]
Insert cell
getEnums = function( hintNode, hintField ) {
var fieldEle = x3duom4.querySelector(`[name=${hintNode}] [name=${hintField}]`);
var enums = [];
if (fieldEle) {
enums = [...fieldEle.querySelectorAll('enumeration')]
.map( e => e.getAttribute('value'))
}
return enums
}
Insert cell
Insert cell
Insert cell
x3dom = window.x3dom
Insert cell
comps = Object.keys(x3dom.components)
Insert cell
dd = (new x3dom.components.CADGeometry.QuadSet())
Insert cell
dd.typeName()
Insert cell
ee=dd._cf.coord.type

Insert cell
x3dom.nodeTypes.Anchor.superClass.superClass.superClass.superClass.superClass
Insert cell
inheritsFrom = function (node, superClass) {
while (node.superClass) {
if ( node.superClass == superClass ) return true;
node = node.superClass;
}
return false
}
Insert cell
inheritsFrom(x3dom.nodeTypes.Anchor, x3dom.nodeTypes.X3DNode)
Insert cell
getx3domAttr = function (node) {
var a = {};
Object.keys(node?._vf).forEach( k => {
a[k] = [ node._vf[k].toString() ];
a[k].push(...getEnums(node.typeName(), k));
});
return a
}

Insert cell
getx3domAttr(dd)
Insert cell
getx3domChildTypes = function ( superClass ) {
var childTypes = [];
for ( var n in x3dom.nodeTypes ) {
if ( inheritsFrom( x3dom.nodeTypes[n], superClass ) ) childTypes.push( n )
}
return childTypes
}
Insert cell
getx3domChildTypes( x3dom.nodeTypes.X3DAppearanceChildNode )
Insert cell
getx3domChildren = function (node) {
var children = []
for ( var cf in node?._cf ) {
children.push(getx3domChildTypes(node._cf[cf].type));
}
return children.flat().filter( name => ! name.startsWith('X3D') )
}
Insert cell
getx3domChildren( new x3dom.nodeTypes.Appearance() )
Insert cell
nodes = comps.map( c => Object.keys(x3dom.components[c]).filter( n => !n.startsWith('X3D')).map( n => x3dom.components[c][n])).flat()
Insert cell
x3domhints = {
var h = {};
nodes.forEach( n => {
try {
var node = new n();
h[node.typeName()] = {
attrs: getx3domAttr(node),
children: getx3domChildren(node)
}
} catch (m) {};
})
return h
}
Insert cell
JSON.stringify(x3domhints)
Insert cell
Insert cell
jlib = require ('json-schema-library')
Insert cell
limit = {
jlib.settings.GET_TEMPLATE_RECURSION_LIMIT = 1;
return jlib.settings.GET_TEMPLATE_RECURSION_LIMIT
}
Insert cell
x3dtool = limit, new jlib.Draft04(x3dschema)
Insert cell
limit, jlib.settings
Insert cell
x3dtool.compileSchema({"$ref": "/definitions/X3D"})
Insert cell
x3dTemplate = x3dtool.getTemplate( )
Insert cell
x3dTemplate.X3D.Scene["-children"][0].Anchor
Insert cell
{ let c = []; x3dtool.each( {X3D: {"Scene": {}}}, (s,v,p) => c.push({s,v,p}) ); return c}
Insert cell
Insert cell
refparser=import('https://cdn.skypack.dev/@bcherny/json-schema-ref-parser@10.0.5-fork?min')
Insert cell
//refparser.dereference(Object.assign({},x3dschema))
Insert cell
Insert cell
Insert cell
allXMLNodes[6].getAttribute('forceOutput')
Insert cell
{return {"b": '"aa" "bb"', "a": `${allXMLNodes[6].getAttribute('forceOutput')}` }}
Insert cell
tags.MultiTexture.attrs.mode
Insert cell
x3dtool.getSchema("X3D/Scene/-children/1/Shape/-appearance/Appearance/-texture/MultiTexture/@mode")
Insert cell
getAttributeEnums('MultiTexture','mode')
Insert cell
tags.Scene
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more