作业源码链接

https://github.com/978543210/Frontend-01-Template/blob/master/week04/Realm.html

思路:

从ECMA262 中找到JS引擎中内置的对象,以这些对象为基础。通过遍历这些对象的原型、值属性和访问器属性的方法获得所有内置对象。

内置的对象包括:(ECMA262 P102 15. Standard Built-in ECMAScript Objects )

  1. var globalProperties = [
  2. "eval","isFinite","isNaN","parseFloat","parseInt",
  3. "decodeURI","decodeURIComponent","encodeURI",
  4. "encodeURIComponent","Array","Date","RegExp",
  5. "Promise","Proxy","Map","WeakMap","Set",
  6. "WeakSet","Function","Boolean","String",
  7. "Number","Symbol","Object","Error",
  8. "EvalError","RangeError","ReferenceError",
  9. "SyntaxError","TypeError","URIError",
  10. "ArrayBuffer","SharedArrayBuffer","DataView",
  11. "Float32Array","Float64Array","Int8Array",
  12. "Int16Array","Int32Array","Uint8Array",
  13. "Uint16Array","Uint32Array","Uint8ClampedArray",
  14. "Atomics","JSON","Math","Reflect"];

避免重复添加,使用set去重,最终set中的所有的所有对象即为所求。

广度优先遍历

先将globalProperties中的所有对象入队,依次查找对象的原型、值属性和访问器属性中的对象,并将其入队,并放入set集合中自动去重,依次检索队列中所有对象知道直到队列为空。
自从知道可以在电脑上乱写乱画之后,总合计折腾一些新的玩法,正好试试瞎画一下,然后生成一个gif文件,毕竟一图胜千言……
BFS2.gif
忽然想到,对象的关系如果不是树形结构,是一个图,里面要是有环什么办……

可视化

生成数据

可视化结果应该是一个关系图,对于图来说,我们重点关注顶点和边的生成,
参考g6的demo,我们需要使用json格式生成nodes和edges
因此,

  • 在每次把节点装入集合中的时候,我们同时把对象的“toString()”结果放到nodes中;
  • 在每次按照线索找到对象的时候,把原对象和目标对象的“toString()”结果放到edges中。

程序中的bug:

有些对象调用toString()方法报错。 目前偷懒,直接使用try屏蔽了,考虑的解决方案是生成一个字典,对于这些特殊对象,查表得到对应的字符串。

代码如下:

  1. var set = new Set();
  2. var jsondata = {nodes: [],edges: [],};
  3. var globalProperties = [
  4. "eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI",
  5. "encodeURIComponent","Array","Date","RegExp","Promise","Proxy","Map","WeakMap","Set",
  6. "WeakSet","Function","Boolean","String","Number","Symbol","Object","Error",
  7. "EvalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError",
  8. "ArrayBuffer","SharedArrayBuffer","DataView","Float32Array","Float64Array","Int8Array",
  9. "Int16Array","Int32Array","Uint8Array","Uint16Array","Uint32Array","Uint8ClampedArray",
  10. "Atomics","JSON","Math","Reflect"];
  11. var queue = [];
  12. for (var p of globalProperties){
  13. queue.push({
  14. path: [p],
  15. object:this[p]
  16. });
  17. }
  18. let current;
  19. while(queue.length){
  20. current = queue.shift();
  21. console.log(current.path.join('.'));
  22. if (set.has(current.object))
  23. continue;
  24. if (current.object == undefined )
  25. continue;
  26. set.add(current.object);
  27. try {
  28. jsondata.nodes.push({id: current.object.toString(), label: current.object.toString()})
  29. } catch (error) {
  30. console.log(current.object)
  31. }
  32. // console.log(current.object)
  33. let proto = Object.getPrototypeOf(current.object);
  34. if(proto){
  35. queue.push({
  36. path: current.path.concat("__proto__"),
  37. object: proto
  38. });
  39. try {
  40. jsondata.edges.push({source: current.object.toString(), target: proto.toString()})
  41. } catch (error) {
  42. console.log(proto)
  43. }
  44. }
  45. for (let p of Object.getOwnPropertyNames(current.object)) {
  46. var property = Object.getOwnPropertyDescriptor(current.object,p)
  47. if (property.hasOwnProperty("value") &&
  48. ((property.value != null) && (typeof property.value == "object") || (typeof property.value == "object"))
  49. && property.value instanceof Object){
  50. queue.push({
  51. path: current.path.concat([p]),
  52. object:property.value
  53. });
  54. try {
  55. jsondata.edges.push({source: current.object.toString(), target: property.value.toString()})
  56. } catch (error) {
  57. console.log(property.value)
  58. }
  59. }
  60. if (property.hasOwnProperty("get") && (typeof property.get == "function") ) {
  61. queue.push({
  62. path:current.path.concat([p]),
  63. object:property.get
  64. });
  65. try {
  66. jsondata.edges.push({source: current.object.toString(), target: property.get.toString()})
  67. } catch (error) {
  68. console.log(property.get)
  69. }
  70. }
  71. if (property.hasOwnProperty("set") && (typeof property.get == "function") ) {
  72. queue.push({
  73. path:current.path.concat([p]),
  74. object:property.set
  75. });
  76. try {
  77. jsondata.edges.push({source: current.object.toString(), target: property.set.toString()})
  78. } catch (error) {
  79. console.log(property.set)
  80. }
  81. }
  82. }
  83. }
  84. console.log(set)
  85. console.log(jsondata)

测试可视化g6的使用、

生成nodes和edges数据后,使用默认demo程序测试一下,结果如图
image.png

期待的数据关系

观察数据结果,就像人物关系网一样,想把核心的,高密度的放在中间逐步外扩。
考虑使用的方案是,计算每个顶点的出度和入度,入度越多,说明重要性越高。越应该放置在中心。
可以类似PageRank算法,生成各个节点的权值,然后再去做布局。
还有就是考虑按照名称,比如都包含error的,按照一定的聚类算法,使其最终呈现在一起。

尝试新的模型

试过几种模型,force的,没有想好如何去设置,引力和斥力最终都聚集到一起了,如果设置得当,应该能很好的体现聚类的效果
在不修改代码,人为计算入度、权值、聚类的情况下,觉得Radial展示效果比较符合我个人预期,就先这样吧。

  1. const graph = new G6.Graph({
  2. container: 'mountNode', // 指定图画布的容器 id
  3. // 画布宽高
  4. width: 2000,
  5. height: 2000,
  6. modes: {
  7. default: ['drag-canvas', 'drag-node'],
  8. },
  9. layout: {
  10. type: 'radial',
  11. linkDistance: 300, // 设置边长为 100
  12. preventOverlap: true, // 设置防止重叠
  13. },
  14. animate: true,
  15. defaultNode: {
  16. size: 30,
  17. style: {
  18. lineWidth: 2,
  19. fill: '#C6E5FF',
  20. stroke: '#5B8FF9',
  21. },
  22. },
  23. defaultEdge: {
  24. size: 3,
  25. color: '#e2e2e2',
  26. style: {
  27. endArrow: {
  28. path: 'M 0,0 L 8,4 L 8,-4 Z',
  29. fill: '#e2e2e2'
  30. },
  31. },
  32. },
  33. });
  34. graph.data(jsondata);
  35. graph.render();

Radial 辐射布局

image.png