Minder.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. //展现脑图,数据样式如下
  2. //var data = {
  3. // "root": {
  4. // "data": {"id": "9f92035021ac", "text": "软装修"},
  5. // "children": [{
  6. // "data": {"id": "b45yogtullsg", "created": 1463069010918, "text": "包阳台"},
  7. // "children": [{
  8. // "data": {"id": "3jl3i3j43", "created": 1463069010923, "text": "凤铝"}
  9. // }, {
  10. // "data": {"id": "3jl3i3j44", "created": 1463069010923, "text": "断桥"}
  11. // }]
  12. // },
  13. // {
  14. // "data": {"id": "b45yohdlynco", "created": 1463069012113, "text": "衣柜"}, "children": [
  15. // {"data": {"id": "b45yohdlynco", "created": 1463069012113, "text": "主卧"}},
  16. // {"data": {"id": "b45yohdlynco", "created": 1463069012113, "text": "次卧"}}
  17. // ]
  18. // },
  19. // {"data": {"id": "b45yohdlynco", "created": 1463069012113, "text": "床"}, "children": []},
  20. // {"data": {"id": "b45yohdlynco", "created": 1463069012113, "text": "餐桌"}, "children": []},
  21. // {"data": {"id": "b45yohdlynco", "created": 1463069012113, "text": "灯具"}, "children": []},
  22. // {"data": {"id": "b45yohdlynco", "created": 1463069012113, "text": "窗帘"}, "children": []}
  23. // ]
  24. // }
  25. //};
  26. MWF.xApplication.Execution = MWF.xApplication.Execution || {};
  27. MWF.xApplication.Execution.Minder = new Class({
  28. Extends: MWF.widget.Common,
  29. Implements: [Options, Events],
  30. options: {
  31. "style": "default",
  32. "template" : "default", //fish-bone
  33. "theme": "fresh-blue", //"fresh-blue-compat"
  34. "hasNavi" : true,
  35. "align" : "center"
  36. },
  37. initialize: function (container, app, data, options) {
  38. this.setOptions(options);
  39. this.container = container;
  40. this.app = app;
  41. this.lp = this.app.lp.minder;
  42. this.actions = this.app.restActions;
  43. this.path = "../x_component_Execution/$Minder/";
  44. this.cssPath = this.path+this.options.style+"/css.wcss";
  45. this._loadCss();
  46. this.data = data;
  47. },
  48. load: function () {
  49. this.loadResource( function(){
  50. this.loadKityMinder( this.data );
  51. }.bind(this) );
  52. this.attachEvent();
  53. },
  54. reload : function( data ){
  55. this.container.empty();
  56. this.loadKityMinder( data || this.data )
  57. },
  58. refresh : function(){
  59. //this.alreadyBind = false;
  60. //this.km.execCommand('camera');
  61. this.moveToCenter();
  62. },
  63. destroy: function(){
  64. if(this.navi){
  65. this.navi.destroy();
  66. delete this.navi;
  67. }
  68. if(this.km)delete this.km;
  69. delete this;
  70. },
  71. loadResource: function (callback) {
  72. var kityminderPath = "../x_desktop/res/framework/kityminder/";
  73. COMMON.AjaxModule.loadCss(kityminderPath + "core/src/kityminder.css", function () {
  74. COMMON.AjaxModule.load("kity", function () {
  75. COMMON.AjaxModule.load("kityminder", function () {
  76. if (callback)callback();
  77. }.bind(this));
  78. }.bind(this))
  79. }.bind(this))
  80. },
  81. loadKityMinder: function ( data ) {
  82. var _self = this;
  83. this.isMovingCenter = true;
  84. // 创建 km 实例
  85. /* global kityminder */
  86. var km = this.km = new kityminder.Minder();
  87. //var target = document.querySelector('#minder-view');
  88. km.renderTo(this.container);
  89. data.theme = data.theme || this.options.theme;
  90. data.template = data.template || this.options.template;
  91. this.deepestLevel = 0;
  92. km.on("import", function (e) {
  93. if ( !_self.alreadyBind ) {
  94. var nodes = km.getAllNode();
  95. nodes.forEach(function (node) {
  96. var level = node.getLevel();
  97. _self.deepestLevel = level > _self.deepestLevel ? level : _self.deepestLevel;
  98. _self.fireEvent( "postLoadNode", node );
  99. });
  100. _self.alreadyBind = true;
  101. if( _self.options.hasNavi )_self.loadNavi();
  102. _self.fireEvent( "postLoad" , _self );
  103. }
  104. });
  105. //km.on("execCommand", function(e){
  106. // if (e.commandName === "template" ) {
  107. // _self.moveToCenter();
  108. // }
  109. //})
  110. km.on("layoutallfinish",function(){
  111. if( _self.templateChanged || _self.isMovingCenter ){
  112. _self.moveToCenter();
  113. _self.templateChanged = false;
  114. _self.isMovingCenter = false;
  115. }
  116. });
  117. km.importJson(data);
  118. km.execCommand('hand');
  119. },
  120. loadNavi : function( container ) {
  121. this.navi = new MWF.xApplication.Execution.Minder.Navigation(container || this.container, this, this.km, this.app, this.css);
  122. this.navi.load();
  123. },
  124. moveToCenter: function(){
  125. //setTimeout( this._moveToCenter.bind(this) , 100 );
  126. this._moveToCenter();
  127. },
  128. _moveToCenter: function(){
  129. if( this.options.align != "center")return;
  130. //图形居中
  131. var minderView = this.km.getRenderContainer().getRenderBox('screen'); //.getBoundaryBox();
  132. var containerView = this.container.getCoordinates();
  133. var root = this.km.getRoot();
  134. var rootView = root.getRenderContainer().getRenderBox('screen'); //getRenderBox('top');
  135. var rootClientTop = rootView.top - minderView.top;
  136. var rootClientLeft = rootView.left - minderView.left;
  137. var rootChildrenLength = root.getChildren().length;
  138. var template = this.km.queryCommandValue("template");
  139. var left, top, isCamera = false;
  140. if( minderView.width > containerView.width ){ //如果图形宽度大于容器宽度
  141. if( template == "fish-bone" || rootChildrenLength < 2 ){
  142. left = 50;
  143. }else{
  144. isCamera = true;
  145. }
  146. }else{
  147. left = parseInt( ( containerView.width - minderView.width ) / 2 + rootClientLeft + 50 );
  148. }
  149. if( minderView.height > containerView.height ){ //如果图形高度大于容器高度
  150. if( rootClientTop > containerView.height ){
  151. if( template == "fish-bone" ) {
  152. top = containerView.height - rootView.height
  153. }else if( rootChildrenLength < 2){
  154. top = parseInt( containerView.width / 2 );
  155. }else{
  156. isCamera = true;
  157. }
  158. }else{
  159. top = rootClientTop + 50;
  160. }
  161. }else{
  162. top = parseInt( ( containerView.height - minderView.height ) / 2 ) + rootClientTop;
  163. }
  164. if( isCamera ){
  165. this.km.execCommand('camera', this.km.getRoot(), 600);
  166. }else{
  167. var dragger = this.km.getViewDragger();
  168. dragger.moveTo(new kity.Point(left, top) , 300 );
  169. }
  170. },
  171. attachEvent: function(){
  172. this.container.addEvent("mousewheel", function(ev){ //鼠标滚轮事件
  173. if( ev.wheel == 1){ //向上滚动,放大
  174. this.km.execCommand('zoomIn');
  175. if( this.navi && this.navi.navZoompanIndicator ){
  176. var marginTop = parseInt( this.navi.navZoompanIndicator.getStyle("margin-top"));
  177. if( marginTop > 0 ){
  178. this.navi.navZoompanIndicator.setStyle( "margin-top", (marginTop - 10) + "px" );
  179. }
  180. }
  181. }else{ //向下滚动,缩小
  182. this.km.execCommand('zoomOut');
  183. if( this.navi && this.navi.navZoompanIndicator ){
  184. var totalHeight = parseInt( this.navi.navZoompan.getStyle("height") );
  185. var marginTop = parseInt( this.navi.navZoompanIndicator.getStyle("margin-top"));
  186. if( marginTop < totalHeight ){
  187. this.navi.navZoompanIndicator.setStyle( "margin-top", (marginTop + 10 ) + "px" );
  188. }
  189. }
  190. }
  191. }.bind(this))
  192. }
  193. });
  194. MWF.xApplication.Execution.Minder.Navigation = new Class({
  195. Implements: [Options, Events],
  196. initialize: function (container, minder, km, app, css) {
  197. this.container = container;
  198. this.app = app;
  199. this.lp = this.app.lp.minder;
  200. this.actions = this.app.restActions;
  201. this.css = css;
  202. this.minder = minder;
  203. this.km = km;
  204. },
  205. load: function (callback) {
  206. this.createNavigation();
  207. //this.navMoveNode.click();
  208. },
  209. destroy: function(){
  210. this.node.destroy();
  211. delete this;
  212. },
  213. createNavigation: function(){
  214. this.node = new Element("div",{ "styles" : this.css.nav }).inject(this.container);
  215. this.navZoomIn = new Element("div",{ "styles" : this.css.navButton , "title" : this.lp.navZoomin }).inject(this.node);
  216. new Element("div",{ "styles" : this.css.navZoominIcon }).inject(this.navZoomIn);
  217. this.navZoomIn.addEvent("click",function(){
  218. this.km.execCommand('zoomIn');
  219. var marginTop = parseInt( this.navZoompanIndicator.getStyle("margin-top"));
  220. if( marginTop > 0 ){
  221. this.navZoompanIndicator.setStyle( "margin-top", (marginTop - 10) + "px" );
  222. }
  223. }.bind(this));
  224. this.navZoompan = new Element("div",{ "styles" : this.css.navZoompan }).inject(this.node);
  225. this.navZoompanOrigin = new Element("div",{ "styles" : this.css.navZoompanOrigin }).inject(this.navZoompan);
  226. this.navZoompanOrigin.addEvent("click",function(){
  227. this.km.execCommand('zoom', 100);
  228. this.navZoompanIndicator.setStyle( "margin-top", "30px" );
  229. }.bind(this));
  230. this.navZoompanIndicator = new Element("div",{ "styles" : this.css.navZoompanIndicator }).inject(this.navZoompan);
  231. this.navZoomout = new Element("div",{ "styles" : this.css.navButton , "title" : this.lp.navZoomout }).inject(this.node);
  232. new Element("div",{ "styles" : this.css.navZoomoutIcon }).inject(this.navZoomout);
  233. this.navZoomout.addEvent("click",function(){
  234. this.km.execCommand('zoomOut');
  235. var totalHeight = parseInt( this.navZoompan.getStyle("height") );
  236. var marginTop = parseInt( this.navZoompanIndicator.getStyle("margin-top"));
  237. if( marginTop < totalHeight ){
  238. this.navZoompanIndicator.setStyle( "margin-top", (marginTop + 10 ) + "px" );
  239. }
  240. }.bind(this));
  241. //
  242. //this.navCreateMainWork = new Element("div",{ "styles" : this.css.navButton , "title" : this.lp.workTask.newTask }).inject(this.node);
  243. //new Element("div",{ "styles" : this.css.navCreateMainWorkIcon }).inject(this.navCreateMainWork);
  244. //this.navCreateMainWork.addEvent("click",function(){
  245. //
  246. // MWF.xDesktop.requireApp("Execution", "WorkDeploy", function(){
  247. // this.explorer = new MWF.xApplication.Execution.WorkDeploy(this, this.actions,{},{"isEdited":true} );
  248. // this.explorer.load();
  249. // }.bind(this))
  250. //
  251. //}.bind(this))
  252. this.navCameraNode = new Element("div",{ "styles" : this.css.navButton , "title" : this.lp.navCamera }).inject(this.node);
  253. new Element("div",{ "styles" : this.css.navCameraIcon }).inject(this.navCameraNode);
  254. this.navCameraNode.addEvent("click",function(){
  255. this.km.execCommand('camera', this.km.getRoot(), 600);
  256. //this.minder.moveToCenter()
  257. }.bind(this));
  258. this.navExpandNode = new Element("div",{ "styles" : this.css.navButton , "title" : "展开节点" }).inject(this.node);
  259. new Element("div",{ "styles" : this.css.navExpandIcon }).inject(this.navExpandNode);
  260. this.navExpandNode.addEvent("click",function(ev){
  261. this.showExpendNode( ev );
  262. ev.stopPropagation();
  263. }.bind(this));
  264. this.navTrigger = new Element("div",{ "styles" : this.css.navButton , "title" : this.lp.navTrigger }).inject(this.node);
  265. new Element("div",{ "styles" : this.css.navTriggerIcon }).inject(this.navTrigger);
  266. this.navTrigger.addEvent( "click", function(){
  267. this.toggleOpenPreViewer();
  268. }.bind(this) );
  269. this.createrPreViewer();
  270. this.navMoveNode = new Element("div",{ "styles" : this.css.navButton , "title" : this.lp.allowDrag }).inject(this.node);
  271. this.navMoveNode.setStyles( this.css.navButton_over );
  272. this.moveOpen = true;
  273. new Element("div",{ "styles" : this.css.navMoveIcon }).inject(this.navMoveNode);
  274. this.navMoveNode.addEvent("click",function(){
  275. this.moveOpen = !this.moveOpen;
  276. if( this.moveOpen ){
  277. this.navMoveNode.setStyles( this.css.navButton_over );
  278. }else{
  279. this.navMoveNode.setStyles( this.css.navButton );
  280. }
  281. this.km.execCommand('hand');
  282. }.bind(this));
  283. this.navTemplateNode = new Element("div",{ "styles" : this.css.navButton , "title" : this.lp.changeTemplate }).inject(this.node);
  284. new Element("div",{ "styles" : this.css.navTemplateIcon }).inject(this.navTemplateNode);
  285. this.navTemplateNode.addEvent("click",function( ev ){
  286. this.selectTemplate( ev );
  287. ev.stopPropagation();
  288. }.bind(this));
  289. this.navSearchNode = new Element("div",{ "styles" : this.css.navButton , "title" : this.lp.search }).inject(this.node);
  290. new Element("div",{ "styles" : this.css.navSearchIcon }).inject(this.navSearchNode);
  291. this.navSearchNode.addEvent("click",function(){
  292. if( !this.isShowedSearch ){
  293. this.showSearch();
  294. }else{
  295. this.hideSearch();
  296. }
  297. }.bind(this));
  298. //this.navExpand = new Element("div",{ "styles" : this.css.navButton , "title" : "展开" }).inject(this.node);
  299. //new Element("div",{ "styles" : this.css.navExpandIcon }).inject(this.navExpand);
  300. },
  301. toggleOpenPreViewer: function(){
  302. this.previewOpened = !this.previewOpened;
  303. if( this.previewOpened ){
  304. this.navTrigger.setStyles( this.css.navButton_over );
  305. }else{
  306. this.navTrigger.setStyles( this.css.navButton );
  307. }
  308. this.preview.toggleOpen( this.previewOpened );
  309. },
  310. createrPreViewer: function(){
  311. this.preview = new MWF.xApplication.Execution.Minder.Preview( this, this.node, this.km, this.app, this.css );
  312. this.preview.load();
  313. },
  314. showSearch: function(){
  315. this.isShowedSearch = true;
  316. if( !this.searchBar ){
  317. this.searchBar = new MWF.xApplication.Execution.Minder.SearchBar( this, this.node, this.km, this.app, this.css );
  318. this.searchBar.load();
  319. }else{
  320. this.searchBar.show()
  321. }
  322. this.navSearchNode.setStyles( this.css.navButton_over );
  323. },
  324. hideSearch: function(){
  325. this.isShowedSearch = false;
  326. this.searchBar.hide();
  327. this.navSearchNode.setStyles( this.css.navButton );
  328. },
  329. selectTemplate: function(){
  330. this.templateOpen = !this.templateOpen;
  331. if( this.templateOpen ){
  332. if( this.templateSelectNode ){
  333. this.templateSelectNode.setStyle("display","block")
  334. }else{
  335. this.createTemplateSelectNode();
  336. }
  337. this.navTemplateNode.setStyles( this.css.navButton_over );
  338. }else{
  339. this.hideTemplateSelectNode();
  340. }
  341. },
  342. hideTemplateSelectNode: function(){
  343. this.templateOpen = false;
  344. this.navTemplateNode.setStyles( this.css.navButton );
  345. if( this.templateSelectNode ){
  346. this.templateSelectNode.setStyle("display","none");
  347. }
  348. },
  349. createTemplateSelectNode: function(){
  350. this.templateSelectNode = new Element("div",{
  351. styles : this.css.templateSelectNode
  352. }).inject(this.node);
  353. this.minderTemplate = new Element("div",{
  354. styles : this.css.minderTemplate,
  355. title : this.lp.minderTemplate
  356. }).inject(this.templateSelectNode);
  357. this.minderTemplate.addEvents({
  358. "mouseover" : function(){ this.minderTemplate.setStyles( this.css.minderTemplate_over )}.bind(this),
  359. "mouseout" : function(){ this.minderTemplate.setStyles( this.css.minderTemplate )}.bind(this),
  360. "click" : function(){
  361. this.minder.templateChanged = true;
  362. this.km.execCommand('template', "default");
  363. this.hideTemplateSelectNode();
  364. //this.minder.moveToCenter();
  365. }.bind(this)
  366. });
  367. this.fishboneTemplate = new Element("div",{
  368. styles : this.css.fishboneTemplate,
  369. title : this.lp.fishBoneTemplate
  370. }).inject(this.templateSelectNode);
  371. this.fishboneTemplate.addEvents({
  372. "mouseover" : function(){ this.fishboneTemplate.setStyles( this.css.fishboneTemplate_over )}.bind(this),
  373. "mouseout" : function(){ this.fishboneTemplate.setStyles( this.css.fishboneTemplate )}.bind(this),
  374. "click" : function(){
  375. //this.km.on("execCommand", function (e) {
  376. // if (e.commandName === "template" ) {
  377. // this.minder.moveToCenter();
  378. // }
  379. //}.bind(this));
  380. this.minder.templateChanged = true;
  381. this.km.execCommand('template', "fish-bone");
  382. this.hideTemplateSelectNode();
  383. //this.minder.moveToCenter();
  384. }.bind(this)
  385. });
  386. this.app.content.addEvent("click",function(){
  387. this.hideTemplateSelectNode();
  388. }.bind(this))
  389. },
  390. showExpendNode: function(){
  391. this.expendNodeOpen = !this.expendNodeOpen;
  392. if( this.expendNodeOpen ){
  393. if( this.expendArea ){
  394. this.expendArea.setStyle("display","block")
  395. }else{
  396. this.createExpandArea();
  397. }
  398. this.navExpandNode.setStyles( this.css.navButton_over );
  399. }else{
  400. this.hideExpendArea();
  401. }
  402. },
  403. hideExpendArea: function(){
  404. this.expendNodeOpen = false;
  405. this.navExpandNode.setStyles( this.css.navButton );
  406. if( this.expendArea ){
  407. this.expendArea.setStyle("display","none");
  408. }
  409. },
  410. createExpandArea: function(){
  411. var deepestLevel = this.minder.deepestLevel;
  412. this.expendArea = new Element("div",{
  413. styles : this.css.expendArea
  414. }).inject(this.node);
  415. this.expendArea.setStyle("height",this.css.expendNode.height * (deepestLevel+1));
  416. var expendAllNode = new Element("div",{
  417. styles : this.css.expendNode,
  418. text : "展开所有节点"
  419. }).inject(this.expendArea);
  420. expendAllNode.addEvents({
  421. "mouseover" : function(){ this.node.setStyles( this.navi.css.expendNode_over )}.bind( { navi : this, node : expendAllNode} ),
  422. "mouseout" : function(){ this.node.setStyles( this.navi.css.expendNode )}.bind({ navi : this, node : expendAllNode}),
  423. "click" : function(){
  424. this.navi.km.execCommand('expandtolevel', deepestLevel);
  425. this.navi.hideExpendArea();
  426. }.bind({ navi : this, node : expendAllNode})
  427. });
  428. for( var i=1; i<=deepestLevel; i++ ){
  429. var expendNode = new Element("div",{
  430. styles : this.css.expendNode,
  431. text : "展开到"+i+"级节点"
  432. }).inject(this.expendArea);
  433. expendNode.addEvents({
  434. "mouseover" : function(){ this.node.setStyles( this.navi.css.expendNode_over )}.bind( { navi : this, node : expendNode} ),
  435. "mouseout" : function(){ this.node.setStyles( this.navi.css.expendNode )}.bind({ navi : this, node : expendNode}),
  436. "click" : function(){
  437. this.navi.km.execCommand('expandtolevel', this.level);
  438. this.navi.hideExpendArea();
  439. }.bind({ navi : this, node : expendNode, level : i})
  440. })
  441. }
  442. this.app.content.addEvent("click",function(){
  443. this.hideExpendArea();
  444. }.bind(this))
  445. }
  446. });
  447. MWF.xApplication.Execution.Minder.Preview = new Class({
  448. options : {
  449. "show" : "true"
  450. },
  451. Implements: [Options, Events],
  452. initialize: function (navi, container, km, app, css) {
  453. this.navi = navi;
  454. this.container = container;
  455. this.app = app;
  456. this.lp = this.app.lp.minder;
  457. this.actions = this.app.restActions;
  458. this.css = css;
  459. this.km = km;
  460. },
  461. load: function (callback) {
  462. this.navPreviewer = new Element("div",{ "styles" : this.css.navPreviewer }).inject(this.container);
  463. this.initPreViewer();
  464. if( this.options.show )this.navi.toggleOpenPreViewer();
  465. },
  466. initPreViewer: function(){
  467. // 画布,渲染缩略图
  468. var paper = this.paper = new kity.Paper( this.navPreviewer );
  469. // 用两个路径来挥之节点和连线的缩略图
  470. this.nodeThumb = paper.put(new kity.Path());
  471. this.connectionThumb = paper.put(new kity.Path());
  472. // 表示可视区域的矩形
  473. this.visibleRect = paper.put(new kity.Rect(100, 100).stroke('red', '1%'));
  474. this.contentView = new kity.Box();
  475. this.visibleView = new kity.Box();
  476. /**
  477. * 增加一个对天盘图情况缩略图的处理,
  478. * @Editor: Naixor line 104~129
  479. * @Date: 2015.11.3
  480. */
  481. this.pathHandler = this.getPathHandler(this.km.getTheme());
  482. this.navigate();
  483. },
  484. getPathHandler: function (theme) {
  485. switch (theme) {
  486. case "tianpan":
  487. case "tianpan-compact":
  488. return function(nodePathData, x, y, width, height) {
  489. var r = width >> 1;
  490. nodePathData.push('M', x, y + r,
  491. 'a', r, r, 0, 1, 1, 0, 0.01,
  492. 'z');
  493. };
  494. default: {
  495. return function(nodePathData, x, y, width, height) {
  496. nodePathData.push('M', x, y,
  497. 'h', width, 'v', height,
  498. 'h', -width, 'z');
  499. }
  500. }
  501. }
  502. },
  503. toggleOpen : function( open ) {
  504. if (open) {
  505. this.navPreviewer.setStyle("display","block");
  506. this.bindPreviewerEvent();
  507. this.updateContentView();
  508. this.updateVisibleView();
  509. } else{
  510. this.navPreviewer.setStyle("display","none");
  511. this.unbindPreviewerEvent();
  512. }
  513. },
  514. bindPreviewerEvent : function(){
  515. this.updateContentViewFun = this.updateContentViewFun || this.updateContentView.bind(this);
  516. this.updateVisibleViewFun = this.updateVisibleViewFun || this.updateVisibleView.bind(this);
  517. this.km.on('layout layoutallfinish', this.updateContentViewFun );
  518. this.km.on('viewchange', this.updateVisibleViewFun );
  519. },
  520. unbindPreviewerEvent : function(){
  521. this.km.off('layout layoutallfinish', this.updateContentViewFun );
  522. this.km.off('viewchange', this.updateVisibleViewFun );
  523. },
  524. moveView: function(center, duration) {
  525. var box = this.visibleView;
  526. center.x = -center.x;
  527. center.y = -center.y;
  528. var viewMatrix = this.km.getPaper().getViewPortMatrix();
  529. box = viewMatrix.transformBox(box);
  530. var targetPosition = center.offset(box.width / 2, box.height / 2);
  531. this.km.getViewDragger().moveTo(targetPosition, duration);
  532. },
  533. navigate: function() {
  534. var _self = this;
  535. this.dragging = false;
  536. this.paper.on('mousedown', function(e) {
  537. _self.dragging = true;
  538. _self.moveView(e.getPosition('top'), 200);
  539. _self.navPreviewer.setStyles( _self.css.navPreviewerGrab );
  540. });
  541. this.paper.on('mousemove', function(e) {
  542. if (_self.dragging) {
  543. _self.moveView(e.getPosition('top'));
  544. }
  545. });
  546. $(window).addEvent('mouseup', function() {
  547. _self.dragging = false;
  548. if(_self.navPreviewer)_self.navPreviewer.setStyles( _self.css.navPreviewerNoGrab );
  549. });
  550. },
  551. updateContentView: function(){
  552. var view = this.km.getRenderContainer().getBoundaryBox();
  553. this.contentView = view;
  554. var padding = 30;
  555. this.paper.setViewBox(
  556. view.x - padding - 0.5,
  557. view.y - padding - 0.5,
  558. view.width + padding * 2 + 1,
  559. view.height + padding * 2 + 1);
  560. var nodePathData = [];
  561. var connectionThumbData = [];
  562. this.km.getRoot().traverse(function(node) {
  563. var box = node.getLayoutBox();
  564. this.pathHandler(nodePathData, box.x, box.y, box.width, box.height);
  565. if (node.getConnection() && node.parent && node.parent.isExpanded()) {
  566. connectionThumbData.push(node.getConnection().getPathData());
  567. }
  568. }.bind(this));
  569. this.paper.setStyle('background', this.km.getStyle('background'));
  570. if (nodePathData.length) {
  571. this.nodeThumb
  572. .fill(this.km.getStyle('root-background'))
  573. .setPathData(nodePathData);
  574. } else {
  575. this.nodeThumb.setPathData(null);
  576. }
  577. if (connectionThumbData.length) {
  578. this.connectionThumb
  579. .stroke(this.km.getStyle('connect-color'), '0.5%')
  580. .setPathData(connectionThumbData);
  581. } else {
  582. this.connectionThumb.setPathData(null);
  583. }
  584. this.updateVisibleView();
  585. },
  586. updateVisibleView: function(){
  587. this.visibleView = this.km.getViewDragger().getView();
  588. this.visibleRect.setBox(this.visibleView.intersect(this.contentView));
  589. }
  590. });
  591. MWF.xApplication.Execution.Minder.SearchBar = new Class({
  592. Implements: [Options, Events],
  593. initialize: function (navi, container, km, app, css) {
  594. this.navi = navi;
  595. this.container = container;
  596. this.app = app;
  597. this.lp = this.app.lp.minder;
  598. this.actions = this.app.restActions;
  599. this.css = css;
  600. this.km = km;
  601. },
  602. load: function (callback) {
  603. this.createSearchBar();
  604. this.nodeSequence = [];
  605. this.searchSequence = [];
  606. this.km.on('contentchange', this.makeNodeSequence.bind(this));
  607. this.makeNodeSequence();
  608. },
  609. show : function(){
  610. this.node.setStyle("display","block")
  611. },
  612. hide: function(){
  613. //this.km.execCommand('camera');
  614. this.node.setStyle("display","none")
  615. },
  616. createSearchBar : function(){
  617. this.node = new Element("div", { "styles" : this.css.searchBar }).inject(this.container);
  618. this.searchInput = new Element("input" , {
  619. "type" : "text",
  620. "styles" : this.css.searchInput,
  621. "value" : this.lp.searchText
  622. }).inject(this.node);
  623. this.searchInput.addEvents({
  624. "focus" : function( ev ){
  625. if( this.searchInput.get("value")==this.lp.searchText){
  626. this.searchInput.set("value","")
  627. }
  628. }.bind(this),
  629. "blur" : function( ev ){
  630. if( this.searchInput.get("value").trim()==""){
  631. this.searchInput.set("value", this.lp.searchText);
  632. }
  633. }.bind(this),
  634. "keyup" : function(){
  635. this.doSearch(this.searchInput.get("value"),"next");
  636. }.bind(this)
  637. });
  638. //this.searchButton = new Element("div", {"styles" : this.css.searchButton, "text" : this.lp.search } ).inject(this.node);
  639. this.resultInforNode = new Element("div", {
  640. "styles" : this.css.resultInforNode,
  641. "text" : "0/0"
  642. } ).inject(this.node);
  643. this.prevButton = new Element("div", {"styles" : this.css.prevButton , "title" : this.lp.prev} ).inject(this.node);
  644. this.prevButton.addEvent("click",function(){
  645. this.goPrev();
  646. }.bind(this));
  647. this.nextButton = new Element("div", {"styles" : this.css.nextButton , "title" : this.lp.next } ).inject(this.node);
  648. this.nextButton.addEvent("click",function(){
  649. this.goNext();
  650. }.bind(this));
  651. this.closeButton = new Element("div", {"styles" : this.css.closeButton , "title" : this.lp.close } ).inject(this.node);
  652. this.closeButton.addEvent("click",function(){
  653. this.close();
  654. }.bind(this))
  655. },
  656. goNext : function(){
  657. this.doSearch( this.searchInput.get("value"),"next" );
  658. },
  659. goPrev : function(){
  660. this.doSearch( this.searchInput.get("value"),"prev" );
  661. },
  662. close : function(){
  663. this.navi.hideSearch();
  664. },
  665. makeNodeSequence: function() {
  666. this.nodeSequence = [];
  667. this.km.getRoot().traverse(function(node) {
  668. this.nodeSequence.push(node);
  669. }.bind(this));
  670. },
  671. makeSearchSequence: function(keyword) {
  672. this.searchSequence = [];
  673. for (var i = 0; i < this.nodeSequence.length; i++) {
  674. var node = this.nodeSequence[i];
  675. var text = node.getText().toLowerCase();
  676. if (text.indexOf(keyword) != -1) {
  677. this.searchSequence.push({node:node});
  678. }
  679. var note = node.getData('note');
  680. if (note && note.toLowerCase().indexOf(keyword) != -1) {
  681. this.searchSequence.push({node: node, keyword: keyword});
  682. }
  683. }
  684. },
  685. doSearch : function(keyword, direction) {
  686. this.km.fire('hidenoterequest');
  687. if (!keyword || !/\S/.exec(keyword)) {
  688. this.searchInput.focus();
  689. return;
  690. }
  691. // 当搜索不到节点时候默认的选项
  692. this.curIndex = 0;
  693. this.resultNum = 0;
  694. keyword = keyword.toLowerCase();
  695. var newSearch = this.lastKeyword != keyword;
  696. this.lastKeyword = keyword;
  697. if (newSearch) {
  698. this.makeSearchSequence(keyword);
  699. }
  700. this.resultNum = this.searchSequence.length;
  701. if (this.searchSequence.length) {
  702. var curIndex = newSearch ? 0 : (direction === 'next' ? this.lastIndex + 1 : this.lastIndex - 1) || 0;
  703. curIndex = (this.searchSequence.length + curIndex) % this.searchSequence.length;
  704. this.setSearchResult(this.searchSequence[curIndex].node, this.searchSequence[curIndex].keyword);
  705. this.lastIndex = curIndex;
  706. this.curIndex = curIndex + 1;
  707. this.resultInforNode.set("text", this.curIndex+"/"+this.searchSequence.length);
  708. }
  709. },
  710. setSearchResult : function(node, previewKeyword) {
  711. setTimeout(function () {
  712. if (previewKeyword) {
  713. this.km.fire('shownoterequest', {node: node, keyword: previewKeyword});
  714. }
  715. if (!node.isExpanded()){
  716. this.km.select(node, true);
  717. this.km.execCommand('expand', true);
  718. }else{
  719. this.km.select(node, true);
  720. this.km.execCommand('camera', node, 50);
  721. }
  722. }.bind(this), 60);
  723. }
  724. });