UNPKG

@7polo/kityminder-core

Version:
1,423 lines (1,401 loc) 379 kB
/*! * ==================================================== * Kity Minder Core - v1.4.54 - 2023-06-04 * https://github.com/fex-team/kityminder-core * GitHub: https://github.com/fex-team/kityminder-core.git * Copyright (c) 2023 Baidu FEX; Licensed BSD-3-Clause * ==================================================== */ (function () { var _p = { r: function(index) { if (_p[index].inited) { return _p[index].value; } if (typeof _p[index].value === "function") { var module = { exports: {} }, returnValue = _p[index].value(null, module.exports, module); _p[index].inited = true; _p[index].value = returnValue; if (returnValue !== undefined) { return returnValue; } else { for (var key in module.exports) { if (module.exports.hasOwnProperty(key)) { _p[index].inited = true; _p[index].value = module.exports; return module.exports; } } } } else { _p[index].inited = true; return _p[index].value; } } }; //src/connect/arc.js /** * @fileOverview * * 圆弧连线 * * @author: techird * @copyright: Baidu FEX, 2014 */ _p[0] = { value: function(require, exports, module) { var kity = _p.r(17); var connect = _p.r(11); var connectMarker = new kity.Marker().pipe(function() { var r = 7; var dot = new kity.Circle(r - 1); this.addShape(dot); this.setRef(r - 1, 0).setViewBox(-r, -r, r + r, r + r).setWidth(r).setHeight(r); this.dot = dot; this.node.setAttribute("markerUnits", "userSpaceOnUse"); }); connect.register("arc", function(node, parent, connection, width, color) { var box = node.getLayoutBox(), pBox = parent.getLayoutBox(); var start, end, vector; var abs = Math.abs; var pathData = []; var side = box.x > pBox.x ? "right" : "left"; node.getMinder().getPaper().addResource(connectMarker); start = new kity.Point(pBox.cx, pBox.cy); end = side == "left" ? new kity.Point(box.right + 2, box.cy) : new kity.Point(box.left - 2, box.cy); vector = kity.Vector.fromPoints(start, end); pathData.push("M", start); pathData.push("A", abs(vector.x), abs(vector.y), 0, 0, vector.x * vector.y > 0 ? 0 : 1, end); connection.setMarker(connectMarker); connectMarker.dot.fill(color); connection.setPathData(pathData); }); } }; //src/connect/arc_tp.js /** * * 圆弧连线 * * @author: along * @copyright: bpd729@163.com , 2015 */ _p[1] = { value: function(require, exports, module) { var kity = _p.r(17); var connect = _p.r(11); var connectMarker = new kity.Marker().pipe(function() { var r = 7; var dot = new kity.Circle(r - 1); this.addShape(dot); this.setRef(r - 1, 0).setViewBox(-r, -r, r + r, r + r).setWidth(r).setHeight(r); this.dot = dot; this.node.setAttribute("markerUnits", "userSpaceOnUse"); }); /** * 天盘图连线除了连接当前节点和前一个节点外, 还需要渲染当前节点和后一个节点的连接, 防止样式上的断线 * 这是天盘图与其余的模板不同的地方 */ connect.register("arc_tp", function(node, parent, connection, width, color) { var end_box = node.getLayoutBox(), start_box = parent.getLayoutBox(); var index = node.getIndex(); var nextNode = parent.getChildren()[index + 1]; if (node.getIndex() > 0) { start_box = parent.getChildren()[index - 1].getLayoutBox(); } var start, end, vector; var abs = Math.abs; var pathData = []; var side = end_box.x > start_box.x ? "right" : "left"; node.getMinder().getPaper().addResource(connectMarker); start = new kity.Point(start_box.cx, start_box.cy); end = new kity.Point(end_box.cx, end_box.cy); var jl = Math.sqrt(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2)); //两圆中心点距离 jl = node.getIndex() == 0 ? jl * .4 : jl; vector = kity.Vector.fromPoints(start, end); pathData.push("M", start); pathData.push("A", jl, jl, 0, 0, 1, end); connection.setMarker(connectMarker); connectMarker.dot.fill(color); connection.setPathData(pathData); // 设置下一个的节点的连接线 if (nextNode && nextNode.getConnection()) { var nextConnection = nextNode.getConnection(); var next_end_box = nextNode.getLayoutBox(); var next_end = new kity.Point(next_end_box.cx, next_end_box.cy); var jl2 = Math.sqrt(Math.pow(end.x - next_end.x, 2) + Math.pow(end.y - next_end.y, 2)); //两圆中心点距离 pathData = []; pathData.push("M", end); pathData.push("A", jl2, jl2, 0, 0, 1, next_end); nextConnection.setMarker(connectMarker); connectMarker.dot.fill(color); nextConnection.setPathData(pathData); } }); } }; //src/connect/bezier.js /** * @fileOverview * * 提供折线相连的方法 * * @author: techird * @copyright: Baidu FEX, 2014 */ _p[2] = { value: function(require, exports, module) { var kity = _p.r(17); var connect = _p.r(11); connect.register("bezier", function(node, parent, connection) { // 连线起点和终点 var po = parent.getLayoutVertexOut(), pi = node.getLayoutVertexIn(); // 连线矢量和方向 var v = parent.getLayoutVectorOut().normalize(); var r = Math.round; var abs = Math.abs; var pathData = []; pathData.push("M", r(po.x), r(po.y)); if (abs(v.x) > abs(v.y)) { // x - direction var hx = (pi.x + po.x) / 2; pathData.push("C", hx, po.y, hx, pi.y, pi.x, pi.y); } else { // y - direction var hy = (pi.y + po.y) / 2; pathData.push("C", po.x, hy, pi.x, hy, pi.x, pi.y); } connection.setMarker(null); connection.setPathData(pathData); }); } }; //src/connect/fish-bone-master.js /** * @fileOverview * * 鱼骨头主干连线 * * @author: techird * @copyright: Baidu FEX, 2014 */ _p[3] = { value: function(require, exports, module) { var kity = _p.r(17); var connect = _p.r(11); connect.register("fish-bone-master", function(node, parent, connection) { var pout = parent.getLayoutVertexOut(), pin = node.getLayoutVertexIn(); var abs = Math.abs; var dy = abs(pout.y - pin.y), dx = abs(pout.x - pin.x); var pathData = []; pathData.push("M", pout.x, pout.y); pathData.push("h", dx - dy); pathData.push("L", pin.x, pin.y); connection.setMarker(null); connection.setPathData(pathData); }); } }; //src/connect/l.js /** * @fileOverview * * "L" 连线 * * @author: techird * @copyright: Baidu FEX, 2014 */ _p[4] = { value: function(require, exports, module) { var kity = _p.r(17); var connect = _p.r(11); connect.register("l", function(node, parent, connection) { var po = parent.getLayoutVertexOut(); var pi = node.getLayoutVertexIn(); var vo = parent.getLayoutVectorOut(); var pathData = []; var r = Math.round, abs = Math.abs; pathData.push("M", po.round()); if (abs(vo.x) > abs(vo.y)) { pathData.push("H", r(pi.x)); } else { pathData.push("V", pi.y); } pathData.push("L", pi); connection.setPathData(pathData); }); } }; //src/connect/poly.js /** * @fileOverview * * 提供折线相连的方法 * * @author: techird * @copyright: Baidu FEX, 2014 */ _p[5] = { value: function(require, exports, module) { var kity = _p.r(17); var connect = _p.r(11); connect.register("poly", function(node, parent, connection, width) { // 连线起点和终点 var po = parent.getLayoutVertexOut(), pi = node.getLayoutVertexIn(); // 连线矢量和方向 var v = parent.getLayoutVectorOut().normalize(); var r = Math.round; var abs = Math.abs; var pathData = []; pathData.push("M", r(po.x), r(po.y)); switch (true) { case abs(v.x) > abs(v.y) && v.x < 0: // left pathData.push("h", -parent.getStyle("margin-left")); pathData.push("v", pi.y - po.y); pathData.push("H", pi.x); break; case abs(v.x) > abs(v.y) && v.x >= 0: // right pathData.push("h", parent.getStyle("margin-right")); pathData.push("v", pi.y - po.y); pathData.push("H", pi.x); break; case abs(v.x) <= abs(v.y) && v.y < 0: // top pathData.push("v", -parent.getStyle("margin-top")); pathData.push("h", pi.x - po.x); pathData.push("V", pi.y); break; case abs(v.x) <= abs(v.y) && v.y >= 0: // bottom pathData.push("v", parent.getStyle("margin-bottom")); pathData.push("h", pi.x - po.x); pathData.push("V", pi.y); break; } connection.setMarker(null); connection.setPathData(pathData); }); } }; //src/connect/under.js /** * @fileOverview * * 下划线连线 * * @author: techird * @copyright: Baidu FEX, 2014 */ _p[6] = { value: function(require, exports, module) { var kity = _p.r(17); var connect = _p.r(11); connect.register("under", function(node, parent, connection, width, color) { var box = node.getLayoutBox(), pBox = parent.getLayoutBox(); var start, end, vector; var abs = Math.abs; var pathData = []; var side = box.x > pBox.x ? "right" : "left"; var radius = node.getStyle("connect-radius"); var underY = box.bottom + 3; var startY = parent.getType() == "sub" ? pBox.bottom + 3 : pBox.cy; var p1, p2, p3, mx; if (side == "right") { p1 = new kity.Point(pBox.right, startY); p2 = new kity.Point(box.left - 10, underY); p3 = new kity.Point(box.right, underY); } else { p1 = new kity.Point(pBox.left, startY); p2 = new kity.Point(box.right + 10, underY); p3 = new kity.Point(box.left, underY); } mx = (p1.x + p2.x) / 2; pathData.push("M", p1); pathData.push("C", mx, p1.y, mx, p2.y, p2); pathData.push("L", p3); connection.setMarker(null); connection.setPathData(pathData); }); } }; //src/core/_boxv.js /** * @fileOverview * * 调试工具:为 kity.Box 提供一个可视化的渲染 * * @author: techird * @copyright: Baidu FEX, 2014 */ _p[7] = { value: function(require, exports, module) { var kity = _p.r(17); var Minder = _p.r(19); 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); }); }); } } }; //src/core/animate.js /** * @fileOverview * * 动画控制 * * @author: techird * @copyright: Baidu FEX, 2014 */ _p[8] = { value: function(require, exports, module) { var Minder = _p.r(19); var animateDefaultOptions = { enableAnimation: true, layoutAnimationDuration: 300, viewAnimationDuration: 100, zoomAnimationDuration: 300 }; var resoredAnimationOptions = {}; Minder.registerInitHook(function() { this.setDefaultOptions(animateDefaultOptions); if (!this.getOption("enableAnimation")) { this.disableAnimation(); } }); Minder.prototype.enableAnimation = function() { for (var name in animateDefaultOptions) { if (animateDefaultOptions.hasOwnProperty(name)) { this.setOption(resoredAnimationOptions[name]); } } }; Minder.prototype.disableAnimation = function() { for (var name in animateDefaultOptions) { if (animateDefaultOptions.hasOwnProperty(name)) { resoredAnimationOptions[name] = this.getOption(name); this.setOption(name, 0); } } }; } }; //src/core/command.js _p[9] = { value: function(require, exports, module) { var kity = _p.r(17); var utils = _p.r(33); var Minder = _p.r(19); var MinderNode = _p.r(21); var MinderEvent = _p.r(13); var COMMAND_STATE_NORMAL = 0; var COMMAND_STATE_DISABLED = -1; var COMMAND_STATE_ACTIVED = 1; /** * 表示一个命令,包含命令的查询及执行 */ var Command = kity.createClass("Command", { constructor: function() { this._isContentChange = true; this._isSelectionChange = false; }, execute: function(minder, args) { throw new Error("Not Implement: Command.execute()"); }, setContentChanged: function(val) { this._isContentChange = !!val; }, isContentChanged: function() { return this._isContentChange; }, setSelectionChanged: function(val) { this._isSelectionChange = !!val; }, isSelectionChanged: function() { return this._isContentChange; }, queryState: function(km) { return COMMAND_STATE_NORMAL; }, queryValue: function(km) { return 0; }, isNeedUndo: function() { return true; } }); Command.STATE_NORMAL = COMMAND_STATE_NORMAL; Command.STATE_ACTIVE = COMMAND_STATE_ACTIVED; Command.STATE_DISABLED = COMMAND_STATE_DISABLED; kity.extendClass(Minder, { _getCommand: function(name) { return this._commands[name.toLowerCase()]; }, _queryCommand: function(name, type, args) { var cmd = this._getCommand(name); if (cmd) { var queryCmd = cmd["query" + type]; if (queryCmd) return queryCmd.apply(cmd, [ this ].concat(args)); } return 0; }, /** * @method queryCommandState() * @for Minder * @description 查询指定命令的状态 * * @grammar queryCommandName(name) => {number} * * @param {string} name 要查询的命令名称 * * @return {number} * -1: 命令不存在或命令当前不可用 * 0: 命令可用 * 1: 命令当前可用并且已经执行过 */ queryCommandState: function(name) { return this._queryCommand(name, "State", [].slice.call(arguments, 1)); }, /** * @method queryCommandValue() * @for Minder * @description 查询指定命令当前的执行值 * * @grammar queryCommandValue(name) => {any} * * @param {string} name 要查询的命令名称 * * @return {any} * 如果命令不存在,返回 undefined * 不同命令具有不同返回值,具体请查看 [Command](command) 章节 */ queryCommandValue: function(name) { return this._queryCommand(name, "Value", [].slice.call(arguments, 1)); }, /** * @method execCommand() * @for Minder * @description 执行指定的命令。 * * @grammar execCommand(name, args...) * * @param {string} name 要执行的命令名称 * @param {argument} args 要传递给命令的其它参数 */ execCommand: function(name) { if (!name) return null; name = name.toLowerCase(); var cmdArgs = [].slice.call(arguments, 1), cmd, stoped, result, eventParams; var me = this; cmd = this._getCommand(name); eventParams = { command: cmd, commandName: name.toLowerCase(), commandArgs: cmdArgs }; if (!cmd || !~this.queryCommandState(name)) { return false; } if (!this._hasEnterExecCommand) { this._hasEnterExecCommand = true; stoped = this._fire(new MinderEvent("beforeExecCommand", eventParams, true)); if (!stoped) { this._fire(new MinderEvent("preExecCommand", eventParams, false)); result = cmd.execute.apply(cmd, [ me ].concat(cmdArgs)); this._fire(new MinderEvent("execCommand", eventParams, false)); if (cmd.isContentChanged()) { this._firePharse(new MinderEvent("contentchange")); } this._interactChange(); } this._hasEnterExecCommand = false; } else { result = cmd.execute.apply(cmd, [ me ].concat(cmdArgs)); if (!this._hasEnterExecCommand) { this._interactChange(); } } return result === undefined ? null : result; } }); module.exports = Command; } }; //src/core/compatibility.js _p[10] = { value: function(require, exports, module) { var utils = _p.r(33); function compatibility(json) { var version = json.version || (json.root ? "1.4.0" : "1.1.3"); switch (version) { case "1.1.3": c_113_120(json); /* falls through */ case "1.2.0": case "1.2.1": c_120_130(json); /* falls through */ case "1.3.0": case "1.3.1": case "1.3.2": case "1.3.3": case "1.3.4": case "1.3.5": /* falls through */ c_130_140(json); } return json; } function traverse(node, fn) { fn(node); if (node.children) node.children.forEach(function(child) { traverse(child, fn); }); } /* 脑图数据升级 */ function c_120_130(json) { traverse(json, function(node) { var data = node.data; delete data.layout_bottom_offset; delete data.layout_default_offset; delete data.layout_filetree_offset; }); } /** * 脑图数据升级 * v1.1.3 => v1.2.0 * */ function c_113_120(json) { // 原本的布局风格 var ocs = json.data.currentstyle; delete json.data.currentstyle; // 为 1.2 选择模板,同时保留老版本文件的皮肤 if (ocs == "bottom") { json.template = "structure"; json.theme = "snow"; } else if (ocs == "default") { json.template = "default"; json.theme = "classic"; } traverse(json, function(node) { var data = node.data; // 升级优先级、进度图标 if ("PriorityIcon" in data) { data.priority = data.PriorityIcon; delete data.PriorityIcon; } if ("ProgressIcon" in data) { data.progress = 1 + (data.ProgressIcon - 1 << 1); delete data.ProgressIcon; } // 删除过时属性 delete data.point; delete data.layout; }); } function c_130_140(json) { json.root = { data: json.data, children: json.children }; delete json.data; delete json.children; } return compatibility; } }; //src/core/connect.js _p[11] = { value: function(require, exports, module) { var kity = _p.r(17); var utils = _p.r(33); var Module = _p.r(20); var Minder = _p.r(19); var MinderNode = _p.r(21); // 连线提供方 var _connectProviders = {}; function register(name, provider) { _connectProviders[name] = provider; } register("default", function(node, parent, connection) { connection.setPathData([ "M", parent.getLayoutVertexOut(), "L", node.getLayoutVertexIn() ]); }); kity.extendClass(MinderNode, { /** * @private * @method getConnect() * @for MinderNode * @description 获取当前节点的连线类型 * * @grammar getConnect() => {string} */ getConnect: function() { return this.data.connect || "default"; }, getConnectProvider: function() { return _connectProviders[this.getConnect()] || _connectProviders["default"]; }, /** * @private * @method getConnection() * @for MinderNode * @description 获取当前节点的连线对象 * * @grammar getConnection() => {kity.Path} */ getConnection: function() { return this._connection || null; } }); kity.extendClass(Minder, { getConnectContainer: function() { return this._connectContainer; }, createConnect: function(node) { if (node.isRoot()) return; var connection = new kity.Path(); node._connection = connection; this._connectContainer.addShape(connection); this.updateConnect(node); }, removeConnect: function(node) { var me = this; node.traverse(function(node) { me._connectContainer.removeShape(node._connection); node._connection = null; }); }, updateConnect: function(node) { var connection = node._connection; var parent = node.parent; if (!parent || !connection) return; if (parent.isCollapsed()) { connection.setVisible(false); return; } connection.setVisible(true); var provider = node.getConnectProvider(); var strokeColor = node.getStyle("connect-color") || "white", strokeWidth = node.getStyle("connect-width") || 2; connection.stroke(strokeColor, strokeWidth); provider(node, parent, connection, strokeWidth, strokeColor); if (strokeWidth % 2 === 0) { connection.setTranslate(.5, .5); } else { connection.setTranslate(0, 0); } } }); Module.register("Connect", { init: function() { this._connectContainer = new kity.Group().setId(utils.uuid("minder_connect_group")); this.getRenderContainer().prependShape(this._connectContainer); }, events: { nodeattach: function(e) { this.createConnect(e.node); }, nodedetach: function(e) { this.removeConnect(e.node); }, "layoutapply layoutfinish noderender": function(e) { this.updateConnect(e.node); } } }); exports.register = register; } }; //src/core/data.js _p[12] = { value: function(require, exports, module) { var kity = _p.r(17); var utils = _p.r(33); var Minder = _p.r(19); var MinderNode = _p.r(21); var MinderEvent = _p.r(13); var compatibility = _p.r(10); var Promise = _p.r(25); var protocols = {}; function registerProtocol(name, protocol) { protocols[name] = protocol; for (var pname in protocols) { if (protocols.hasOwnProperty(pname)) { protocols[pname] = protocols[pname]; protocols[pname].name = pname; } } } function getRegisterProtocol(name) { return name === undefined ? protocols : protocols[name] || null; } exports.registerProtocol = registerProtocol; exports.getRegisterProtocol = getRegisterProtocol; // 导入导出 kity.extendClass(Minder, { // 自动导入 setup: function(target) { if (typeof target == "string") { target = document.querySelector(target); } if (!target) return; var protocol = target.getAttribute("minder-data-type"); if (protocol in protocols) { var data = target.textContent; target.textContent = null; this.renderTo(target); this.importData(protocol, data); } return this; }, /** * @method exportJson() * @for Minder * @description * 导出当前脑图数据为 JSON 对象,导出的数据格式请参考 [Data](data) 章节。 * @grammar exportJson() => {plain} */ exportJson: function() { /* 导出 node 上整棵树的数据为 JSON */ function exportNode(node) { var exported = {}; exported.data = node.getData(); var childNodes = node.getChildren(); exported.children = []; for (var i = 0; i < childNodes.length; i++) { exported.children.push(exportNode(childNodes[i])); } return exported; } var json = { root: exportNode(this.getRoot()) }; json.template = this.getTemplate(); json.theme = this.getTheme(); json.version = Minder.version; return JSON.parse(JSON.stringify(json)); }, /** * function Text2Children(MinderNode, String) * @param {MinderNode} node 要导入数据的节点 * @param {String} text 导入的text数据 * @Desc: 用于批量插入子节点,并不会修改被插入的父节点 * @Editor: Naixor * @Date: 2015.9.21 * @example: 用于批量导入如下类型的节点 * 234 * 3456346 asadf * 12312414 * wereww * 12314 * 1231412 * 13123 */ Text2Children: function(node, text) { if (!(node instanceof kityminder.Node)) { return; } var children = [], jsonMap = {}, level = 0; var LINE_SPLITTER = /\r|\n|\r\n/, TAB_REGEXP = /^(\t|\x20{4})/; var lines = text.split(LINE_SPLITTER), line = "", jsonNode, i = 0; var minder = this; function isEmpty(line) { return line === "" && !/\S/.test(line); } function getNode(line) { return { data: { text: line.replace(/^(\t|\x20{4})+/, "").replace(/(\t|\x20{4})+$/, "") }, children: [] }; } function getLevel(text) { var level = 0; while (TAB_REGEXP.test(text)) { text = text.replace(TAB_REGEXP, ""); level++; } return level; } function addChild(parent, node) { parent.children.push(node); } function importChildren(node, children) { for (var i = 0, l = children.length; i < l; i++) { var childNode = minder.createNode(null, node); childNode.setData("text", children[i].data.text || ""); importChildren(childNode, children[i].children); } } while ((line = lines[i++]) !== undefined) { line = line.replace(/&nbsp;/g, ""); if (isEmpty(line)) continue; level = getLevel(line); jsonNode = getNode(line); if (level === 0) { jsonMap = {}; children.push(jsonNode); jsonMap[0] = children[children.length - 1]; } else { if (!jsonMap[level - 1]) { throw new Error("Invalid local format"); } addChild(jsonMap[level - 1], jsonNode); jsonMap[level] = jsonNode; } } importChildren(node, children); minder.refresh(); }, /** * @method exportNode(MinderNode) * @param {MinderNode} node 当前要被导出的节点 * @return {Object} 返回只含有data和children的Object * @Editor: Naixor * @Date: 2015.9.22 */ exportNode: function(node) { var exported = {}; exported.data = node.getData(); var childNodes = node.getChildren(); exported.children = []; for (var i = 0; i < childNodes.length; i++) { exported.children.push(this.exportNode(childNodes[i])); } return exported; }, /** * @method importNode() * @description 根据纯json {data, children}数据转换成为脑图节点 * @Editor: Naixor * @Date: 2015.9.20 */ importNode: function(node, json) { var data = json.data; node.data = {}; for (var field in data) { node.setData(field, data[field]); } var childrenTreeData = json.children || []; for (var i = 0; i < childrenTreeData.length; i++) { var childNode = this.createNode(null, node); this.importNode(childNode, childrenTreeData[i]); } return node; }, /** * @method importJson() * @for Minder * @description 导入脑图数据,数据为 JSON 对象,具体的数据字段形式请参考 [Data](data) 章节。 * * @grammar importJson(json) => {this} * * @param {plain} json 要导入的数据 */ importJson: function(json) { if (!json) return; /** * @event preimport * @for Minder * @when 导入数据之前 */ this._fire(new MinderEvent("preimport", null, false)); // 删除当前所有节点 while (this._root.getChildren().length) { this.removeNode(this._root.getChildren()[0]); } json = compatibility(json); this.importNode(this._root, json.root); this.setTemplate(json.template || "default"); this.setTheme(json.theme || null); this.refresh(); /** * @event import,contentchange,interactchange * @for Minder * @when 导入数据之后 */ this.fire("import"); this._firePharse({ type: "contentchange" }); this._interactChange(); return this; }, /** * @method exportData() * @for Minder * @description 使用指定使用的数据协议,导入脑图数据 * * @grammar exportData(protocol) => Promise<data> * * @param {string} protocol 指定的数据协议(默认内置五种数据协议 `json`、`text`、`markdown`、`svg` 和 `png`) */ exportData: function(protocolName, option) { var json, protocol; json = this.exportJson(); // 指定了协议进行导出,需要检测协议是否支持 if (protocolName) { protocol = protocols[protocolName]; if (!protocol || !protocol.encode) { return Promise.reject(new Error("Not supported protocol:" + protocolName)); } } // 导出前抛个事件 this._fire(new MinderEvent("beforeexport", { json: json, protocolName: protocolName, protocol: protocol })); return Promise.resolve(protocol.encode(json, this, option)); }, /** * @method importData() * @for Minder * @description 使用指定的数据协议,导入脑图数据,覆盖当前实例的脑图 * * @grammar importData(protocol, callback) => Promise<json> * * @param {string} protocol 指定的用于解析数据的数据协议(默认内置三种数据协议 `json`、`text` 和 `markdown` 的支持) * @param {any} data 要导入的数据 */ importData: function(protocolName, data, option) { var json, protocol; var minder = this; // 指定了协议进行导入,需要检测协议是否支持 if (protocolName) { protocol = protocols[protocolName]; if (!protocol || !protocol.decode) { return Promise.reject(new Error("Not supported protocol:" + protocolName)); } } var params = { local: data, protocolName: protocolName, protocol: protocol }; // 导入前抛事件 this._fire(new MinderEvent("beforeimport", params)); return Promise.resolve(protocol.decode(data, this, option)).then(function(json) { minder.importJson(json); return json; }); }, /** * @method decodeData() * @for Minder * @description 使用指定的数据协议,解析为脑图数据,与 importData 的区别在于:不覆盖当前实例的脑图 * * @grammar decodeData(protocol, callback) => Promise<json> * * @param {string} protocol 指定的用于解析数据的数据协议(默认内置三种数据协议 `json`、`text` 和 `markdown` 的支持) * @param {any} data 要导入的数据 */ decodeData: function(protocolName, data, option) { var json, protocol; var minder = this; // 指定了协议进行导入,需要检测协议是否支持 if (protocolName) { protocol = protocols[protocolName]; if (!protocol || !protocol.decode) { return Promise.reject(new Error("Not supported protocol:" + protocolName)); } } var params = { local: data, protocolName: protocolName, protocol: protocol }; // 导入前抛事件 this._fire(new MinderEvent("beforeimport", params)); return Promise.resolve(protocol.decode(data, this, option)); } }); } }; //src/core/event.js _p[13] = { value: function(require, exports, module) { var kity = _p.r(17); var utils = _p.r(33); var Minder = _p.r(19); /** * @class MinderEvent * @description 表示一个脑图中发生的事件 */ var MinderEvent = kity.createClass("MindEvent", { constructor: function(type, params, canstop) { params = params || {}; if (params.getType && params.getType() == "ShapeEvent") { /** * @property kityEvent * @for MinderEvent * @description 如果事件是从一个 kity 的事件派生的,会有 kityEvent 属性指向原来的 kity 事件 * @type {KityEvent} */ this.kityEvent = params; /** * @property originEvent * @for MinderEvent * @description 如果事件是从原声 Dom 事件派生的(如 click、mousemove 等),会有 originEvent 指向原来的 Dom 事件 * @type {DomEvent} */ this.originEvent = params.originEvent; } else if (params.target && params.preventDefault) { this.originEvent = params; } else { kity.Utils.extend(this, params); } /** * @property type * @for MinderEvent * @description 事件的类型,如 `click`、`contentchange` 等 * @type {string} */ this.type = type; this._canstop = canstop || false; }, /** * @method getPosition() * @for MinderEvent * @description 如果事件是从一个 kity 事件派生的,会有 `getPosition()` 获取事件发生的坐标 * * @grammar getPosition(refer) => {kity.Point} * * @param {string|kity.Shape} refer * 参照的坐标系, * `"screen"` - 以浏览器屏幕为参照坐标系 * `"minder"` - (默认)以脑图画布为参照坐标系 * `{kity.Shape}` - 指定以某个 kity 图形为参照坐标系 */ getPosition: function(refer) { if (!this.kityEvent) return; if (!refer || refer == "minder") { return this.kityEvent.getPosition(this.minder.getRenderContainer()); } return this.kityEvent.getPosition.call(this.kityEvent, refer); }, /** * @method getTargetNode() * @for MinderEvent * @description 当发生的事件是鼠标事件时,获取事件位置命中的脑图节点 * * @grammar getTargetNode() => {MinderNode} */ getTargetNode: function() { var findShape = this.kityEvent && this.kityEvent.targetShape; if (!findShape) return null; while (!findShape.minderNode && findShape.container) { findShape = findShape.container; } var node = findShape.minderNode; if (node && findShape.getOpacity() < 1) return null; return node || null; }, /** * @method stopPropagation() * @for MinderEvent * @description 当发生的事件是鼠标事件时,获取事件位置命中的脑图节点 * * @grammar getTargetNode() => {MinderNode} */ stopPropagation: function() { this._stoped = true; }, stopPropagationImmediately: function() { this._immediatelyStoped = true; this._stoped = true; }, shouldStopPropagation: function() { return this._canstop && this._stoped; }, shouldStopPropagationImmediately: function() { return this._canstop && this._immediatelyStoped; }, preventDefault: function() { this.originEvent.preventDefault(); }, isRightMB: function() { var isRightMB = false; if (!this.originEvent) { return false; } if ("which" in this.originEvent) isRightMB = this.originEvent.which == 3; else if ("button" in this.originEvent) isRightMB = this.originEvent.button == 2; return isRightMB; }, getKeyCode: function() { var evt = this.originEvent; return evt.keyCode || evt.which; } }); Minder.registerInitHook(function(option) { this._initEvents(); }); kity.extendClass(Minder, { _initEvents: function() { this._eventCallbacks = {}; }, _resetEvents: function() { this._initEvents(); this._bindEvents(); }, _bindEvents: function() { /* jscs:disable maximumLineLength */ this._paper.on("click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop", this._firePharse.bind(this)); if (window) { window.addEventListener("resize", this._firePharse.bind(this)); } }, /** * @method dispatchKeyEvent * @description 派发键盘(相关)事件到脑图实例上,让实例的模块处理 * @grammar dispatchKeyEvent(e) => {this} * @param {Event} e 原生的 Dom 事件对象 */ dispatchKeyEvent: function(e) { this._firePharse(e); }, _firePharse: function(e) { var beforeEvent, preEvent, executeEvent; if (e.type == "DOMMouseScroll") { e.type = "mousewheel"; e.wheelDelta = e.originEvent.wheelDelta = e.originEvent.detail * -10; e.wheelDeltaX = e.originEvent.mozMovementX; e.wheelDeltaY = e.originEvent.mozMovementY; } beforeEvent = new MinderEvent("before" + e.type, e, true); if (this._fire(beforeEvent)) { return; } preEvent = new MinderEvent("pre" + e.type, e, true); executeEvent = new MinderEvent(e.type, e, true); if (this._fire(preEvent) || this._fire(executeEvent)) this._fire(new MinderEvent("after" + e.type, e, false)); }, _interactChange: function(e) { var me = this; if (me._interactScheduled) return; setTimeout(function() { me._fire(new MinderEvent("interactchange")); me._interactScheduled = false; }, 100); me._interactScheduled = true; }, _listen: function(type, callback) { var callbacks = this._eventCallbacks[type] || (this._eventCallbacks[type] = []); callbacks.push(callback); }, _fire: function(e) { /** * @property minder * @description 产生事件的 Minder 对象 * @for MinderShape * @type {Minder} */ e.minder = this; var status = this.getStatus(); var callbacks = this._eventCallbacks[e.type.toLowerCase()] || []; if (status) { callbacks = callbacks.concat(this._eventCallbacks[status + "." + e.type.toLowerCase()] || []); } if (callbacks.length === 0) { return; } var lastStatus = this.getStatus(); for (var i = 0; i < callbacks.length; i++) { callbacks[i].call(this, e); /* this.getStatus() != lastStatus ||*/ if (e.shouldStopPropagationImmediately()) { break; } } return e.shouldStopPropagation(); }, on: function(name, callback) { var km = this; name.split(/\s+/).forEach(function(n) { km._listen(n.toLowerCase(), callback); }); return this; }, off: function(name, callback) { var types = name.split(/\s+/); var i, j, callbacks, removeIndex; for (i = 0; i < types.length; i++) { callbacks = this._eventCallbacks[types[i].toLowerCase()]; if (callbacks) { removeIndex = null; for (j = 0; j < callbacks.length; j++) { if (callbacks[j] == callback) { removeIndex = j; } } if (removeIndex !== null) { callbacks.splice(removeIndex, 1); } } } }, fire: function(type, params) { var e = new MinderEvent(type, params); this._fire(e); return this; } }); module.exports = MinderEvent; } }; //src/core/focus.js _p[14] = { value: function(require, exports, module) { var kity = _p.r(17); var Minder = _p.r(19); Minder.registerInitHook(function() { this.on("beforemousedown", function(e) { this.focus(); e.preventDefault(); }); this.on("paperrender", function() { this.focus(); }); }); kity.extendClass(Minder, { focus: function() { if (!this.isFocused()) { var renderTarget = this._renderTarget; renderTarget.classList.add("focus"); this.renderNodeBatch(this.getSelectedNodes()); } this.fire("focus"); return this; }, blur: function() { if (this.isFocused()) { var renderTarget = this._renderTarget; renderTarget.classList.remove("focus"); this.renderNodeBatch(this.getSelectedNodes()); } this.fire("blur"); return this; }, isFocused: function() { var renderTarget = this._renderTarget; return renderTarget && renderTarget.classList.contains("focus"); } }); } }; //src/core/keymap.js _p[15] = { value: function(require, exports, module) { var keymap = { Backspace: 8, Tab: 9, Enter: 13, Shift: 16, Control: 17, Alt: 18, CapsLock: 20, Esc: 27, Spacebar: 32, PageUp: 33, PageDown: 34, End: 35, Home: 36, Insert: 45, Left: 37, Up: 38, Right: 39, Down: 40, direction: { 37: 1, 38: 1, 39: 1, 40: 1 }, Del: 46, NumLock: 144, Cmd: 91, CmdFF: 224, F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123, "`": 192, "=": 187, "-": 189, "/": 191, ".": 190, controlKeys: { 16: 1, 17: 1, 18: 1, 20: 1, 91: 1, 224: 1 }, notContentChange: { 13: 1, 9: 1, 33: 1, 34: 1, 35: 1, 36: 1, 16: 1, 17: 1, 18: 1, 20: 1, 91: 1, //上下左右 37: 1, 38: 1, 39: 1, 40: 1, 113: 1, 114: 1, 115: 1, 144: 1, 27: 1 }, isSelectedNodeKey: { //上下左右 37: 1, 38: 1, 39: 1, 40: 1, 13: 1, 9: 1 } }; // 小写适配 for (var key in keymap) { if (keymap.hasOwnProperty(key)) { keymap[key.toLowerCase()] = keymap[key]; } } var aKeyCode = 65; var aCharCode = "a".charCodeAt(0);