174 lines
3.2 KiB
HTML
174 lines
3.2 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset="utf-8">
|
|
<style>
|
|
|
|
.node circle {
|
|
fill: #999;
|
|
}
|
|
|
|
.node text {
|
|
font: 10px sans-serif;
|
|
}
|
|
|
|
.node--internal circle {
|
|
fill: #555;
|
|
}
|
|
|
|
.node--internal text {
|
|
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
|
|
}
|
|
|
|
.link {
|
|
fill: none;
|
|
stroke: #555;
|
|
stroke-opacity: 0.4;
|
|
stroke-width: 1.5px;
|
|
}
|
|
|
|
</style>
|
|
<svg width="960" height="512"></svg>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.1/d3.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/acorn/4.0.11/acorn.min.js"></script>
|
|
<script>
|
|
|
|
fetch("../apps/loader/js/main.js")
|
|
.then(response => response.text())
|
|
.then(text => {
|
|
const ast = acorn.parse(text, {
|
|
sourceType: "module",
|
|
// collect ranges for each node
|
|
ranges: true,
|
|
// collect comments in Esprima's format
|
|
onComment: null,
|
|
// collect token ranges
|
|
onToken: null
|
|
})
|
|
|
|
console.info(ast)
|
|
|
|
drawAst(ast)
|
|
})
|
|
|
|
/*
|
|
*
|
|
*/
|
|
function drawAst(ast) {
|
|
|
|
// Create SVG element
|
|
//---------------------------
|
|
let svg = d3.select("svg")
|
|
const width = svg.attr("width")
|
|
const height = svg.attr("height")
|
|
let g = svg.append("g").attr("transform", "translate(40,0)")
|
|
|
|
// Convert data
|
|
//---------------------------
|
|
const data = acornToHierarchy(ast)
|
|
|
|
// Create D3 Hierarchy
|
|
//---------------------------
|
|
let root = d3.hierarchy(data).sort((a, b) => {
|
|
return (a.height - b.height) || a.data.name.localeCompare(b.data.name);
|
|
})
|
|
|
|
// Create D3 Cluster
|
|
//---------------------------
|
|
let tree = d3.cluster().size([height, width - 200])
|
|
tree(root)
|
|
|
|
// Create SVG elements
|
|
//---------------------------
|
|
let link = g.selectAll(".link")
|
|
.data(root.descendants().slice(1))
|
|
.enter().append("path")
|
|
.attr("class", "link")
|
|
.attr("d", d => {
|
|
return `M${d.y},${d.x}C${d.parent.y + 100},${d.x} ${d.parent.y + 100},${d.parent.x} ${d.parent.y},${d.parent.x}`
|
|
})
|
|
|
|
let node = g.selectAll(".node")
|
|
.data(root.descendants())
|
|
.enter().append("g")
|
|
.attr("class", d => "node" + (d.children ? " node--internal" : " node--leaf"))
|
|
.attr("transform", d => `translate(${d.y},${d.x})`)
|
|
|
|
node.append("circle")
|
|
.attr("r", 5)
|
|
|
|
node.append("text")
|
|
.attr("dy", 3)
|
|
.attr("x", d => d.children ? -8 : 8)
|
|
.style("text-anchor", d => d.children ? "end" : "start")
|
|
.text(d => d.data.name)
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
function acornToHierarchy(ast) {
|
|
|
|
console.info(JSON.stringify(ast))
|
|
|
|
let data = {}
|
|
|
|
for (const clazz of ast.body) {
|
|
if (clazz.type === "ClassDeclaration") {
|
|
data.name = clazz.id.name
|
|
data.children = []
|
|
|
|
for (const method of clazz.body.body) {
|
|
if (method.type === "MethodDefinition") {
|
|
data.children.push({
|
|
name: method.key.name,
|
|
children: []
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
const data = {
|
|
"name": "Eve",
|
|
"children": [{
|
|
"name": "Cain"
|
|
}, {
|
|
"name": "Seth",
|
|
"children": [{
|
|
"name": "Enos"
|
|
}, {
|
|
"name": "Noam"
|
|
}]
|
|
}, {
|
|
"name": "Abel"
|
|
}, {
|
|
"name": "Awan",
|
|
"children": [{
|
|
"name": "Enoch"
|
|
}]
|
|
}, {
|
|
"name": "Azura"
|
|
}]
|
|
}
|
|
*/
|
|
|
|
return data
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script> |