GoodReason – 8 sektoria / 7 tasoa (SVG)
// Beta-hierarchy renderer (vanilla JS)
// Rakentaa käännettävän hierarkian pre/post -viitteistä ja renderöi sen HTML-listana.
// API:
// buildHierarchy(graph, { root, direction, depth, roles, domain })
// renderHierarchy(container, tree)
function indexById(nodes){ const m = new Map(); nodes.forEach(n=>m.set(n.id,n)); return m; }
function filterByDomain(nodes, domain){
if(!domain) return nodes;
return nodes.filter(n => (n.facets && n.facets.domain || []).includes(domain));
}
export function buildHierarchy(graph, { root, direction="post", depth=10, roles=["π","Δψ","Ω"], domain=null } = {}){
const nodes = filterByDomain(graph.nodes, domain);
const byId = indexById(nodes);
const childrenKey = direction === "pre" ? "pre" : "post";
const visited = new Set();
function pickRoles(n){
const out = {};
if(!n.roles) return out;
roles.forEach(r => { if(n.roles[r]) out[r] = n.roles[r]; });
return out;
}
function dfs(id, d=0){
const node = byId.get(id);
if(!node || visited.has(id) || d > depth) return null;
visited.add(id);
const children = (node[childrenKey] || []).map(next => dfs(next, d+1)).filter(Boolean);
return { id: node.id, label: node.label, roles: pickRoles(node), children };
}
return dfs(root);
}
export function renderHierarchy(container, tree){
if(!tree){ container.innerHTML = "
Nothing to render"; return; }
function roleToHTML(k, v){
if(typeof v === "string"){
return `
${k}: ${v}
`;
}
const text = v.text ? `
${k}: ${v.text}
` : "";
const pre = Array.isArray(v.pre)
? `
pre
` +
v.pre.map(p => `${p.symbol}
${p.term || ""} — ${p.description || ""} `).join("") +
`
`
: "";
const post = v.post ? `
post: ${v.post}
` : "";
return `
${text}${pre}${post}
`;
}
function nodeHTML(n){
const rolesHTML = Object.entries(n.roles || {}).map(([k, v]) => roleToHTML(k, v)).join("");
const kids = (n.children || []).map(nodeHTML).join("");
return `
${n.label} (${n.id})
${rolesHTML}
${kids ? `` : ""}
`;
}
container.innerHTML = `
`;
}