graph.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*##############################################################################
  2. # Copyright (C) 2011 HPCC Systems.
  3. #
  4. # All rights reserved. This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU Affero General Public License as
  6. # published by the Free Software Foundation, either version 3 of the
  7. # License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU Affero General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Affero General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ############################################################################## */
  17. var labelPopup = null;
  18. var popupWidth = 0;
  19. var popupHeight= 0;
  20. var popupTimerId = null;
  21. var prevWidth = 0;
  22. var prevHeight= 0;
  23. var processingPopup = false;
  24. function resize_graph(svg)
  25. {
  26. if (!svg)
  27. svg=document.getElementById('SVGGraph');
  28. if (!svg)
  29. return;
  30. var root=svg.getSVGDocument().rootElement;
  31. if (!root)
  32. return;
  33. var maxW = svg.offsetWidth;
  34. var maxH = svg.offsetHeight;
  35. if (Math.abs(maxW - prevWidth) < 100 && Math.abs(maxH - prevHeight) < 100)
  36. return;
  37. root.currentScale = 1;
  38. root.currentTranslate.x = 0;
  39. root.currentTranslate.y = 0;
  40. prevWidth = maxW;
  41. prevHeight = maxH;
  42. }
  43. function get_popup_div(popup_id)
  44. {
  45. var frame=document.frames['popupFrame'];
  46. if(!frame)
  47. return null;
  48. var div=frame.document.getElementById('popup_'+popup_id);
  49. if(!div)
  50. return null;
  51. if(div.length)
  52. return null; //multiple
  53. return div;
  54. }
  55. function show_popup(evt, popup_id,x,y)
  56. {
  57. if (processingPopup || !evt || !evt.shiftKey || evt.ctrlKey || evt.altKey)
  58. {
  59. processingPopup = false;
  60. return;
  61. }
  62. processingPopup = true;
  63. if (labelPopup)
  64. hide_popup();
  65. labelPopup = window.createPopup();
  66. var svg=document.getElementById('SVGGraph');
  67. if(!svg)
  68. {
  69. processingPopup = false;
  70. return;
  71. }
  72. if (!labelPopup.isOpen || window.top.activepopup != popup_id)
  73. {
  74. var div = get_popup_div(popup_id);
  75. if (!div)
  76. {
  77. processingPopup = false;
  78. return;
  79. }
  80. if(!x || !y)
  81. {
  82. var o=svg.getSVGDocument().getElementById(popup_id);
  83. if(!o)
  84. {
  85. processingPopup = false;
  86. return;
  87. }
  88. var root=svg.getSVGDocument().rootElement,
  89. scale=root.currentScale,
  90. shift=root.currentTranslate;
  91. var rect=o.getBBox();
  92. x=rect.x*scale+shift.x+rect.width*scale;
  93. y=rect.y*scale+shift.y+rect.height*scale;
  94. }
  95. window.top.activepopup=popup_id;
  96. stop_popup_timer();
  97. var popupBody=labelPopup.document.body;
  98. popupBody.style.border = "outset black 1px";
  99. popupBody.innerHTML=div.innerHTML;
  100. popupBody.style.overflow = "auto";
  101. popupBody.onmouseenter=stop_popup_timer;
  102. popupBody.onmouseleave=start_popup_timer;
  103. var tab = labelPopup.document.getElementById('tab');
  104. var link = labelPopup.document.getElementById('captionRow');
  105. link.style.display = 'block';
  106. labelPopup.show(2000,2000,640,480,null);
  107. popupWidth=tab.clientWidth+2,
  108. popupHeight=tab.clientHeight+2;
  109. if (popupWidth > screen.width)
  110. popupWidth = screen.width;
  111. if (popupHeight > screen.height)
  112. popupHeight = screen.height;
  113. }
  114. else
  115. {
  116. stop_popup_timer();
  117. start_popup_timer();
  118. processingPopup = false;
  119. return;
  120. }
  121. var xp=x+svg.offsetLeft-document.body.scrollLeft+window.screenLeft,
  122. yp=y+svg.offsetTop-document.body.scrollTop+window.screenTop;
  123. labelPopup.show(xp+5,yp+5,popupWidth,popupHeight,null);
  124. start_popup_timer();
  125. processingPopup = false;
  126. }
  127. function hide_popup()
  128. {
  129. stop_popup_timer();
  130. window.top.activepopup=null;
  131. if(labelPopup)
  132. {
  133. if (labelPopup.isOpen)
  134. labelPopup.hide();
  135. labelPopup=null;
  136. }
  137. }
  138. function start_popup_timer()
  139. {
  140. popupTimerId = setTimeout(hide_popup, 2000);//2 seconds
  141. }
  142. function stop_popup_timer()
  143. {
  144. if (popupTimerId)
  145. {
  146. clearTimeout(popupTimerId);
  147. popupTimerId = null;
  148. }
  149. }
  150. function load_svg(srcNode)
  151. {
  152. var svg=document.getElementById('SVGGraph');
  153. if(!svg)
  154. return null;
  155. var win=svg.getWindow();
  156. var doc = win.document;
  157. var srcRoot = srcNode.documentElement;
  158. var newsvg = win.parseXML(srcNode.text, doc);
  159. var root = doc.documentElement;
  160. //remove all existing children from root
  161. for (var child = root.firstChild; child; child = root.firstChild)
  162. root.removeChild(child);
  163. var width = srcRoot.getAttribute('width');
  164. if (width)
  165. root.setAttribute('width', width);
  166. var height = srcRoot.getAttribute('height')
  167. if (height)
  168. root.setAttribute('height', height);
  169. var viewBox = srcRoot.getAttribute('viewBox');
  170. if (viewBox)
  171. root.setAttribute('viewBox', viewBox);
  172. var children = newsvg.firstChild.childNodes;
  173. for (var i=0; i<children.length; i++)
  174. root.appendChild( children.item(i));
  175. return root;
  176. }
  177. function test_svg()
  178. {
  179. try
  180. {
  181. if(document.getElementById('SVGGraph').getAttribute('window'))
  182. {
  183. var re=/.*;\s*(\d+.\d*)/.exec(document.getElementById('SVGGraph').getSVGViewerVersion());
  184. if(re && re[1]>=3.0)
  185. return true;
  186. }
  187. }
  188. catch(e)
  189. {
  190. }
  191. document.getElementById('SVGLink').innerHTML='<br />You need Adobe&reg; SVG Viewer v3.0 to view graphs.'+
  192. 'It can be downloaded <a href="http://www.adobe.com/svg/viewer/install/">here</a>.<br />' +
  193. 'Adobe&reg; SVG Viewer is no longer supported by Adobe.<br />' +
  194. 'If you don&prime;t already have this software installed, please use GVC Graph Viewer Option';
  195. return false;
  196. }
  197. function showNodeOrEdgeDetails(popupId, graphName, wuid, queryName)
  198. {
  199. hide_popup();
  200. processingPopup = true;
  201. var win = window.open("about:blank", "_blank",
  202. "toolbar=no, location=no, directories=no, status=no, menubar=no" +
  203. ", scrollbars=yes, resizable=yes, width=640, height=300");
  204. if (!win)
  205. {
  206. alert("Popup window could not be opened! Please disable any popup killer and try again.");
  207. processingPopup = false;
  208. return;
  209. }
  210. var doc = win.document;
  211. var elementType = popupId.indexOf('_')== -1 ? 'Node':'Edge';
  212. var s = new Array();
  213. var i = 0;
  214. s[i++] = '<h3>Graph ';
  215. s[i++] = elementType;
  216. s[i++] = ' Information</h3>';
  217. var div = get_popup_div(popupId);
  218. if (!div || div.innerHTML.length==0)
  219. {
  220. s[i++] = '<table id="tab" style="font:menu;">';
  221. s[i++] = '<colgroup><col align="left" valign="top"/></colgroup>';
  222. if (wuid || queryName)
  223. {
  224. s[i++] = '<tr><th>';
  225. s[i++] = wuid ? 'workunit' : 'query';
  226. s[i++] = '</th><td>';
  227. s[i++] = wuid ? wuid : queryName;
  228. s[i++] = '</td></tr>';
  229. }
  230. if (graphName)
  231. {
  232. s[i++] = '<tr><th>graph</th><td>';
  233. s[i++] = graphName;
  234. s[i++] = '</td></tr>';
  235. }
  236. s[i++] = '<tr><th>id</th><td>';
  237. s[i++] = popupId;
  238. s[i++] = '</td></tr>';
  239. s[i++] = '<tr><th colspan="2">No additional information is available.</th></tr>';
  240. s[i++] = '</table>';
  241. doc.write( s.join('') );
  242. }
  243. else
  244. {
  245. s[i++] = div.innerHTML;
  246. doc.write( s.join('') );
  247. var row = doc.getElementById('wuRow');
  248. if (wuid && row.cells.length==2 && row.cells[1].innerText != '')
  249. row.style.display = 'block';
  250. if (graphName)
  251. {
  252. row = doc.getElementById('graphNameRow');
  253. row.style.display = 'block';
  254. }
  255. row = doc.getElementById('idRow');
  256. if (row)
  257. row.style.display = 'block';
  258. }
  259. doc.title = elementType + ' ' + popupId + graphName ? (' [' + graphName + ']'): '';
  260. processingPopup = false;
  261. }
  262. var tipsWnd = null;
  263. function showViewingTips()
  264. {
  265. if (tipsWnd)
  266. {
  267. tipsWnd.close();
  268. }
  269. var win = window.open( "about:blank", "_blank",
  270. "toolbar=0,location=0,directories=0,status=0,menubar=0," +
  271. "scrollbars=1, resizable=1, width=640, height=300");
  272. if (!win)
  273. {
  274. alert( "Popup window could not be opened! " +
  275. "Please disable any popup killer and try again.");
  276. }
  277. else
  278. {
  279. tipsWnd = win;
  280. var s = [];
  281. var i = 0;
  282. s[i++] = '<h3>Graph Viewing Tips</h3><table align="left"><colgroup>';
  283. s[i++] = '<col span="*" align="left"/></colgroup><tbody><tr><th>Pan</th>';
  284. s[i++] = '<th>:</th><td>Press Alt key and drag graph with the hand cursor</td>';
  285. s[i++] = '</tr><tr><th nowrap="true">Zoom In</th><th>:</th>';
  286. s[i++] = '<td>Press Ctrl key and click left mouse button</td></tr>';
  287. s[i++] = '<tr><th nowrap="true">Zoom Out</th><th>:</th>';
  288. s[i++] = '<td>Press Shift-Ctrl and click left mouse button</td></tr>';
  289. s[i++] = '<tr><th>Tooltips</th><th>:</th><td>Press Shift key while ';
  290. s[i++] = 'moving cursor over nodes and edges</td></tr><tr valign="top">';
  291. s[i++] = '<th nowrap="true">Increase size</th><th>:</th><td>Collapse ';
  292. s[i++] = 'left frame by dragging or clicking on separator.<br/>Toggle ';
  293. s[i++] = 'full screen view by pressing F11</td></tr><tr valign="top" ';
  294. s[i++] = 'style="border-bottom:gray 1px solid"><th>More</th><th>:</th>';
  295. s[i++] = '<td>The contex menu offers options like: Find, Copy SVG, View ';
  296. s[i++] = 'Source, Zoom In/Out, Save As, and Help</td></tr></tbody></table>';
  297. var doc = win.document.open("text/html", "replace");
  298. doc.write( s.join('') );
  299. doc.title = 'Graph Viewing Tips';
  300. }
  301. }
  302. function go(url)
  303. {
  304. document.location.href=url;
  305. }
  306. var prevFoundPolygon = null;
  307. var prevFill = null;
  308. function findGraphNode(id, svg)
  309. {
  310. if (id.length == 0) {
  311. alert("Please specify a node id to find in graph!");
  312. return;
  313. }
  314. var root = getGraphRoot(svg);
  315. if (!svg)
  316. svg=document.getElementById('SVGGraph');
  317. if (!svg)
  318. return;
  319. var root=svg.getSVGDocument().rootElement;
  320. if (!root)
  321. return;
  322. var node = root.getElementById(id);
  323. var polygon = null;
  324. if (node)
  325. {
  326. var links = node.getElementsByTagName('a');
  327. if (links.length)
  328. {
  329. polygons = links.item(0).getElementsByTagName('polygon');
  330. if (polygons.length)
  331. polygon = polygons.item(0);
  332. }
  333. }
  334. if (polygon != prevFoundPolygon && prevFoundPolygon)
  335. {
  336. if (prevFill == '')
  337. prevFoundPolygon.style.removeProperty('fill');
  338. else
  339. prevFoundPolygon.style.setProperty('fill', prevFill, "");
  340. prevFoundPolygon = null;
  341. }
  342. if (!polygon)
  343. {
  344. alert('Graph node not found!');
  345. resetFindGraphNode();
  346. }
  347. else
  348. if (polygon != prevFoundPolygon)
  349. {
  350. prevFoundPolygon = polygon;
  351. var textNodes = node.getElementsByTagName('text');
  352. if (textNodes.length > 0)
  353. {
  354. var firstChild = textNodes.item(0);
  355. var x = firstChild.getAttribute('x');
  356. var y = firstChild.getAttribute('y');
  357. //get svg plugin dimenstions
  358. var width = svg.offsetWidth;
  359. var height = svg.offsetHeight;
  360. //browser crashes if we zoom in too much so avoid it
  361. //
  362. //get graph dimensions
  363. var maxW = root.getAttribute('width') / 10;
  364. var maxH = root.getAttribute('height') / 10;
  365. width = Math.max(width, maxW);
  366. height = Math.max(height, maxH);
  367. var viewBox = (x-width/2) + ' ' + (y-height/2) + ' ' + width + ' ' + height;
  368. root.currentScale = 1;
  369. root.currentTranslate.x = 0;
  370. root.currentTranslate.y = 0;
  371. root.setAttribute('viewBox', viewBox);
  372. var resetFindBtn = document.getElementById('resetFindBtn');
  373. if (resetFindBtn)
  374. resetFindBtn.disabled = false;
  375. prevFill = polygon.style.getPropertyValue('fill');
  376. polygon.style.setProperty('fill' , 'yellow', "");
  377. }
  378. }
  379. }
  380. function getGraphRoot(svg)
  381. {
  382. if (!svg)
  383. svg=document.getElementById('SVGGraph');
  384. return svg ? svg.getSVGDocument().rootElement : null;
  385. }
  386. function resetFindGraphNode(svg)
  387. {
  388. var root = getGraphRoot(svg);
  389. if (root)
  390. {
  391. root.setAttribute('viewBox', '0 0 ' + root.getAttribute('width') + ' ' + root.getAttribute('height'));
  392. root.currentScale = 1;
  393. root.currentTranslate.x = 0;
  394. root.currentTranslate.y = 0;
  395. }
  396. if (prevFoundPolygon)
  397. {
  398. if (prevFill == '')
  399. prevFoundPolygon.style.removeProperty('fill');
  400. else
  401. prevFoundPolygon.style.setProperty('fill', prevFill, "")
  402. prevFoundPolygon = null;
  403. }
  404. var resetFindBtn = document.getElementById('resetFindBtn');
  405. if (resetFindBtn)
  406. resetFindBtn.disabled = true;
  407. }