1. 程式人生 > 實用技巧 >搜尋視覺化工具

搜尋視覺化工具

簡介

本工具可以直觀地看到程式遍歷圖的過程

截圖

使用方法

複製以下程式碼, 儲存為html檔案

<!DOCTYPE>

<html>
	<head>
		<title>Cytoscape</title>
		<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
		<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
		<script src="https://unpkg.com/webcola/WebCola/cola.min.js"></script>
		<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
		<script src="https://cdn.jsdelivr.net/gh//cytoscape/cytoscape.js-cola/cytoscape-cola.js"></script>
		<meta charset="utf-8">
		<style>
			body {
				font-family: helvetica;
				font-size: 14px;
			}
			#cy {
				width: 100%;
				height: 100%;
				position: absolute;
				left: 0;
				top: 0;
				z-index: 999;
			}
		</style>

		<script>
		    var ifsx = true;
            document.onkeydown = function(event) {
                var e = event || window.event || arguments.callee.caller.arguments[0];
                if (!window.cy) return;
                if (e && e.keyCode == 70) {
                    if (ifsx) {
                        cy.$("edge").css("curve-style","bezier")
                    } else {
                        cy.$("edge").css("curve-style","")    
                    }
                    ifsx = !ifsx;
                    event.preventDefault();
                } else if(e.keyCode == 40 || e.keyCode == 39 || e.keyCode == 78) {
                    nxt();
                } else if(e.keyCode == 38 || e.keyCode == 37 || e.keyCode == 80) {
                    pre();
                }
            };
            function read(files) {
                if (files.length) {
                    var file = files[0];
                    var reader = new FileReader();
                    reader.onload = function() {
                        start(this.result);
                    }
                    reader.readAsText(file); 
                }
            }
            var colorings = [];
            var ci = 0;
            var timeid = 0;
            var history = [];
            function update(op) {
                color = ['#aaaaaa', 'red', 'yellow', 'blue', 'orange', 'green', 'purple', 'pink'];
                if (parseInt(op[2]) > 7) op[2] = 0;
                color = color[parseInt(op[2])];
                cy.$(`#${op[0]}`).css('background-color', color);
                cy.$(`#${op[1]}`).css('background-color', color);
                cy.$(`#${op[0]}_${op[1]}`).css('line-color', color);
            }
            function getcolor(op) {
                return [op[0], op[1], cy.$(`#${op[0]}`).css('background-color'), cy.$(`#${op[1]}`).css('background-color'), cy.$(`#${op[0]}_${op[1]}`).css('line-color')]
            }
            function updatepre(op) {
                cy.$(`#${op[0]}`).css('background-color', op[2]);
                cy.$(`#${op[1]}`).css('background-color', op[3]);
                cy.$(`#${op[0]}_${op[1]}`).css('line-color', op[4]);
            }
            function pre() {
                if (ci <= 0) return;
                ci--;
                updatepre(history[ci]);
            }
            function nxt() {
                if (ci >= colorings.length) return;
                history[ci] = getcolor(colorings[ci]);
                update(colorings[ci]);
                ci++;
            }
            function start(data) {
                $("#cy").css("display", "block");
                $("#file").css("display", "none");
                node = {};
                edges = [];
                nodes = [];
                for (var i of data.split('\n')) {
                    var line = i.split(' ');
                    if (line[0] == 'c' && line.length > 3) {
                        colorings.push([line[1], line[2], line[3]]);
                    } else {
                        if (line.length < 2) continue;
                        node[line[0]] = 1, node[line[1]] = 1;
                        if (line.length > 2)
                            edges.push({ data: { id: `${line[0]}_${line[1]}`, source: `${line[0]}`, target: `${line[1]}`, weight: `${line[2]}`} });
                        else
                            edges.push({ data: { id: `${line[0]}_${line[1]}`, source: `${line[0]}`, target: `${line[1]}`} });
                    }
                }
                for (var i in node) {
                    nodes.push({ data: { id: `${i}` }});
                }
                createGraph({
                    nodes: nodes,
                    edges: edges
                })
		    }
            function createGraph(data) {
                var cy = window.cy = cytoscape({
                    container: document.getElementById('cy'),
                    autounselectify: true,
				    boxSelectionEnabled: false,
				    layout: {
						    name: 'cola'
				    },
                    style: [
                        {
                            selector: 'node',
                            style: {
                                'label': 'data(id)',
                                'background-color':'white',
                                'border-width': '2px',
                                'border-color': 'black'
                            }
                        }, {
                            selector: 'edge',
                            style: {
                                //'curve-style': 'bezier',
                                'curve-style': 'none',
                                'target-arrow-shape': 'triangle',
                                'line-color': '#aaa', 
                                'target-arrow-shape': 'triangle', 
                                'width': '2px',
                                'label': 'data(weight)'
                            }
                        }
                    ],
                    elements: data
                });
                cy.$('node').on('cxttapend', (e)=>{cy.fit(cy.$(`[id='${e.target.id()}']`),200)})
            }
		</script>
	</head>

	<body>
		<div id="cy" style="display: none;"></div>
		<input id="file" type="file" onchange="read(this.files)"/> 
	</body>
</html>

使用瀏覽器開啟, 選擇資料檔案即可

資料檔案語法:

對於資料檔案的每行:

  1. 如果全部由數字構成, 則表示圖的結構:
  • 每行兩個數字\(u\), \(v\) 表示邊的起點和終點, 例如3 2

  • 每行三個數字\(u\), \(v\)\(w\) 表示邊的起點, 終點和權值, 例如3 2 1
  1. 如果該行由字母c開始, 則表示一條著色命令,
  • 每行由一個字母c和三個數字\(u\), \(v\), \(c\)構成, 表示邊的起點, 終點和顏色

    0 : 灰色
    1 : 紅色
    2 : 黃色
    3 : 藍色
    4 : 橙色
    5 : 綠色
    6 : 紫色
    7 : 粉色
    

新的顏色會覆蓋舊的顏色, 著色命令將按順序從上至下以此執行

這是一個符合語法的資料檔案內容:

5 8 
5 4 
5 3 
5 2
4 3 
3 1 
3 2 
2 1
c 5 8 1
c 5 4 1
c 5 3 1
c 5 2 1
c 4 3 1
c 3 2 1
c 3 1 1
c 2 1 1

操作

圖預設為無向圖, 按f鍵可轉換有向圖和無向圖

n,右箭頭 或 下箭頭可依次執行著色命令。

p,左箭頭 或 上箭頭可依次撤銷著色命令。

右鍵點選某節點可移動焦點至該節點(不知道有啥用)

平面直角座標系

適用於平面直角座標系的可視工具, 檔案內容需要為一個符合Js語法的三維陣列, 第一維是時間, 第二,三維是x, y座標

  • 0 : 白色
  • 1 : 黑色
  • 2 : 藍色
  • 3 : 紅色
  • 4 : 綠色
  • 5 : 紫色
<html>
<head>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <meta charset="utf-8"/>
	<script>
    	function add(x, y, s, color) {
       		$("body").append(`<div id="${x}_${y}" style="background: ${color}; height:${s}px; width:${s}px; position: absolute; border: 1px solid; left: ${x}px; top: ${y}px;"></div>`)
    	}
		var width = 30, l = 5;
		function update(t) {
			$("body").empty();
			for (var i = 1; i < t.length; i++) {
				for (var j = 1; j < t[i].length; j++) {
					var color, x = j + 1, y = i + 1;
					if (t[i][j] == 0) color = "white";
					else if(t[i][j] == 1) color = "black";
					else if(t[i][j] == 2) color = "blue";
					else if(t[i][j] == 3) color = "red";
					else if(t[i][j] == 4) color = "green";
					else if(t[i][j] == 5) color = "purple";
					else color = "yellow";
					add(l * x + width * (x - 1), l * y + width * (y - 1), width, color);
				}
			}
		}
		function read(files) {
            if (files.length) {
                var file = files[0];
                var reader = new FileReader();
                reader.onload = function() {
                    start(eval(this.result));
                }
                reader.readAsText(file); 
            }
        }
		var map, li, timeid;
		function start(a) {
			map = a;
			li = 0;
			timeid = setInterval(loop, 1);
		}
		function loop() {
			update(map[li++]);
			if (li >= map.length) clearInterval(timeid);
		}
    </script>
</head>
<body>
  <input type="file" onchange="read(this.files)"/> 
</body>
</html>