kmsjsmap.js 120 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353
  1. var $conTextMenu = '';
  2. // an noop function define
  3. var _noop = function() {};
  4. // 河蟹IE8 时 没有Object.keys方法
  5. if (!Object.keys) {
  6. Object.keys = (function() {
  7. 'use strict';
  8. var hasOwnProperty = Object.prototype.hasOwnProperty,
  9. hasDontEnumBug = !({
  10. toString: null
  11. }).propertyIsEnumerable('toString'),
  12. dontEnums = [
  13. 'toString',
  14. 'toLocaleString',
  15. 'valueOf',
  16. 'hasOwnProperty',
  17. 'isPrototypeOf',
  18. 'propertyIsEnumerable',
  19. 'constructor'
  20. ],
  21. dontEnumsLength = dontEnums.length;
  22. return function(obj) {
  23. if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
  24. throw new TypeError('Object.keys called on non-object');
  25. }
  26. var result = [],
  27. prop, i;
  28. for (prop in obj) {
  29. if (hasOwnProperty.call(obj, prop)) {
  30. result.push(prop);
  31. }
  32. }
  33. if (hasDontEnumBug) {
  34. for (i = 0; i < dontEnumsLength; i++) {
  35. if (hasOwnProperty.call(obj, dontEnums[i])) {
  36. result.push(dontEnums[i]);
  37. }
  38. }
  39. }
  40. return result;
  41. };
  42. }());
  43. }
  44. $(function() {
  45. var html = '<div id="kmsjsmap_contextmenu"><ul class="kmsjsmap-dropdown-menu"><li><a href="javascript: kmsjsmap.add_node();">添加节点</a></li><li><a href="javascript: kmsjsmap.modify_node()">编辑节点</a></li><li><a href="javascript: kmsjsmap.del_node()">删除节点</a></li><li><a href="javascript: kmsjsmap.relation_node()">关联节点</a></li></ul></div>';
  46. $('body').append(html);
  47. $conTextMenu = $('div#kmsjsmap_contextmenu');
  48. });
  49. /*
  50. * Released under BSD License
  51. * Copyright (c) 2014-2015 hizzgdev@163.com
  52. *
  53. * Project Home:
  54. * https://github.com/hizzgdev/jsmind/
  55. */
  56. (function($w) {
  57. 'use strict';
  58. // set 'jsMind' as the library name.
  59. // __name__ should be a const value, Never try to change it easily.
  60. var __name__ = 'jsMind';
  61. // library version
  62. var __version__ = '0.4.6';
  63. var logger = (typeof console === 'undefined') ? {
  64. log: _noop,
  65. debug: _noop,
  66. error: _noop,
  67. warn: _noop,
  68. info: _noop
  69. } : console;
  70. if (!logger.debug) logger.debug = _noop;
  71. // check global variables
  72. if (typeof module === 'undefined' || !module.exports) {
  73. if (typeof $w[__name__] != 'undefined') {
  74. logger.log(__name__ + ' has been already exist.');
  75. return;
  76. }
  77. }
  78. // shortcut of methods in dom
  79. var $d = $w.document;
  80. var $g = function(id) {
  81. return $d.getElementById(id);
  82. };
  83. var $c = function(tag) {
  84. return $d.createElement(tag);
  85. };
  86. var $t = function(n, t) {
  87. if (n.hasChildNodes()) {
  88. n.firstChild.nodeValue = t;
  89. } else {
  90. n.appendChild($d.createTextNode(t));
  91. }
  92. };
  93. var $h = function(n, t) {
  94. n.innerHTML = t;
  95. };
  96. // detect isElement
  97. var $i = function(el) {
  98. return !!el && (typeof el === 'object') && (el.nodeType === 1) && (typeof el.style === 'object') && (typeof el.ownerDocument === 'object');
  99. };
  100. if (typeof String.prototype.startsWith != 'function') {
  101. String.prototype.startsWith = function(p) {
  102. return this.slice(0, p.length) === p;
  103. };
  104. }
  105. var DEFAULT_OPTIONS = {
  106. container: '', // id of the container
  107. editable: false, // you can change it in your options
  108. theme: null,
  109. mode: 'full', // full or side
  110. support_html: true,
  111. view: {
  112. hmargin: 100,
  113. vmargin: 50,
  114. line_width: 2,
  115. line_color: '#555'
  116. },
  117. layout: {
  118. hspace: 30,
  119. vspace: 20,
  120. pspace: 13
  121. },
  122. default_event_handle: {
  123. enable_mousedown_handle: true,
  124. enable_click_handle: true,
  125. enable_dblclick_handle: true
  126. },
  127. shortcut: {
  128. enable: true,
  129. handles: {},
  130. mapping: {
  131. addchild: 45, // Insert
  132. addbrother: 13, // Enter
  133. editnode: 113, // F2
  134. delnode: 46, // Delete
  135. toggle: 32, // Space
  136. left: 37, // Left
  137. up: 38, // Up
  138. right: 39, // Right
  139. down: 40, // Down
  140. }
  141. },
  142. };
  143. // core object
  144. var jm = function(options) {
  145. jm.current = this;
  146. this.version = __version__;
  147. var opts = {};
  148. jm.util.json.merge(opts, DEFAULT_OPTIONS);
  149. jm.util.json.merge(opts, options);
  150. if (!opts.container) {
  151. logger.error('the options.container should not be null or empty.');
  152. return;
  153. }
  154. this.options = opts;
  155. this.inited = false;
  156. this.mind = null;
  157. this.event_handles = [];
  158. this.init();
  159. };
  160. // ============= static object =============================================
  161. jm.direction = {
  162. left: -1,
  163. center: 0,
  164. right: 1
  165. };
  166. jm.event_type = {
  167. show: 1,
  168. resize: 2,
  169. edit: 3,
  170. select: 4
  171. };
  172. jm.node = function(sId, iIndex, sTopic, oData, bIsRoot, oParent, eDirection, bExpanded) {
  173. if (!sId) {
  174. logger.error('invalid nodeid');
  175. return;
  176. }
  177. if (typeof iIndex != 'number') {
  178. logger.error('invalid node index');
  179. return;
  180. }
  181. if (typeof bExpanded === 'undefined') {
  182. bExpanded = true;
  183. }
  184. this.id = sId;
  185. this.index = iIndex;
  186. this.topic = sTopic;
  187. this.data = oData || {};
  188. this.isroot = bIsRoot;
  189. this.parent = oParent;
  190. this.direction = eDirection;
  191. this.expanded = !!bExpanded;
  192. this.children = [];
  193. this._data = {};
  194. };
  195. jm.node.compare = function(node1, node2) {
  196. // '-1' is alwary the last
  197. var r = 0;
  198. var i1 = node1.index;
  199. var i2 = node2.index;
  200. if (i1 >= 0 && i2 >= 0) {
  201. r = i1 - i2;
  202. } else if (i1 == -1 && i2 == -1) {
  203. r = 0;
  204. } else if (i1 == -1) {
  205. r = 1;
  206. } else if (i2 == -1) {
  207. r = -1;
  208. } else {
  209. r = 0;
  210. }
  211. //logger.debug(i1+' <> '+i2+' = '+r);
  212. return r;
  213. };
  214. jm.node.inherited = function(pnode, node) {
  215. if (!!pnode && !!node) {
  216. if (pnode.id === node.id) {
  217. return true;
  218. }
  219. if (pnode.isroot) {
  220. return true;
  221. }
  222. var pid = pnode.id;
  223. var p = node;
  224. while (!p.isroot) {
  225. p = p.parent;
  226. if (p.id === pid) {
  227. return true;
  228. }
  229. }
  230. }
  231. return false;
  232. };
  233. jm.node.prototype = {
  234. get_location: function() {
  235. var vd = this._data.view;
  236. return {
  237. x: vd.abs_x,
  238. y: vd.abs_y
  239. };
  240. },
  241. get_size: function() {
  242. var vd = this._data.view;
  243. return {
  244. w: vd.width,
  245. h: vd.height
  246. }
  247. }
  248. };
  249. jm.mind = function() {
  250. this.name = null;
  251. this.author = null;
  252. this.version = null;
  253. this.root = null;
  254. this.selected = null;
  255. this.nodes = {};
  256. };
  257. jm.mind.prototype = {
  258. get_node: function(nodeid) {
  259. if (nodeid in this.nodes) {
  260. return this.nodes[nodeid];
  261. } else {
  262. logger.warn('the node[id=' + nodeid + '] can not be found');
  263. return null;
  264. }
  265. },
  266. set_root: function(nodeid, topic, data) {
  267. if (this.root == null) {
  268. this.root = new jm.node(nodeid, 0, topic, data, true);
  269. this._put_node(this.root);
  270. } else {
  271. logger.error('root node is already exist');
  272. }
  273. },
  274. add_node: function(parent_node, nodeid, topic, data, idx, direction, expanded) {
  275. if (!jm.util.is_node(parent_node)) {
  276. var the_parent_node = this.get_node(parent_node);
  277. if (!the_parent_node) {
  278. logger.error('the parent_node[id=' + parent_node + '] can not be found.');
  279. return null;
  280. } else {
  281. return this.add_node(the_parent_node, nodeid, topic, data, idx, direction, expanded);
  282. }
  283. }
  284. var nodeindex = idx || -1;
  285. var node = null;
  286. if (parent_node.isroot) {
  287. var d = jm.direction.right;
  288. if (!direction || isNaN(direction)) {
  289. var children = parent_node.children;
  290. var children_len = children.length;
  291. var r = 0;
  292. for (var i = 0; i < children_len; i++) {
  293. if (children[i].direction === jm.direction.left) {
  294. r--;
  295. } else {
  296. r++;
  297. }
  298. }
  299. d = (children_len > 1 && r > 0) ? jm.direction.left : jm.direction.right;
  300. } else {
  301. d = (direction != jm.direction.left) ? jm.direction.right : jm.direction.left;
  302. }
  303. node = new jm.node(nodeid, nodeindex, topic, data, false, parent_node, d, expanded);
  304. } else {
  305. node = new jm.node(nodeid, nodeindex, topic, data, false, parent_node, parent_node.direction, expanded);
  306. }
  307. if (this._put_node(node)) {
  308. parent_node.children.push(node);
  309. this._reindex(parent_node);
  310. } else {
  311. logger.error('fail, the nodeid \'' + node.id + '\' has been already exist.');
  312. node = null;
  313. }
  314. return node;
  315. },
  316. insert_node_before: function(node_before, nodeid, topic, data) {
  317. if (!jm.util.is_node(node_before)) {
  318. var the_node_before = this.get_node(node_before);
  319. if (!the_node_before) {
  320. logger.error('the node_before[id=' + node_before + '] can not be found.');
  321. return null;
  322. } else {
  323. return this.insert_node_before(the_node_before, nodeid, topic, data);
  324. }
  325. }
  326. var node_index = node_before.index - 0.5;
  327. return this.add_node(node_before.parent, nodeid, topic, data, node_index);
  328. },
  329. get_node_before: function(node) {
  330. if (!jm.util.is_node(node)) {
  331. var the_node = this.get_node(node);
  332. if (!the_node) {
  333. logger.error('the node[id=' + node + '] can not be found.');
  334. return null;
  335. } else {
  336. return this.get_node_before(the_node);
  337. }
  338. }
  339. if (node.isroot) {
  340. return null;
  341. }
  342. var idx = node.index - 2;
  343. if (idx >= 0) {
  344. return node.parent.children[idx];
  345. } else {
  346. return null;
  347. }
  348. },
  349. insert_node_after: function(node_after, nodeid, topic, data) {
  350. if (!jm.util.is_node(node_after)) {
  351. var the_node_after = this.get_node(node_before);
  352. if (!the_node_after) {
  353. logger.error('the node_after[id=' + node_after + '] can not be found.');
  354. return null;
  355. } else {
  356. return this.insert_node_after(the_node_after, nodeid, topic, data);
  357. }
  358. }
  359. var node_index = node_after.index + 0.5;
  360. return this.add_node(node_after.parent, nodeid, topic, data, node_index);
  361. },
  362. get_node_after: function(node) {
  363. if (!jm.util.is_node(node)) {
  364. var the_node = this.get_node(node);
  365. if (!the_node) {
  366. logger.error('the node[id=' + node + '] can not be found.');
  367. return null;
  368. } else {
  369. return this.get_node_after(the_node);
  370. }
  371. }
  372. if (node.isroot) {
  373. return null;
  374. }
  375. var idx = node.index;
  376. var brothers = node.parent.children;
  377. if (brothers.length >= idx) {
  378. return node.parent.children[idx];
  379. } else {
  380. return null;
  381. }
  382. },
  383. move_node: function(node, beforeid, parentid, direction) {
  384. if (!jm.util.is_node(node)) {
  385. var the_node = this.get_node(node);
  386. if (!the_node) {
  387. logger.error('the node[id=' + node + '] can not be found.');
  388. return null;
  389. } else {
  390. return this.move_node(the_node, beforeid, parentid, direction);
  391. }
  392. }
  393. if (!parentid) {
  394. parentid = node.parent.id;
  395. }
  396. return this._move_node(node, beforeid, parentid, direction);
  397. },
  398. _flow_node_direction: function(node, direction) {
  399. if (typeof direction === 'undefined') {
  400. direction = node.direction;
  401. } else {
  402. node.direction = direction;
  403. }
  404. var len = node.children.length;
  405. while (len--) {
  406. this._flow_node_direction(node.children[len], direction);
  407. }
  408. },
  409. _move_node_internal: function(node, beforeid) {
  410. if (!!node && !!beforeid) {
  411. if (beforeid == '_last_') {
  412. node.index = -1;
  413. this._reindex(node.parent);
  414. } else if (beforeid == '_first_') {
  415. node.index = 0;
  416. this._reindex(node.parent);
  417. } else {
  418. var node_before = (!!beforeid) ? this.get_node(beforeid) : null;
  419. if (node_before != null && node_before.parent != null && node_before.parent.id == node.parent.id) {
  420. node.index = node_before.index - 0.5;
  421. this._reindex(node.parent);
  422. }
  423. }
  424. }
  425. return node;
  426. },
  427. _move_node: function(node, beforeid, parentid, direction) {
  428. if (!!node && !!parentid) {
  429. if (node.parent.id != parentid) {
  430. // remove from parent's children
  431. var sibling = node.parent.children;
  432. var si = sibling.length;
  433. while (si--) {
  434. if (sibling[si].id == node.id) {
  435. sibling.splice(si, 1);
  436. break;
  437. }
  438. }
  439. node.parent = this.get_node(parentid);
  440. node.parent.children.push(node);
  441. }
  442. if (node.parent.isroot) {
  443. if (direction == jsMind.direction.left) {
  444. node.direction = direction;
  445. } else {
  446. node.direction = jm.direction.right;
  447. }
  448. } else {
  449. node.direction = node.parent.direction;
  450. }
  451. this._move_node_internal(node, beforeid);
  452. this._flow_node_direction(node);
  453. }
  454. return node;
  455. },
  456. remove_node: function(node) {
  457. if (!jm.util.is_node(node)) {
  458. var the_node = this.get_node(node);
  459. if (!the_node) {
  460. logger.error('the node[id=' + node + '] can not be found.');
  461. return false;
  462. } else {
  463. return this.remove_node(the_node);
  464. }
  465. }
  466. if (!node) {
  467. logger.error('fail, the node can not be found');
  468. return false;
  469. }
  470. if (node.isroot) {
  471. logger.error('fail, can not remove root node');
  472. return false;
  473. }
  474. // 清除右上角badge
  475. $('div.leo-badge[nodeid$="' + node.id + '"]').remove();
  476. if (this.selected != null && this.selected.id == node.id) {
  477. this.selected = null;
  478. }
  479. // clean all subordinate nodes
  480. var children = node.children;
  481. var ci = children.length;
  482. while (ci--) {
  483. this.remove_node(children[ci]);
  484. }
  485. // clean all children
  486. children.length = 0;
  487. // remove from parent's children
  488. var sibling = node.parent.children;
  489. var si = sibling.length;
  490. while (si--) {
  491. if (sibling[si].id == node.id) {
  492. sibling.splice(si, 1);
  493. break;
  494. }
  495. }
  496. // remove from global nodes
  497. delete this.nodes[node.id];
  498. // clean all properties
  499. for (var k in node) {
  500. delete node[k];
  501. }
  502. // remove it's self
  503. node = null;
  504. //delete node;
  505. return true;
  506. },
  507. _put_node: function(node) {
  508. if (node.id in this.nodes) {
  509. logger.warn('the nodeid \'' + node.id + '\' has been already exist.');
  510. return false;
  511. } else {
  512. this.nodes[node.id] = node;
  513. return true;
  514. }
  515. },
  516. _reindex: function(node) {
  517. if (node instanceof jm.node) {
  518. node.children.sort(jm.node.compare);
  519. for (var i = 0; i < node.children.length; i++) {
  520. node.children[i].index = i + 1;
  521. }
  522. }
  523. },
  524. };
  525. jm.format = {
  526. node_tree: {
  527. example: {
  528. "meta": {
  529. "name": __name__,
  530. "version": __version__
  531. },
  532. "format": "node_tree",
  533. "data": {
  534. "id": "root",
  535. "topic": "jsMind Example"
  536. }
  537. },
  538. get_mind: function(source) {
  539. var df = jm.format.node_tree;
  540. var mind = new jm.mind();
  541. mind.name = source.meta.name;
  542. mind.author = source.meta.author;
  543. mind.version = source.meta.version;
  544. df._parse(mind, source.data);
  545. return mind;
  546. },
  547. get_data: function(mind) {
  548. var df = jm.format.node_tree;
  549. var json = {};
  550. json.meta = {
  551. name: mind.name,
  552. author: mind.author,
  553. version: mind.version
  554. };
  555. json.format = 'node_tree';
  556. json.data = df._buildnode(mind.root);
  557. return json;
  558. },
  559. _parse: function(mind, node_root) {
  560. var df = jm.format.node_tree;
  561. var data = df._extract_data(node_root);
  562. mind.set_root(node_root.id, node_root.topic, data);
  563. if ('children' in node_root) {
  564. var children = node_root.children;
  565. for (var i = 0; i < children.length; i++) {
  566. df._extract_subnode(mind, mind.root, children[i]);
  567. }
  568. }
  569. },
  570. _extract_data: function(node_json) {
  571. var data = {};
  572. for (var k in node_json) {
  573. if (k == 'id' || k == 'topic' || k == 'children' || k == 'direction' || k == 'expanded') {
  574. continue;
  575. }
  576. data[k] = node_json[k];
  577. }
  578. return data;
  579. },
  580. _extract_subnode: function(mind, node_parent, node_json) {
  581. var df = jm.format.node_tree;
  582. var data = df._extract_data(node_json);
  583. var d = null;
  584. if (node_parent.isroot) {
  585. d = node_json.direction == 'left' ? jm.direction.left : jm.direction.right;
  586. }
  587. var node = mind.add_node(node_parent, node_json.id, node_json.topic, data, null, d, node_json.expanded);
  588. if ('children' in node_json) {
  589. var children = node_json.children;
  590. for (var i = 0; i < children.length; i++) {
  591. df._extract_subnode(mind, node, children[i]);
  592. }
  593. }
  594. },
  595. _buildnode: function(node) {
  596. var df = jm.format.node_tree;
  597. if (!(node instanceof jm.node)) {
  598. return;
  599. }
  600. var o = {
  601. id: node.id,
  602. topic: node.topic,
  603. expanded: node.expanded
  604. };
  605. if (!!node.parent && node.parent.isroot) {
  606. o.direction = node.direction == jm.direction.left ? 'left' : 'right';
  607. }
  608. if (node.data != null) {
  609. var node_data = node.data;
  610. for (var k in node_data) {
  611. o[k] = node_data[k];
  612. }
  613. }
  614. var children = node.children;
  615. if (children.length > 0) {
  616. o.children = [];
  617. for (var i = 0; i < children.length; i++) {
  618. o.children.push(df._buildnode(children[i]));
  619. }
  620. }
  621. return o;
  622. }
  623. },
  624. node_array: {
  625. example: {
  626. "meta": {
  627. "name": __name__,
  628. "version": __version__
  629. },
  630. "format": "node_array",
  631. "data": [{
  632. "id": "root",
  633. "topic": "jsMind Example",
  634. "isroot": true
  635. }]
  636. },
  637. get_mind: function(source) {
  638. var df = jm.format.node_array;
  639. var mind = new jm.mind();
  640. mind.name = source.meta.name;
  641. mind.author = source.meta.author;
  642. mind.version = source.meta.version;
  643. df._parse(mind, source.data);
  644. return mind;
  645. },
  646. get_data: function(mind) {
  647. var df = jm.format.node_array;
  648. var json = {};
  649. json.meta = {
  650. name: mind.name,
  651. author: mind.author,
  652. version: mind.version
  653. };
  654. json.format = 'node_array';
  655. json.data = [];
  656. df._array(mind, json.data);
  657. return json;
  658. },
  659. _parse: function(mind, node_array) {
  660. var df = jm.format.node_array;
  661. var narray = node_array.slice(0);
  662. // reverse array for improving looping performance
  663. narray.reverse();
  664. var root_id = df._extract_root(mind, narray);
  665. if (!!root_id) {
  666. df._extract_subnode(mind, root_id, narray);
  667. } else {
  668. logger.error('root node can not be found');
  669. }
  670. },
  671. _extract_root: function(mind, node_array) {
  672. var df = jm.format.node_array;
  673. var i = node_array.length;
  674. while (i--) {
  675. if ('isroot' in node_array[i] && node_array[i].isroot) {
  676. var root_json = node_array[i];
  677. var data = df._extract_data(root_json);
  678. mind.set_root(root_json.id, root_json.topic, data);
  679. node_array.splice(i, 1);
  680. return root_json.id;
  681. }
  682. }
  683. return null;
  684. },
  685. _extract_subnode: function(mind, parentid, node_array) {
  686. var df = jm.format.node_array;
  687. var i = node_array.length;
  688. var node_json = null;
  689. var data = null;
  690. var extract_count = 0;
  691. while (i--) {
  692. node_json = node_array[i];
  693. if (node_json.parentid == parentid) {
  694. data = df._extract_data(node_json);
  695. var d = null;
  696. var node_direction = node_json.direction;
  697. if (!!node_direction) {
  698. d = node_direction == 'left' ? jm.direction.left : jm.direction.right;
  699. }
  700. mind.add_node(parentid, node_json.id, node_json.topic, data, null, d, node_json.expanded);
  701. node_array.splice(i, 1);
  702. extract_count++;
  703. var sub_extract_count = df._extract_subnode(mind, node_json.id, node_array);
  704. if (sub_extract_count > 0) {
  705. // reset loop index after extract subordinate node
  706. i = node_array.length;
  707. extract_count += sub_extract_count;
  708. }
  709. }
  710. }
  711. return extract_count;
  712. },
  713. _extract_data: function(node_json) {
  714. var data = {};
  715. for (var k in node_json) {
  716. if (k == 'id' || k == 'topic' || k == 'parentid' || k == 'isroot' || k == 'direction' || k == 'expanded') {
  717. continue;
  718. }
  719. data[k] = node_json[k];
  720. }
  721. return data;
  722. },
  723. _array: function(mind, node_array) {
  724. var df = jm.format.node_array;
  725. df._array_node(mind.root, node_array);
  726. },
  727. _array_node: function(node, node_array) {
  728. var df = jm.format.node_array;
  729. if (!(node instanceof jm.node)) {
  730. return;
  731. }
  732. var o = {
  733. id: node.id,
  734. topic: node.topic,
  735. expanded: node.expanded
  736. };
  737. if (!!node.parent) {
  738. o.parentid = node.parent.id;
  739. }
  740. if (node.isroot) {
  741. o.isroot = true;
  742. }
  743. if (!!node.parent && node.parent.isroot) {
  744. o.direction = node.direction == jm.direction.left ? 'left' : 'right';
  745. }
  746. if (node.data != null) {
  747. var node_data = node.data;
  748. for (var k in node_data) {
  749. o[k] = node_data[k];
  750. }
  751. }
  752. node_array.push(o);
  753. var ci = node.children.length;
  754. for (var i = 0; i < ci; i++) {
  755. df._array_node(node.children[i], node_array);
  756. }
  757. },
  758. },
  759. freemind: {
  760. example: {
  761. "meta": {
  762. "name": __name__,
  763. "version": __version__
  764. },
  765. "format": "freemind",
  766. "data": "<map version=\"1.0.1\"><node ID=\"root\" TEXT=\"freemind Example\"/></map>"
  767. },
  768. get_mind: function(source) {
  769. var df = jm.format.freemind;
  770. var mind = new jm.mind();
  771. mind.name = source.meta.name;
  772. mind.author = source.meta.author;
  773. mind.version = source.meta.version;
  774. var xml = source.data;
  775. var xml_doc = df._parse_xml(xml);
  776. var xml_root = df._find_root(xml_doc);
  777. df._load_node(mind, null, xml_root);
  778. return mind;
  779. },
  780. get_data: function(mind) {
  781. var df = jm.format.freemind;
  782. var json = {};
  783. json.meta = {
  784. name: mind.name,
  785. author: mind.author,
  786. version: mind.version
  787. };
  788. json.format = 'freemind';
  789. var xmllines = [];
  790. xmllines.push('<map version=\"1.0.1\">');
  791. df._buildmap(mind.root, xmllines);
  792. xmllines.push('</map>');
  793. json.data = xmllines.join(' ');
  794. return json;
  795. },
  796. _parse_xml: function(xml) {
  797. var xml_doc = null;
  798. if (window.DOMParser) {
  799. var parser = new DOMParser();
  800. xml_doc = parser.parseFromString(xml, 'text/xml');
  801. } else { // Internet Explorer
  802. xml_doc = new ActiveXObject('Microsoft.XMLDOM');
  803. xml_doc.async = false;
  804. xml_doc.loadXML(xml);
  805. }
  806. return xml_doc;
  807. },
  808. _find_root: function(xml_doc) {
  809. var nodes = xml_doc.childNodes;
  810. var node = null;
  811. var root = null;
  812. var n = null;
  813. for (var i = 0; i < nodes.length; i++) {
  814. n = nodes[i];
  815. if (n.nodeType == 1 && n.tagName == 'map') {
  816. node = n;
  817. break;
  818. }
  819. }
  820. if (!!node) {
  821. var ns = node.childNodes;
  822. node = null;
  823. for (var i = 0; i < ns.length; i++) {
  824. n = ns[i];
  825. if (n.nodeType == 1 && n.tagName == 'node') {
  826. node = n;
  827. break;
  828. }
  829. }
  830. }
  831. return node;
  832. },
  833. _load_node: function(mind, parent_id, xml_node) {
  834. var df = jm.format.freemind;
  835. var node_id = xml_node.getAttribute('ID');
  836. var node_topic = xml_node.getAttribute('TEXT');
  837. // look for richcontent
  838. if (node_topic == null) {
  839. var topic_children = xml_node.childNodes;
  840. var topic_child = null;
  841. for (var i = 0; i < topic_children.length; i++) {
  842. topic_child = topic_children[i];
  843. //logger.debug(topic_child.tagName);
  844. if (topic_child.nodeType == 1 && topic_child.tagName === 'richcontent') {
  845. node_topic = topic_child.textContent;
  846. break;
  847. }
  848. }
  849. }
  850. var node_data = df._load_attributes(xml_node);
  851. var node_expanded = ('expanded' in node_data) ? (node_data.expanded == 'true') : true;
  852. delete node_data.expanded;
  853. var node_position = xml_node.getAttribute('POSITION');
  854. var node_direction = null;
  855. if (!!node_position) {
  856. node_direction = node_position == 'left' ? jm.direction.left : jm.direction.right;
  857. }
  858. //logger.debug(node_position +':'+ node_direction);
  859. if (!!parent_id) {
  860. mind.add_node(parent_id, node_id, node_topic, node_data, null, node_direction, node_expanded);
  861. } else {
  862. mind.set_root(node_id, node_topic, node_data);
  863. }
  864. var children = xml_node.childNodes;
  865. var child = null;
  866. for (var i = 0; i < children.length; i++) {
  867. child = children[i];
  868. if (child.nodeType == 1 && child.tagName == 'node') {
  869. df._load_node(mind, node_id, child);
  870. }
  871. }
  872. },
  873. _load_attributes: function(xml_node) {
  874. var children = xml_node.childNodes;
  875. var attr = null;
  876. var attr_data = {};
  877. for (var i = 0; i < children.length; i++) {
  878. attr = children[i];
  879. if (attr.nodeType == 1 && attr.tagName === 'attribute') {
  880. attr_data[attr.getAttribute('NAME')] = attr.getAttribute('VALUE');
  881. }
  882. }
  883. return attr_data;
  884. },
  885. _buildmap: function(node, xmllines) {
  886. var df = jm.format.freemind;
  887. var pos = null;
  888. if (!!node.parent && node.parent.isroot) {
  889. pos = node.direction === jm.direction.left ? 'left' : 'right';
  890. }
  891. xmllines.push('<node');
  892. xmllines.push('ID=\"' + node.id + '\"');
  893. if (!!pos) {
  894. xmllines.push('POSITION=\"' + pos + '\"');
  895. }
  896. xmllines.push('TEXT=\"' + node.topic + '\">');
  897. // store expanded status as an attribute
  898. xmllines.push('<attribute NAME=\"expanded\" VALUE=\"' + node.expanded + '\"/>');
  899. // for attributes
  900. var node_data = node.data;
  901. if (node_data != null) {
  902. for (var k in node_data) {
  903. xmllines.push('<attribute NAME=\"' + k + '\" VALUE=\"' + node_data[k] + '\"/>');
  904. }
  905. }
  906. // for children
  907. var children = node.children;
  908. for (var i = 0; i < children.length; i++) {
  909. df._buildmap(children[i], xmllines);
  910. }
  911. xmllines.push('</node>');
  912. },
  913. },
  914. };
  915. // ============= utility object =============================================
  916. jm.util = {
  917. is_node: function(node) {
  918. return !!node && node instanceof jm.node;
  919. },
  920. ajax: {
  921. _xhr: function() {
  922. var xhr = null;
  923. if (window.XMLHttpRequest) {
  924. xhr = new XMLHttpRequest();
  925. } else {
  926. try {
  927. xhr = new ActiveXObject('Microsoft.XMLHTTP');
  928. } catch (e) {}
  929. }
  930. return xhr;
  931. },
  932. _eurl: function(url) {
  933. return encodeURIComponent(url);
  934. },
  935. request: function(url, param, method, callback, fail_callback) {
  936. var a = jm.util.ajax;
  937. var p = null;
  938. var tmp_param = [];
  939. for (var k in param) {
  940. tmp_param.push(a._eurl(k) + '=' + a._eurl(param[k]));
  941. }
  942. if (tmp_param.length > 0) {
  943. p = tmp_param.join('&');
  944. }
  945. var xhr = a._xhr();
  946. if (!xhr) {
  947. return;
  948. }
  949. xhr.onreadystatechange = function() {
  950. if (xhr.readyState == 4) {
  951. if (xhr.status == 200 || xhr.status == 0) {
  952. if (typeof callback === 'function') {
  953. var data = jm.util.json.string2json(xhr.responseText);
  954. if (data != null) {
  955. callback(data);
  956. } else {
  957. callback(xhr.responseText);
  958. }
  959. }
  960. } else {
  961. if (typeof fail_callback === 'function') {
  962. fail_callback(xhr);
  963. } else {
  964. logger.error('xhr request failed.', xhr);
  965. }
  966. }
  967. }
  968. }
  969. method = method || 'GET';
  970. xhr.open(method, url, true);
  971. xhr.setRequestHeader('If-Modified-Since', '0');
  972. if (method == 'POST') {
  973. xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
  974. xhr.send(p);
  975. } else {
  976. xhr.send();
  977. }
  978. },
  979. get: function(url, callback) {
  980. return jm.util.ajax.request(url, {}, 'GET', callback);
  981. },
  982. post: function(url, param, callback) {
  983. return jm.util.ajax.request(url, param, 'POST', callback);
  984. }
  985. },
  986. dom: {
  987. //target,eventType,handler
  988. add_event: function(t, e, h) {
  989. if (!!t.addEventListener) {
  990. t.addEventListener(e, h, false);
  991. } else {
  992. t.attachEvent('on' + e, h);
  993. }
  994. }
  995. },
  996. canvas: {
  997. bezierto: function(ctx, x1, y1, x2, y2) {
  998. ctx.beginPath();
  999. ctx.moveTo(x1, y1);
  1000. ctx.bezierCurveTo(x1 + (x2 - x1) * 2 / 3, y1, x1, y2, x2, y2);
  1001. ctx.stroke();
  1002. },
  1003. lineto: function(ctx, x1, y1, x2, y2) {
  1004. ctx.beginPath();
  1005. ctx.moveTo(x1, y1);
  1006. ctx.lineTo(x2, y2);
  1007. ctx.stroke();
  1008. },
  1009. clear: function(ctx, x, y, w, h) {
  1010. ctx.clearRect(x, y, w, h);
  1011. }
  1012. },
  1013. file: {
  1014. read: function(file_data, fn_callback) {
  1015. var reader = new FileReader();
  1016. reader.onload = function() {
  1017. if (typeof fn_callback === 'function') {
  1018. fn_callback(this.result, file_data.name);
  1019. }
  1020. };
  1021. reader.readAsText(file_data);
  1022. },
  1023. save: function(file_data, type, name) {
  1024. var blob;
  1025. if (typeof $w.Blob === 'function') {
  1026. blob = new Blob([file_data], {
  1027. type: type
  1028. });
  1029. } else {
  1030. var BlobBuilder = $w.BlobBuilder || $w.MozBlobBuilder || $w.WebKitBlobBuilder || $w.MSBlobBuilder;
  1031. var bb = new BlobBuilder();
  1032. bb.append(file_data);
  1033. blob = bb.getBlob(type);
  1034. }
  1035. if (navigator.msSaveBlob) {
  1036. navigator.msSaveBlob(blob, name);
  1037. } else {
  1038. var URL = $w.URL || $w.webkitURL;
  1039. var bloburl = URL.createObjectURL(blob);
  1040. var anchor = $c('a');
  1041. if ('download' in anchor) {
  1042. anchor.style.visibility = 'hidden';
  1043. anchor.href = bloburl;
  1044. anchor.download = name;
  1045. $d.body.appendChild(anchor);
  1046. var evt = $d.createEvent('MouseEvents');
  1047. evt.initEvent('click', true, true);
  1048. anchor.dispatchEvent(evt);
  1049. $d.body.removeChild(anchor);
  1050. } else {
  1051. location.href = bloburl;
  1052. }
  1053. }
  1054. }
  1055. },
  1056. json: {
  1057. json2string: function(json) {
  1058. if (!!JSON) {
  1059. try {
  1060. var json_str = JSON.stringify(json);
  1061. return json_str;
  1062. } catch (e) {
  1063. logger.warn(e);
  1064. logger.warn('can not convert to string');
  1065. return null;
  1066. }
  1067. }
  1068. },
  1069. string2json: function(json_str) {
  1070. if (!!JSON) {
  1071. try {
  1072. var json = JSON.parse(json_str);
  1073. return json;
  1074. } catch (e) {
  1075. logger.warn(e);
  1076. logger.warn('can not parse to json');
  1077. return null;
  1078. }
  1079. }
  1080. },
  1081. merge: function(b, a) {
  1082. for (var o in a) {
  1083. if (o in b) {
  1084. if (typeof b[o] === 'object' &&
  1085. Object.prototype.toString.call(b[o]).toLowerCase() == '[object object]' &&
  1086. !b[o].length) {
  1087. jm.util.json.merge(b[o], a[o]);
  1088. } else {
  1089. b[o] = a[o];
  1090. }
  1091. } else {
  1092. b[o] = a[o];
  1093. }
  1094. }
  1095. return b;
  1096. }
  1097. },
  1098. uuid: {
  1099. newid: function() {
  1100. return (new Date().getTime().toString(16) + Math.random().toString(16).substr(2)).substr(2, 16);
  1101. }
  1102. },
  1103. text: {
  1104. is_empty: function(s) {
  1105. if (!s) {
  1106. return true;
  1107. }
  1108. return s.replace(/\s*/, '').length == 0;
  1109. }
  1110. }
  1111. };
  1112. jm.prototype = {
  1113. init: function() {
  1114. if (this.inited) {
  1115. return;
  1116. }
  1117. this.inited = true;
  1118. var opts = this.options;
  1119. var opts_layout = {
  1120. mode: opts.mode,
  1121. hspace: opts.layout.hspace,
  1122. vspace: opts.layout.vspace,
  1123. pspace: opts.layout.pspace
  1124. }
  1125. var opts_view = {
  1126. container: opts.container,
  1127. support_html: opts.support_html,
  1128. hmargin: opts.view.hmargin,
  1129. vmargin: opts.view.vmargin,
  1130. line_width: opts.view.line_width,
  1131. line_color: opts.view.line_color
  1132. };
  1133. // create instance of function provider
  1134. this.data = new jm.data_provider(this);
  1135. this.layout = new jm.layout_provider(this, opts_layout);
  1136. this.view = new jm.view_provider(this, opts_view);
  1137. this.shortcut = new jm.shortcut_provider(this, opts.shortcut);
  1138. this.data.init();
  1139. this.layout.init();
  1140. this.view.init();
  1141. this.shortcut.init();
  1142. this._event_bind();
  1143. jm.init_plugins(this);
  1144. },
  1145. enable_edit: function() {
  1146. this.options.editable = true;
  1147. },
  1148. disable_edit: function() {
  1149. this.options.editable = false;
  1150. },
  1151. // call enable_event_handle('dblclick')
  1152. // options are 'mousedown', 'click', 'dblclick'
  1153. enable_event_handle: function(event_handle) {
  1154. this.options.default_event_handle['enable_' + event_handle + '_handle'] = true;
  1155. },
  1156. // call disable_event_handle('dblclick')
  1157. // options are 'mousedown', 'click', 'dblclick'
  1158. disable_event_handle: function(event_handle) {
  1159. this.options.default_event_handle['enable_' + event_handle + '_handle'] = false;
  1160. },
  1161. get_editable: function() {
  1162. return this.options.editable;
  1163. },
  1164. set_theme: function(theme) {
  1165. var theme_old = this.options.theme;
  1166. this.options.theme = (!!theme) ? theme : null;
  1167. if (theme_old != this.options.theme) {
  1168. this.view.reset_theme();
  1169. this.view.reset_custom_style();
  1170. }
  1171. },
  1172. _event_bind: function() {
  1173. this.view.add_event(this, 'mousedown', this.mousedown_handle);
  1174. this.view.add_event(this, 'click', this.click_handle);
  1175. this.view.add_event(this, 'dblclick', this.dblclick_handle);
  1176. },
  1177. mousedown_handle: function(e) {
  1178. if (!this.options.default_event_handle['enable_mousedown_handle']) {
  1179. return;
  1180. }
  1181. var element = e.target || event.srcElement;
  1182. var nodeid = this.view.get_binded_nodeid(element);
  1183. if (!!nodeid) {
  1184. this.select_node(nodeid);
  1185. } else {
  1186. this.select_clear();
  1187. }
  1188. },
  1189. click_handle: function(e) {
  1190. if (!this.options.default_event_handle['enable_click_handle']) {
  1191. return;
  1192. }
  1193. var element = e.target || event.srcElement;
  1194. var isexpander = this.view.is_expander(element);
  1195. if (isexpander) {
  1196. var nodeid = this.view.get_binded_nodeid(element);
  1197. if (!!nodeid) {
  1198. this.toggle_node(nodeid);
  1199. return;
  1200. }
  1201. }
  1202. // 不可编辑下单机触发关联事件
  1203. if (!this.get_editable()) {
  1204. var onRelation = this.options.onRelation;
  1205. if (!onRelation)
  1206. return;
  1207. var nodeid = this.view.get_binded_nodeid(element);
  1208. if (!!nodeid) {
  1209. onRelation(this.mind.selected);
  1210. }
  1211. }
  1212. },
  1213. dblclick_handle: function(e) {
  1214. if (!this.options.default_event_handle['enable_dblclick_handle']) {
  1215. return;
  1216. }
  1217. if (this.get_editable()) {
  1218. var element = e.target || event.srcElement;
  1219. var nodeid = this.view.get_binded_nodeid(element);
  1220. if (!!nodeid) {
  1221. this.begin_edit(nodeid);
  1222. }
  1223. }
  1224. },
  1225. begin_edit: function(node) {
  1226. if (!jm.util.is_node(node)) {
  1227. var the_node = this.get_node(node);
  1228. if (!the_node) {
  1229. logger.error('the node[id=' + node + '] can not be found.');
  1230. return false;
  1231. } else {
  1232. return this.begin_edit(the_node);
  1233. }
  1234. }
  1235. if (this.get_editable()) {
  1236. this.view.edit_node_begin(node);
  1237. } else {
  1238. logger.error('fail, this mind map is not editable.');
  1239. return;
  1240. }
  1241. },
  1242. end_edit: function() {
  1243. this.view.edit_node_end();
  1244. },
  1245. toggle_node: function(node) {
  1246. if (!jm.util.is_node(node)) {
  1247. var the_node = this.get_node(node);
  1248. if (!the_node) {
  1249. logger.error('the node[id=' + node + '] can not be found.');
  1250. return;
  1251. } else {
  1252. return this.toggle_node(the_node);
  1253. }
  1254. }
  1255. if (node.isroot) {
  1256. return;
  1257. }
  1258. this.view.save_location(node);
  1259. this.layout.toggle_node(node);
  1260. this.view.relayout();
  1261. this.view.restore_location(node);
  1262. },
  1263. expand_node: function(node) {
  1264. if (!jm.util.is_node(node)) {
  1265. var the_node = this.get_node(node);
  1266. if (!the_node) {
  1267. logger.error('the node[id=' + node + '] can not be found.');
  1268. return;
  1269. } else {
  1270. return this.expand_node(the_node);
  1271. }
  1272. }
  1273. if (node.isroot) {
  1274. return;
  1275. }
  1276. this.view.save_location(node);
  1277. this.layout.expand_node(node);
  1278. this.view.relayout();
  1279. this.view.restore_location(node);
  1280. },
  1281. collapse_node: function(node) {
  1282. if (!jm.util.is_node(node)) {
  1283. var the_node = this.get_node(node);
  1284. if (!the_node) {
  1285. logger.error('the node[id=' + node + '] can not be found.');
  1286. return;
  1287. } else {
  1288. return this.collapse_node(the_node);
  1289. }
  1290. }
  1291. if (node.isroot) {
  1292. return;
  1293. }
  1294. this.view.save_location(node);
  1295. this.layout.collapse_node(node);
  1296. this.view.relayout();
  1297. this.view.restore_location(node);
  1298. },
  1299. expand_all: function() {
  1300. this.layout.expand_all();
  1301. this.view.relayout();
  1302. },
  1303. collapse_all: function() {
  1304. this.layout.collapse_all();
  1305. this.view.relayout();
  1306. },
  1307. expand_to_depth: function(depth) {
  1308. this.layout.expand_to_depth(depth);
  1309. this.view.relayout();
  1310. },
  1311. _reset: function() {
  1312. this.view.reset();
  1313. this.layout.reset();
  1314. this.data.reset();
  1315. },
  1316. _show: function(mind) {
  1317. var m = mind || jm.format.node_array.example;
  1318. this.mind = this.data.load(m);
  1319. if (!this.mind) {
  1320. logger.error('data.load error');
  1321. return;
  1322. } else {
  1323. logger.debug('data.load ok');
  1324. }
  1325. this.view.load();
  1326. logger.debug('view.load ok');
  1327. this.layout.layout();
  1328. logger.debug('layout.layout ok');
  1329. this.view.show(true);
  1330. logger.debug('view.show ok');
  1331. this.invoke_event_handle(jm.event_type.show, {
  1332. data: [mind]
  1333. });
  1334. },
  1335. show: function(mind) {
  1336. this._reset();
  1337. this._show(mind);
  1338. },
  1339. get_meta: function() {
  1340. return {
  1341. name: this.mind.name,
  1342. author: this.mind.author,
  1343. version: this.mind.version
  1344. };
  1345. },
  1346. get_data: function(data_format) {
  1347. var df = data_format || 'node_tree';
  1348. return this.data.get_data(df);
  1349. },
  1350. get_root: function() {
  1351. return this.mind.root;
  1352. },
  1353. get_node: function(nodeid) {
  1354. return this.mind.get_node(nodeid);
  1355. },
  1356. add_node: function(parent_node, nodeid, topic, data) {
  1357. if (this.get_editable()) {
  1358. var node = this.mind.add_node(parent_node, nodeid, topic, data);
  1359. if (!!node) {
  1360. this.view.add_node(node);
  1361. this.layout.layout();
  1362. this.view.show(false);
  1363. this.view.reset_node_custom_style(node);
  1364. this.expand_node(parent_node);
  1365. this.invoke_event_handle(jm.event_type.edit, {
  1366. evt: 'add_node',
  1367. data: [parent_node.id, nodeid, topic, data],
  1368. node: nodeid
  1369. });
  1370. }
  1371. return node;
  1372. } else {
  1373. logger.error('fail, this mind map is not editable');
  1374. return null;
  1375. }
  1376. },
  1377. insert_node_before: function(node_before, nodeid, topic, data) {
  1378. if (this.get_editable()) {
  1379. var beforeid = jm.util.is_node(node_before) ? node_before.id : node_before;
  1380. var node = this.mind.insert_node_before(node_before, nodeid, topic, data);
  1381. if (!!node) {
  1382. this.view.add_node(node);
  1383. this.layout.layout();
  1384. this.view.show(false);
  1385. this.invoke_event_handle(jm.event_type.edit, {
  1386. evt: 'insert_node_before',
  1387. data: [beforeid, nodeid, topic, data],
  1388. node: nodeid
  1389. });
  1390. }
  1391. return node;
  1392. } else {
  1393. logger.error('fail, this mind map is not editable');
  1394. return null;
  1395. }
  1396. },
  1397. insert_node_after: function(node_after, nodeid, topic, data) {
  1398. if (this.get_editable()) {
  1399. var afterid = jm.util.is_node(node_after) ? node_after.id : node_after;
  1400. var node = this.mind.insert_node_after(node_after, nodeid, topic, data);
  1401. if (!!node) {
  1402. this.view.add_node(node);
  1403. this.layout.layout();
  1404. this.view.show(false);
  1405. this.invoke_event_handle(jm.event_type.edit, {
  1406. evt: 'insert_node_after',
  1407. data: [afterid, nodeid, topic, data],
  1408. node: nodeid
  1409. });
  1410. }
  1411. return node;
  1412. } else {
  1413. logger.error('fail, this mind map is not editable');
  1414. return null;
  1415. }
  1416. },
  1417. remove_node: function(node) {
  1418. if (!jm.util.is_node(node)) {
  1419. var the_node = this.get_node(node);
  1420. if (!the_node) {
  1421. logger.error('the node[id=' + node + '] can not be found.');
  1422. return false;
  1423. } else {
  1424. return this.remove_node(the_node);
  1425. }
  1426. }
  1427. if (this.get_editable()) {
  1428. if (node.isroot) {
  1429. logger.error('fail, can not remove root node');
  1430. return false;
  1431. }
  1432. var nodeid = node.id;
  1433. var parentid = node.parent.id;
  1434. var parent_node = this.get_node(parentid);
  1435. this.view.save_location(parent_node);
  1436. this.view.remove_node(node);
  1437. this.mind.remove_node(node);
  1438. this.layout.layout();
  1439. this.view.show(false);
  1440. this.view.restore_location(parent_node);
  1441. this.invoke_event_handle(jm.event_type.edit, {
  1442. evt: 'remove_node',
  1443. data: [nodeid],
  1444. node: parentid
  1445. });
  1446. return true;
  1447. } else {
  1448. logger.error('fail, this mind map is not editable');
  1449. return false;
  1450. }
  1451. },
  1452. update_node: function(nodeid, topic) {
  1453. if (this.get_editable()) {
  1454. if (jm.util.text.is_empty(topic)) {
  1455. logger.warn('fail, topic can not be empty');
  1456. return;
  1457. }
  1458. var node = this.get_node(nodeid);
  1459. if (!!node) {
  1460. if (node.topic === topic) {
  1461. logger.info('nothing changed');
  1462. this.view.update_node(node);
  1463. return;
  1464. }
  1465. node.topic = topic;
  1466. this.view.update_node(node);
  1467. this.layout.layout();
  1468. this.view.show(false);
  1469. this.invoke_event_handle(jm.event_type.edit, {
  1470. evt: 'update_node',
  1471. data: [nodeid, topic],
  1472. node: nodeid
  1473. });
  1474. }
  1475. } else {
  1476. logger.error('fail, this mind map is not editable');
  1477. return;
  1478. }
  1479. },
  1480. move_node: function(nodeid, beforeid, parentid, direction) {
  1481. if (this.get_editable()) {
  1482. var node = this.mind.move_node(nodeid, beforeid, parentid, direction);
  1483. if (!!node) {
  1484. this.view.update_node(node);
  1485. this.layout.layout();
  1486. this.view.show(false);
  1487. this.invoke_event_handle(jm.event_type.edit, {
  1488. evt: 'move_node',
  1489. data: [nodeid, beforeid, parentid, direction],
  1490. node: nodeid
  1491. });
  1492. }
  1493. } else {
  1494. logger.error('fail, this mind map is not editable');
  1495. return;
  1496. }
  1497. },
  1498. select_node: function(node) {
  1499. if (!jm.util.is_node(node)) {
  1500. var the_node = this.get_node(node);
  1501. if (!the_node) {
  1502. logger.error('the node[id=' + node + '] can not be found.');
  1503. return;
  1504. } else {
  1505. return this.select_node(the_node);
  1506. }
  1507. }
  1508. if (!this.layout.is_visible(node)) {
  1509. return;
  1510. }
  1511. this.mind.selected = node;
  1512. this.view.select_node(node);
  1513. },
  1514. get_selected_node: function() {
  1515. if (!!this.mind) {
  1516. return this.mind.selected;
  1517. } else {
  1518. return null;
  1519. }
  1520. },
  1521. select_clear: function() {
  1522. if (!!this.mind) {
  1523. this.mind.selected = null;
  1524. this.view.select_clear();
  1525. }
  1526. },
  1527. is_node_visible: function(node) {
  1528. return this.layout.is_visible(node);
  1529. },
  1530. find_node_before: function(node) {
  1531. if (!jm.util.is_node(node)) {
  1532. var the_node = this.get_node(node);
  1533. if (!the_node) {
  1534. logger.error('the node[id=' + node + '] can not be found.');
  1535. return;
  1536. } else {
  1537. return this.find_node_before(the_node);
  1538. }
  1539. }
  1540. if (node.isroot) {
  1541. return null;
  1542. }
  1543. var n = null;
  1544. if (node.parent.isroot) {
  1545. var c = node.parent.children;
  1546. var prev = null;
  1547. var ni = null;
  1548. for (var i = 0; i < c.length; i++) {
  1549. ni = c[i];
  1550. if (node.direction === ni.direction) {
  1551. if (node.id === ni.id) {
  1552. n = prev;
  1553. }
  1554. prev = ni;
  1555. }
  1556. }
  1557. } else {
  1558. n = this.mind.get_node_before(node);
  1559. }
  1560. return n;
  1561. },
  1562. find_node_after: function(node) {
  1563. if (!jm.util.is_node(node)) {
  1564. var the_node = this.get_node(node);
  1565. if (!the_node) {
  1566. logger.error('the node[id=' + node + '] can not be found.');
  1567. return;
  1568. } else {
  1569. return this.find_node_after(the_node);
  1570. }
  1571. }
  1572. if (node.isroot) {
  1573. return null;
  1574. }
  1575. var n = null;
  1576. if (node.parent.isroot) {
  1577. var c = node.parent.children;
  1578. var getthis = false;
  1579. var ni = null;
  1580. for (var i = 0; i < c.length; i++) {
  1581. ni = c[i];
  1582. if (node.direction === ni.direction) {
  1583. if (getthis) {
  1584. n = ni;
  1585. break;
  1586. }
  1587. if (node.id === ni.id) {
  1588. getthis = true;
  1589. }
  1590. }
  1591. }
  1592. } else {
  1593. n = this.mind.get_node_after(node);
  1594. }
  1595. return n;
  1596. },
  1597. set_node_color: function(nodeid, bgcolor, fgcolor) {
  1598. if (this.get_editable()) {
  1599. var node = this.mind.get_node(nodeid);
  1600. if (!!node) {
  1601. if (!!bgcolor) {
  1602. node.data['background-color'] = bgcolor;
  1603. }
  1604. if (!!fgcolor) {
  1605. node.data['foreground-color'] = fgcolor;
  1606. }
  1607. this.view.reset_node_custom_style(node);
  1608. }
  1609. } else {
  1610. logger.error('fail, this mind map is not editable');
  1611. return null;
  1612. }
  1613. },
  1614. set_node_font_style: function(nodeid, size, weight, style) {
  1615. if (this.get_editable()) {
  1616. var node = this.mind.get_node(nodeid);
  1617. if (!!node) {
  1618. if (!!size) {
  1619. node.data['font-size'] = size;
  1620. }
  1621. if (!!weight) {
  1622. node.data['font-weight'] = weight;
  1623. }
  1624. if (!!style) {
  1625. node.data['font-style'] = style;
  1626. }
  1627. this.view.reset_node_custom_style(node);
  1628. this.view.update_node(node);
  1629. this.layout.layout();
  1630. this.view.show(false);
  1631. }
  1632. } else {
  1633. logger.error('fail, this mind map is not editable');
  1634. return null;
  1635. }
  1636. },
  1637. set_node_background_image: function(nodeid, image, width, height, rotation) {
  1638. if (this.get_editable()) {
  1639. var node = this.mind.get_node(nodeid);
  1640. if (!!node) {
  1641. if (!!image) {
  1642. node.data['background-image'] = image;
  1643. }
  1644. if (!!width) {
  1645. node.data['width'] = width;
  1646. }
  1647. if (!!height) {
  1648. node.data['height'] = height;
  1649. }
  1650. if (!!rotation) {
  1651. node.data['background-rotation'] = rotation;
  1652. }
  1653. this.view.reset_node_custom_style(node);
  1654. this.view.update_node(node);
  1655. this.layout.layout();
  1656. this.view.show(false);
  1657. }
  1658. } else {
  1659. logger.error('fail, this mind map is not editable');
  1660. return null;
  1661. }
  1662. },
  1663. set_node_background_rotation: function(nodeid, rotation) {
  1664. if (this.get_editable()) {
  1665. var node = this.mind.get_node(nodeid);
  1666. if (!!node) {
  1667. if (!node.data['background-image']) {
  1668. logger.error('fail, only can change rotation angle of node with background image');
  1669. return null;
  1670. }
  1671. node.data['background-rotation'] = rotation;
  1672. this.view.reset_node_custom_style(node);
  1673. this.view.update_node(node);
  1674. this.layout.layout();
  1675. this.view.show(false);
  1676. }
  1677. } else {
  1678. logger.error('fail, this mind map is not editable');
  1679. return null;
  1680. }
  1681. },
  1682. resize: function() {
  1683. this.view.resize();
  1684. },
  1685. // callback(type ,data)
  1686. add_event_listener: function(callback) {
  1687. if (typeof callback === 'function') {
  1688. this.event_handles.push(callback);
  1689. }
  1690. },
  1691. invoke_event_handle: function(type, data) {
  1692. var j = this;
  1693. $w.setTimeout(function() {
  1694. j._invoke_event_handle(type, data);
  1695. }, 0);
  1696. },
  1697. _invoke_event_handle: function(type, data) {
  1698. var l = this.event_handles.length;
  1699. for (var i = 0; i < l; i++) {
  1700. this.event_handles[i](type, data);
  1701. }
  1702. }
  1703. };
  1704. // ============= data provider =============================================
  1705. jm.data_provider = function(jm) {
  1706. this.jm = jm;
  1707. };
  1708. jm.data_provider.prototype = {
  1709. init: function() {
  1710. logger.debug('data.init');
  1711. },
  1712. reset: function() {
  1713. logger.debug('data.reset');
  1714. },
  1715. load: function(mind_data) {
  1716. var df = null;
  1717. var mind = null;
  1718. if (typeof mind_data === 'object') {
  1719. if (!!mind_data.format) {
  1720. df = mind_data.format;
  1721. } else {
  1722. df = 'node_tree';
  1723. }
  1724. } else {
  1725. df = 'freemind';
  1726. }
  1727. if (df == 'node_array') {
  1728. mind = jm.format.node_array.get_mind(mind_data);
  1729. } else if (df == 'node_tree') {
  1730. mind = jm.format.node_tree.get_mind(mind_data);
  1731. } else if (df == 'freemind') {
  1732. mind = jm.format.freemind.get_mind(mind_data);
  1733. } else {
  1734. logger.warn('unsupported format');
  1735. }
  1736. return mind;
  1737. },
  1738. get_data: function(data_format) {
  1739. var data = null;
  1740. if (data_format == 'node_array') {
  1741. data = jm.format.node_array.get_data(this.jm.mind);
  1742. } else if (data_format == 'node_tree') {
  1743. data = jm.format.node_tree.get_data(this.jm.mind);
  1744. } else if (data_format == 'freemind') {
  1745. data = jm.format.freemind.get_data(this.jm.mind);
  1746. } else {
  1747. logger.error('unsupported ' + data_format + ' format');
  1748. }
  1749. return data;
  1750. },
  1751. };
  1752. // ============= layout provider ===========================================
  1753. jm.layout_provider = function(jm, options) {
  1754. this.opts = options;
  1755. this.jm = jm;
  1756. this.isside = (this.opts.mode == 'side');
  1757. this.bounds = null;
  1758. this.cache_valid = false;
  1759. };
  1760. jm.layout_provider.prototype = {
  1761. init: function() {
  1762. logger.debug('layout.init');
  1763. },
  1764. reset: function() {
  1765. logger.debug('layout.reset');
  1766. this.bounds = {
  1767. n: 0,
  1768. s: 0,
  1769. w: 0,
  1770. e: 0
  1771. };
  1772. },
  1773. layout: function() {
  1774. logger.debug('layout.layout');
  1775. this.layout_direction();
  1776. this.layout_offset();
  1777. },
  1778. layout_direction: function() {
  1779. this._layout_direction_root();
  1780. },
  1781. _layout_direction_root: function() {
  1782. var node = this.jm.mind.root;
  1783. // logger.debug(node);
  1784. var layout_data = null;
  1785. if ('layout' in node._data) {
  1786. layout_data = node._data.layout;
  1787. } else {
  1788. layout_data = {};
  1789. node._data.layout = layout_data;
  1790. }
  1791. var children = node.children;
  1792. var children_count = children.length;
  1793. layout_data.direction = jm.direction.center;
  1794. layout_data.side_index = 0;
  1795. if (this.isside) {
  1796. var i = children_count;
  1797. while (i--) {
  1798. this._layout_direction_side(children[i], jm.direction.right, i);
  1799. }
  1800. } else {
  1801. var i = children_count;
  1802. var subnode = null;
  1803. while (i--) {
  1804. subnode = children[i];
  1805. if (subnode.direction == jm.direction.left) {
  1806. this._layout_direction_side(subnode, jm.direction.left, i);
  1807. } else {
  1808. this._layout_direction_side(subnode, jm.direction.right, i);
  1809. }
  1810. }
  1811. /*
  1812. var boundary = Math.ceil(children_count/2);
  1813. var i = children_count;
  1814. while(i--){
  1815. if(i>=boundary){
  1816. this._layout_direction_side(children[i],jm.direction.left, children_count-i-1);
  1817. }else{
  1818. this._layout_direction_side(children[i],jm.direction.right, i);
  1819. }
  1820. }*/
  1821. }
  1822. },
  1823. _layout_direction_side: function(node, direction, side_index) {
  1824. var layout_data = null;
  1825. if ('layout' in node._data) {
  1826. layout_data = node._data.layout;
  1827. } else {
  1828. layout_data = {};
  1829. node._data.layout = layout_data;
  1830. }
  1831. var children = node.children;
  1832. var children_count = children.length;
  1833. layout_data.direction = direction;
  1834. layout_data.side_index = side_index;
  1835. var i = children_count;
  1836. while (i--) {
  1837. this._layout_direction_side(children[i], direction, i);
  1838. }
  1839. },
  1840. layout_offset: function() {
  1841. var node = this.jm.mind.root;
  1842. var layout_data = node._data.layout;
  1843. layout_data.offset_x = 0;
  1844. layout_data.offset_y = 0;
  1845. layout_data.outer_height = 0;
  1846. var children = node.children;
  1847. var i = children.length;
  1848. var left_nodes = [];
  1849. var right_nodes = [];
  1850. var subnode = null;
  1851. while (i--) {
  1852. subnode = children[i];
  1853. if (subnode._data.layout.direction == jm.direction.right) {
  1854. right_nodes.unshift(subnode);
  1855. } else {
  1856. left_nodes.unshift(subnode);
  1857. }
  1858. }
  1859. layout_data.left_nodes = left_nodes;
  1860. layout_data.right_nodes = right_nodes;
  1861. layout_data.outer_height_left = this._layout_offset_subnodes(left_nodes);
  1862. layout_data.outer_height_right = this._layout_offset_subnodes(right_nodes);
  1863. this.bounds.e = node._data.view.width / 2;
  1864. this.bounds.w = 0 - this.bounds.e;
  1865. //logger.debug(this.bounds.w);
  1866. this.bounds.n = 0;
  1867. this.bounds.s = Math.max(layout_data.outer_height_left, layout_data.outer_height_right);
  1868. },
  1869. // layout both the x and y axis
  1870. _layout_offset_subnodes: function(nodes) {
  1871. var total_height = 0;
  1872. var nodes_count = nodes.length;
  1873. var i = nodes_count;
  1874. var node = null;
  1875. var node_outer_height = 0;
  1876. var layout_data = null;
  1877. var base_y = 0;
  1878. var pd = null; // parent._data
  1879. while (i--) {
  1880. node = nodes[i];
  1881. layout_data = node._data.layout;
  1882. if (pd == null) {
  1883. pd = node.parent._data;
  1884. }
  1885. node_outer_height = this._layout_offset_subnodes(node.children);
  1886. if (!node.expanded) {
  1887. node_outer_height = 0;
  1888. this.set_visible(node.children, false);
  1889. }
  1890. node_outer_height = Math.max(node._data.view.height, node_outer_height);
  1891. layout_data.outer_height = node_outer_height;
  1892. layout_data.offset_y = base_y - node_outer_height / 2;
  1893. layout_data.offset_x = this.opts.hspace * layout_data.direction + pd.view.width * (pd.layout.direction + layout_data.direction) / 2;
  1894. if (!node.parent.isroot) {
  1895. layout_data.offset_x += this.opts.pspace * layout_data.direction;
  1896. }
  1897. base_y = base_y - node_outer_height - this.opts.vspace;
  1898. total_height += node_outer_height;
  1899. }
  1900. if (nodes_count > 1) {
  1901. total_height += this.opts.vspace * (nodes_count - 1);
  1902. }
  1903. i = nodes_count;
  1904. var middle_height = total_height / 2;
  1905. while (i--) {
  1906. node = nodes[i];
  1907. node._data.layout.offset_y += middle_height;
  1908. }
  1909. return total_height;
  1910. },
  1911. // layout the y axis only, for collapse/expand a node
  1912. _layout_offset_subnodes_height: function(nodes) {
  1913. var total_height = 0;
  1914. var nodes_count = nodes.length;
  1915. var i = nodes_count;
  1916. var node = null;
  1917. var node_outer_height = 0;
  1918. var layout_data = null;
  1919. var base_y = 0;
  1920. var pd = null; // parent._data
  1921. while (i--) {
  1922. node = nodes[i];
  1923. layout_data = node._data.layout;
  1924. if (pd == null) {
  1925. pd = node.parent._data;
  1926. }
  1927. node_outer_height = this._layout_offset_subnodes_height(node.children);
  1928. if (!node.expanded) {
  1929. node_outer_height = 0;
  1930. }
  1931. node_outer_height = Math.max(node._data.view.height, node_outer_height);
  1932. layout_data.outer_height = node_outer_height;
  1933. layout_data.offset_y = base_y - node_outer_height / 2;
  1934. base_y = base_y - node_outer_height - this.opts.vspace;
  1935. total_height += node_outer_height;
  1936. }
  1937. if (nodes_count > 1) {
  1938. total_height += this.opts.vspace * (nodes_count - 1);
  1939. }
  1940. i = nodes_count;
  1941. var middle_height = total_height / 2;
  1942. while (i--) {
  1943. node = nodes[i];
  1944. node._data.layout.offset_y += middle_height;
  1945. //logger.debug(node.topic);
  1946. //logger.debug(node._data.layout.offset_y);
  1947. }
  1948. return total_height;
  1949. },
  1950. get_node_offset: function(node) {
  1951. var layout_data = node._data.layout;
  1952. var offset_cache = null;
  1953. if (('_offset_' in layout_data) && this.cache_valid) {
  1954. offset_cache = layout_data._offset_;
  1955. } else {
  1956. offset_cache = {
  1957. x: -1,
  1958. y: -1
  1959. };
  1960. layout_data._offset_ = offset_cache;
  1961. }
  1962. if (offset_cache.x == -1 || offset_cache.y == -1) {
  1963. var x = layout_data.offset_x;
  1964. var y = layout_data.offset_y;
  1965. if (!node.isroot) {
  1966. var offset_p = this.get_node_offset(node.parent);
  1967. x += offset_p.x;
  1968. y += offset_p.y;
  1969. }
  1970. offset_cache.x = x;
  1971. offset_cache.y = y;
  1972. }
  1973. return offset_cache;
  1974. },
  1975. get_node_point: function(node) {
  1976. var view_data = node._data.view;
  1977. var offset_p = this.get_node_offset(node);
  1978. //logger.debug(offset_p);
  1979. var p = {};
  1980. p.x = offset_p.x + view_data.width * (node._data.layout.direction - 1) / 2;
  1981. p.y = offset_p.y - view_data.height / 2;
  1982. //logger.debug(p);
  1983. return p;
  1984. },
  1985. get_node_point_in: function(node) {
  1986. var p = this.get_node_offset(node);
  1987. return p;
  1988. },
  1989. get_node_point_out: function(node) {
  1990. var layout_data = node._data.layout;
  1991. var pout_cache = null;
  1992. if (('_pout_' in layout_data) && this.cache_valid) {
  1993. pout_cache = layout_data._pout_;
  1994. } else {
  1995. pout_cache = {
  1996. x: -1,
  1997. y: -1
  1998. };
  1999. layout_data._pout_ = pout_cache;
  2000. }
  2001. if (pout_cache.x == -1 || pout_cache.y == -1) {
  2002. if (node.isroot) {
  2003. pout_cache.x = 0;
  2004. pout_cache.y = 0;
  2005. } else {
  2006. var view_data = node._data.view;
  2007. var offset_p = this.get_node_offset(node);
  2008. pout_cache.x = offset_p.x + (view_data.width + this.opts.pspace) * node._data.layout.direction;
  2009. pout_cache.y = offset_p.y;
  2010. //logger.debug('pout');
  2011. //logger.debug(pout_cache);
  2012. }
  2013. }
  2014. return pout_cache;
  2015. },
  2016. get_expander_point: function(node) {
  2017. var p = this.get_node_point_out(node);
  2018. var ex_p = {};
  2019. if (node._data.layout.direction == jm.direction.right) {
  2020. ex_p.x = p.x - this.opts.pspace;
  2021. } else {
  2022. ex_p.x = p.x;
  2023. }
  2024. ex_p.y = p.y - Math.ceil(this.opts.pspace / 2);
  2025. return ex_p;
  2026. },
  2027. get_min_size: function() {
  2028. var nodes = this.jm.mind.nodes;
  2029. var node = null;
  2030. var pout = null;
  2031. for (var nodeid in nodes) {
  2032. node = nodes[nodeid];
  2033. if (node.parent && !node.parent.expanded) {
  2034. continue;
  2035. }
  2036. pout = this.get_node_point_out(node);
  2037. //logger.debug(pout.x);
  2038. if (pout.x > this.bounds.e) {
  2039. this.bounds.e = pout.x;
  2040. }
  2041. if (pout.x < this.bounds.w) {
  2042. this.bounds.w = pout.x;
  2043. }
  2044. }
  2045. return {
  2046. w: this.bounds.e - this.bounds.w,
  2047. h: this.bounds.s - this.bounds.n
  2048. }
  2049. },
  2050. toggle_node: function(node) {
  2051. if (node.isroot) {
  2052. return;
  2053. }
  2054. if (node.expanded) {
  2055. this.collapse_node(node);
  2056. } else {
  2057. this.expand_node(node);
  2058. }
  2059. },
  2060. // 展开节点
  2061. expand_node: function(node) {
  2062. node.expanded = true;
  2063. this.part_layout(node);
  2064. this.set_visible(node.children, true);
  2065. this.toggleBadge(node.children, true);
  2066. },
  2067. // 收叠节点
  2068. collapse_node: function(node) {
  2069. node.expanded = false;
  2070. this.part_layout(node);
  2071. this.set_visible(node.children, false);
  2072. this.toggleBadge(node.children, false);
  2073. },
  2074. // 隐藏/显示 badger
  2075. // true: 显示
  2076. // false: 隐藏
  2077. toggleBadge: function(nodes, isShow) {
  2078. // console.log(isShow === true ? '显示' : '隐藏', nodes)
  2079. var that = this;
  2080. nodes.forEach(function(e) {
  2081. // var visible = e._data.layout.visible
  2082. var visible = that.jm.is_node_visible(e);
  2083. // console.log('visible', visible)
  2084. if (visible === true) return true;
  2085. // 多层级显示隐藏
  2086. that.toggleBadge(e.children, isShow);
  2087. var $ele = $('div.leo-badge[nodeid$="' + e.id + '"]');
  2088. if (isShow === true) {
  2089. $ele.show();
  2090. } else {
  2091. $ele.hide();
  2092. }
  2093. });
  2094. },
  2095. expand_all: function() {
  2096. var nodes = this.jm.mind.nodes;
  2097. var c = 0;
  2098. var node;
  2099. for (var nodeid in nodes) {
  2100. node = nodes[nodeid];
  2101. if (!node.expanded) {
  2102. node.expanded = true;
  2103. c++;
  2104. }
  2105. }
  2106. if (c > 0) {
  2107. var root = this.jm.mind.root;
  2108. this.part_layout(root);
  2109. this.set_visible(root.children, true);
  2110. }
  2111. },
  2112. collapse_all: function() {
  2113. var nodes = this.jm.mind.nodes;
  2114. var c = 0;
  2115. var node;
  2116. for (var nodeid in nodes) {
  2117. node = nodes[nodeid];
  2118. if (node.expanded && !node.isroot) {
  2119. node.expanded = false
  2120. c++;
  2121. }
  2122. }
  2123. if (c > 0) {
  2124. var root = this.jm.mind.root;
  2125. this.part_layout(root);
  2126. this.set_visible(root.children, true);
  2127. }
  2128. },
  2129. expand_to_depth: function(target_depth, curr_nodes, curr_depth) {
  2130. if (target_depth < 1) {
  2131. return;
  2132. }
  2133. var nodes = curr_nodes || this.jm.mind.root.children;
  2134. var depth = curr_depth || 1;
  2135. var i = nodes.length;
  2136. var node = null;
  2137. while (i--) {
  2138. node = nodes[i];
  2139. if (depth < target_depth) {
  2140. if (!node.expanded) {
  2141. this.expand_node(node);
  2142. }
  2143. this.expand_to_depth(target_depth, node.children, depth + 1);
  2144. }
  2145. if (depth == target_depth) {
  2146. if (node.expanded) {
  2147. this.collapse_node(node);
  2148. }
  2149. }
  2150. }
  2151. },
  2152. part_layout: function(node) {
  2153. var root = this.jm.mind.root;
  2154. if (!!root) {
  2155. var root_layout_data = root._data.layout;
  2156. if (node.isroot) {
  2157. root_layout_data.outer_height_right = this._layout_offset_subnodes_height(root_layout_data.right_nodes);
  2158. root_layout_data.outer_height_left = this._layout_offset_subnodes_height(root_layout_data.left_nodes);
  2159. } else {
  2160. if (node._data.layout.direction == jm.direction.right) {
  2161. root_layout_data.outer_height_right = this._layout_offset_subnodes_height(root_layout_data.right_nodes);
  2162. } else {
  2163. root_layout_data.outer_height_left = this._layout_offset_subnodes_height(root_layout_data.left_nodes);
  2164. }
  2165. }
  2166. this.bounds.s = Math.max(root_layout_data.outer_height_left, root_layout_data.outer_height_right);
  2167. this.cache_valid = false;
  2168. } else {
  2169. logger.warn('can not found root node');
  2170. }
  2171. },
  2172. set_visible: function(nodes, visible) {
  2173. var i = nodes.length;
  2174. var node = null;
  2175. var layout_data = null;
  2176. while (i--) {
  2177. node = nodes[i];
  2178. layout_data = node._data.layout;
  2179. if (node.expanded) {
  2180. this.set_visible(node.children, visible);
  2181. } else {
  2182. this.set_visible(node.children, false);
  2183. }
  2184. if (!node.isroot) {
  2185. node._data.layout.visible = visible;
  2186. }
  2187. }
  2188. },
  2189. is_expand: function(node) {
  2190. return node.expanded;
  2191. },
  2192. is_visible: function(node) {
  2193. var layout_data = node._data.layout;
  2194. if (('visible' in layout_data) && !layout_data.visible) {
  2195. return false;
  2196. } else {
  2197. return true;
  2198. }
  2199. },
  2200. };
  2201. // view provider
  2202. jm.view_provider = function(jm, options) {
  2203. this.opts = options;
  2204. this.jm = jm;
  2205. this.layout = jm.layout;
  2206. this.container = null;
  2207. this.e_panel = null;
  2208. this.e_nodes = null;
  2209. this.e_canvas = null;
  2210. this.canvas_ctx = null;
  2211. this.size = {
  2212. w: 0,
  2213. h: 0
  2214. };
  2215. this.selected_node = null;
  2216. this.editing_node = null;
  2217. };
  2218. jm.view_provider.prototype = {
  2219. init: function() {
  2220. logger.debug('view.init');
  2221. this.container = $i(this.opts.container) ? this.opts.container : $g(this.opts.container);
  2222. if (!this.container) {
  2223. logger.error('the options.view.container was not be found in dom');
  2224. return;
  2225. }
  2226. this.e_panel = $c('div');
  2227. this.e_canvas = $c('canvas');
  2228. this.e_nodes = $c('jmnodes');
  2229. this.e_editor = $c('input');
  2230. this.e_panel.className = 'jsmind-inner';
  2231. this.e_panel.appendChild(this.e_canvas);
  2232. this.e_panel.appendChild(this.e_nodes);
  2233. this.e_editor.className = 'jsmind-editor';
  2234. this.e_editor.type = 'text';
  2235. this.actualZoom = 1;
  2236. this.zoomStep = 0.1;
  2237. this.minZoom = 0.5;
  2238. this.maxZoom = 2;
  2239. var v = this;
  2240. jm.util.dom.add_event(this.e_editor, 'keydown', function(e) {
  2241. var evt = e || event;
  2242. if (evt.keyCode == 13) {
  2243. v.edit_node_end();
  2244. evt.stopPropagation();
  2245. }
  2246. });
  2247. jm.util.dom.add_event(this.e_editor, 'blur', function(e) {
  2248. v.edit_node_end();
  2249. });
  2250. this.container.appendChild(this.e_panel);
  2251. this.init_canvas();
  2252. },
  2253. add_event: function(obj, event_name, event_handle) {
  2254. jm.util.dom.add_event(this.e_nodes, event_name, function(e) {
  2255. var evt = e || event;
  2256. event_handle.call(obj, evt);
  2257. });
  2258. },
  2259. get_binded_nodeid: function(element) {
  2260. if (element == null) {
  2261. return null;
  2262. }
  2263. var tagName = element.tagName.toLowerCase();
  2264. if (tagName == 'jmnodes' || tagName == 'body' || tagName == 'html') {
  2265. return null;
  2266. }
  2267. if (tagName == 'jmnode' || tagName == 'jmexpander') {
  2268. return element.getAttribute('nodeid');
  2269. } else {
  2270. return this.get_binded_nodeid(element.parentElement);
  2271. }
  2272. },
  2273. is_expander: function(element) {
  2274. return (element.tagName.toLowerCase() == 'jmexpander');
  2275. },
  2276. reset: function() {
  2277. logger.debug('view.reset');
  2278. this.selected_node = null;
  2279. this.clear_lines();
  2280. this.clear_nodes();
  2281. this.reset_theme();
  2282. },
  2283. reset_theme: function() {
  2284. var theme_name = this.jm.options.theme;
  2285. if (!!theme_name) {
  2286. this.e_nodes.className = 'theme-' + theme_name;
  2287. } else {
  2288. this.e_nodes.className = '';
  2289. }
  2290. },
  2291. reset_custom_style: function() {
  2292. var nodes = this.jm.mind.nodes;
  2293. for (var nodeid in nodes) {
  2294. this.reset_node_custom_style(nodes[nodeid]);
  2295. }
  2296. },
  2297. load: function() {
  2298. logger.debug('view.load');
  2299. this.init_nodes();
  2300. },
  2301. expand_size: function() {
  2302. var min_size = this.layout.get_min_size();
  2303. var min_width = min_size.w + this.opts.hmargin * 2;
  2304. var min_height = min_size.h + this.opts.vmargin * 2;
  2305. var client_w = this.e_panel.clientWidth;
  2306. var client_h = this.e_panel.clientHeight;
  2307. if (client_w < min_width) {
  2308. client_w = min_width;
  2309. }
  2310. if (client_h < min_height) {
  2311. client_h = min_height;
  2312. }
  2313. this.size.w = client_w;
  2314. this.size.h = client_h;
  2315. },
  2316. init_canvas: function() {
  2317. var ctx = this.e_canvas.getContext('2d');
  2318. this.canvas_ctx = ctx;
  2319. },
  2320. init_nodes_size: function(node) {
  2321. var view_data = node._data.view;
  2322. view_data.width = view_data.element.clientWidth;
  2323. view_data.height = view_data.element.clientHeight;
  2324. },
  2325. init_nodes: function() {
  2326. var nodes = this.jm.mind.nodes;
  2327. var doc_frag = $d.createDocumentFragment();
  2328. for (var nodeid in nodes) {
  2329. this.create_node_element(nodes[nodeid], doc_frag);
  2330. }
  2331. this.e_nodes.appendChild(doc_frag);
  2332. for (var nodeid in nodes) {
  2333. this.init_nodes_size(nodes[nodeid]);
  2334. }
  2335. },
  2336. add_node: function(node) {
  2337. this.create_node_element(node, this.e_nodes);
  2338. this.init_nodes_size(node);
  2339. },
  2340. create_node_element: function(node, parent_node) {
  2341. var view_data = null;
  2342. if ('view' in node._data) {
  2343. view_data = node._data.view;
  2344. } else {
  2345. view_data = {};
  2346. node._data.view = view_data;
  2347. }
  2348. var d = $c('jmnode');
  2349. if (node.isroot) {
  2350. d.className = 'root';
  2351. } else {
  2352. var d_e = $c('jmexpander'); // 右侧的小东西
  2353. $t(d_e, '-');
  2354. d_e.setAttribute('nodeid', node.id);
  2355. d_e.style.visibility = 'hidden';
  2356. parent_node.appendChild(d_e);
  2357. view_data.expander = d_e;
  2358. }
  2359. if (!!node.topic) {
  2360. if (this.opts.support_html) {
  2361. $h(d, node.topic);
  2362. } else {
  2363. $t(d, node.topic);
  2364. }
  2365. }
  2366. // 创建右上角的小图标 雕漆里
  2367. var badge = $c('div');
  2368. badge.className = 'leo-badge'
  2369. parent_node.appendChild(badge);
  2370. $t(badge, node._data.badge)
  2371. badge.setAttribute('nodeid', node.id);
  2372. badge.style.visibility = 'hidden';
  2373. view_data.badge = badge;
  2374. d.setAttribute('nodeid', node.id);
  2375. d.style.visibility = 'hidden';
  2376. // 设置node节点的链接图标
  2377. if (node.data.isLink === true) {
  2378. $(d).addClass('isLink')
  2379. } else {
  2380. $(d).removeClass('isLink')
  2381. }
  2382. this._reset_node_custom_style(d, node.data);
  2383. parent_node.appendChild(d);
  2384. view_data.element = d;
  2385. },
  2386. remove_node: function(node) {
  2387. if (this.selected_node != null && this.selected_node.id == node.id) {
  2388. this.selected_node = null;
  2389. }
  2390. if (this.editing_node != null && this.editing_node.id == node.id) {
  2391. node._data.view.element.removeChild(this.e_editor);
  2392. this.editing_node = null;
  2393. }
  2394. var children = node.children;
  2395. var i = children.length;
  2396. while (i--) {
  2397. this.remove_node(children[i]);
  2398. }
  2399. if (node._data.view) {
  2400. var element = node._data.view.element;
  2401. var expander = node._data.view.expander;
  2402. this.e_nodes.removeChild(element);
  2403. this.e_nodes.removeChild(expander);
  2404. node._data.view.element = null;
  2405. node._data.view.expander = null;
  2406. }
  2407. },
  2408. update_node: function(node) {
  2409. var view_data = node._data.view;
  2410. var element = view_data.element;
  2411. if (!!node.topic) {
  2412. if (this.opts.support_html) {
  2413. $h(element, node.topic);
  2414. } else {
  2415. $t(element, node.topic);
  2416. }
  2417. }
  2418. view_data.width = element.clientWidth;
  2419. view_data.height = element.clientHeight;
  2420. },
  2421. select_node: function(node) {
  2422. if (!!this.selected_node) {
  2423. this.selected_node._data.view.element.className =
  2424. this.selected_node._data.view.element.className.replace(/\s*selected\b/i, '');
  2425. this.reset_node_custom_style(this.selected_node);
  2426. }
  2427. if (!!node) {
  2428. this.selected_node = node;
  2429. node._data.view.element.className += ' selected';
  2430. this.clear_node_custom_style(node);
  2431. }
  2432. },
  2433. select_clear: function() {
  2434. this.select_node(null);
  2435. },
  2436. get_editing_node: function() {
  2437. return this.editing_node;
  2438. },
  2439. is_editing: function() {
  2440. return (!!this.editing_node);
  2441. },
  2442. edit_node_begin: function(node) {
  2443. if (!node.topic) {
  2444. logger.warn("don't edit image nodes");
  2445. return;
  2446. }
  2447. if (this.editing_node != null) {
  2448. this.edit_node_end();
  2449. }
  2450. this.editing_node = node;
  2451. var view_data = node._data.view;
  2452. var element = view_data.element;
  2453. var topic = node.topic;
  2454. var ncs = getComputedStyle(element);
  2455. this.e_editor.value = topic;
  2456. this.e_editor.style.width = (element.clientWidth - parseInt(ncs.getPropertyValue('padding-left')) - parseInt(ncs.getPropertyValue('padding-right'))) + 'px';
  2457. element.innerHTML = '';
  2458. element.appendChild(this.e_editor);
  2459. element.style.zIndex = 5;
  2460. this.e_editor.focus();
  2461. this.e_editor.select();
  2462. },
  2463. edit_node_end: function() {
  2464. if (this.editing_node != null) {
  2465. var node = this.editing_node;
  2466. this.editing_node = null;
  2467. var view_data = node._data.view;
  2468. var element = view_data.element;
  2469. var topic = this.e_editor.value;
  2470. element.style.zIndex = 'auto';
  2471. element.removeChild(this.e_editor);
  2472. if (jm.util.text.is_empty(topic) || node.topic === topic) {
  2473. if (this.opts.support_html) {
  2474. $h(element, node.topic);
  2475. } else {
  2476. $t(element, node.topic);
  2477. }
  2478. } else {
  2479. this.jm.update_node(node.id, topic);
  2480. }
  2481. }
  2482. },
  2483. get_view_offset: function() {
  2484. var bounds = this.layout.bounds;
  2485. var _x = (this.size.w - bounds.e - bounds.w) / 2;
  2486. var _y = this.size.h / 2;
  2487. return {
  2488. x: _x,
  2489. y: _y
  2490. };
  2491. },
  2492. resize: function() {
  2493. this.e_canvas.width = 1;
  2494. this.e_canvas.height = 1;
  2495. this.e_nodes.style.width = '1px';
  2496. this.e_nodes.style.height = '1px';
  2497. this.expand_size();
  2498. this._show();
  2499. },
  2500. _show: function() {
  2501. this.e_canvas.width = this.size.w;
  2502. this.e_canvas.height = this.size.h;
  2503. this.e_nodes.style.width = this.size.w + 'px';
  2504. this.e_nodes.style.height = this.size.h + 'px';
  2505. this.show_nodes();
  2506. this.show_lines();
  2507. //this.layout.cache_valid = true;
  2508. this.jm.invoke_event_handle(jm.event_type.resize, {
  2509. data: []
  2510. });
  2511. },
  2512. zoomIn: function() {
  2513. return this.setZoom(this.actualZoom + this.zoomStep);
  2514. },
  2515. zoomOut: function() {
  2516. return this.setZoom(this.actualZoom - this.zoomStep);
  2517. },
  2518. setZoom: function(zoom) {
  2519. if ((zoom < this.minZoom) || (zoom > this.maxZoom)) {
  2520. return false;
  2521. }
  2522. this.actualZoom = zoom;
  2523. for (var i = 0; i < this.e_panel.children.length; i++) {
  2524. this.e_panel.children[i].style.transform = 'scale(' + zoom + ')';
  2525. this.e_panel.children[i].style["-ms-transform"] = 'scale(' + zoom + ')';
  2526. };
  2527. this.show(true);
  2528. return true;
  2529. },
  2530. _center_root: function() {
  2531. // center root node
  2532. var outer_w = this.e_panel.clientWidth;
  2533. var outer_h = this.e_panel.clientHeight;
  2534. if (this.size.w > outer_w) {
  2535. var _offset = this.get_view_offset();
  2536. this.e_panel.scrollLeft = _offset.x - outer_w / 2;
  2537. }
  2538. if (this.size.h > outer_h) {
  2539. this.e_panel.scrollTop = (this.size.h - outer_h) / 2;
  2540. }
  2541. },
  2542. show: function(keep_center) {
  2543. logger.debug('view.show');
  2544. this.expand_size();
  2545. this._show();
  2546. if (!!keep_center) {
  2547. this._center_root();
  2548. }
  2549. },
  2550. relayout: function() {
  2551. this.expand_size();
  2552. this._show();
  2553. },
  2554. save_location: function(node) {
  2555. var vd = node._data.view;
  2556. vd._saved_location = {
  2557. x: parseInt(vd.element.style.left) - this.e_panel.scrollLeft,
  2558. y: parseInt(vd.element.style.top) - this.e_panel.scrollTop,
  2559. };
  2560. },
  2561. restore_location: function(node) {
  2562. var vd = node._data.view;
  2563. this.e_panel.scrollLeft = parseInt(vd.element.style.left) - vd._saved_location.x;
  2564. this.e_panel.scrollTop = parseInt(vd.element.style.top) - vd._saved_location.y;
  2565. },
  2566. clear_nodes: function() {
  2567. var mind = this.jm.mind;
  2568. if (mind == null) {
  2569. return;
  2570. }
  2571. var nodes = mind.nodes;
  2572. var node = null;
  2573. for (var nodeid in nodes) {
  2574. node = nodes[nodeid];
  2575. node._data.view.element = null;
  2576. node._data.view.expander = null;
  2577. }
  2578. this.e_nodes.innerHTML = '';
  2579. },
  2580. show_nodes: function() {
  2581. var nodes = this.jm.mind.nodes;
  2582. var node = null;
  2583. var node_element = null;
  2584. var expander = null;
  2585. var p = null;
  2586. var p_expander = null;
  2587. var expander_text = '-';
  2588. var view_data = null;
  2589. var _offset = this.get_view_offset();
  2590. for (var nodeid in nodes) {
  2591. node = nodes[nodeid];
  2592. view_data = node._data.view;
  2593. node_element = view_data.element;
  2594. expander = view_data.expander;
  2595. if (!this.layout.is_visible(node)) {
  2596. node_element.style.display = 'none';
  2597. expander.style.display = 'none';
  2598. continue;
  2599. }
  2600. this.reset_node_custom_style(node);
  2601. p = this.layout.get_node_point(node);
  2602. view_data.abs_x = _offset.x + p.x;
  2603. view_data.abs_y = _offset.y + p.y;
  2604. node_element.style.left = (_offset.x + p.x) + 'px';
  2605. node_element.style.top = (_offset.y + p.y) + 'px';
  2606. node_element.style.display = '';
  2607. node_element.style.visibility = 'visible';
  2608. p_expander = this.layout.get_expander_point(node);
  2609. // 创建右侧expander收缩按钮
  2610. if (!node.isroot && node.children.length > 0) {
  2611. expander_text = node.expanded ? '-' : '+';
  2612. expander.style.left = (_offset.x + p_expander.x) + 'px';
  2613. expander.style.top = (_offset.y + p_expander.y) + 'px';
  2614. expander.style.display = '';
  2615. expander.style.visibility = 'visible';
  2616. $t(expander, expander_text);
  2617. }
  2618. // 当下面已经没有children时,隐藏expander收缩按钮
  2619. if (!node.isroot && node.children.length == 0) {
  2620. expander.style.display = 'none';
  2621. expander.style.visibility = 'hidden';
  2622. }
  2623. // 创建右上角的小图标 丢那妈
  2624. if (!node.data.badge || node.data.badge < 1) continue;
  2625. var badge = view_data.badge;
  2626. badge.style.left = (_offset.x + p_expander.x - 10) + 'px';
  2627. badge.style.top = (_offset.y + p_expander.y - 20) + 'px';
  2628. badge.style.display = '';
  2629. badge.style.visibility = 'visible';
  2630. $t(badge, node.data.badge);
  2631. }
  2632. },
  2633. reset_node_custom_style: function(node) {
  2634. this._reset_node_custom_style(node._data.view.element, node.data);
  2635. },
  2636. _reset_node_custom_style: function(node_element, node_data) {
  2637. if ('background-color' in node_data) {
  2638. node_element.style.backgroundColor = node_data['background-color'];
  2639. }
  2640. if ('foreground-color' in node_data) {
  2641. node_element.style.color = node_data['foreground-color'];
  2642. }
  2643. if ('width' in node_data) {
  2644. node_element.style.width = node_data['width'] + 'px';
  2645. }
  2646. if ('height' in node_data) {
  2647. node_element.style.height = node_data['height'] + 'px';
  2648. }
  2649. if ('font-size' in node_data) {
  2650. node_element.style.fontSize = node_data['font-size'] + 'px';
  2651. }
  2652. if ('font-weight' in node_data) {
  2653. node_element.style.fontWeight = node_data['font-weight'];
  2654. }
  2655. if ('font-style' in node_data) {
  2656. node_element.style.fontStyle = node_data['font-style'];
  2657. }
  2658. if ('background-image' in node_data) {
  2659. var backgroundImage = node_data['background-image'];
  2660. if (backgroundImage.startsWith('data') && node_data['width'] && node_data['height']) {
  2661. var img = new Image();
  2662. img.onload = function() {
  2663. var c = $c('canvas');
  2664. c.width = node_element.clientWidth;
  2665. c.height = node_element.clientHeight;
  2666. var img = this;
  2667. if (c.getContext) {
  2668. var ctx = c.getContext('2d');
  2669. ctx.drawImage(img, 2, 2, node_element.clientWidth, node_element.clientHeight);
  2670. var scaledImageData = c.toDataURL();
  2671. node_element.style.backgroundImage = 'url(' + scaledImageData + ')';
  2672. }
  2673. };
  2674. img.src = backgroundImage;
  2675. } else {
  2676. node_element.style.backgroundImage = 'url(' + backgroundImage + ')';
  2677. }
  2678. node_element.style.backgroundSize = '99%';
  2679. if ('background-rotation' in node_data) {
  2680. node_element.style.transform = 'rotate(' + node_data['background-rotation'] + 'deg)';
  2681. }
  2682. }
  2683. },
  2684. clear_node_custom_style: function(node) {
  2685. var node_element = node._data.view.element;
  2686. node_element.style.backgroundColor = "";
  2687. node_element.style.color = "";
  2688. },
  2689. clear_lines: function(canvas_ctx) {
  2690. var ctx = canvas_ctx || this.canvas_ctx;
  2691. jm.util.canvas.clear(ctx, 0, 0, this.size.w, this.size.h);
  2692. },
  2693. show_lines: function(canvas_ctx) {
  2694. this.clear_lines(canvas_ctx);
  2695. var nodes = this.jm.mind.nodes;
  2696. var node = null;
  2697. var pin = null;
  2698. var pout = null;
  2699. var _offset = this.get_view_offset();
  2700. for (var nodeid in nodes) {
  2701. node = nodes[nodeid];
  2702. if (!!node.isroot) {
  2703. continue;
  2704. }
  2705. if (('visible' in node._data.layout) && !node._data.layout.visible) {
  2706. continue;
  2707. }
  2708. pin = this.layout.get_node_point_in(node);
  2709. pout = this.layout.get_node_point_out(node.parent);
  2710. this.draw_line(pout, pin, _offset, canvas_ctx);
  2711. }
  2712. },
  2713. draw_line: function(pin, pout, offset, canvas_ctx) {
  2714. var ctx = canvas_ctx || this.canvas_ctx;
  2715. ctx.strokeStyle = this.opts.line_color;
  2716. ctx.lineWidth = this.opts.line_width;
  2717. ctx.lineCap = 'round';
  2718. jm.util.canvas.bezierto(
  2719. ctx,
  2720. pin.x + offset.x,
  2721. pin.y + offset.y,
  2722. pout.x + offset.x,
  2723. pout.y + offset.y);
  2724. },
  2725. };
  2726. // shortcut provider
  2727. jm.shortcut_provider = function(jm, options) {
  2728. this.jm = jm;
  2729. this.opts = options;
  2730. this.mapping = options.mapping;
  2731. this.handles = options.handles;
  2732. this._mapping = {};
  2733. };
  2734. jm.shortcut_provider.prototype = {
  2735. init: function() {
  2736. jm.util.dom.add_event($d, 'keydown', this.handler.bind(this));
  2737. this.handles['addchild'] = this.handle_addchild;
  2738. this.handles['addbrother'] = this.handle_addbrother;
  2739. this.handles['editnode'] = this.handle_editnode;
  2740. this.handles['delnode'] = this.handle_delnode;
  2741. this.handles['toggle'] = this.handle_toggle;
  2742. this.handles['up'] = this.handle_up;
  2743. this.handles['down'] = this.handle_down;
  2744. this.handles['left'] = this.handle_left;
  2745. this.handles['right'] = this.handle_right;
  2746. for (var handle in this.mapping) {
  2747. if (!!this.mapping[handle] && (handle in this.handles)) {
  2748. this._mapping[this.mapping[handle]] = this.handles[handle];
  2749. }
  2750. }
  2751. },
  2752. enable_shortcut: function() {
  2753. this.opts.enable = true;
  2754. },
  2755. disable_shortcut: function() {
  2756. this.opts.enable = false;
  2757. },
  2758. handler: function(e) {
  2759. if (this.jm.view.is_editing()) {
  2760. return;
  2761. }
  2762. var evt = e || event;
  2763. if (!this.opts.enable) {
  2764. return true;
  2765. }
  2766. var kc = evt.keyCode;
  2767. if (kc in this._mapping) {
  2768. this._mapping[kc].call(this, this.jm, e);
  2769. }
  2770. },
  2771. handle_addchild: function(_jm, e) {
  2772. var selected_node = _jm.get_selected_node();
  2773. if (!!selected_node) {
  2774. var nodeid = jm.util.uuid.newid();
  2775. var node = _jm.add_node(selected_node, nodeid, 'New Node');
  2776. if (!!node) {
  2777. _jm.select_node(nodeid);
  2778. _jm.begin_edit(nodeid);
  2779. }
  2780. }
  2781. },
  2782. handle_addbrother: function(_jm, e) {
  2783. var selected_node = _jm.get_selected_node();
  2784. if (!!selected_node && !selected_node.isroot) {
  2785. var nodeid = jm.util.uuid.newid();
  2786. var node = _jm.insert_node_after(selected_node, nodeid, 'New Node');
  2787. if (!!node) {
  2788. _jm.select_node(nodeid);
  2789. _jm.begin_edit(nodeid);
  2790. }
  2791. }
  2792. },
  2793. handle_editnode: function(_jm, e) {
  2794. var selected_node = _jm.get_selected_node();
  2795. if (!!selected_node) {
  2796. _jm.begin_edit(selected_node);
  2797. }
  2798. },
  2799. handle_delnode: function(_jm, e) {
  2800. var selected_node = _jm.get_selected_node();
  2801. if (!!selected_node && !selected_node.isroot) {
  2802. _jm.select_node(selected_node.parent);
  2803. _jm.remove_node(selected_node);
  2804. }
  2805. },
  2806. handle_toggle: function(_jm, e) {
  2807. var evt = e || event;
  2808. var selected_node = _jm.get_selected_node();
  2809. if (!!selected_node) {
  2810. _jm.toggle_node(selected_node.id);
  2811. evt.stopPropagation();
  2812. evt.preventDefault();
  2813. }
  2814. },
  2815. handle_up: function(_jm, e) {
  2816. var evt = e || event;
  2817. var selected_node = _jm.get_selected_node();
  2818. if (!!selected_node) {
  2819. var up_node = _jm.find_node_before(selected_node);
  2820. if (!up_node) {
  2821. var np = _jm.find_node_before(selected_node.parent);
  2822. if (!!np && np.children.length > 0) {
  2823. up_node = np.children[np.children.length - 1];
  2824. }
  2825. }
  2826. if (!!up_node) {
  2827. _jm.select_node(up_node);
  2828. }
  2829. evt.stopPropagation();
  2830. evt.preventDefault();
  2831. }
  2832. },
  2833. handle_down: function(_jm, e) {
  2834. var evt = e || event;
  2835. var selected_node = _jm.get_selected_node();
  2836. if (!!selected_node) {
  2837. var down_node = _jm.find_node_after(selected_node);
  2838. if (!down_node) {
  2839. var np = _jm.find_node_after(selected_node.parent);
  2840. if (!!np && np.children.length > 0) {
  2841. down_node = np.children[0];
  2842. }
  2843. }
  2844. if (!!down_node) {
  2845. _jm.select_node(down_node);
  2846. }
  2847. evt.stopPropagation();
  2848. evt.preventDefault();
  2849. }
  2850. },
  2851. handle_left: function(_jm, e) {
  2852. this._handle_direction(_jm, e, jm.direction.left);
  2853. },
  2854. handle_right: function(_jm, e) {
  2855. this._handle_direction(_jm, e, jm.direction.right);
  2856. },
  2857. _handle_direction: function(_jm, e, d) {
  2858. var evt = e || event;
  2859. var selected_node = _jm.get_selected_node();
  2860. var node = null;
  2861. if (!!selected_node) {
  2862. if (selected_node.isroot) {
  2863. var c = selected_node.children;
  2864. var children = [];
  2865. for (var i = 0; i < c.length; i++) {
  2866. if (c[i].direction === d) {
  2867. children.push(i)
  2868. }
  2869. }
  2870. node = c[children[Math.floor((children.length - 1) / 2)]];
  2871. } else if (selected_node.direction === d) {
  2872. var children = selected_node.children;
  2873. var childrencount = children.length;
  2874. if (childrencount > 0) {
  2875. node = children[Math.floor((childrencount - 1) / 2)]
  2876. }
  2877. } else {
  2878. node = selected_node.parent;
  2879. }
  2880. if (!!node) {
  2881. _jm.select_node(node);
  2882. }
  2883. evt.stopPropagation();
  2884. evt.preventDefault();
  2885. }
  2886. },
  2887. };
  2888. // plugin
  2889. jm.plugin = function(name, init) {
  2890. this.name = name;
  2891. this.init = init;
  2892. };
  2893. jm.plugins = [];
  2894. jm.register_plugin = function(plugin) {
  2895. if (plugin instanceof jm.plugin) {
  2896. jm.plugins.push(plugin);
  2897. }
  2898. };
  2899. jm.init_plugins = function(sender) {
  2900. $w.setTimeout(function() {
  2901. jm._init_plugins(sender);
  2902. }, 0);
  2903. };
  2904. jm._init_plugins = function(sender) {
  2905. var l = jm.plugins.length;
  2906. var fn_init = null;
  2907. for (var i = 0; i < l; i++) {
  2908. fn_init = jm.plugins[i].init;
  2909. if (typeof fn_init === 'function') {
  2910. fn_init(sender);
  2911. }
  2912. }
  2913. };
  2914. // quick way
  2915. jm.show = function(options, mind) {
  2916. var _jm = new jm(options);
  2917. _jm.show(mind);
  2918. return _jm;
  2919. };
  2920. $w[__name__] = jm;
  2921. })(window);
  2922. /*
  2923. * Released under BSD License
  2924. * Copyright (c) 2014-2015 hizzgdev@163.com
  2925. *
  2926. * Project Home:
  2927. * https://github.com/hizzgdev/jsmind/
  2928. */
  2929. (function($w) {
  2930. 'use strict';
  2931. var $d = $w.document;
  2932. var __name__ = 'jsMind';
  2933. var jsMind = $w[__name__];
  2934. if (!jsMind) {
  2935. return;
  2936. }
  2937. if (typeof jsMind.draggable != 'undefined') {
  2938. return;
  2939. }
  2940. var jdom = jsMind.util.dom;
  2941. var jcanvas = jsMind.util.canvas;
  2942. var clear_selection = 'getSelection' in $w ? function() {
  2943. $w.getSelection().removeAllRanges();
  2944. } : function() {
  2945. $d.selection.empty();
  2946. };
  2947. var options = {
  2948. line_width: 5,
  2949. lookup_delay: 500,
  2950. lookup_interval: 80
  2951. };
  2952. jsMind.draggable = function(jm) {
  2953. this.jm = jm;
  2954. this.e_canvas = null;
  2955. this.canvas_ctx = null;
  2956. this.shadow = null;
  2957. this.shadow_w = 0;
  2958. this.shadow_h = 0;
  2959. this.active_node = null;
  2960. this.target_node = null;
  2961. this.target_direct = null;
  2962. this.client_w = 0;
  2963. this.client_h = 0;
  2964. this.offset_x = 0;
  2965. this.offset_y = 0;
  2966. this.hlookup_delay = 0;
  2967. this.hlookup_timer = 0;
  2968. this.capture = false;
  2969. this.moved = false;
  2970. };
  2971. jsMind.draggable.prototype = {
  2972. init: function() {
  2973. this._create_canvas();
  2974. this._create_shadow();
  2975. this._event_bind();
  2976. },
  2977. resize: function() {
  2978. this.jm.view.e_nodes.appendChild(this.shadow);
  2979. this.e_canvas.width = this.jm.view.size.w;
  2980. this.e_canvas.height = this.jm.view.size.h;
  2981. },
  2982. _create_canvas: function() {
  2983. var c = $d.createElement('canvas');
  2984. this.jm.view.e_panel.appendChild(c);
  2985. var ctx = c.getContext('2d');
  2986. this.e_canvas = c;
  2987. this.canvas_ctx = ctx;
  2988. },
  2989. _create_shadow: function() {
  2990. var s = $d.createElement('jmnode');
  2991. s.style.visibility = 'hidden';
  2992. s.style.zIndex = '3';
  2993. s.style.cursor = 'move';
  2994. s.style.opacity = '0.7';
  2995. this.shadow = s;
  2996. },
  2997. reset_shadow: function(el) {
  2998. var s = this.shadow.style;
  2999. this.shadow.innerHTML = el.innerHTML;
  3000. s.left = el.style.left;
  3001. s.top = el.style.top;
  3002. s.width = el.style.width;
  3003. s.height = el.style.height;
  3004. s.backgroundImage = el.style.backgroundImage;
  3005. s.backgroundSize = el.style.backgroundSize;
  3006. s.transform = el.style.transform;
  3007. this.shadow_w = this.shadow.clientWidth;
  3008. this.shadow_h = this.shadow.clientHeight;
  3009. },
  3010. show_shadow: function() {
  3011. if (!this.moved) {
  3012. this.shadow.style.visibility = 'visible';
  3013. }
  3014. },
  3015. hide_shadow: function() {
  3016. this.shadow.style.visibility = 'hidden';
  3017. },
  3018. clear_lines: function() {
  3019. jcanvas.clear(this.canvas_ctx, 0, 0, this.jm.view.size.w, this.jm.view.size.h);
  3020. },
  3021. _magnet_shadow: function(node) {
  3022. if (!!node) {
  3023. this.canvas_ctx.lineWidth = options.line_width;
  3024. this.canvas_ctx.strokeStyle = 'rgba(0,0,0,0.3)';
  3025. this.canvas_ctx.lineCap = 'round';
  3026. this.clear_lines();
  3027. jcanvas.lineto(this.canvas_ctx,
  3028. node.sp.x,
  3029. node.sp.y,
  3030. node.np.x,
  3031. node.np.y);
  3032. }
  3033. },
  3034. _lookup_close_node: function() {
  3035. var root = this.jm.get_root();
  3036. var root_location = root.get_location();
  3037. var root_size = root.get_size();
  3038. var root_x = root_location.x + root_size.w / 2;
  3039. var sw = this.shadow_w;
  3040. var sh = this.shadow_h;
  3041. var sx = this.shadow.offsetLeft;
  3042. var sy = this.shadow.offsetTop;
  3043. var ns, nl;
  3044. var direct = (sx + sw / 2) >= root_x ?
  3045. jsMind.direction.right : jsMind.direction.left;
  3046. var nodes = this.jm.mind.nodes;
  3047. var node = null;
  3048. var min_distance = Number.MAX_VALUE;
  3049. var distance = 0;
  3050. var closest_node = null;
  3051. var closest_p = null;
  3052. var shadow_p = null;
  3053. for (var nodeid in nodes) {
  3054. var np, sp;
  3055. node = nodes[nodeid];
  3056. if (node.isroot || node.direction == direct) {
  3057. if (node.id == this.active_node.id) {
  3058. continue;
  3059. }
  3060. ns = node.get_size();
  3061. nl = node.get_location();
  3062. if (direct == jsMind.direction.right) {
  3063. if (sx - nl.x - ns.w <= 0) {
  3064. continue;
  3065. }
  3066. distance = Math.abs(sx - nl.x - ns.w) + Math.abs(sy + sh / 2 - nl.y - ns.h / 2);
  3067. np = {
  3068. x: nl.x + ns.w - options.line_width,
  3069. y: nl.y + ns.h / 2
  3070. };
  3071. sp = {
  3072. x: sx + options.line_width,
  3073. y: sy + sh / 2
  3074. };
  3075. } else {
  3076. if (nl.x - sx - sw <= 0) {
  3077. continue;
  3078. }
  3079. distance = Math.abs(sx + sw - nl.x) + Math.abs(sy + sh / 2 - nl.y - ns.h / 2);
  3080. np = {
  3081. x: nl.x + options.line_width,
  3082. y: nl.y + ns.h / 2
  3083. };
  3084. sp = {
  3085. x: sx + sw - options.line_width,
  3086. y: sy + sh / 2
  3087. };
  3088. }
  3089. if (distance < min_distance) {
  3090. closest_node = node;
  3091. closest_p = np;
  3092. shadow_p = sp;
  3093. min_distance = distance;
  3094. }
  3095. }
  3096. }
  3097. var result_node = null;
  3098. if (!!closest_node) {
  3099. result_node = {
  3100. node: closest_node,
  3101. direction: direct,
  3102. sp: shadow_p,
  3103. np: closest_p
  3104. };
  3105. }
  3106. return result_node;
  3107. },
  3108. lookup_close_node: function() {
  3109. var node_data = this._lookup_close_node();
  3110. if (!!node_data) {
  3111. this._magnet_shadow(node_data);
  3112. this.target_node = node_data.node;
  3113. this.target_direct = node_data.direction;
  3114. }
  3115. },
  3116. _event_bind: function() {
  3117. var jd = this;
  3118. var container = this.jm.view.container;
  3119. // 鼠标右键 (leo 加的)
  3120. jdom.add_event(container, 'contextmenu', function(e) {
  3121. // console.log('鼠标右键')
  3122. var evt = e || event;
  3123. jd.dragend.call(jd, evt);
  3124. });
  3125. // 鼠标按下
  3126. jdom.add_event(container, 'mousedown', function(e) {
  3127. // console.log('鼠标按下')
  3128. $conTextMenu.hide();
  3129. var evt = e || event;
  3130. jd.dragstart.call(jd, evt);
  3131. });
  3132. // 鼠标移动
  3133. jdom.add_event(container, 'mousemove', function(e) {
  3134. // console.log('鼠标移动')
  3135. var evt = e || event;
  3136. jd.drag.call(jd, evt);
  3137. });
  3138. // 鼠标弹起
  3139. jdom.add_event(container, 'mouseup', function(e) {
  3140. // console.log('鼠标弹起')
  3141. var evt = e || event;
  3142. jd.dragend.call(jd, evt);
  3143. });
  3144. jdom.add_event(container, 'touchstart', function(e) {
  3145. // console.log('touchstart')
  3146. var evt = e || event;
  3147. jd.dragstart.call(jd, evt);
  3148. });
  3149. jdom.add_event(container, 'touchmove', function(e) {
  3150. // console.log('touchmove')
  3151. var evt = e || event;
  3152. jd.drag.call(jd, evt);
  3153. });
  3154. jdom.add_event(container, 'touchend', function(e) {
  3155. // console.log('touchend')
  3156. var evt = e || event;
  3157. jd.dragend.call(jd, evt);
  3158. });
  3159. },
  3160. dragstart: function(e) {
  3161. if (!this.jm.get_editable()) {
  3162. return;
  3163. }
  3164. if (this.capture) {
  3165. return;
  3166. }
  3167. this.active_node = null;
  3168. var jview = this.jm.view;
  3169. var el = e.target || event.srcElement;
  3170. if (el.tagName.toLowerCase() != 'jmnode') {
  3171. return;
  3172. }
  3173. var nodeid = jview.get_binded_nodeid(el);
  3174. if (!!nodeid) {
  3175. var node = this.jm.get_node(nodeid);
  3176. if (!node.isroot) {
  3177. this.reset_shadow(el);
  3178. this.active_node = node;
  3179. this.offset_x = (e.clientX || e.touches[0].clientX) - el.offsetLeft;
  3180. this.offset_y = (e.clientY || e.touches[0].clientY) - el.offsetTop;
  3181. this.client_hw = Math.floor(el.clientWidth / 2);
  3182. this.client_hh = Math.floor(el.clientHeight / 2);
  3183. if (this.hlookup_delay != 0) {
  3184. $w.clearTimeout(this.hlookup_delay);
  3185. }
  3186. if (this.hlookup_timer != 0) {
  3187. $w.clearInterval(this.hlookup_timer);
  3188. }
  3189. var jd = this;
  3190. this.hlookup_delay = $w.setTimeout(function() {
  3191. jd.hlookup_delay = 0;
  3192. jd.hlookup_timer = $w.setInterval(function() {
  3193. jd.lookup_close_node.call(jd);
  3194. }, options.lookup_interval);
  3195. }, options.lookup_delay);
  3196. this.capture = true;
  3197. }
  3198. }
  3199. },
  3200. drag: function(e) {
  3201. if (!this.jm.get_editable()) {
  3202. return;
  3203. }
  3204. if (this.capture) {
  3205. e.preventDefault();
  3206. this.show_shadow();
  3207. this.moved = true;
  3208. clear_selection();
  3209. var px = (e.clientX || e.touches[0].clientX) - this.offset_x;
  3210. var py = (e.clientY || e.touches[0].clientY) - this.offset_y;
  3211. var cx = px + this.client_hw;
  3212. var cy = py + this.client_hh;
  3213. this.shadow.style.left = px + 'px';
  3214. this.shadow.style.top = py + 'px';
  3215. clear_selection();
  3216. }
  3217. },
  3218. dragend: function(e) {
  3219. if (!this.jm.get_editable()) {
  3220. return;
  3221. }
  3222. if (this.capture) {
  3223. if (this.hlookup_delay != 0) {
  3224. $w.clearTimeout(this.hlookup_delay);
  3225. this.hlookup_delay = 0;
  3226. this.clear_lines();
  3227. }
  3228. if (this.hlookup_timer != 0) {
  3229. $w.clearInterval(this.hlookup_timer);
  3230. this.hlookup_timer = 0;
  3231. this.clear_lines();
  3232. }
  3233. if (this.moved) {
  3234. var src_node = this.active_node;
  3235. var target_node = this.target_node;
  3236. var target_direct = this.target_direct;
  3237. this.move_node(src_node, target_node, target_direct);
  3238. }
  3239. this.hide_shadow();
  3240. }
  3241. this.moved = false;
  3242. this.capture = false;
  3243. },
  3244. move_node: function(src_node, target_node, target_direct) {
  3245. var shadow_h = this.shadow.offsetTop;
  3246. if (!!target_node && !!src_node && !jsMind.node.inherited(src_node, target_node)) {
  3247. // lookup before_node
  3248. var sibling_nodes = target_node.children;
  3249. var sc = sibling_nodes.length;
  3250. var node = null;
  3251. var delta_y = Number.MAX_VALUE;
  3252. var node_before = null;
  3253. var beforeid = '_last_';
  3254. while (sc--) {
  3255. node = sibling_nodes[sc];
  3256. if (node.direction == target_direct && node.id != src_node.id) {
  3257. var dy = node.get_location().y - shadow_h;
  3258. if (dy > 0 && dy < delta_y) {
  3259. delta_y = dy;
  3260. node_before = node;
  3261. beforeid = '_first_';
  3262. }
  3263. }
  3264. }
  3265. if (!!node_before) {
  3266. beforeid = node_before.id;
  3267. }
  3268. this.jm.move_node(src_node.id, beforeid, target_node.id, target_direct);
  3269. }
  3270. this.active_node = null;
  3271. this.target_node = null;
  3272. this.target_direct = null;
  3273. },
  3274. jm_event_handle: function(type, data) {
  3275. if (type === jsMind.event_type.resize) {
  3276. this.resize();
  3277. }
  3278. }
  3279. };
  3280. var draggable_plugin = new jsMind.plugin('draggable', function(jm) {
  3281. var jd = new jsMind.draggable(jm);
  3282. jd.init();
  3283. jm.add_event_listener(function(type, data) {
  3284. jd.jm_event_handle.call(jd, type, data);
  3285. });
  3286. });
  3287. jsMind.register_plugin(draggable_plugin);
  3288. })(window);
  3289. /*
  3290. * Released under BSD License
  3291. * Copyright (c) 2014-2015 hizzgdev@163.com
  3292. *
  3293. * Project Home:
  3294. * https://github.com/hizzgdev/jsmind/
  3295. */
  3296. (function($w) {
  3297. 'use strict';
  3298. var __name__ = 'jsMind';
  3299. var jsMind = $w[__name__];
  3300. if (!jsMind) {
  3301. return;
  3302. }
  3303. if (typeof jsMind.screenshot != 'undefined') {
  3304. return;
  3305. }
  3306. var $d = $w.document;
  3307. var $c = function(tag) {
  3308. return $d.createElement(tag);
  3309. };
  3310. var css = function(cstyle, property_name) {
  3311. return cstyle.getPropertyValue(property_name);
  3312. };
  3313. var is_visible = function(cstyle) {
  3314. var visibility = css(cstyle, 'visibility');
  3315. var display = css(cstyle, 'display');
  3316. return (visibility !== 'hidden' && display !== 'none');
  3317. };
  3318. var jcanvas = jsMind.util.canvas;
  3319. jcanvas.rect = function(ctx, x, y, w, h, r) {
  3320. if (w < 2 * r) r = w / 2;
  3321. if (h < 2 * r) r = h / 2;
  3322. ctx.moveTo(x + r, y);
  3323. ctx.arcTo(x + w, y, x + w, y + h, r);
  3324. ctx.arcTo(x + w, y + h, x, y + h, r);
  3325. ctx.arcTo(x, y + h, x, y, r);
  3326. ctx.arcTo(x, y, x + w, y, r);
  3327. };
  3328. jcanvas.text_multiline = function(ctx, text, x, y, w, h, lineheight) {
  3329. var line = '';
  3330. var text_len = text.length;
  3331. var chars = text.split('');
  3332. var test_line = null;
  3333. ctx.textAlign = 'left';
  3334. ctx.textBaseline = 'top';
  3335. for (var i = 0; i < text_len; i++) {
  3336. test_line = line + chars[i];
  3337. if (ctx.measureText(test_line).width > w && i > 0) {
  3338. ctx.fillText(line, x, y);
  3339. line = chars[i];
  3340. y += lineheight;
  3341. } else {
  3342. line = test_line;
  3343. }
  3344. }
  3345. ctx.fillText(line, x, y);
  3346. };
  3347. jcanvas.text_ellipsis = function(ctx, text, x, y, w, h) {
  3348. var center_y = y + h / 2;
  3349. var text = jcanvas.fittingString(ctx, text, w);
  3350. ctx.textAlign = 'left';
  3351. ctx.textBaseline = 'middle';
  3352. ctx.fillText(text, x, center_y, w);
  3353. };
  3354. jcanvas.fittingString = function(ctx, text, max_width) {
  3355. var width = ctx.measureText(text).width;
  3356. var ellipsis = '…'
  3357. var ellipsis_width = ctx.measureText(ellipsis).width;
  3358. if (width <= max_width || width <= ellipsis_width) {
  3359. return text;
  3360. } else {
  3361. var len = text.length;
  3362. while (width >= max_width - ellipsis_width && len-- > 0) {
  3363. text = text.substring(0, len);
  3364. width = ctx.measureText(text).width;
  3365. }
  3366. return text + ellipsis;
  3367. }
  3368. };
  3369. jcanvas.image = function(ctx, backgroundUrl, x, y, w, h, r, rotation, callback) {
  3370. var img = new Image();
  3371. img.onload = function() {
  3372. ctx.save();
  3373. ctx.translate(x, y);
  3374. ctx.save();
  3375. ctx.beginPath();
  3376. jcanvas.rect(ctx, 0, 0, w, h, r);
  3377. ctx.closePath();
  3378. ctx.clip();
  3379. ctx.translate(w / 2, h / 2);
  3380. ctx.rotate(rotation * Math.PI / 180);
  3381. ctx.drawImage(img, -w / 2, -h / 2);
  3382. ctx.restore();
  3383. ctx.restore();
  3384. callback();
  3385. }
  3386. img.src = backgroundUrl;
  3387. };
  3388. jsMind.screenshot = function(jm) {
  3389. this.jm = jm;
  3390. this.canvas_elem = null;
  3391. this.canvas_ctx = null;
  3392. this._inited = false;
  3393. };
  3394. jsMind.screenshot.prototype = {
  3395. init: function() {
  3396. if (this._inited) {
  3397. return;
  3398. }
  3399. var c = $c('canvas');
  3400. var ctx = c.getContext('2d');
  3401. this.canvas_elem = c;
  3402. this.canvas_ctx = ctx;
  3403. this.jm.view.e_panel.appendChild(c);
  3404. this._inited = true;
  3405. this.resize();
  3406. },
  3407. shoot: function(callback) {
  3408. this.init();
  3409. this._watermark();
  3410. var jms = this;
  3411. this._draw(function() {
  3412. if (!!callback) {
  3413. callback(jms);
  3414. }
  3415. jms.clean();
  3416. });
  3417. },
  3418. shootDownload: function() {
  3419. this.shoot(function(jms) {
  3420. jms._download();
  3421. });
  3422. },
  3423. shootAsDataURL: function(callback) {
  3424. this.shoot(function(jms) {
  3425. callback(jms.canvas_elem.toDataURL());
  3426. });
  3427. },
  3428. resize: function() {
  3429. if (this._inited) {
  3430. this.canvas_elem.width = this.jm.view.size.w;
  3431. this.canvas_elem.height = this.jm.view.size.h;
  3432. }
  3433. },
  3434. clean: function() {
  3435. var c = this.canvas_elem;
  3436. this.canvas_ctx.clearRect(0, 0, c.width, c.height);
  3437. },
  3438. _draw: function(callback) {
  3439. var ctx = this.canvas_ctx;
  3440. ctx.textAlign = 'left';
  3441. ctx.textBaseline = 'top';
  3442. this._draw_lines();
  3443. this._draw_nodes(callback);
  3444. },
  3445. _watermark: function() {
  3446. var c = this.canvas_elem;
  3447. var ctx = this.canvas_ctx;
  3448. ctx.textAlign = 'right';
  3449. ctx.textBaseline = 'bottom';
  3450. ctx.fillStyle = '#000';
  3451. ctx.font = '11px Verdana,Arial,Helvetica,sans-serif';
  3452. ctx.fillText('hizzgdev.github.io/jsmind', c.width - 5.5, c.height - 2.5);
  3453. ctx.textAlign = 'left';
  3454. ctx.fillText($w.location, 5.5, c.height - 2.5);
  3455. },
  3456. _draw_lines: function() {
  3457. this.jm.view.show_lines(this.canvas_ctx);
  3458. },
  3459. _draw_nodes: function(callback) {
  3460. var nodes = this.jm.mind.nodes;
  3461. var node;
  3462. for (var nodeid in nodes) {
  3463. node = nodes[nodeid];
  3464. this._draw_node(node);
  3465. }
  3466. function check_nodes_ready() {
  3467. var allOk = true;
  3468. for (var nodeid in nodes) {
  3469. node = nodes[nodeid];
  3470. allOk = allOk & node.ready;
  3471. }
  3472. if (!allOk) {
  3473. $w.setTimeout(check_nodes_ready, 200);
  3474. } else {
  3475. $w.setTimeout(callback, 200);
  3476. }
  3477. }
  3478. check_nodes_ready();
  3479. },
  3480. _draw_node: function(node) {
  3481. var ctx = this.canvas_ctx;
  3482. var view_data = node._data.view;
  3483. var node_element = view_data.element;
  3484. var ncs = getComputedStyle(node_element);
  3485. if (!is_visible(ncs)) {
  3486. node.ready = true;
  3487. return;
  3488. }
  3489. var bgcolor = css(ncs, 'background-color');
  3490. var round_radius = parseInt(css(ncs, 'border-top-left-radius'));
  3491. var color = css(ncs, 'color');
  3492. var padding_left = parseInt(css(ncs, 'padding-left'));
  3493. var padding_right = parseInt(css(ncs, 'padding-right'));
  3494. var padding_top = parseInt(css(ncs, 'padding-top'));
  3495. var padding_bottom = parseInt(css(ncs, 'padding-bottom'));
  3496. var text_overflow = css(ncs, 'text-overflow');
  3497. var font = css(ncs, 'font-style') + ' ' +
  3498. css(ncs, 'font-variant') + ' ' +
  3499. css(ncs, 'font-weight') + ' ' +
  3500. css(ncs, 'font-size') + '/' + css(ncs, 'line-height') + ' ' +
  3501. css(ncs, 'font-family');
  3502. var rb = {
  3503. x: view_data.abs_x,
  3504. y: view_data.abs_y,
  3505. w: view_data.width + 1,
  3506. h: view_data.height + 1
  3507. };
  3508. var tb = {
  3509. x: rb.x + padding_left,
  3510. y: rb.y + padding_top,
  3511. w: rb.w - padding_left - padding_right,
  3512. h: rb.h - padding_top - padding_bottom
  3513. };
  3514. ctx.font = font;
  3515. ctx.fillStyle = bgcolor;
  3516. ctx.beginPath();
  3517. jcanvas.rect(ctx, rb.x, rb.y, rb.w, rb.h, round_radius);
  3518. ctx.closePath();
  3519. ctx.fill();
  3520. ctx.fillStyle = color;
  3521. if ('background-image' in node.data) {
  3522. var backgroundUrl = css(ncs, 'background-image').slice(5, -2);
  3523. node.ready = false;
  3524. var rotation = 0;
  3525. if ('background-rotation' in node.data) {
  3526. rotation = node.data['background-rotation'];
  3527. }
  3528. jcanvas.image(ctx, backgroundUrl, rb.x, rb.y, rb.w, rb.h, round_radius, rotation,
  3529. function() {
  3530. node.ready = true;
  3531. });
  3532. }
  3533. if (!!node.topic) {
  3534. if (text_overflow === 'ellipsis') {
  3535. jcanvas.text_ellipsis(ctx, node.topic, tb.x, tb.y, tb.w, tb.h);
  3536. } else {
  3537. var line_height = parseInt(css(ncs, 'line-height'));
  3538. jcanvas.text_multiline(ctx, node.topic, tb.x, tb.y, tb.w, tb.h, line_height);
  3539. }
  3540. }
  3541. if (!!view_data.expander) {
  3542. this._draw_expander(view_data.expander);
  3543. }
  3544. if (!('background-image' in node.data)) {
  3545. node.ready = true;
  3546. }
  3547. },
  3548. _draw_expander: function(expander) {
  3549. var ctx = this.canvas_ctx;
  3550. var ncs = getComputedStyle(expander);
  3551. if (!is_visible(ncs)) {
  3552. return;
  3553. }
  3554. var style_left = css(ncs, 'left');
  3555. var style_top = css(ncs, 'top');
  3556. var font = css(ncs, 'font');
  3557. var left = parseInt(style_left);
  3558. var top = parseInt(style_top);
  3559. var is_plus = expander.innerHTML === '+';
  3560. ctx.lineWidth = 1;
  3561. ctx.beginPath();
  3562. ctx.arc(left + 7, top + 7, 5, 0, Math.PI * 2, true);
  3563. ctx.moveTo(left + 10, top + 7);
  3564. ctx.lineTo(left + 4, top + 7);
  3565. if (is_plus) {
  3566. ctx.moveTo(left + 7, top + 4);
  3567. ctx.lineTo(left + 7, top + 10);
  3568. }
  3569. ctx.closePath();
  3570. ctx.stroke();
  3571. },
  3572. _download: function() {
  3573. var c = this.canvas_elem;
  3574. var name = this.jm.mind.name + '.png';
  3575. if (navigator.msSaveBlob && (!!c.msToBlob)) {
  3576. var blob = c.msToBlob();
  3577. navigator.msSaveBlob(blob, name);
  3578. } else {
  3579. var bloburl = this.canvas_elem.toDataURL();
  3580. var anchor = $c('a');
  3581. if ('download' in anchor) {
  3582. anchor.style.visibility = 'hidden';
  3583. anchor.href = bloburl;
  3584. anchor.download = name;
  3585. $d.body.appendChild(anchor);
  3586. var evt = $d.createEvent('MouseEvents');
  3587. evt.initEvent('click', true, true);
  3588. anchor.dispatchEvent(evt);
  3589. $d.body.removeChild(anchor);
  3590. } else {
  3591. location.href = bloburl;
  3592. }
  3593. }
  3594. },
  3595. jm_event_handle: function(type, data) {
  3596. if (type === jsMind.event_type.resize) {
  3597. this.resize();
  3598. }
  3599. }
  3600. };
  3601. var screenshot_plugin = new jsMind.plugin('screenshot', function(jm) {
  3602. var jss = new jsMind.screenshot(jm);
  3603. jm.screenshot = jss;
  3604. jm.shoot = function() {
  3605. jss.shoot();
  3606. };
  3607. jm.add_event_listener(function(type, data) {
  3608. jss.jm_event_handle.call(jss, type, data);
  3609. });
  3610. });
  3611. jsMind.register_plugin(screenshot_plugin);
  3612. })(window);
  3613. /*
  3614. * ContextMenu - jQuery plugin for right-click context menus
  3615. * Version: r2
  3616. * Date: 16 July 2007
  3617. * For documentation visit http://www.trendskitchens.co.nz/jquery/contextmenu/
  3618. */
  3619. (function($) {
  3620. var menu, shadow, trigger, content, hash, currentTarget;
  3621. var defaults = {
  3622. menuStyle: {
  3623. listStyle: 'none',
  3624. padding: '1px',
  3625. margin: '0px',
  3626. backgroundColor: '#fff',
  3627. border: '1px solid #999',
  3628. width: '100px'
  3629. },
  3630. itemStyle: {
  3631. margin: '0px',
  3632. color: '#000',
  3633. display: 'block',
  3634. cursor: 'default',
  3635. padding: '3px',
  3636. border: '1px solid #fff',
  3637. backgroundColor: 'transparent'
  3638. },
  3639. itemHoverStyle: {
  3640. border: '1px solid #0a246a',
  3641. backgroundColor: '#b6bdd2'
  3642. },
  3643. eventPosX: 'pageX',
  3644. eventPosY: 'pageY',
  3645. shadow: true,
  3646. onContextMenu: null,
  3647. onShowMenu: null
  3648. };
  3649. $.fn.contextMenu = function(id, options) {
  3650. if (!menu) { // Create singleton menu
  3651. menu = $('<div id="jqContextMenu"></div>')
  3652. .hide()
  3653. .css({
  3654. position: 'absolute',
  3655. zIndex: '500'
  3656. })
  3657. .appendTo('body')
  3658. .bind('click', function(e) {
  3659. e.stopPropagation();
  3660. });
  3661. }
  3662. if (!shadow) {
  3663. shadow = $('<div></div>')
  3664. .css({
  3665. backgroundColor: '#000',
  3666. position: 'absolute',
  3667. opacity: 0.2,
  3668. zIndex: 499
  3669. })
  3670. .appendTo('body')
  3671. .hide();
  3672. }
  3673. hash = hash || [];
  3674. hash.push({
  3675. id: id,
  3676. menuStyle: $.extend({}, defaults.menuStyle, options.menuStyle || {}),
  3677. itemStyle: $.extend({}, defaults.itemStyle, options.itemStyle || {}),
  3678. itemHoverStyle: $.extend({}, defaults.itemHoverStyle, options.itemHoverStyle || {}),
  3679. bindings: options.bindings || {},
  3680. shadow: options.shadow || options.shadow === false ? options.shadow : defaults.shadow,
  3681. onContextMenu: options.onContextMenu || defaults.onContextMenu,
  3682. onShowMenu: options.onShowMenu || defaults.onShowMenu,
  3683. eventPosX: options.eventPosX || defaults.eventPosX,
  3684. eventPosY: options.eventPosY || defaults.eventPosY
  3685. });
  3686. var index = hash.length - 1;
  3687. $(this).bind('contextmenu', function(e) {
  3688. // Check if onContextMenu() defined
  3689. var bShowContext = (!!hash[index].onContextMenu) ? hash[index].onContextMenu(e) : true;
  3690. if (bShowContext) display(index, this, e, options);
  3691. return false;
  3692. });
  3693. return this;
  3694. };
  3695. function display(index, trigger, e, options) {
  3696. var cur = hash[index];
  3697. content = $('#' + cur.id).find('ul:first').clone(true);
  3698. content.css(cur.menuStyle).find('li').css(cur.itemStyle).hover(
  3699. function() {
  3700. $(this).css(cur.itemHoverStyle);
  3701. },
  3702. function() {
  3703. $(this).css(cur.itemStyle);
  3704. }
  3705. ).find('img').css({
  3706. verticalAlign: 'middle',
  3707. paddingRight: '2px'
  3708. });
  3709. // Send the content to the menu
  3710. menu.html(content);
  3711. // if there's an onShowMenu, run it now -- must run after content has been added
  3712. // if you try to alter the content variable before the menu.html(), IE6 has issues
  3713. // updating the content
  3714. if (!!cur.onShowMenu) menu = cur.onShowMenu(e, menu);
  3715. $.each(cur.bindings, function(id, func) {
  3716. $('#' + id, menu).bind('click', function(ev) {
  3717. hide();
  3718. func(trigger, e.currentTarget);
  3719. });
  3720. });
  3721. var left = e[cur.eventPosX];
  3722. var top = e[cur.eventPosY];
  3723. if (left + menu.outerWidth() > $(document.body).width()) {
  3724. left -= menu.outerWidth();
  3725. }
  3726. if (top + menu.outerHeight() > $(document.body).height()) {
  3727. top -= menu.outerHeight();
  3728. }
  3729. menu.css({
  3730. 'left': left,
  3731. 'top': top
  3732. }).show();
  3733. //if (cur.shadow) shadow.css({ width: menu.width(), height: menu.height(), left: e.pageX + 2, top: e.pageY + 2 }).show();
  3734. if (cur.shadow) shadow.css({
  3735. width: menu.width(),
  3736. height: menu.height(),
  3737. left: left + 2,
  3738. top: top + 2
  3739. }).show();
  3740. $(document).one('click', hide);
  3741. }
  3742. function hide() {
  3743. menu.hide();
  3744. shadow.hide();
  3745. }
  3746. // Apply defaults
  3747. $.contextMenu = {
  3748. defaults: function(userDefaults) {
  3749. $.each(userDefaults, function(i, val) {
  3750. if (typeof val == 'object' && defaults[i]) {
  3751. $.extend(defaults[i], val);
  3752. } else defaults[i] = val;
  3753. });
  3754. }
  3755. };
  3756. })(jQuery);
  3757. // kmsjsmap
  3758. // 思维导图JS库
  3759. (function($w) {
  3760. if (!$w.jsMind) return;
  3761. var __NAME__ = 'kmsjsmap'
  3762. var logger = (typeof console === 'undefined') ? {
  3763. log: _noop,
  3764. debug: _noop,
  3765. error: _noop,
  3766. warn: _noop,
  3767. info: _noop
  3768. } : console;
  3769. if (!logger.debug) logger.debug = _noop;
  3770. if (typeof module === 'undefined' || !module.exports) {
  3771. if (typeof $w[__NAME__] !== 'undefined') {
  3772. logger.log(__NAME__ + '已经存在啦啦啦啦~');
  3773. return;
  3774. }
  3775. }
  3776. var kmsjsmap = {
  3777. options: '',
  3778. isInit: false,
  3779. editable: true,
  3780. onRelation: _noop
  3781. }
  3782. kmsjsmap.init = function(options) {
  3783. // console.log('init:', options)
  3784. if (!options || Object.keys(options).length === 0) {
  3785. logger.warn('请对' + __NAME__ + '.init()传入必要的参数');
  3786. return;
  3787. }
  3788. if (this.isInit) return;
  3789. this.isInit = true;
  3790. this.options = options;
  3791. this.editable = options.editable === true ? true : false;
  3792. if (options.onRelation) this.onRelation = options.onRelation;
  3793. this._load_jsmind();
  3794. this._init_button();
  3795. return _jm;
  3796. }
  3797. var _jm = null;
  3798. // 初始化思维导图
  3799. kmsjsmap._load_jsmind = function() {
  3800. var options = {
  3801. container: this.options.container,
  3802. editable: this.editable,
  3803. theme: 'kms1',
  3804. mode: 'full',
  3805. shortcut: {
  3806. enable: false // 是否启用快捷键
  3807. },
  3808. onRelation: this.onRelation,
  3809. view: {
  3810. line_width: 2,
  3811. line_color: '#5385EE'
  3812. }
  3813. }
  3814. var mind = {
  3815. 'meta': {
  3816. 'name': '思维导图JS库',
  3817. 'author': 'Leo',
  3818. 'version': '1.0'
  3819. },
  3820. 'format': 'node_array',
  3821. 'data': this.options.data
  3822. }
  3823. _jm = new jsMind(options);
  3824. _jm.show(mind);
  3825. var innerToolBar = $("<div class='lui-jsmind-innerToolBar'><ul><li class='lui_map_icon_zoom_reset mui mui-history_handler_back' title='还原' data-opt='zoomReset' ></li>" +
  3826. " <li class='lui_map_icon_zoom_in mui mui-addition' title='放大' data-opt='zoomIn'></li> " +
  3827. " <li class='lui_map_icon_zoom_out mui mui-delete' title='缩小' data-opt='zoomOut'></li>" +
  3828. " </ul></div>");
  3829. $(_jm.view.container).prepend(innerToolBar);
  3830. $(_jm.view.container).css("position", "relative");
  3831. var self = this;
  3832. $(innerToolBar).on("click", function(e) {
  3833. var $t = $(e.target),
  3834. type = $t.attr("data-opt");
  3835. if (type) {
  3836. if (self[type]) {
  3837. self[type]();
  3838. }
  3839. }
  3840. });
  3841. }
  3842. // 创建功能按钮
  3843. kmsjsmap._init_button = function() {
  3844. $(function() {
  3845. // 0517去掉 - 内置保存按钮
  3846. // var html = '<a href="javascript: kmsjsmap.onSave()" class="sui-btn btn-xlarge btn-primary">保存思维导图</a>';
  3847. // $('#' + kmsjsmap.options.container).prepend(html);
  3848. // 给每个节点加上右键菜单事件
  3849. $('jmnode').on('contextmenu', kmsjsmap._conTextMenuEvenHandle);
  3850. })
  3851. }
  3852. // 右键菜单方法
  3853. kmsjsmap._conTextMenuEvenHandle = function(e) {
  3854. e.preventDefault();
  3855. if (!kmsjsmap.editable) return;
  3856. // console.log('右键拉拉拉拉')
  3857. $conTextMenu.show().css({
  3858. left: e.pageX,
  3859. top: e.pageY
  3860. })
  3861. }
  3862. kmsjsmap._get_selected_nodeid = function() {
  3863. var selected_node = _jm.get_selected_node();
  3864. if (!!selected_node) {
  3865. return selected_node.id;
  3866. } else {
  3867. return null;
  3868. }
  3869. }
  3870. // 思维导图库JS 保存回调
  3871. kmsjsmap.save = function(cb) {
  3872. var data = _jm.get_data('node_array').data;
  3873. // console.log(data)
  3874. // var cb = this.options.onSave;
  3875. cb && cb(data);
  3876. }
  3877. // 删除节点
  3878. kmsjsmap.del_node = function() {
  3879. var that = this;
  3880. $conTextMenu.hide();
  3881. var flag = confirm('确认删除此节点吗?');
  3882. if (!flag) return;
  3883. var selected_id = that._get_selected_nodeid();
  3884. _jm.remove_node(selected_id);
  3885. }
  3886. // 编辑节点
  3887. kmsjsmap.modify_node = function() {
  3888. $conTextMenu.hide();
  3889. var node = _jm.get_selected_node();
  3890. _jm.begin_edit(node);
  3891. }
  3892. // 新增节点
  3893. kmsjsmap.add_node = function() {
  3894. $conTextMenu.hide();
  3895. var nodeid = jsMind.util.uuid.newid();
  3896. var topic = '请输入子节点名称';
  3897. var node = _jm.add_node(_jm.get_selected_node(), nodeid, topic, {
  3898. badge: 0
  3899. }, 'right');
  3900. // console.log(node);
  3901. _jm.begin_edit(node);
  3902. // 为了给新添加的节点也加上右键菜单
  3903. $('jmnode').off('contextmenu', function() {});
  3904. $('jmnode').on('contextmenu', kmsjsmap._conTextMenuEvenHandle);
  3905. }
  3906. // 关联节点
  3907. kmsjsmap.relation_node = function() {
  3908. $conTextMenu.hide();
  3909. var node = _jm.get_selected_node();
  3910. kmsjsmap.onRelation(node);
  3911. }
  3912. kmsjsmap.screenshot = function() {
  3913. _jm.screenshot.shootDownload();
  3914. }
  3915. kmsjsmap.shootAsDataURL = function(callback) {
  3916. _jm.screenshot.shootAsDataURL(callback);
  3917. }
  3918. kmsjsmap.zoomIn = function() {
  3919. _jm.view.zoomIn();
  3920. }
  3921. kmsjsmap.zoomOut = function() {
  3922. _jm.view.zoomOut();
  3923. }
  3924. kmsjsmap.zoomReset = function() {
  3925. _jm.view.setZoom(1);
  3926. }
  3927. kmsjsmap.fullScreen = function(element) {
  3928. if (!element) element = _jm.view.container;
  3929. var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
  3930. if (requestMethod) requestMethod.call(element);
  3931. }
  3932. kmsjsmap.exitFullscreen = function(element) {
  3933. var elem = document;
  3934. if (elem.webkitCancelFullScreen) {
  3935. elem.webkitCancelFullScreen();
  3936. } else if (elem.mozCancelFullScreen) {
  3937. element.mozCancelFullScreen();
  3938. } else if (elem.cancelFullScreen) {
  3939. elem.cancelFullScreen();
  3940. } else if (elem.exitFullscreen) {
  3941. elem.exitFullscreen();
  3942. } else {
  3943. //浏览器不支持全屏API或已被禁用
  3944. };
  3945. }
  3946. kmsjsmap.setLinkStatus = function(options) {
  3947. var id = options.id;
  3948. var isLink = options.isLink;
  3949. if (!id || typeof isLink !== 'boolean') return logger.error('setLinkStatus传入参数有误');
  3950. var $dom = $('#' + kmsjsmap.options.container).find('jmnode[nodeid="' + id + '"]');
  3951. if (!$dom.length === 0) return;
  3952. var node = _jm.get_selected_node();
  3953. if (isLink) {
  3954. $dom.addClass('isLink');
  3955. node.data.isLink = true;
  3956. } else {
  3957. $dom.removeClass('isLink');
  3958. node.data.isLink = false;
  3959. }
  3960. }
  3961. $w[__NAME__] = kmsjsmap
  3962. })(window);