/** * Plugin for Freemind import. * See https://github.com/jiangxin/freemind-mmx/tree/master/freemind */ Draw.loadPlugin(function(ui) { var graph = ui.editor.graph; // Adds resource for action mxResources.parse('importFreemind=Freemind'); // Parses Freemind data function importFreemindData(data) { // Gets the default parent for inserting new cells. This // is normally the first child of the root (ie. layer 0). var defaultParent = graph.getDefaultParent(); var cells = []; var defaultWidth = 80; var defaultHeight = 30; var mainConceptHeight = 40; var defaultHorizontalSpaceBetweenVertex = 40; var defaultVerticalSpaceBetweenVertex = 10; var freeMindMainConceptVertexStyle = "ellipse;whiteSpace=wrap;html=1;align=center;collapsible=0;container=1;recursiveResize=0;"; var freeMindBranchVertexStyle = "whiteSpace=wrap;html=1;shape=partialRectangle;top=0;left=0;bottom=1;right=0;points=[[0,1],[1,1]];strokeColor=#000000;fillColor=none;align=center;verticalAlign=bottom;routingCenterY=0.5;snapToPoint=1;collapsible=0;container=1;recursiveResize=0;autosize=1;"; var freeMindConceptVertexStyle = "whiteSpace=wrap;html=1;rounded=1;arcSize=50;align=center;verticalAlign=middle;collapsible=0;container=1;recursiveResize=0;strokeWidth=1;autosize=1;spacing=4;"; var freeMindEdgeStyle = "edgeStyle=entityRelationEdgeStyle;startArrow=none;endArrow=none;segment=10;curved=1;html=1;"; // Tells whether or not a node has child ideas var hasChilds = function(node){ for (var i = 0; i < node.childNodes.length; i++){ if (node.childNodes[i].nodeName == "node"){ return true; } } return false; }; // Generates useful info on the nodes to be used later. var generatePreprocessingNodeInfo = function(node){ var childCount = 0; var maxChildsInHierarchy = 0; for (var i = 0; i < node.childNodes.length; i++){ var childNode = node.childNodes[i]; if (childNode.nodeName == "node"){ var maxChilds = generatePreprocessingNodeInfo(childNode); maxChildsInHierarchy = Math.max(maxChildsInHierarchy, maxChilds); childCount++; } } node.childCount = childCount; node.maxChilds = Math.max(childCount, maxChildsInHierarchy); return childCount; } // Main node generation funcion (recursive) var processFreeMindNode = function(node, nodeParent, x, y){ var mainConcept = false; var vertexStyle = freeMindBranchVertexStyle; if (nodeParent == defaultParent){ mainConcept = true; vertexStyle = freeMindMainConceptVertexStyle; }else if (hasChilds(node)){ // Concept, style appropiately vertexStyle = freeMindConceptVertexStyle; } var nodeName = node.getAttribute('TEXT') || ""; var nodeVertex = graph.insertVertex(defaultParent, null, nodeName, x, y, defaultWidth, defaultHeight, vertexStyle); graph.cellLabelChanged(nodeVertex,nodeName,true); if (mainConcept){ nodeVertex.geometry.height = mainConceptHeight; // TODO: Maybe set height according to it's width, so it's rounded? } if (nodeParent != defaultParent){ // Don't generate an edge for the first node graph.insertEdge(defaultParent, null, '', nodeParent, nodeVertex, freeMindEdgeStyle); } cells.push(nodeVertex); // Insert child nodes, on correct positions var childNumber = 0; for (var i = 0; i < node.childNodes.length; i++){ var childNode = node.childNodes[i]; if (childNode.nodeName == "node"){ var childX = x + nodeVertex.geometry.width + defaultHorizontalSpaceBetweenVertex; var childY = y + (defaultHeight + defaultVerticalSpaceBetweenVertex) * childNumber; childNumber += childNode.maxChilds == 0? 1 : childNode.maxChilds; processFreeMindNode(childNode, nodeVertex, childX, childY); } } } // Makes the import one undoable edit graph.getModel().beginUpdate(); try { // Gets point for free space in the graph for insert var pt = graph.getFreeInsertPoint(); var freeMindParser = new DOMParser(); freeMindDOM = freeMindParser.parseFromString(data, "text/xml"); var freeMindDOMchilds = freeMindDOM.children[0]; // Transverse the childs, and generate relevant input for (var i = 0; i < freeMindDOMchilds.childNodes.length; i++){ if (freeMindDOMchilds.childNodes[i].nodeName == "node"){ generatePreprocessingNodeInfo(freeMindDOMchilds.childNodes[i]); } } // Generate the nodes for (var i = 0; i < freeMindDOMchilds.childNodes.length; i++){ if (freeMindDOMchilds.childNodes[i].nodeName == "node"){ processFreeMindNode(freeMindDOMchilds.childNodes[i], defaultParent, pt.x, pt.y); } } // Applies current styles to new cells (might not be needed) graph.fireEvent(new mxEventObject('cellsInserted', 'cells', cells)); } finally { graph.getModel().endUpdate(); } // Selects new cells and scrolls into view graph.setSelectionCells(cells); graph.scrollCellToVisible(graph.getSelectionCell()); }; // Adds action ui.actions.addAction('importFreemind...', function() { // Only modern browsers for now. We'll move the import // code above to the main codebase later if (Graph.fileSupport && !mxClient.IS_IE && !mxClient.IS_IE11) { var input = document.createElement('input'); input.setAttribute('type', 'file'); mxEvent.addListener(input, 'change', function() { if (input.files != null) { // Only one file for now... var reader = new FileReader(); reader.onload = function(e) { importFreemindData(e.target.result); }; reader.readAsText(input.files[0]); } }); input.click(); } }); // Adds menu ui.menubar.addMenu('Import', function(menu, parent) { ui.menus.addMenuItem(menu, 'importFreemind'); }); // Moves import menu to before help menu ui.menubar.container.insertBefore(ui.menubar.container.lastChild, ui.menubar.container.lastChild.previousSibling.previousSibling.previousSibling); });