Commit 16302366 authored by techird's avatar techird

dev

parent cc623c59
{
"name": "kityminder-core",
"title": "Kity Minder Core",
"description": "Powerful online mind graphic visualization and editor (command based)",
"version": "1.3.6",
"main": "src/kityminder.js",
"keywords": ["kityminder", "kity", "svg"],
"homepage": "https://github.com/fex-team/kityminder-core",
"devDependencies": {
"seajs": "~2.3.0"
},
"licenses": [{
"type": "BSD",
"url": "https://github.com/fex-team/kityminder-core/blob/dev/LICENSE"
}],
"bugs": {
"url": "https://github.com/fex-team/kityminder-core/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/fex-team/kityminder-core.git"
},
"author": {
"name": "Baidu FEX",
"url": "http://fex.baidu.com"
"name": "kityminder-core",
"title": "Kity Minder Core",
"description": "Powerful online mind graphic visualization and editor (command based)",
"version": "1.3.6",
"main": "src/kityminder.js",
"keywords": [
"kityminder",
"kity",
"svg"
],
"homepage": "https://github.com/fex-team/kityminder-core",
"devDependencies": {
"seajs": "~2.3.0"
},
"licenses": [
{
"type": "BSD",
"url": "https://github.com/fex-team/kityminder-core/blob/dev/LICENSE"
}
}
\ No newline at end of file
],
"bugs": {
"url": "https://github.com/fex-team/kityminder-core/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/fex-team/kityminder-core.git"
},
"author": {
"name": "Baidu FEX",
"url": "http://fex.baidu.com"
},
"dependencies": {
"json-diff": "*"
}
}
/**
* @fileOverview
*
* 调试工具:为 kity.Box 提供一个可视化的渲染
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
define(function(require, exports, module) {
var kity = require('./kity');
var Minder = require('./minder');
if (location.href.indexOf('boxv') != -1) {
var vrect;
Object.defineProperty(kity.Box.prototype, 'visualization', {
get: function() {
if (!vrect) return null;
return vrect.setBox(this);
}
});
Minder.registerInitHook(function() {
this.on('paperrender', function() {
vrect = new kity.Rect();
vrect.fill('rgba(200, 200, 200, .5)');
vrect.stroke('orange');
this.getRenderContainer().addShape(vrect);
});
});
}
});
\ No newline at end of file
......@@ -134,23 +134,18 @@ define(function(require, exports, module) {
return false;
}
if (!this._hasEnterExecCommand && cmd.isNeedUndo()) {
if (!this._hasEnterExecCommand) {
this._hasEnterExecCommand = true;
stoped = this._fire(new MinderEvent('beforeExecCommand', eventParams, true));
if (!stoped) {
//保存场景
this._fire(new MinderEvent('saveScene'));
this._fire(new MinderEvent('preExecCommand', eventParams, false));
result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
this._fire(new MinderEvent('execCommand', eventParams, false));
//保存场景
this._fire(new MinderEvent('saveScene'));
if (cmd.isContentChanged()) {
this._firePharse(new MinderEvent('contentchange'));
}
......
......@@ -46,11 +46,9 @@ define(function(require, exports, module) {
var exported = {};
exported.data = node.getData();
var childNodes = node.getChildren();
if (childNodes.length) {
exported.children = [];
for (var i = 0; i < childNodes.length; i++) {
exported.children.push(exportNode(childNodes[i]));
}
exported.children = [];
for (var i = 0; i < childNodes.length; i++) {
exported.children.push(exportNode(childNodes[i]));
}
return exported;
}
......@@ -63,7 +61,7 @@ define(function(require, exports, module) {
json.theme = this.getTheme();
json.version = Minder.version;
return json;
return JSON.parse(JSON.stringify(json));
},
/**
......
......@@ -34,7 +34,7 @@ define(function(require, exports, module) {
* children[i].setLayoutTransform(new kity.Matrix().translate(x, y));
* }
*/
doLayout: function(node) {
doLayout: function(parent, children) {
throw new Error('Not Implement: Layout.doLayout()');
},
......@@ -234,10 +234,6 @@ define(function(require, exports, module) {
return this.parent.getLayoutInstance().getOrderHint(this);
},
getExpandPosition: function() {
return this.getLayoutInstance().getExpandPosition();
},
/**
* 获取当前节点相对于父节点的布局变换
*/
......@@ -255,7 +251,7 @@ define(function(require, exports, module) {
var matrix = this.getLayoutTransform();
var offset = this.getLayoutOffset();
if (offset) {
matrix.translate(offset.x, offset.y);
matrix = matrix.clone().translate(offset.x, offset.y);
}
return pMatrix.merge(matrix);
},
......@@ -359,16 +355,10 @@ define(function(require, exports, module) {
setLayoutOffset: function(p) {
if (!this.parent) return this;
if (p && !this.hasLayoutOffset()) {
var m = this.getLayoutTransform().m;
p = p.offset(m.e, m.f);
this.setLayoutTransform(null);
}
this.setData('layout_' + this.parent.getLayout() + '_offset', p ? {
x: p.x,
y: p.y
} : null);
} : undefined);
return this;
},
......@@ -421,7 +411,7 @@ define(function(require, exports, module) {
var childrenInFlow = node.getChildren().filter(function(child) {
return !child.hasLayoutOffset();
});
layout.doLayout(node, childrenInFlow, round);
layout.doLayout(node, node.getChildren(), round);
}
// 第一轮布局
......@@ -471,7 +461,7 @@ define(function(require, exports, module) {
}
function apply(node, pMatrix) {
var matrix = node.getLayoutTransform().merge(pMatrix);
var matrix = node.getLayoutTransform().merge(pMatrix.clone());
var lastMatrix = node.getGlobalLayoutTransform() || new kity.Matrix();
var offset = node.getLayoutOffset();
......@@ -480,7 +470,6 @@ define(function(require, exports, module) {
matrix.m.e = Math.round(matrix.m.e);
matrix.m.f = Math.round(matrix.m.f);
// 如果当前有动画,停止动画
if (node._layoutTimeline) {
node._layoutTimeline.stop();
......@@ -518,7 +507,6 @@ define(function(require, exports, module) {
apply(node.children[i], matrix);
}
}
apply(root, root.parent ? root.parent.getGlobalLayoutTransform() : new kity.Matrix());
return this;
},
......
......@@ -72,6 +72,16 @@ define(function(require, exports, module) {
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;
},
/**
* 获得节点的深度
*/
......@@ -122,7 +132,16 @@ define(function(require, exports, module) {
},
setData: function(key, value) {
this.data[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;
},
/**
......@@ -305,6 +324,29 @@ define(function(require, exports, module) {
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', {
......
/**
* @fileOverview
*
* 打补丁
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
define(function(require, exports, module) {
var kity = require('./kity');
var Minder = require('./minder');
function insertNode(minder, info, parent, index) {
parent = minder.createNode(info.data, parent, index);
info.children.forEach(function(childInfo, index) {
insertNode(minder, childInfo, parent, index);
});
return parent;
}
function applyPatch(minder, patch) {
// patch.op - 操作,包括 remove, add, replace
// patch.path - 路径,如 '/root/children/1/data'
// patch.value - 数据,如 { text: "思路" }
var path = patch.path.split('/');
path.shift();
var changed = path.shift();
if (changed == 'root') {
var dataIndex = path.indexOf('data');
if (dataIndex > -1) {
changed = 'data';
var dataPath = path.splice(dataIndex + 1);
patch.field = dataPath.shift();
} else {
changed = 'node';
}
var node = minder.getRoot();
var segment, index;
while (segment = path.shift()) {
if (segment == 'children') continue;
if (typeof index != 'undefined') node = node.getChild(index);
index = +segment;
}
patch.index = index;
patch.node = node;
}
var express = [changed, patch.op].join('.');
switch (express) {
case 'theme.replace':
minder.useTheme(patch.value);
break;
case 'template.replace':
minder.useTemplate(patch.value);
break;
case 'node.add':
insertNode(minder, patch.value, patch.node, patch.index).renderTree();
minder.layout();
break;
case 'node.remove':
minder.removeNode(patch.node.getChild(patch.index));
minder.layout();
break;
case 'data.add':
case 'data.replace':
case 'data.remove':
patch.node.setData(patch.field, patch.value).renderTree();
minder.layout();
}
}
kity.extendClass(Minder, {
applyPatches: function(patches) {
for (var i = 0; i < patches.length; i++) {
applyPatch(this, patches[i]);
}
this.fire('contentchange');
return this;
}
});
});
\ No newline at end of file
......@@ -80,7 +80,6 @@ define(function(require, exports, module) {
this.renderChangedSelection(lastSelect);
return this;
},
//当前选区中的节点在给定的节点范围内的保留选中状态,
//没在给定范围的取消选中,给定范围中的但没在当前选中范围的也做选中效果
toggleSelect: function(node) {
......
......@@ -64,6 +64,7 @@ define(function(require, exports, module) {
},
setTheme: function(name) {
if (name && !_themes[name]) throw new Error('Theme ' + name + ' not exists!');
var lastTheme = this._theme;
this._theme = name || null;
var container = this.getRenderTarget();
......
......@@ -39,6 +39,8 @@ define(function(require, exports, module) {
kityminder.Theme = require('./core/theme');
kityminder.Template = require('./core/template');
kityminder.Promise = require('./core/promise');
require('./core/_boxv');
require('./core/patch');
// 模块依赖
require('./module/arrange');
......@@ -47,7 +49,6 @@ define(function(require, exports, module) {
require('./module/dragtree');
require('./module/expand');
require('./module/font');
require('./module/history');
require('./module/hyperlink');
require('./module/image');
require('./module/keynav');
......@@ -81,6 +82,7 @@ define(function(require, exports, module) {
require('./theme/fresh');
require('./theme/fish');
require('./theme/snow');
require('./theme/wire');
require('./connect/arc');
require('./connect/bezier');
......
......@@ -112,7 +112,7 @@ define(function(require, exports, module) {
this.stack(children, oppsite[axis]);
var bbox = this.getBranchBox(children);
var xAdjust, yAdjust;
var xAdjust = 0, yAdjust = 0;
if (axis == 'x') {
xAdjust = pbox[name];
......
......@@ -29,7 +29,7 @@ define(function(require, exports, module) {
function sendToClipboard(nodes) {
if (!nodes.length) return;
nodes.sort(function(a, b) {
return b.getIndex() - a.getIndex();
return a.getIndex() - b.getIndex();
});
_clipboardNodes = nodes.map(function(node) {
return node.clone();
......
define(function(require, exports, module) {
var kity = require('../core/kity');
var utils = require('../core/utils');
var Minder = require('../core/minder');
var MinderNode = require('../core/node');
var Command = require('../core/command');
var Module = require('../core/module');
function compareObject(source, target) {
var tmp;
if (isEmptyObject(source) !== isEmptyObject(target)) {
return false;
}
if (getObjectLength(source) != getObjectLength(target)) {
return false;
}
for (var p in source) {
if (source.hasOwnProperty(p)) {
tmp = source[p];
if (target[p] === undefined) {
return false;
}
if (utils.isObject(tmp) || utils.isArray(tmp)) {
if (utils.isObject(target[p]) !== utils.isObject(tmp)) {
return false;
}
if (utils.isArray(tmp) !== utils.isArray(target[p])) {
return false;
}
if (compareObject(tmp, target[p]) === false) {
return false;
}
} else {
if (tmp != target[p]) {
return false;
}
}
}
}
return true;
}
function getObjectLength(obj) {
if (utils.isArray(obj) || utils.isString(obj)) return obj.length;
var count = 0;
for (var key in obj)
if (obj.hasOwnProperty(key)) count++;
return count;
}
function isEmptyObject(obj) {
if (obj === null || obj === undefined) return true;
if (utils.isArray(obj) || utils.isString(obj)) return obj.length === 0;
for (var key in obj)
if (obj.hasOwnProperty(key)) return false;
return true;
}
function getValueByIndex(data, index) {
var initIndex = 0,
result = 0;
data.forEach(function(arr, i) {
if (initIndex + arr.length >= index) {
if (index - initIndex == arr.length) {
if (arr.length == 1 && arr[0].width === 0) {
initIndex++;
return;
}
result = {
x: arr[arr.length - 1].x + arr[arr.length - 1].width,
y: arr[arr.length - 1].y
};
} else {
result = arr[index - initIndex];
}
return false;
} else {
initIndex += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
}
});
return result;
}
function getNodeIndex(node, ignoreTextNode) {
var preNode = node,
i = 0;
while (preNode = preNode.previousSibling) {
if (ignoreTextNode && preNode.nodeType == 3) {
if (preNode.nodeType != preNode.nextSibling.nodeType) {
i++;
}
continue;
}
i++;
}
return i;
}
var km = this;
var Scene = kity.createClass('Scene', {
constructor: function(root, inputStatus) {
this.data = root.clone();
this.inputStatus = inputStatus;
},
getData: function() {
return this.data;
},
cloneData: function() {
return this.getData().clone();
},
equals: function(scene) {
return this.getData().compareTo(scene.getData());
},
isInputStatus: function() {
return this.inputStatus;
},
setInputStatus: function(status) {
this.inputStatus = status;
}
});
var HistoryManager = kity.createClass('HistoryManager', {
constructor: function(km) {
this.list = [];
this.index = 0;
this.hasUndo = false;
this.hasRedo = false;
this.km = km;
},
undo: function() {
if (this.hasUndo) {
var currentScene = this.list[this.index];
//如果是输入文字时的保存,直接回复当前场景
if (currentScene && currentScene.isInputStatus()) {
this.saveScene();
this.restore(--this.index);
currentScene.setInputStatus(false);
return;
}
if (this.list.length == 1) {
this.restore(0);
return;
}
if (!this.list[this.index - 1] && this.list.length == 1) {
this.reset();
return;
}
while (this.list[this.index].equals(this.list[this.index - 1])) {
this.index--;
if (this.index === 0) {
return this.restore(0);
}
}
this.restore(--this.index);
}
},
redo: function() {
if (this.hasRedo) {
while (this.list[this.index].equals(this.list[this.index + 1])) {
this.index++;
if (this.index == this.list.length - 1) {
return this.restore(this.index);
}
}
this.restore(++this.index);
}
},
partialRenewal: function(target) {
var selectedNodes = [];
function compareNode(source, target) {
if (source.getText() != target.getText()) {
return false;
}
if (compareObject(source.getData(), target.getData()) === false) {
return false;
}
return true;
}
function appendChildNode(parent, child) {
if (child.isSelected()) {
selectedNodes.push(child);
}
km.appendNode(child, parent);
child.render();
var children = child.children.slice();
for (var i = 0, ci; ci = children[i++];) {
appendChildNode(child, ci);
}
}
function traverseNode(srcNode, tagNode) {
if (compareNode(srcNode, tagNode) === false) {
srcNode.setValue(tagNode);
}
//todo,这里有性能问题,变成全部render了
srcNode.render();
if (srcNode.isSelected()) {
selectedNodes.push(srcNode);
}
for (var i = 0, j = 0, si, tj;
(si = srcNode.children[i], tj = tagNode.children[j], si || tj); i++, j++) {
if (si && !tj) {
i--;
km.removeNode(si);
} else if (!si && tj) {
j--;
appendChildNode(srcNode, tj);
} else {
traverseNode(si, tj);
}
}
}
var km = this.km;
traverseNode(km.getRoot(), target);
km.layout(200);
km.select(selectedNodes, true);
selectedNodes = [];
},
restore: function(index) {
index = index === undefined ? this.index : index;
var scene = this.list[index];
this.partialRenewal(scene.cloneData());
this.update();
this.km.fire('restoreScene');
this.km.fire('contentChange');
},
getScene: function(inputStatus) {
return new Scene(this.km.getRoot(), inputStatus);
},
saveScene: function(inputStatus) {
var currentScene = this.getScene(inputStatus);
var lastScene = this.list[this.index];
if (lastScene && lastScene.equals(currentScene)) {
if (inputStatus) {
lastScene.setInputStatus(true);
this.update();
}
return;
}
this.list = this.list.slice(0, this.index + 1);
this.list.push(currentScene);
//如果大于最大数量了,就把最前的剔除
if (this.list.length > this.km.getOption('maxUndoCount')) {
this.list.shift();
}
this.index = this.list.length - 1;
//跟新undo/redo状态
this.update();
},
update: function() {
this.hasRedo = !!this.list[this.index + 1];
this.hasUndo = !!this.list[this.index - 1];
var currentScene = this.list[this.index];
if (currentScene && currentScene.isInputStatus()) {
this.hasUndo = true;
}
},
reset: function() {
this.list = [];
this.index = 0;
this.hasUndo = false;
this.hasRedo = false;
}
});
Module.register('HistoryModule', function() {
//为km实例添加history管理
this.historyManager = new HistoryManager(this);
return {
defaultOptions: {
maxUndoCount: 20,
maxInputCount: 20
},
'commands': {
/**
* @command Undo
* @description 回退上一步操作
* @state
* 0: 当前有可回退的内容
* -1: 当前没有可回退的内容
*/
'undo': kity.createClass('UndoCommand', {
base: Command,
execute: function(km) {
km.historyManager.undo();
},
queryState: function(km) {
return km.historyManager.hasUndo ? 0 : -1;
},
isNeedUndo: function() {
return false;
}
}),
/**
* @command Redo
* @description 重做下一步已回退的操作
* @state
* 0: 当前有可重做的内容
* -1: 当前没有可重做的内容
*/
'redo': kity.createClass('RedoCommand', {
base: Command,
execute: function(km) {
km.historyManager.redo();
},
queryState: function(km) {
return km.historyManager.hasRedo ? 0 : -1;
},
isNeedUndo: function() {
return false;
}
})
},
commandShortcutKeys: {
'undo': 'ctrl+z', //undo
'redo': 'ctrl+y' //redo
},
'events': {
'saveScene': function(e) {
this.historyManager.saveScene(e.inputStatus);
},
'import': function() {
this.historyManager.reset();
}
}
};
});
});
\ No newline at end of file
......@@ -31,8 +31,7 @@ define(function(require, exports, module) {
bottom: p.y + p.height,
width: p.width,
height: p.height,
node: node,
text: node.getText()
node: node
});
}
});
......@@ -57,10 +56,19 @@ define(function(require, exports, module) {
else if (yDist < 0) dist = xDist;
else dist = sqrt(xDist * xDist + yDist * yDist);
return {
cx: dist,
cy: dist
};
var node1 = box1.node;
var node2 = box2.node;
// sibling
if (node1.parent == node2.parent) {
dist /= 10;
}
// parent
if (node2.parent == node1) {
dist /= 5;
}
return dist;
}
function findClosestPointsFor(pointIndexes, iFind) {
......@@ -78,9 +86,9 @@ define(function(require, exports, module) {
// left check
if (current.right < find.left) {
if (!most.left || dist.cx < most.left.dist) {
if (!most.left || dist < most.left.dist) {
most.left = {
dist: dist.cx,
dist: dist,
node: current.node
};
}
......@@ -88,9 +96,9 @@ define(function(require, exports, module) {
// right check
if (current.left > find.right) {
if (!most.right || dist.cx < most.right.dist) {
if (!most.right || dist < most.right.dist) {
most.right = {
dist: dist.cx,
dist: dist,
node: current.node
};
}
......@@ -98,9 +106,9 @@ define(function(require, exports, module) {
// top check
if (current.bottom < find.top) {
if (!most.top || dist.cy < most.top.dist) {
if (!most.top || dist < most.top.dist) {
most.top = {
dist: dist.cy,
dist: dist,
node: current.node
};
}
......@@ -108,9 +116,9 @@ define(function(require, exports, module) {
// bottom check
if (current.top > find.bottom) {
if (!most.down || dist.cy < most.down.dist) {
if (!most.down || dist < most.down.dist) {
most.down = {
dist: dist.cy,
dist: dist,
node: current.node
};
}
......
......@@ -23,10 +23,15 @@ define(function(require, exports, module) {
if (!parent) {
return null;
}
parent.expand();
var node = km.createNode(text, parent);
km.select(node, true);
node.render();
if (parent.isExpanded()) {
node.render();
}
else {
parent.expand();
parent.renderTree();
}
km.layout(600);
},
queryState: function(km) {
......@@ -115,7 +120,7 @@ define(function(require, exports, module) {
},
queryState: function(km) {
var nodes = km.getSelectedNodes();
if (!nodes.length) return;
if (!nodes.length) return -1;
var parent = nodes[0].parent;
if (!parent) return -1;
for (var i = 1; i < nodes.length; i++) {
......
......@@ -132,7 +132,7 @@ define(function(require, exports, module) {
// 点中了节点,并且按了 shift 键:
// 被点中的节点切换选中状态
else if (e.originEvent.shiftKey) {
else if (e.isShortcutKey('Ctrl')) {
this.toggleSelect(downNode);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment