import.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /**
  2. * Plugin for Freemind import.
  3. * See https://github.com/jiangxin/freemind-mmx/tree/master/freemind
  4. */
  5. Draw.loadPlugin(function(ui)
  6. {
  7. var graph = ui.editor.graph;
  8. // Adds resource for action
  9. mxResources.parse('importFreemind=Freemind');
  10. // Parses Freemind data
  11. function importFreemindData(data)
  12. {
  13. // Gets the default parent for inserting new cells. This
  14. // is normally the first child of the root (ie. layer 0).
  15. var defaultParent = graph.getDefaultParent();
  16. var cells = [];
  17. var defaultWidth = 80;
  18. var defaultHeight = 30;
  19. var mainConceptHeight = 40;
  20. var defaultHorizontalSpaceBetweenVertex = 40;
  21. var defaultVerticalSpaceBetweenVertex = 10;
  22. var freeMindMainConceptVertexStyle = 'ellipse;whiteSpace=wrap;html=1;align=center;collapsible=0;container=1;recursiveResize=0;';
  23. 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;';
  24. 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;';
  25. var freeMindEdgeStyle = 'edgeStyle=entityRelationEdgeStyle;startArrow=none;endArrow=none;segment=10;curved=1;html=1;';
  26. // Tells whether or not a node has child ideas
  27. var hasChilds = function(node)
  28. {
  29. for (var i = 0; i < node.childNodes.length; i++)
  30. {
  31. if (node.childNodes[i].nodeName == 'node')
  32. {
  33. return true;
  34. }
  35. }
  36. return false;
  37. };
  38. // Generates useful info on the nodes to be used later.
  39. var generatePreprocessingNodeInfo = function(node)
  40. {
  41. var childCount = 0;
  42. var maxChildsInHierarchy = 0;
  43. for (var i = 0; i < node.childNodes.length; i++)
  44. {
  45. var childNode = node.childNodes[i];
  46. if (childNode.nodeName == 'node')
  47. {
  48. var maxChilds = generatePreprocessingNodeInfo(childNode);
  49. maxChildsInHierarchy = Math.max(maxChildsInHierarchy, maxChilds);
  50. childCount++;
  51. }
  52. }
  53. node.childCount = childCount;
  54. node.maxChilds = Math.max(childCount, maxChildsInHierarchy);
  55. return childCount;
  56. }
  57. // Main node generation funcion (recursive)
  58. var processFreeMindNode = function(node, nodeParent, x, y)
  59. {
  60. var mainConcept = false;
  61. var vertexStyle = freeMindBranchVertexStyle;
  62. if (nodeParent == defaultParent)
  63. {
  64. mainConcept = true;
  65. vertexStyle = freeMindMainConceptVertexStyle;
  66. }
  67. else if (hasChilds(node))
  68. {
  69. // Concept, style appropiately
  70. vertexStyle = freeMindConceptVertexStyle;
  71. }
  72. var nodeName = node.getAttribute('TEXT') || '';
  73. var nodeVertex = graph.insertVertex(defaultParent, null, nodeName, x, y, defaultWidth,
  74. defaultHeight, vertexStyle);
  75. graph.cellLabelChanged(nodeVertex, nodeName, true);
  76. if (mainConcept)
  77. {
  78. nodeVertex.geometry.height = mainConceptHeight; // TODO: Maybe set height according to it's width, so it's rounded?
  79. }
  80. if (nodeParent != defaultParent)
  81. {
  82. // Don't generate an edge for the first node
  83. graph.insertEdge(defaultParent, null, '', nodeParent, nodeVertex, freeMindEdgeStyle);
  84. }
  85. cells.push(nodeVertex);
  86. // Insert child nodes, on correct positions
  87. var childNumber = 0;
  88. for (var i = 0; i < node.childNodes.length; i++)
  89. {
  90. var childNode = node.childNodes[i];
  91. if (childNode.nodeName == 'node')
  92. {
  93. var childX = x + nodeVertex.geometry.width + defaultHorizontalSpaceBetweenVertex;
  94. var childY = y + (defaultHeight + defaultVerticalSpaceBetweenVertex) * childNumber;
  95. childNumber += childNode.maxChilds == 0 ? 1 : childNode.maxChilds;
  96. processFreeMindNode(childNode, nodeVertex, childX, childY);
  97. }
  98. }
  99. }
  100. // Makes the import one undoable edit
  101. graph.getModel().beginUpdate();
  102. try
  103. {
  104. // Gets point for free space in the graph for insert
  105. var pt = graph.getFreeInsertPoint();
  106. var freeMindDOM = mxUtils.parseXml(data);
  107. var freeMindDOMchilds = freeMindDOM.children[0];
  108. // Transverse the childs, and generate relevant input
  109. for (var i = 0; i < freeMindDOMchilds.childNodes.length; i++)
  110. {
  111. if (freeMindDOMchilds.childNodes[i].nodeName == 'node')
  112. {
  113. generatePreprocessingNodeInfo(freeMindDOMchilds.childNodes[i]);
  114. }
  115. }
  116. // Generate the nodes
  117. for (var i = 0; i < freeMindDOMchilds.childNodes.length; i++)
  118. {
  119. if (freeMindDOMchilds.childNodes[i].nodeName == 'node')
  120. {
  121. processFreeMindNode(freeMindDOMchilds.childNodes[i], defaultParent, pt.x, pt.y);
  122. }
  123. }
  124. // Applies current styles to new cells (might not be needed)
  125. graph.fireEvent(new mxEventObject('cellsInserted', 'cells', cells));
  126. }
  127. finally
  128. {
  129. graph.getModel().endUpdate();
  130. }
  131. // Selects new cells and scrolls into view
  132. graph.setSelectionCells(cells);
  133. graph.scrollCellToVisible(graph.getSelectionCell());
  134. };
  135. // Adds action
  136. ui.actions.addAction('importFreemind...', function()
  137. {
  138. // Only modern browsers for now. We'll move the import
  139. // code above to the main codebase later
  140. if (Graph.fileSupport && !mxClient.IS_IE && !mxClient.IS_IE11)
  141. {
  142. var input = document.createElement('input');
  143. input.setAttribute('type', 'file');
  144. mxEvent.addListener(input, 'change', function()
  145. {
  146. if (input.files != null)
  147. {
  148. // Only one file for now...
  149. var reader = new FileReader();
  150. reader.onload = function(e)
  151. {
  152. importFreemindData(e.target.result);
  153. };
  154. reader.readAsText(input.files[0]);
  155. }
  156. });
  157. input.click();
  158. }
  159. });
  160. // Adds menu
  161. ui.menubar.addMenu('Import', function(menu, parent)
  162. {
  163. ui.menus.addMenuItem(menu, 'importFreemind');
  164. });
  165. // Moves import menu to before help menu
  166. ui.menubar.container.insertBefore(ui.menubar.container.lastChild,
  167. ui.menubar.container.lastChild.previousSibling.previousSibling.previousSibling);
  168. });