node.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. define(function(require, exports, module) {
  2. var kity = require('./kity');
  3. var utils = require('./utils');
  4. var Minder = require('./minder');
  5. /**
  6. * @class MinderNode
  7. *
  8. * 表示一个脑图节点
  9. */
  10. var MinderNode = kity.createClass('MinderNode', {
  11. /**
  12. * 创建一个游离的脑图节点
  13. *
  14. * @param {String|Object} textOrData
  15. * 节点的初始数据或文本
  16. */
  17. constructor: function(textOrData) {
  18. // 指针
  19. this.parent = null;
  20. this.root = this;
  21. this.children = [];
  22. // 数据
  23. this.data = {
  24. id: utils.guid(),
  25. created: +new Date()
  26. };
  27. // 绘图容器
  28. this.initContainers();
  29. if (utils.isString(textOrData)) {
  30. this.setText(textOrData);
  31. } else if (utils.isObject(textOrData)) {
  32. utils.extend(this.data, textOrData);
  33. }
  34. },
  35. initContainers: function() {
  36. this.rc = new kity.Group().setId(utils.uuid('minder_node'));
  37. this.rc.minderNode = this;
  38. },
  39. /**
  40. * 判断节点是否根节点
  41. */
  42. isRoot: function() {
  43. return this.root === this;
  44. },
  45. /**
  46. * 判断节点是否叶子
  47. */
  48. isLeaf: function() {
  49. return this.children.length === 0;
  50. },
  51. /**
  52. * 获取节点的根节点
  53. */
  54. getRoot: function() {
  55. return this.root || this;
  56. },
  57. /**
  58. * 获得节点的父节点
  59. */
  60. getParent: function() {
  61. return this.parent;
  62. },
  63. getSiblings: function() {
  64. var children = this.parent.children;
  65. var siblings = [];
  66. var self = this;
  67. children.forEach(function(child) {
  68. if (child != self) siblings.push(child);
  69. });
  70. return siblings;
  71. },
  72. /**
  73. * 获得节点的深度
  74. */
  75. getLevel: function() {
  76. var level = 0,
  77. ancestor = this.parent;
  78. while (ancestor) {
  79. level++;
  80. ancestor = ancestor.parent;
  81. }
  82. return level;
  83. },
  84. /**
  85. * 获得节点的复杂度(即子树中节点的数量)
  86. */
  87. getComplex: function() {
  88. var complex = 0;
  89. this.traverse(function() {
  90. complex++;
  91. });
  92. return complex;
  93. },
  94. /**
  95. * 获得节点的类型(root|main|sub)
  96. */
  97. getType: function(type) {
  98. this.type = ['root', 'main', 'sub'][Math.min(this.getLevel(), 2)];
  99. return this.type;
  100. },
  101. /**
  102. * 判断当前节点是否被测试节点的祖先
  103. * @param {MinderNode} test 被测试的节点
  104. */
  105. isAncestorOf: function(test) {
  106. var ancestor = test.parent;
  107. while (ancestor) {
  108. if (ancestor == this) return true;
  109. ancestor = ancestor.parent;
  110. }
  111. return false;
  112. },
  113. getData: function(key) {
  114. return key ? this.data[key] : this.data;
  115. },
  116. setData: function(key, value) {
  117. if (typeof key == 'object') {
  118. var data = key;
  119. for (key in data) if (data.hasOwnProperty(key)) {
  120. this.data[key] = data[key];
  121. }
  122. }
  123. else {
  124. this.data[key] = value;
  125. }
  126. return this;
  127. },
  128. /**
  129. * 设置节点的文本数据
  130. * @param {String} text 文本数据
  131. */
  132. setText: function(text) {
  133. return this.data.text = text;
  134. },
  135. /**
  136. * 获取节点的文本数据
  137. * @return {String}
  138. */
  139. getText: function() {
  140. return this.data.text || null;
  141. },
  142. /**
  143. * 先序遍历当前节点树
  144. * @param {Function} fn 遍历函数
  145. */
  146. preTraverse: function(fn, excludeThis) {
  147. var children = this.getChildren();
  148. if (!excludeThis) fn(this);
  149. for (var i = 0; i < children.length; i++) {
  150. children[i].preTraverse(fn);
  151. }
  152. },
  153. /**
  154. * 后序遍历当前节点树
  155. * @param {Function} fn 遍历函数
  156. */
  157. postTraverse: function(fn, excludeThis) {
  158. var children = this.getChildren();
  159. for (var i = 0; i < children.length; i++) {
  160. children[i].postTraverse(fn);
  161. }
  162. if (!excludeThis) fn(this);
  163. },
  164. traverse: function(fn, excludeThis) {
  165. return this.postTraverse(fn, excludeThis);
  166. },
  167. getChildren: function() {
  168. return this.children;
  169. },
  170. getIndex: function() {
  171. return this.parent ? this.parent.children.indexOf(this) : -1;
  172. },
  173. insertChild: function(node, index) {
  174. if (index === undefined) {
  175. index = this.children.length;
  176. }
  177. if (node.parent) {
  178. node.parent.removeChild(node);
  179. }
  180. node.parent = this;
  181. node.root = this.root;
  182. this.children.splice(index, 0, node);
  183. },
  184. appendChild: function(node) {
  185. return this.insertChild(node);
  186. },
  187. prependChild: function(node) {
  188. return this.insertChild(node, 0);
  189. },
  190. removeChild: function(elem) {
  191. var index = elem,
  192. removed;
  193. if (elem instanceof MinderNode) {
  194. index = this.children.indexOf(elem);
  195. }
  196. if (index >= 0) {
  197. removed = this.children.splice(index, 1)[0];
  198. removed.parent = null;
  199. removed.root = removed;
  200. }
  201. },
  202. clearChildren: function() {
  203. this.children = [];
  204. },
  205. getChild: function(index) {
  206. return this.children[index];
  207. },
  208. getRenderContainer: function() {
  209. return this.rc;
  210. },
  211. getCommonAncestor: function(node) {
  212. return MinderNode.getCommonAncestor(this, node);
  213. },
  214. contains: function(node) {
  215. return this == node || this.isAncestorOf(node);
  216. },
  217. clone: function() {
  218. var cloned = new MinderNode();
  219. cloned.data = utils.clone(this.data);
  220. this.children.forEach(function(child) {
  221. cloned.appendChild(child.clone());
  222. });
  223. return cloned;
  224. },
  225. compareTo: function(node) {
  226. if (!utils.comparePlainObject(this.data, node.data)) return false;
  227. if (!utils.comparePlainObject(this.temp, node.temp)) return false;
  228. if (this.children.length != node.children.length) return false;
  229. var i = 0;
  230. while (this.children[i]) {
  231. if (!this.children[i].compareTo(node.children[i])) return false;
  232. i++;
  233. }
  234. return true;
  235. },
  236. getMinder: function() {
  237. return this.getRoot().minder;
  238. }
  239. });
  240. MinderNode.getCommonAncestor = function(nodeA, nodeB) {
  241. if (nodeA instanceof Array) {
  242. return MinderNode.getCommonAncestor.apply(this, nodeA);
  243. }
  244. switch (arguments.length) {
  245. case 1:
  246. return nodeA.parent || nodeA;
  247. case 2:
  248. if (nodeA.isAncestorOf(nodeB)) {
  249. return nodeA;
  250. }
  251. if (nodeB.isAncestorOf(nodeA)) {
  252. return nodeB;
  253. }
  254. var ancestor = nodeA.parent;
  255. while (ancestor && !ancestor.isAncestorOf(nodeB)) {
  256. ancestor = ancestor.parent;
  257. }
  258. return ancestor;
  259. default:
  260. return Array.prototype.reduce.call(arguments,
  261. function(prev, current) {
  262. return MinderNode.getCommonAncestor(prev, current);
  263. },
  264. nodeA
  265. );
  266. }
  267. };
  268. kity.extendClass(Minder, {
  269. getRoot: function() {
  270. return this._root;
  271. },
  272. setRoot: function(root) {
  273. this._root = root;
  274. root.minder = this;
  275. },
  276. getAllNode: function() {
  277. var nodes = [];
  278. this.getRoot().traverse(function(node) {
  279. nodes.push(node);
  280. });
  281. return nodes;
  282. },
  283. getNodeById: function(id) {
  284. return this.getNodesById([id])[0];
  285. },
  286. getNodesById: function(ids) {
  287. var nodes = this.getAllNode();
  288. var result = [];
  289. nodes.forEach(function(node) {
  290. if (ids.indexOf(node.getData('id')) != -1) {
  291. result.push(node);
  292. }
  293. });
  294. return result;
  295. },
  296. createNode: function(textOrData, parent, index) {
  297. var node = new MinderNode(textOrData);
  298. this.fire('nodecreate', {
  299. node: node,
  300. parent: parent,
  301. index: index
  302. });
  303. this.appendNode(node, parent, index);
  304. return node;
  305. },
  306. appendNode: function(node, parent, index) {
  307. if (parent) parent.insertChild(node, index);
  308. this.attachNode(node);
  309. return this;
  310. },
  311. removeNode: function(node) {
  312. if (node.parent) {
  313. node.parent.removeChild(node);
  314. this.detachNode(node);
  315. this.fire('noderemove', {
  316. node: node
  317. });
  318. }
  319. },
  320. attachNode: function(node) {
  321. var rc = this.getRenderContainer();
  322. node.traverse(function(current) {
  323. current.attached = true;
  324. rc.addShape(current.getRenderContainer());
  325. });
  326. rc.addShape(node.getRenderContainer());
  327. this.fire('nodeattach', {
  328. node: node
  329. });
  330. },
  331. detachNode: function(node) {
  332. var rc = this.getRenderContainer();
  333. node.traverse(function(current) {
  334. current.attached = false;
  335. rc.removeShape(current.getRenderContainer());
  336. });
  337. this.fire('nodedetach', {
  338. node: node
  339. });
  340. },
  341. getMinderTitle: function() {
  342. return this.getRoot().getText();
  343. }
  344. });
  345. module.exports = MinderNode;
  346. });