1 /** 2 * Creates a new CanvasPresenter. The canvas presenter is responsible for drawing the mind map onto a 3 * canvas view and reacting to user input on the map (e.g. dragging a node, double clicking it etc.) 4 * 5 * @constructor 6 * @param {mindmaps.EventBus} eventBus 7 * @param {mindmaps.CommandRegistry} commandRegistry 8 * @param {mindmaps.MindMapModel} mindmapModel 9 * @param {mindmaps.CanvasView} view 10 * @param {mindmaps.ZoomController} zoomController 11 */ 12 mindmaps.CanvasPresenter = function(eventBus, commandRegistry, mindmapModel, 13 view, zoomController) { 14 var self = this; 15 var creator = view.getCreator(); 16 17 /** 18 * Initializes this presenter. 19 */ 20 this.init = function() { 21 var editCaptionCommand = commandRegistry 22 .get(mindmaps.EditNodeCaptionCommand); 23 editCaptionCommand.setHandler(this.editNodeCaption.bind(this)); 24 25 var toggleNodeFoldedCommand = commandRegistry 26 .get(mindmaps.ToggleNodeFoldedCommand); 27 toggleNodeFoldedCommand.setHandler(toggleFold); 28 }; 29 30 /** 31 * Handles the edit caption command. Tells view to start edit mode for node. 32 * 33 * @param {mindmaps.Node} node 34 */ 35 this.editNodeCaption = function(node) { 36 if (!node) { 37 node = mindmapModel.selectedNode; 38 } 39 view.editNodeCaption(node); 40 }; 41 42 /** 43 * Toggles the fold state of a node. 44 * 45 * @param {mindmaps.Node} node 46 */ 47 var toggleFold = function(node) { 48 if (!node) { 49 node = mindmapModel.selectedNode; 50 } 51 52 // toggle node visibility 53 var action = new mindmaps.action.ToggleNodeFoldAction(node); 54 mindmapModel.executeAction(action); 55 }; 56 57 /** 58 * Tells the view to select a node. 59 * 60 * @param {mindmaps.Node} selectedNode 61 * @param {mindmaps.Node} oldSelectedNode 62 */ 63 var selectNode = function(selectedNode, oldSelectedNode) { 64 65 // deselect old node 66 if (oldSelectedNode) { 67 view.unhighlightNode(oldSelectedNode); 68 } 69 view.highlightNode(selectedNode); 70 }; 71 72 // listen to events from view 73 /** 74 * View callback: Zoom on mouse wheel. 75 * 76 * @ignore 77 */ 78 view.mouseWheeled = function(delta) { 79 view.stopEditNodeCaption(); 80 81 if (delta > 0) { 82 zoomController.zoomIn(); 83 } else { 84 zoomController.zoomOut(); 85 } 86 }; 87 88 /** 89 * View callback: Attach creator to node if mouse hovers over node. 90 * 91 * @ignore 92 */ 93 view.nodeMouseOver = function(node) { 94 if (view.isNodeDragging() || creator.isDragging()) { 95 // dont relocate the creator if we are dragging 96 } else { 97 creator.attachToNode(node); 98 } 99 }; 100 101 /** 102 * View callback: Attach creator to node if mouse hovers over node caption. 103 * 104 * @ignore 105 */ 106 view.nodeCaptionMouseOver = function(node) { 107 if (view.isNodeDragging() || creator.isDragging()) { 108 // dont relocate the creator if we are dragging 109 } else { 110 creator.attachToNode(node); 111 } 112 }; 113 114 /** 115 * View callback: Select node if mouse was pressed. 116 * 117 * @ignore 118 */ 119 view.nodeMouseDown = function(node) { 120 mindmapModel.selectNode(node); 121 // show creator 122 creator.attachToNode(node); 123 }; 124 125 // view.nodeMouseUp = function(node) { 126 // }; 127 128 /** 129 * View callback: Go into edit mode when node was double clicked. 130 * 131 * @ignore 132 */ 133 view.nodeDoubleClicked = function(node) { 134 view.editNodeCaption(node); 135 }; 136 137 // view.nodeDragging = function() { 138 // }; 139 140 /** 141 * View callback: Execute MoveNodeAction when node was dragged. 142 * 143 * @ignore 144 */ 145 view.nodeDragged = function(node, offset) { 146 // view has updated itself 147 148 // update model 149 var action = new mindmaps.action.MoveNodeAction(node, offset); 150 mindmapModel.executeAction(action); 151 }; 152 153 /** 154 * View callback: Toggle fold mode when fold button was clicked. 155 * 156 * @ignore 157 */ 158 view.foldButtonClicked = function(node) { 159 toggleFold(node); 160 }; 161 162 // CREATOR TOOL 163 /** 164 * View callback: Return new random color to view when creator tool was 165 * started to drag. 166 * 167 * @ignore 168 */ 169 creator.dragStarted = function(node) { 170 // set edge color for new node. inherit from parent or random when root 171 var color = node.isRoot() ? mindmaps.Util.randomColor() 172 : node.branchColor; 173 return color; 174 }; 175 176 /** 177 * View callback: Create a new node when creator tool was stopped. 178 * 179 * @ignore 180 */ 181 creator.dragStopped = function(parent, offsetX, offsetY, distance) { 182 // disregard if the creator was only dragged a bit 183 if (distance < 50) { 184 return; 185 } 186 187 // update the model 188 var node = new mindmaps.Node(); 189 node.branchColor = creator.lineColor; 190 node.offset = new mindmaps.Point(offsetX, offsetY); 191 // indicate that we want to set this nodes caption after creation 192 node.shouldEditCaption = true; 193 194 mindmapModel.createNode(node, parent); 195 }; 196 197 /** 198 * View callback: Change node caption when text change was committed in 199 * view. 200 * 201 * @ignore 202 * @param {String} str 203 */ 204 view.nodeCaptionEditCommitted = function(str) { 205 // avoid whitespace only strings 206 var str = $.trim(str); 207 if (!str) { 208 return; 209 } 210 211 view.stopEditNodeCaption(); 212 mindmapModel.changeNodeCaption(null, str); 213 }; 214 215 this.go = function() { 216 view.init(); 217 }; 218 219 /** 220 * Draw the mind map on the canvas. 221 * 222 * @param {mindmaps.Document} doc 223 */ 224 function showMindMap(doc) { 225 view.setZoomFactor(zoomController.DEFAULT_ZOOM); 226 var dimensions = doc.dimensions; 227 view.setDimensions(dimensions.x, dimensions.y); 228 var map = doc.mindmap; 229 view.drawMap(map); 230 view.center(); 231 232 mindmapModel.selectNode(map.root); 233 } 234 235 /** 236 * Hook up with EventBus. 237 */ 238 function bind() { 239 // listen to global events 240 eventBus.subscribe(mindmaps.Event.DOCUMENT_OPENED, function(doc, 241 newDocument) { 242 showMindMap(doc); 243 244 // if (doc.isNew()) { 245 // // edit root node on start 246 // var root = doc.mindmap.root; 247 // view.editNodeCaption(root); 248 // } 249 }); 250 251 eventBus.subscribe(mindmaps.Event.DOCUMENT_CLOSED, function(doc) { 252 view.clear(); 253 }); 254 255 eventBus.subscribe(mindmaps.Event.NODE_MOVED, function(node) { 256 view.positionNode(node); 257 }); 258 259 eventBus.subscribe(mindmaps.Event.NODE_TEXT_CAPTION_CHANGED, function( 260 node) { 261 view.setNodeText(node, node.getCaption()); 262 263 // redraw node in case height has changed 264 // TODO maybe only redraw if height has changed 265 view.redrawNodeConnectors(node); 266 }); 267 268 eventBus.subscribe(mindmaps.Event.NODE_CREATED, function(node) { 269 view.createNode(node); 270 271 // edit node caption immediately if requested 272 if (node.shouldEditCaption) { 273 delete node.shouldEditCaption; 274 // open parent node when creating a new child and the other 275 // children are hidden 276 var parent = node.getParent(); 277 if (parent.foldChildren) { 278 var action = new mindmaps.action.OpenNodeAction(parent); 279 mindmapModel.executeAction(action); 280 } 281 282 // select and go into edit mode on new node 283 mindmapModel.selectNode(node); 284 // attach creator manually, sometimes the mouseover listener wont fire 285 creator.attachToNode(node); 286 view.editNodeCaption(node); 287 } 288 }); 289 290 eventBus.subscribe(mindmaps.Event.NODE_DELETED, function(node, parent) { 291 // select parent if we are deleting a selected node or a descendant 292 var selected = mindmapModel.selectedNode; 293 if (node === selected || node.isDescendant(selected)) { 294 // deselectCurrentNode(); 295 mindmapModel.selectNode(parent); 296 } 297 298 // update view 299 view.deleteNode(node); 300 if (parent.isLeaf()) { 301 view.removeFoldButton(parent); 302 } 303 }); 304 305 eventBus.subscribe(mindmaps.Event.NODE_SELECTED, selectNode); 306 307 eventBus.subscribe(mindmaps.Event.NODE_OPENED, function(node) { 308 view.openNode(node); 309 }); 310 eventBus.subscribe(mindmaps.Event.NODE_CLOSED, function(node) { 311 view.closeNode(node); 312 }); 313 eventBus.subscribe(mindmaps.Event.NODE_FONT_CHANGED, function(node) { 314 view.updateNode(node); 315 }); 316 eventBus.subscribe(mindmaps.Event.NODE_BRANCH_COLOR_CHANGED, function( 317 node) { 318 view.updateNode(node); 319 }); 320 eventBus.subscribe(mindmaps.Event.ZOOM_CHANGED, function(zoomFactor) { 321 view.setZoomFactor(zoomFactor); 322 view.applyViewZoom(); 323 view.scaleMap(); 324 }); 325 } 326 327 bind(); 328 this.init(); 329 };