前端用JavaScript实现桑基图(Sankey图)
桑基图(Sankey图),是流图的一种,常用来展示事物的数量、发展方向、数据量大小等,在可视化分析中经常使用。
本文,演示如何在前端用JavaScript绘制桑基图。注:本例使用JShaman数据展示JS代码混淆加密流程。
先看效果:
因为已有成熟的库可用,比如,可以使用d3引擎,所以sankey的实现较为简单。
众所周知,JShaman是国内知名的JS代码混淆加密平台,我们将用JShaman英文版的混淆返回内容做为数据源,绘制一张JS代码混淆加密流程桑基图。
JShaman数据采集,直接复制即可:
用d3实现桑基图绘制,核心代码如下,文末会提供完整代码。
绘图成功:
桑基图效果说明:从图中,可以看到JShaman对JS代码的混淆加密流程:初始的JS代码,先转为AST(抽象语法树),再进行String reverse、Dead Code Insertion、Eval Encryption等数十种混淆加密操作,生成了新的AST,最后再根据AST重新生成JS代码,这便是JS代码混淆加密的完整流程,由图可以让人一目了然的知晓全过程。
最后,附上完整代码,如果您也需要绘制桑基图,可以参考此代码:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <script src="./libs/d3/d3.min.js"></script>
- <script src="./libs/d3-sankey/d3-sankey.js"></script>
- <script src="./libs/d3-sankey-util.js"></script>
- </head>
- <body>
- <div id="obfuscate_sankey"></div>
- <script>
- obfuscate_result = {
- "status": [
- {
- "feature": "JavaScript 2 AST",
- "time": "2023/09/14 07:56:36",
- "status": 282
- },
- {
- "feature": "Encode JSON",
- "time": "2023/09/14 07:56:36",
- "status": 0
- },
- {
- "feature": "Encode Regexp",
- "time": "2023/09/14 07:56:36",
- "status": 0
- },
- {
- "feature": "String reverse",
- "time": "2023/09/14 07:56:36",
- "status": 2
- },
- {
- "feature": "Dead Code Insertion",
- "time": "2023/09/14 07:56:36",
- "status": 4
- },
- {
- "feature": "Rename Private Identifiers",
- "time": "2023/09/14 07:56:36",
- "status": 2
- },
- {
- "feature": "Rename Global Identifiers",
- "time": "2023/09/14 07:56:36",
- "status": 2
- },
- {
- "feature": "Rename Global Functions",
- "time": "2023/09/14 07:56:36",
- "status": 1
- },
- {
- "feature": "Rename Private Functions",
- "time": "2023/09/14 07:56:36",
- "status": 0
- },
- {
- "feature": "AST Executing",
- "time": "2023/09/14 07:56:36",
- "status": 9
- },
- {
- "feature": "Property Indirection",
- "time": "2023/09/14 07:56:36",
- "status": 34
- },
- {
- "feature": "Assignment To Function",
- "time": "2023/09/14 07:56:36",
- "status": 6
- },
- {
- "feature": "Numbers To Expressions",
- "time": "2023/09/14 07:56:36",
- "status": 9
- },
- {
- "feature": "VM Executing",
- "time": "2023/09/14 07:56:36",
- "status": 15
- },
- {
- "feature": "Expression To Function",
- "time": "2023/09/14 07:56:36",
- "status": 30
- },
- {
- "feature": "Boolean Encoding",
- "time": "2023/09/14 07:56:36",
- "status": 30
- },
- {
- "feature": "Eval Encryption",
- "time": "2023/09/14 07:56:36",
- "status": 27
- },
- {
- "feature": "Encode Strings",
- "time": "2023/09/14 07:56:36",
- "status": 33
- },
- {
- "feature": "Control Flow Flattening",
- "time": "2023/09/14 07:56:36",
- "status": 15
- },
- {
- "feature": "Control Flow Shrinking",
- "time": "2023/09/14 07:56:36",
- "status": 3
- },
- {
- "feature": "String Array",
- "time": "2023/09/14 07:56:36",
- "status": 41
- },
- {
- "feature": "String Array Encoding",
- "time": "2023/09/14 07:56:36",
- "status": 41
- },
- {
- "feature": "AST 2 JavaScript",
- "time": "2023/09/14 07:56:36",
- "status": 5086
- }
- ]
- }
- var label = [{"name":"JavaScript"},{"name":"AST"}];
- var source = [0];
- var target =[1];
- var value = [obfuscate_result.status[0].status];
- for(i=1; i<obfuscate_result.status.length-1; i++){
-
- label.push({"name":obfuscate_result.status[i].feature + " " + obfuscate_result.status[i].status} );
- source.push(1)
- target.push(i+1);
- if(obfuscate_result.status[i].status == 0){
- obfuscate_result.status[i].status =1;
- }
- value.push(obfuscate_result.status[i].status);
- source.push(i+1)
- target.push(obfuscate_result.status.length);
- value.push(obfuscate_result.status[i].status);
- }
- label.push({"name":"AST"});
- label.push({"name":"ObFuscated JavaScript"});
- source.push(label.length-2)
- target.push(label.length-1);
- value.push(obfuscate_result.status[obfuscate_result.status.length-1].status);
- var sankey_data= {}
- sankey_data.nodes = label;
- sankey_data.links = [];
- for(i=0;i<source.length;i++){
- sankey_data.links.push({"source":source[i],"target":target[i],"value":value[i]});
- }
- renderSankey({
- el: 'obfuscate_sankey',
- layoutStyle: {
- width: 1000,
- height: 680
- },
- data: sankey_data
- })
-
- </script>
- </body>
- </html>