GraphWidget.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. /*##############################################################################
  2. # HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. ############################################################################## */
  16. define([
  17. "dojo/_base/declare",
  18. "dojo/_base/lang",
  19. "dojo/i18n",
  20. "dojo/i18n!./nls/common",
  21. "dojo/i18n!./nls/GraphWidget",
  22. "dojo/_base/array",
  23. "dojo/_base/Deferred",
  24. "dojo/aspect",
  25. "dojo/has",
  26. "dojo/dom",
  27. "dojo/dom-construct",
  28. "dojo/dom-class",
  29. "dojo/dom-style",
  30. "dijit/registry",
  31. "dijit/layout/BorderContainer",
  32. "dijit/layout/ContentPane",
  33. "hpcc/_Widget",
  34. "dojo/text!/esp/files/templates/GraphWidget.html",
  35. "dijit/Toolbar",
  36. "dijit/ToolbarSeparator",
  37. "dijit/form/Button"
  38. ], function (declare, lang, i18n, nlsCommon, nlsSpecific, arrayUtil, Deferred, aspect, has, dom, domConstruct, domClass, domStyle,
  39. registry, BorderContainer, ContentPane,
  40. _Widget,
  41. template) {
  42. var GraphView = declare("GraphView", null, {
  43. sourceGraphWidget: null,
  44. rootGlobalIDs: null,
  45. id: null,
  46. depth: null,
  47. distance: null,
  48. xgmml: null,
  49. svg: null,
  50. constructor: function (sourceGraphWidget, rootGlobalIDs, depth, distance, selectedGlobalIDs) {
  51. this.sourceGraphWidget = sourceGraphWidget;
  52. rootGlobalIDs.sort();
  53. this.rootGlobalIDs = rootGlobalIDs;
  54. this.selectedGlobalIDs = selectedGlobalIDs ? selectedGlobalIDs : rootGlobalIDs;
  55. var id = "";
  56. arrayUtil.forEach(this.rootGlobalIDs, function (item, idx) {
  57. if (idx > 0) {
  58. id += ":";
  59. }
  60. id += item;
  61. }, this);
  62. if (depth) {
  63. id += ":" + depth;
  64. }
  65. if (distance) {
  66. id += ":" + distance;
  67. }
  68. this.id = id;
  69. this.depth = depth;
  70. this.distance = distance;
  71. },
  72. changeRootItems: function (globalIDs) {
  73. return this.sourceGraphWidget.getGraphView(globalIDs, this.depth, this.distance);
  74. },
  75. changeScope: function (depth, distance) {
  76. return this.sourceGraphWidget.getGraphView(this.rootGlobalIDs, depth, distance, this.selectedGlobalIDs);
  77. },
  78. refreshXGMML: function (targetGraphWidget) {
  79. targetGraphWidget.setMessage(targetGraphWidget.i18n.FetchingData).then(lang.hitch(this, function (response) {
  80. var rootItems = this.sourceGraphWidget.getItems(this.rootGlobalIDs);
  81. var xgmml = this.sourceGraphWidget.getLocalisedXGMML(rootItems, this.depth, this.distance);
  82. if (targetGraphWidget.loadXGMML(xgmml, true)) {
  83. this.svg = "";
  84. }
  85. targetGraphWidget.setMessage("");
  86. }));
  87. },
  88. refreshLayout: function (targetGraphWidget) {
  89. var context = this;
  90. targetGraphWidget.onLayoutFinished = function () {
  91. context.svg = this._plugin.getSVG();
  92. this.onLayoutFinished = null;
  93. };
  94. targetGraphWidget.startLayout("dot");
  95. },
  96. navigateTo: function (targetGraphWidget, noModifyHistory) {
  97. var deferred = new Deferred();
  98. if (!noModifyHistory) {
  99. targetGraphWidget.graphViewHistory.push(this);
  100. }
  101. if (targetGraphWidget.onLayoutFinished == null) {
  102. targetGraphWidget.setMessage(targetGraphWidget.i18n.FetchingData).then(lang.hitch(this, function (response) {
  103. var rootItems = this.sourceGraphWidget.getItems(this.rootGlobalIDs);
  104. var xgmml = this.sourceGraphWidget.getLocalisedXGMML(rootItems, this.depth, this.distance);
  105. targetGraphWidget.setMessage(targetGraphWidget.i18n.LoadingData).then(lang.hitch(this, function (response) {
  106. var context = this;
  107. if (targetGraphWidget.loadXGMML(xgmml)) {
  108. if (xgmml) {
  109. targetGraphWidget.onLayoutFinished = function () {
  110. this.setSelectedAsGlobalID(context.selectedGlobalIDs);
  111. context.svg = this._plugin.getSVG();
  112. this.onLayoutFinished = null;
  113. if (!noModifyHistory && this.graphViewHistory.getLatest() !== context) {
  114. this.graphViewHistory.getLatest().navigateTo(this);
  115. }
  116. deferred.resolve("Layout Complete.");
  117. };
  118. if (this.svg) {
  119. targetGraphWidget.startCachedLayout(this.svg);
  120. } else {
  121. targetGraphWidget.startLayout("dot");
  122. }
  123. } else {
  124. targetGraphWidget.setMessage(targetGraphWidget.i18n.NothingSelected);
  125. deferred.resolve("No Selection.");
  126. }
  127. } else {
  128. targetGraphWidget.setMessage("");
  129. deferred.resolve("XGMML Did Not Change.");
  130. }
  131. }));
  132. }));
  133. } else {
  134. deferred.resolve("Graph Already in Layout.");
  135. }
  136. return deferred.promise;
  137. }
  138. });
  139. var GraphViewHistory = declare("GraphView", null, {
  140. sourceGraphWidget: null,
  141. history: null,
  142. index: null,
  143. constructor: function (sourceGraphWidget) {
  144. this.sourceGraphWidget = sourceGraphWidget;
  145. this.history = [];
  146. this.index = {};
  147. },
  148. clear: function () {
  149. this.history = [];
  150. this.index = {};
  151. this.sourceGraphWidget.refreshActionState();
  152. },
  153. // Index ----
  154. has: function(id) {
  155. return this.index[id] != null;
  156. },
  157. set: function(id, graphView) {
  158. return this.index[id] = graphView;
  159. },
  160. get: function(id) {
  161. return this.index[id];
  162. },
  163. // History ----
  164. push: function (graphView) {
  165. this.set(graphView.id, graphView);
  166. if (this.hasNext()) {
  167. this.history.splice(this.historicPos + 1, this.history.length);
  168. }
  169. if (this.history[this.history.length - 1] !== graphView) {
  170. this.history.push(graphView);
  171. }
  172. this.historicPos = this.history.length - 1;
  173. this.sourceGraphWidget.refreshActionState();
  174. },
  175. getCurrent: function () {
  176. return this.history[this.historicPos];
  177. },
  178. getLatest: function () {
  179. return this.history[this.history.length - 1];
  180. },
  181. hasPrevious: function () {
  182. return this.historicPos > 0;
  183. },
  184. hasNext: function () {
  185. return this.historicPos < this.history.length - 1;
  186. },
  187. isRootSubgraph: function () {
  188. arrayUtil.forEach(this.history[this.historicPos].rootGlobalIDs, function (item, idx) {
  189. }, this);
  190. },
  191. navigatePrevious: function () {
  192. if (this.hasPrevious()) {
  193. this.historicPos -= 1;
  194. this.history[this.historicPos].navigateTo(this.sourceGraphWidget, true).then(lang.hitch(this, function(response) {
  195. this.sourceGraphWidget.refreshActionState();
  196. }));
  197. }
  198. },
  199. navigateNext: function () {
  200. if (this.hasNext()) {
  201. this.historicPos += 1;
  202. this.history[this.historicPos].navigateTo(this.sourceGraphWidget, true).then(lang.hitch(this, function (response) {
  203. this.sourceGraphWidget.refreshActionState();
  204. }));
  205. }
  206. }
  207. });
  208. return declare("GraphWidget", [_Widget], {
  209. templateString: template,
  210. baseClass: "GraphWidget",
  211. i18n: lang.mixin(nlsCommon, nlsSpecific),
  212. borderContainer: null,
  213. graphContentPane: null,
  214. _isPluginInstalled: false,
  215. _plugin: null,
  216. eventsRegistered: false,
  217. xgmml: null,
  218. dot: "",
  219. svg: "",
  220. isIE11: false,
  221. isIE: false,
  222. // Known control properties ---
  223. DOT_META_ATTR: "DOT_META_ATTR",
  224. constructor: function() {
  225. if (has("ie")) {
  226. this.isIE = true;
  227. } else if (has("trident")) {
  228. this.isIE11 = true;
  229. }
  230. this.graphViewHistory = new GraphViewHistory(this);
  231. },
  232. _onClickRefresh: function () {
  233. var graphView = this.getCurrentGraphView();
  234. graphView.refreshLayout(this);
  235. },
  236. _onClickPrevious: function () {
  237. this.graphViewHistory.navigatePrevious();
  238. },
  239. _onClickNext: function () {
  240. this.graphViewHistory.navigateNext();
  241. },
  242. _onClickZoomOrig: function (args) {
  243. this.setScale(100);
  244. this.centerOnItem(0);
  245. },
  246. _onClickZoomAll: function (args) {
  247. this.centerOnItem(0, true);
  248. },
  249. _onClickZoomWidth: function (args) {
  250. this.centerOnItem(0, true, true);
  251. },
  252. _onDepthChange: function (value) {
  253. this._onRefreshScope();
  254. },
  255. _onDistanceChange: function (value) {
  256. this._onRefreshScope();
  257. },
  258. _onRefreshScope: function () {
  259. var graphView = this.getCurrentGraphView();
  260. if (graphView) {
  261. var depth = this.depth.get("value");
  262. var distance = this.distance.get("value");
  263. graphView = graphView.changeScope(depth, distance);
  264. graphView.navigateTo(this, true);
  265. }
  266. },
  267. _onSyncSelection: function () {
  268. var graphView = this.getCurrentGraphView();
  269. var rootItems = this.getSelectionAsGlobalID();
  270. graphView = graphView.changeRootItems(rootItems);
  271. graphView.navigateTo(this);
  272. },
  273. onSelectionChanged: function (items) {
  274. },
  275. onDoubleClick: function (globalID) {
  276. },
  277. onLayoutFinished: null,
  278. buildRendering: function (args) {
  279. this.inherited(arguments);
  280. },
  281. postCreate: function (args) {
  282. this.inherited(arguments);
  283. this.borderContainer = registry.byId(this.id + "BorderContainer");
  284. this.graphContentPane = registry.byId(this.id + "GraphContentPane");
  285. this.next = registry.byId(this.id + "Next");
  286. this.previous = registry.byId(this.id + "Previous");
  287. this.depth = registry.byId(this.id + "Depth");
  288. this.distance = registry.byId(this.id + "Distance");
  289. this.syncSelection = registry.byId(this.id + "SyncSelection");
  290. },
  291. startup: function (args) {
  292. this.inherited(arguments);
  293. this._isPluginInstalled = this.isPluginInstalled();
  294. this.createPlugin();
  295. this.watchStyleChange();
  296. },
  297. resize: function (args) {
  298. this.inherited(arguments);
  299. this.borderContainer.resize();
  300. },
  301. layout: function (args) {
  302. this.inherited(arguments);
  303. },
  304. // Plugin wrapper ---
  305. showToolbar: function (show) {
  306. if (show) {
  307. domClass.remove(this.id + "Toolbar", "hidden");
  308. } else {
  309. domClass.add(this.id + "Toolbar", "hidden");
  310. }
  311. this.resize();
  312. },
  313. showNextPrevious: function (show) {
  314. if (show) {
  315. domStyle.set(this.previous.domNode, 'display', 'block');
  316. domStyle.set(this.next.domNode, 'display', 'block');
  317. } else {
  318. domStyle.set(this.previous.domNode, 'display', 'none');
  319. domStyle.set(this.next.domNode, 'display', 'none');
  320. }
  321. this.resize();
  322. },
  323. showDistance: function (show) {
  324. if (show) {
  325. domClass.remove(this.id + "DistanceLabel", "hidden");
  326. domStyle.set(this.distance.domNode, 'display', 'block');
  327. } else {
  328. domClass.add(this.id + "DistanceLabel", "hidden");
  329. domStyle.set(this.distance.domNode, 'display', 'none');
  330. }
  331. this.resize();
  332. },
  333. showSyncSelection: function (show) {
  334. if (show) {
  335. domStyle.set(this.syncSelection.domNode, 'display', 'block');
  336. } else {
  337. domStyle.set(this.syncSelection.domNode, 'display', 'none');
  338. }
  339. this.resize();
  340. },
  341. hasPlugin: function () {
  342. return this._plugin !== null;
  343. },
  344. clear: function () {
  345. if (this.hasPlugin()) {
  346. this.xgmml = "";
  347. this.dot = "";
  348. this._plugin.clear();
  349. this.graphViewHistory.clear();
  350. }
  351. },
  352. loadXGMML: function (xgmml, merge) {
  353. if (this.hasPlugin() && this.xgmml !== xgmml) {
  354. this.xgmml = xgmml;
  355. if (merge) {
  356. this._plugin.mergeXGMML(xgmml);
  357. } else {
  358. this._plugin.loadXGMML(xgmml);
  359. }
  360. this.refreshActionState();
  361. return true;
  362. }
  363. return false;
  364. },
  365. mergeXGMML: function (xgmml) {
  366. return this.loadXGMML(xgmml, true);
  367. },
  368. centerOn: function (globalID) {
  369. if (this.hasPlugin()) {
  370. var item = this.getItem(globalID);
  371. if (item) {
  372. this.centerOnItem(item, true);
  373. var items = [item];
  374. this._plugin.setSelected(items, true);
  375. }
  376. }
  377. },
  378. getVersion: function () {
  379. if (this.hasPlugin()) {
  380. return this._plugin.version;
  381. }
  382. return "";
  383. },
  384. getSVG: function () {
  385. return this._plugin.getSVG();
  386. },
  387. getXGMML: function () {
  388. return this.xgmml;
  389. },
  390. localLayout: function(callback) {
  391. var context = this;
  392. require(
  393. ["hpcc/viz"],
  394. function (viz) {
  395. callback(Viz(context.dot, "svg"));
  396. }
  397. );
  398. },
  399. displayProperties: function (globalID, place) {
  400. if (this.hasPlugin()) {
  401. var item = this.getItem(globalID);
  402. if (item) {
  403. var props = this._plugin.getProperties(item);
  404. if (props.id) {
  405. var table = domConstruct.create("h3", {
  406. innerHTML: props.id,
  407. align: "center"
  408. }, place);
  409. delete props.id;
  410. }
  411. if (props.count) {
  412. var table = domConstruct.create("table", { border: 1, cellspacing: 0, width: "100%" }, place);
  413. var tr = domConstruct.create("tr", null, table);
  414. var td = domConstruct.create("td", { innerHTML: this.i18n.Count }, tr);
  415. var td = domConstruct.create("td", {
  416. align: "right",
  417. innerHTML: props.count
  418. }, tr);
  419. delete props.count;
  420. domConstruct.create("br", null, place);
  421. }
  422. if (props.max) {
  423. var table = domConstruct.create("table", { border: 1, cellspacing: 0, width: "100%" }, place);
  424. var tr = domConstruct.create("tr", null, table);
  425. domConstruct.create("th", { innerHTML: " " }, tr);
  426. domConstruct.create("th", { innerHTML: this.i18n.Skew }, tr);
  427. domConstruct.create("th", { innerHTML: this.i18n.Node }, tr);
  428. domConstruct.create("th", { innerHTML: this.i18n.Rows }, tr);
  429. tr = domConstruct.create("tr", null, table);
  430. domConstruct.create("td", { innerHTML: this.i18n.Max }, tr);
  431. domConstruct.create("td", { innerHTML: props.maxskew }, tr);
  432. domConstruct.create("td", { innerHTML: props.maxEndpoint }, tr);
  433. domConstruct.create("td", { innerHTML: props.max }, tr);
  434. tr = domConstruct.create("tr", null, table);
  435. domConstruct.create("td", { innerHTML: this.i18n.Min }, tr);
  436. domConstruct.create("td", { innerHTML: props.minskew }, tr);
  437. domConstruct.create("td", { innerHTML: props.minEndpoint }, tr);
  438. domConstruct.create("td", { innerHTML: props.min }, tr);
  439. delete props.maxskew;
  440. delete props.maxEndpoint;
  441. delete props.max;
  442. delete props.minskew;
  443. delete props.minEndpoint;
  444. delete props.min;
  445. domConstruct.create("br", null, place);
  446. }
  447. if (props.slaves) {
  448. var table = domConstruct.create("table", { border: 1, cellspacing: 0, width: "100%" }, place);
  449. var tr = domConstruct.create("tr", null, table);
  450. domConstruct.create("th", { innerHTML: this.i18n.Slaves }, tr);
  451. domConstruct.create("th", { innerHTML: this.i18n.Started }, tr);
  452. domConstruct.create("th", { innerHTML: this.i18n.Stopped }, tr);
  453. tr = domConstruct.create("tr", null, table);
  454. domConstruct.create("td", { innerHTML: props.slaves }, tr);
  455. domConstruct.create("td", { innerHTML: props.started }, tr);
  456. domConstruct.create("td", { innerHTML: props.stopped }, tr);
  457. delete props.slaves;
  458. delete props.started;
  459. delete props.stopped;
  460. domConstruct.create("br", null, place);
  461. }
  462. var first = true;
  463. var table = {};
  464. var tr = {};
  465. for (var key in props) {
  466. if (key[0] == "_")
  467. continue;
  468. if (first) {
  469. first = false;
  470. table = domConstruct.create("table", { border: 1, cellspacing: 0, width: "100%" }, place);
  471. tr = domConstruct.create("tr", null, table);
  472. domConstruct.create("th", { innerHTML: this.i18n.Property }, tr);
  473. domConstruct.create("th", { innerHTML: this.i18n.Value }, tr);
  474. }
  475. tr = domConstruct.create("tr", null, table);
  476. domConstruct.create("td", { innerHTML: key }, tr);
  477. domConstruct.create("td", { innerHTML: props[key] }, tr);
  478. }
  479. if (first == false) {
  480. domConstruct.create("br", null, place);
  481. }
  482. }
  483. }
  484. },
  485. isPluginInstalled: function () {
  486. if (this.isIE || this.isIE11) {
  487. try {
  488. var o = new ActiveXObject("HPCCSystems.HPCCSystemsGraphViewControl.1");
  489. o = null;
  490. return true;
  491. } catch (e) { }
  492. return false;
  493. } else {
  494. for (var i = 0, p = navigator.plugins, l = p.length; i < l; i++) {
  495. if (p[i].name.indexOf("HPCCSystemsGraphViewControl") > -1) {
  496. return true;
  497. }
  498. }
  499. return false;
  500. }
  501. },
  502. createPlugin: function () {
  503. if (!this.hasPlugin()) {
  504. if (this._isPluginInstalled) {
  505. var pluginID = this.id + "Plugin";
  506. if (this.isIE || this.isIE11) {
  507. this.graphContentPane.domNode.innerHTML = '<object type="application/x-hpccsystemsgraphviewcontrol" '
  508. + 'id="' + pluginID + '" '
  509. + 'name="' + pluginID + '" '
  510. + 'width="100%" '
  511. + 'height="100%">'
  512. + '</object>';
  513. } else {
  514. this.graphContentPane.domNode.innerHTML = '<embed type="application/x-hpccsystemsgraphviewcontrol" '
  515. + 'id="' + pluginID + '" '
  516. + 'name="' + pluginID + '" '
  517. + 'width="100%" '
  518. + 'height="100%">'
  519. + '</embed>';
  520. }
  521. this.checkPluginLoaded(pluginID).then(lang.hitch(this, function (response) {
  522. this.version = response;
  523. this._plugin = dom.byId(pluginID);
  524. this.registerEvents();
  525. this.emit("ready");
  526. }));
  527. } else {
  528. domConstruct.create("div", {
  529. innerHTML: "<h4>" + this.i18n.GraphView + "</h4>" +
  530. "<p>" + this.i18n.Toenablegraphviews + ":</p>" +
  531. this.getResourceLinks()
  532. }, this.graphContentPane.domNode);
  533. }
  534. }
  535. },
  536. checkPluginLoaded: function (pluginID) {
  537. var deferred = new Deferred();
  538. var doCheck = function () {
  539. domNode = dom.byId(pluginID);
  540. if (domNode && domNode.version) {
  541. return {
  542. version: domNode.version,
  543. major: domNode.version_major,
  544. minor: domNode.version_minor,
  545. point: domNode.version_point,
  546. sequence: domNode.version_sequence
  547. };
  548. }
  549. return null;
  550. };
  551. var doBackGroundCheck = function () {
  552. setTimeout(function () {
  553. var version = doCheck();
  554. if (version) {
  555. deferred.resolve(version);
  556. } else {
  557. doBackGroundCheck();
  558. }
  559. }, 20);
  560. };
  561. doBackGroundCheck();
  562. return deferred.promise;
  563. },
  564. getResourceLinks: function () {
  565. return "<a href=\"http://hpccsystems.com/download/free-community-edition/graph-control\" target=\"_blank\">" + this.i18n.BinaryInstalls + "</a><br/>" +
  566. "<a href=\"https://github.com/hpcc-systems/GraphControl\" target=\"_blank\">" + this.i18n.SourceCode + "</a><br/><br/>" +
  567. "<a href=\"http://hpccsystems.com\" target=\"_blank\">" + this.i18n.HPCCSystems + "</a>"
  568. },
  569. setMessage: function (message) {
  570. var deferred = new Deferred();
  571. var retVal = this._plugin ? this._plugin.setMessage(message) : null;
  572. setTimeout(function () {
  573. deferred.resolve(retVal);
  574. }, 20);
  575. return deferred.promise;
  576. },
  577. getLocalisedXGMML: function (selectedItems, depth, distance) {
  578. if (this.hasPlugin()) {
  579. return this._plugin.getLocalisedXGMML(selectedItems, depth, distance);
  580. }
  581. return null;
  582. },
  583. getCurrentGraphView: function () {
  584. return this.graphViewHistory.getCurrent();
  585. },
  586. getGraphView: function (rootGlobalIDs, depth, distance, selectedGlobalIDs) {
  587. var retVal = new GraphView(this, rootGlobalIDs, depth, distance, selectedGlobalIDs);
  588. if (this.graphViewHistory.has(retVal.id)) {
  589. retVal = this.graphViewHistory.get(retVal.id);
  590. } else {
  591. this.graphViewHistory.set(retVal.id, retVal);
  592. }
  593. return retVal;
  594. },
  595. mergeSVG: function (svg) {
  596. if (this.hasPlugin()) {
  597. return this._plugin.mergeSVG(svg);
  598. }
  599. return null;
  600. },
  601. startCachedLayout: function (svg) {
  602. if (this.hasPlugin()) {
  603. var context = this;
  604. this.setMessage(this.i18n.LoadingCachedLayout).then(function (response) {
  605. context._plugin.mergeSVG(svg);
  606. context._onLayoutFinished();
  607. });
  608. }
  609. },
  610. startLayout: function (layout) {
  611. if (this.hasPlugin()) {
  612. this.setMessage(this.i18n.PerformingLayout);
  613. this._plugin.startLayout(layout);
  614. }
  615. },
  616. _onLayoutFinished: function() {
  617. this.centerOnItem(0, true);
  618. this.dot = this._plugin.getDOT();
  619. this.setMessage('');
  620. if (this.onLayoutFinished) {
  621. this.onLayoutFinished();
  622. }
  623. },
  624. find: function (findText) {
  625. if (this.hasPlugin()) {
  626. return this._plugin.find(findText);
  627. }
  628. return [];
  629. },
  630. findAsGlobalID: function (findText) {
  631. if (this.hasPlugin()) {
  632. var items = this.find(findText);
  633. var foundItem = this.getItem(findText);
  634. if (foundItem) {
  635. items.unshift(foundItem);
  636. }
  637. var globalIDs = [];
  638. for (var i = 0; i < items.length; ++i) {
  639. globalIDs.push(this._plugin.getGlobalID(items[i]));
  640. }
  641. return globalIDs;
  642. }
  643. return [];
  644. },
  645. setScale: function(percent) {
  646. if (this.hasPlugin()) {
  647. return this._plugin.setScale(percent);
  648. }
  649. return 100;
  650. },
  651. centerOnItem: function (item, scaleToFit, widthOnly) {
  652. if (this.hasPlugin()) {
  653. return this._plugin.centerOnItem(item, scaleToFit, widthOnly);
  654. }
  655. return null;
  656. },
  657. centerOnGlobalID: function (globalID, scaleToFit, widthOnly) {
  658. if (this.hasPlugin()) {
  659. var item = this.getItem(globalID);
  660. if (item) {
  661. return this.centerOnItem(item, scaleToFit, widthOnly);
  662. }
  663. }
  664. return null;
  665. },
  666. setSelected: function (items) {
  667. if (this.hasPlugin()) {
  668. return this._plugin.setSelected(items);
  669. }
  670. return null;
  671. },
  672. setSelectedAsGlobalID: function (items) {
  673. if (this.hasPlugin()) {
  674. var retVal = this._plugin.setSelectedAsGlobalID(items);
  675. this.refreshActionState();
  676. return retVal;
  677. }
  678. return null;
  679. },
  680. getSelection: function () {
  681. if (this.hasPlugin()) {
  682. return this._plugin.getSelection();
  683. }
  684. return [];
  685. },
  686. getSelectionAsGlobalID: function () {
  687. if (this.hasPlugin()) {
  688. return this._plugin.getSelectionAsGlobalID();
  689. }
  690. return [];
  691. },
  692. getItem: function (globalID) {
  693. if (this.hasPlugin()) {
  694. var retVal = this._plugin.getItem(globalID);
  695. if (retVal === -1) {
  696. retVal = null;
  697. }
  698. return retVal;
  699. }
  700. return null;
  701. },
  702. getItems: function (globalIDs) {
  703. var retVal = [];
  704. if (this.hasPlugin()) {
  705. arrayUtil.forEach(globalIDs, function (globalID, idx) {
  706. var item = this.getItem(globalID);
  707. if (item !== null) {
  708. retVal.push(item);
  709. }
  710. }, this);
  711. }
  712. return retVal;
  713. },
  714. hide: function () {
  715. if (this.hasPlugin()) {
  716. dojo.style(this._plugin, "width", "1px");
  717. dojo.style(this._plugin, "height", "1px");
  718. }
  719. },
  720. show: function () {
  721. if (this.hasPlugin()) {
  722. dojo.style(this._plugin, "width", "100%");
  723. dojo.style(this._plugin, "height", "100%");
  724. }
  725. },
  726. watchSplitter: function (splitter) {
  727. if (has("chrome")) {
  728. // Chrome can ignore splitter events
  729. return;
  730. }
  731. var context = this;
  732. dojo.connect(splitter, "_startDrag", function () {
  733. context.hide();
  734. });
  735. dojo.connect(splitter, "_stopDrag", function (evt) {
  736. context.show();
  737. });
  738. },
  739. watchSelect: function (select) {
  740. if (select) {
  741. // Only chrome needs to monitor select drop downs.
  742. var context = this;
  743. select.watch("_opened", function () {
  744. if (select._opened) {
  745. context.hide();
  746. } else {
  747. context.show();
  748. }
  749. });
  750. }
  751. },
  752. watchStyleChange: function () {
  753. // Prevent control from being "hidden" as it gets destroyed on Chrome/FF/(Maybe IE11?)
  754. var watchList = [];
  755. var context = this;
  756. var domNode = this.domNode;
  757. // There are many places that may cause the plugin to be hidden, the possible places are calculated by walking the hierarchy upwards.
  758. while (domNode) {
  759. if (domNode.id) {
  760. watchList[domNode.id] = false;
  761. }
  762. domNode = domNode.parentElement;
  763. }
  764. // Hijack the dojo style class replacement call and monitor for elements in our watchList.
  765. aspect.around(domClass, "replace", function (origFunc) {
  766. return function (node, addStyle, removeStyle) {
  767. if (node.firstChild && (node.firstChild.id in watchList)) {
  768. if (addStyle == "dijitHidden") {
  769. watchList[node.firstChild.id] = true;
  770. dojo.style(node, "width", "1px");
  771. dojo.style(node, "height", "1px");
  772. dojo.style(node.firstChild, "width", "1px");
  773. dojo.style(node.firstChild, "height", "1px");
  774. return;
  775. } else if (addStyle == "dijitVisible" && watchList[node.firstChild.id] == true) {
  776. watchList[node.firstChild.id] = false;
  777. dojo.style(node, "width", "100%");
  778. dojo.style(node, "height", "100%");
  779. dojo.style(node.firstChild, "width", "100%");
  780. dojo.style(node.firstChild, "height", "100%");
  781. return;
  782. }
  783. }
  784. return origFunc(node, addStyle, removeStyle);
  785. }
  786. });
  787. },
  788. getDotMetaAttributes: function () {
  789. if (this._plugin && this._plugin.getControlProperty) {
  790. return this._plugin.getControlProperty(this.DOT_META_ATTR);
  791. }
  792. return "";
  793. },
  794. setDotMetaAttributes: function (dotMetaAttr) {
  795. if (this._plugin && this._plugin.setControlProperty) {
  796. this._plugin.setControlProperty(this.DOT_META_ATTR, dotMetaAttr);
  797. }
  798. },
  799. getProperty: function (item, key) {
  800. if (this._plugin && this._plugin.getProperty) {
  801. return this._plugin.getProperty(item, key);
  802. }
  803. return "";
  804. },
  805. setProperty: function (item, key, value) {
  806. if (this._plugin && this._plugin.setProperty) {
  807. this._plugin.setProperty(item, key, value);
  808. }
  809. },
  810. getProperties: function (item) {
  811. if (this.hasPlugin()) {
  812. return this._plugin.getProperties(item);
  813. }
  814. return [];
  815. },
  816. getSubgraphsWithProperties: function () {
  817. if (this.hasPlugin()) {
  818. return this._plugin.getSubgraphsWithProperties();
  819. }
  820. return [];
  821. },
  822. getVerticesWithProperties: function () {
  823. if (this.hasPlugin()) {
  824. return this._plugin.getVerticesWithProperties();
  825. }
  826. return [];
  827. },
  828. getEdgesWithProperties: function () {
  829. if (this.hasPlugin()) {
  830. return this._plugin.getEdgesWithProperties();
  831. }
  832. return [];
  833. },
  834. registerEvents: function () {
  835. if (!this.eventsRegistered) {
  836. this.eventsRegistered = true;
  837. var context = this;
  838. this.registerEvent("MouseDoubleClick", function (item) {
  839. context.onDoubleClick(context._plugin.getGlobalID(item));
  840. });
  841. this.registerEvent("LayoutFinished", function () {
  842. context._onLayoutFinished();
  843. });
  844. this.registerEvent("SelectionChanged", function (items) {
  845. context.refreshActionState();
  846. context.onSelectionChanged(items);
  847. });
  848. }
  849. },
  850. registerEvent: function (evt, func) {
  851. if (this.hasPlugin()) {
  852. if (this.isIE11) {
  853. this._plugin["on" + evt] = func;
  854. } else if (this._plugin.attachEvent !== undefined) {
  855. return this._plugin.attachEvent("on" + evt, func);
  856. } else {
  857. return this._plugin.addEventListener(evt, func, false);
  858. }
  859. }
  860. return false;
  861. },
  862. refreshActionState: function () {
  863. this.setDisabled(this.id + "Previous", !this.graphViewHistory.hasPrevious(), "iconLeft", "iconLeftDisabled");
  864. this.setDisabled(this.id + "Next", !this.graphViewHistory.hasNext(), "iconRight", "iconRightDisabled");
  865. var selection = this.getSelection();
  866. this.setDisabled(this.id + "SyncSelection", !this.getSelection().length, "iconSync", "iconSyncDisabled");
  867. }
  868. });
  869. });