nav.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /**
  2. * @fileOverview
  3. *
  4. * 脑图缩略图导航功能
  5. *
  6. * @author: techird
  7. * @copyright: Baidu FEX, 2014
  8. */
  9. KityMinder.registerUI('nav', function(minder) {
  10. var memory = minder.getUI('memory');
  11. var $navBar = $('<div>').addClass('nav-bar').appendTo('#content-wrapper');
  12. var $commandbutton = minder.getUI('widget/commandbutton');
  13. var $zoomIn = $commandbutton.generate('zoom-in').appendTo($navBar[0]);
  14. var $zoomPan = createZoomPan($navBar);
  15. var $zoomOut = $commandbutton.generate('zoom-out').appendTo($navBar[0]);
  16. var $previewNavigator = createViewNavigator();
  17. var $hand = $commandbutton.generate('hand').appendTo($navBar[0]);
  18. var $root = $commandbutton.generate('camera', function() {
  19. minder.execCommand('camera', minder.getRoot(), 600);
  20. }).appendTo($navBar[0]);
  21. var $previewTrigger = createPreviewTrigger($previewNavigator).appendTo($navBar);
  22. function createZoomPan($parent) {
  23. var $pan = $('<div>').addClass('zoom-pan').appendTo($parent);
  24. var zoomStack = minder.getOptions('zoom');
  25. var minValue = zoomStack[0];
  26. var maxValue = zoomStack[zoomStack.length - 1];
  27. var valueRange = maxValue - minValue;
  28. var totalHeight = $pan.height();
  29. function getHeight(value) {
  30. return (1 - (value - minValue) / valueRange) * totalHeight;
  31. }
  32. var $origin = $('<div>')
  33. .addClass('origin')
  34. .appendTo($pan)
  35. .css('y', getHeight(100));
  36. var $indicator = $('<div>')
  37. .addClass('indicator')
  38. .appendTo($pan)
  39. .css('y', getHeight(100));
  40. function indicate(value) {
  41. $indicator.animate({
  42. 'y': getHeight(value)
  43. }, 200);
  44. }
  45. minder.on('zoom', function(e) {
  46. indicate(e.zoom);
  47. });
  48. $origin.click(function() {
  49. minder.execCommand('zoom', 100);
  50. });
  51. return $pan;
  52. }
  53. /**
  54. * 创建导航器的 DOM 元素以及交互的逻辑代码
  55. */
  56. function createViewNavigator() {
  57. var $previewNavigator = $('<div>')
  58. .addClass('preview-navigator')
  59. .appendTo('#content-wrapper');
  60. // 画布,渲染缩略图
  61. var paper = new kity.Paper($previewNavigator[0]);
  62. // 用两个路径来挥之节点和连线的缩略图
  63. var nodeThumb = paper.put(new kity.Path());
  64. var connectionThumb = paper.put(new kity.Path());
  65. // 表示可视区域的矩形
  66. var visibleRect = paper.put(new kity.Rect(100, 100).stroke('red', '1%'));
  67. var contentView = new kity.Box(), visibleView = new kity.Box();
  68. navigate();
  69. $previewNavigator.show = function() {
  70. $.fn.show.call(this);
  71. bind();
  72. updateContentView();
  73. updateVisibleView();
  74. };
  75. $previewNavigator.hide = function() {
  76. $.fn.hide.call(this);
  77. unbind();
  78. };
  79. function bind() {
  80. minder.on('layout layoutallfinish', updateContentView);
  81. minder.on('viewchange', updateVisibleView);
  82. }
  83. function unbind() {
  84. minder.off('layout layoutallfinish', updateContentView);
  85. minder.off('viewchange', updateVisibleView);
  86. }
  87. window.u = updateContentView;
  88. function navigate() {
  89. function moveView(center, duration) {
  90. var box = visibleView;
  91. center.x = -center.x;
  92. center.y = -center.y;
  93. var viewMatrix = minder.getPaper().getViewPortMatrix();
  94. box = viewMatrix.transformBox(box);
  95. var targetPosition = center.offset(box.width / 2, box.height / 2);
  96. minder.getViewDragger().moveTo(targetPosition, duration);
  97. }
  98. var dragging = false;
  99. paper.on('mousedown', function(e) {
  100. dragging = true;
  101. moveView(e.getPosition('top'), 200);
  102. $previewNavigator.addClass('grab');
  103. });
  104. paper.on('mousemove', function(e) {
  105. if (dragging) {
  106. moveView(e.getPosition('top'));
  107. }
  108. });
  109. $(window).on('mouseup', function() {
  110. dragging = false;
  111. $previewNavigator.removeClass('grab');
  112. });
  113. }
  114. function updateContentView() {
  115. var view = minder.getRenderContainer().getBoundaryBox();
  116. contentView = view;
  117. var padding = 30;
  118. paper.setViewBox(
  119. view.x - padding - 0.5,
  120. view.y - padding - 0.5,
  121. view.width + padding * 2 + 1,
  122. view.height + padding * 2 + 1);
  123. var nodePathData = [];
  124. var connectionThumbData = [];
  125. minder.getRoot().traverse(function(node) {
  126. var box = node.getLayoutBox();
  127. nodePathData.push('M', box.x, box.y,
  128. 'h', box.width, 'v', box.height,
  129. 'h', -box.width, 'z');
  130. if (node.getConnection() && node.parent && node.parent.isExpanded()) {
  131. connectionThumbData.push(node.getConnection().getPathData());
  132. }
  133. });
  134. paper.setStyle('background', minder.getStyle('background'));
  135. if (nodePathData.length) {
  136. nodeThumb
  137. .fill(minder.getStyle('root-background'))
  138. .setPathData(nodePathData);
  139. } else {
  140. nodeThumb.setPathData(null);
  141. }
  142. if (connectionThumbData.length) {
  143. connectionThumb
  144. .stroke(minder.getStyle('connect-color'), '0.5%')
  145. .setPathData(connectionThumbData);
  146. } else {
  147. connectionThumb.setPathData(null);
  148. }
  149. updateVisibleView();
  150. }
  151. function updateVisibleView() {
  152. visibleView = minder.getViewDragger().getView();
  153. visibleRect.setBox(visibleView.intersect(contentView));
  154. }
  155. return $previewNavigator;
  156. }
  157. function createPreviewTrigger($previewNavigator) {
  158. var $trigger = $('<div>').addClass('command-button nav-trigger');
  159. $trigger.append('<div class="fui-icon">');
  160. $trigger.click(toggle);
  161. $trigger.attr('title', minder.getLang('ui.navigator'));
  162. function toggle() {
  163. if ($trigger.toggleClass('active').hasClass('active')) {
  164. $previewNavigator.show();
  165. memory.set('navigator-hidden', false);
  166. } else {
  167. $previewNavigator.hide();
  168. memory.set('navigator-hidden', true);
  169. }
  170. }
  171. if (memory.get('navigator-hidden')) toggle();
  172. toggle();
  173. return $trigger;
  174. }
  175. });