@7polo/kityminder-core
Version:
KityMinder Core Implement
407 lines (346 loc) • 11 kB
JavaScript
define(function(require, exports, module) {
var kity = require('./kity');
var utils = require('./utils');
var Minder = require('./minder');
/**
* @class MinderNode
*
* 表示一个脑图节点
*/
var MinderNode = kity.createClass('MinderNode', {
/**
* 创建一个游离的脑图节点
*
* @param {String|Object} textOrData
* 节点的初始数据或文本
*/
constructor: function(textOrData) {
// 指针
this.parent = null;
this.root = this;
this.children = [];
// 数据
this.data = {
id: utils.guid(),
created: +new Date()
};
// 绘图容器
this.initContainers();
if (utils.isString(textOrData)) {
this.setText(textOrData);
} else if (utils.isObject(textOrData)) {
utils.extend(this.data, textOrData);
}
},
initContainers: function() {
this.rc = new kity.Group().setId(utils.uuid('minder_node'));
this.rc.minderNode = this;
},
/**
* 判断节点是否根节点
*/
isRoot: function() {
return this.root === this;
},
/**
* 判断节点是否叶子
*/
isLeaf: function() {
return this.children.length === 0;
},
/**
* 获取节点的根节点
*/
getRoot: function() {
return this.root || this;
},
/**
* 获得节点的父节点
*/
getParent: function() {
return this.parent;
},
getSiblings: function() {
var children = this.parent.children;
var siblings = [];
var self = this;
children.forEach(function(child) {
if (child != self) siblings.push(child);
});
return siblings;
},
/**
* 获得节点的深度
*/
getLevel: function() {
var level = 0,
ancestor = this.parent;
while (ancestor) {
level++;
ancestor = ancestor.parent;
}
return level;
},
/**
* 获得节点的复杂度(即子树中节点的数量)
*/
getComplex: function() {
var complex = 0;
this.traverse(function() {
complex++;
});
return complex;
},
/**
* 获得节点的类型(root|main|sub)
*/
getType: function(type) {
this.type = ['root', 'main', 'sub'][Math.min(this.getLevel(), 2)];
return this.type;
},
/**
* 判断当前节点是否被测试节点的祖先
* @param {MinderNode} test 被测试的节点
*/
isAncestorOf: function(test) {
var ancestor = test.parent;
while (ancestor) {
if (ancestor == this) return true;
ancestor = ancestor.parent;
}
return false;
},
getData: function(key) {
return key ? this.data[key] : this.data;
},
setData: function(key, value) {
if (typeof key == 'object') {
var data = key;
for (key in data) if (data.hasOwnProperty(key)) {
this.data[key] = data[key];
}
}
else {
this.data[key] = value;
}
return this;
},
/**
* 设置节点的文本数据
* @param {String} text 文本数据
*/
setText: function(text) {
return this.data.text = text;
},
/**
* 获取节点的文本数据
* @return {String}
*/
getText: function() {
return this.data.text || null;
},
/**
* 先序遍历当前节点树
* @param {Function} fn 遍历函数
*/
preTraverse: function(fn, excludeThis) {
var children = this.getChildren();
if (!excludeThis) fn(this);
for (var i = 0; i < children.length; i++) {
children[i].preTraverse(fn);
}
},
/**
* 后序遍历当前节点树
* @param {Function} fn 遍历函数
*/
postTraverse: function(fn, excludeThis) {
var children = this.getChildren();
for (var i = 0; i < children.length; i++) {
children[i].postTraverse(fn);
}
if (!excludeThis) fn(this);
},
traverse: function(fn, excludeThis) {
return this.postTraverse(fn, excludeThis);
},
getChildren: function() {
return this.children;
},
getIndex: function() {
return this.parent ? this.parent.children.indexOf(this) : -1;
},
insertChild: function(node, index) {
if (index === undefined) {
index = this.children.length;
}
if (node.parent) {
node.parent.removeChild(node);
}
node.parent = this;
node.root = this.root;
this.children.splice(index, 0, node);
},
appendChild: function(node) {
return this.insertChild(node);
},
prependChild: function(node) {
return this.insertChild(node, 0);
},
removeChild: function(elem) {
var index = elem,
removed;
if (elem instanceof MinderNode) {
index = this.children.indexOf(elem);
}
if (index >= 0) {
removed = this.children.splice(index, 1)[0];
removed.parent = null;
removed.root = removed;
}
},
clearChildren: function() {
this.children = [];
},
getChild: function(index) {
return this.children[index];
},
getRenderContainer: function() {
return this.rc;
},
getCommonAncestor: function(node) {
return MinderNode.getCommonAncestor(this, node);
},
contains: function(node) {
return this == node || this.isAncestorOf(node);
},
clone: function() {
var cloned = new MinderNode();
cloned.data = utils.clone(this.data);
this.children.forEach(function(child) {
cloned.appendChild(child.clone());
});
return cloned;
},
compareTo: function(node) {
if (!utils.comparePlainObject(this.data, node.data)) return false;
if (!utils.comparePlainObject(this.temp, node.temp)) return false;
if (this.children.length != node.children.length) return false;
var i = 0;
while (this.children[i]) {
if (!this.children[i].compareTo(node.children[i])) return false;
i++;
}
return true;
},
getMinder: function() {
return this.getRoot().minder;
}
});
MinderNode.getCommonAncestor = function(nodeA, nodeB) {
if (nodeA instanceof Array) {
return MinderNode.getCommonAncestor.apply(this, nodeA);
}
switch (arguments.length) {
case 1:
return nodeA.parent || nodeA;
case 2:
if (nodeA.isAncestorOf(nodeB)) {
return nodeA;
}
if (nodeB.isAncestorOf(nodeA)) {
return nodeB;
}
var ancestor = nodeA.parent;
while (ancestor && !ancestor.isAncestorOf(nodeB)) {
ancestor = ancestor.parent;
}
return ancestor;
default:
return Array.prototype.reduce.call(arguments,
function(prev, current) {
return MinderNode.getCommonAncestor(prev, current);
},
nodeA
);
}
};
kity.extendClass(Minder, {
getRoot: function() {
return this._root;
},
setRoot: function(root) {
this._root = root;
root.minder = this;
},
getAllNode: function() {
var nodes = [];
this.getRoot().traverse(function(node) {
nodes.push(node);
});
return nodes;
},
getNodeById: function(id) {
return this.getNodesById([id])[0];
},
getNodesById: function(ids) {
var nodes = this.getAllNode();
var result = [];
nodes.forEach(function(node) {
if (ids.indexOf(node.getData('id')) != -1) {
result.push(node);
}
});
return result;
},
createNode: function(textOrData, parent, index) {
var node = new MinderNode(textOrData);
this.fire('nodecreate', {
node: node,
parent: parent,
index: index
});
this.appendNode(node, parent, index);
return node;
},
appendNode: function(node, parent, index) {
if (parent) parent.insertChild(node, index);
this.attachNode(node);
return this;
},
removeNode: function(node) {
if (node.parent) {
node.parent.removeChild(node);
this.detachNode(node);
this.fire('noderemove', {
node: node
});
}
},
attachNode: function(node) {
var rc = this.getRenderContainer();
node.traverse(function(current) {
current.attached = true;
rc.addShape(current.getRenderContainer());
});
rc.addShape(node.getRenderContainer());
this.fire('nodeattach', {
node: node
});
},
detachNode: function(node) {
var rc = this.getRenderContainer();
node.traverse(function(current) {
current.attached = false;
rc.removeShape(current.getRenderContainer());
});
this.fire('nodedetach', {
node: node
});
},
getMinderTitle: function() {
return this.getRoot().getText();
}
});
module.exports = MinderNode;
});