160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			4.1 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>
 |