RGraph.common.context.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. /**
  2. * o------------------------------------------------------------------------------o
  3. * | This file is part of the RGraph package - you can learn more at: |
  4. * | |
  5. * | http://www.rgraph.net |
  6. * | |
  7. * | This package is licensed under the RGraph license. For all kinds of business |
  8. * | purposes there is a small one-time licensing fee to pay and for non |
  9. * | commercial purposes it is free to use. You can read the full license here: |
  10. * | |
  11. * | http://www.rgraph.net/license |
  12. * o------------------------------------------------------------------------------o
  13. */
  14. if (typeof(RGraph) == 'undefined') RGraph = {isRGraph:true,type:'common'};
  15. /**
  16. * This gunction shows a context menu containing the parameters
  17. * provided to it
  18. *
  19. * @param object canvas The canvas object
  20. * @param array menuitems The context menu menuitems
  21. * @param object e The event object
  22. */
  23. RGraph.Contextmenu = function (obj, menuitems, e)
  24. {
  25. var canvas = obj.canvas;
  26. e = RGraph.FixEventObject(e);
  27. /**
  28. * Fire the custom RGraph event onbeforecontextmenu
  29. */
  30. RGraph.FireCustomEvent(obj, 'onbeforecontextmenu');
  31. /**
  32. * Hide any existing menu
  33. */
  34. if (RGraph.Registry.Get('chart.contextmenu')) {
  35. RGraph.HideContext();
  36. }
  37. // Hide any zoomed canvas
  38. RGraph.HideZoomedCanvas();
  39. /**
  40. * Hide the palette if necessary
  41. */
  42. RGraph.HidePalette();
  43. /**
  44. * This is here to ensure annotating is OFF
  45. */
  46. obj.Set('chart.mousedown', false);
  47. var x = e.pageX;
  48. var y = e.pageY;
  49. var div = document.createElement('div');
  50. var bg = document.createElement('div');
  51. div.className = 'RGraph_contextmenu';
  52. div.__canvas__ = canvas; /* Store a reference to the canvas on the contextmenu object */
  53. div.style.position = 'absolute';
  54. div.style.left = 0;
  55. div.style.top = 0;
  56. div.style.border = '1px solid black';
  57. div.style.backgroundColor = 'white';
  58. div.style.boxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
  59. div.style.MozBoxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
  60. div.style.WebkitBoxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
  61. div.style.filter = 'progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa,direction=135)';
  62. div.style.opacity = 0;
  63. bg.className = 'RGraph_contextmenu_background';
  64. bg.style.position = 'absolute';
  65. bg.style.backgroundColor = '#ccc';
  66. bg.style.borderRight = '1px solid #aaa';
  67. bg.style.top = 0;
  68. bg.style.left = 0;
  69. bg.style.width = '18px';
  70. bg.style.height = '100%';
  71. bg.style.opacity = 0;
  72. div = document.body.appendChild(div);
  73. bg = div.appendChild(bg);
  74. /**
  75. * Now add the context menu items
  76. */
  77. for (i=0; i<menuitems.length; ++i) {
  78. var menuitem = document.createElement('div');
  79. menuitem.__object__ = obj;
  80. menuitem.__canvas__ = canvas;
  81. menuitem.__contextmenu__ = div;
  82. menuitem.className = 'RGraph_contextmenu_item';
  83. if (menuitems[i]) {
  84. menuitem.style.padding = '2px 5px 2px 23px';
  85. menuitem.style.fontFamily = 'Arial';
  86. menuitem.style.fontSize = '10pt';
  87. menuitem.style.fontWeight = 'normal';
  88. menuitem.innerHTML = menuitems[i][0];
  89. if (RGraph.is_array(menuitems[i][1])) {
  90. menuitem.style.backgroundImage = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAQUlEQVQImY3NoQ2AMABE0ZewABMyGQ6mqWODzlAclBSFO8HZl8uf0FFxCHtwYkt4Y6ChYE44cGH9/fyae2p2LAleW9oVTQuVf6gAAAAASUVORK5CYII=)';
  91. menuitem.style.backgroundRepeat = 'no-repeat';
  92. menuitem.style.backgroundPosition = '97% center';
  93. }
  94. // Add the mouseover event
  95. if (menuitems[i][1]) {
  96. if (menuitem.addEventListener) {
  97. menuitem.addEventListener("mouseover", function (e) {RGraph.HideContextSubmenu(); e.target.style.backgroundColor = 'rgba(0,0,0,0.2)'; e.target.style.cursor = 'pointer';}, false);
  98. menuitem.addEventListener("mouseout", function (e) {e.target.style.backgroundColor = 'inherit'; e.target.style.cursor = 'default';}, false);
  99. } else {
  100. menuitem.attachEvent("onmouseover", function () {RGraph.HideContextSubmenu();event.srcElement.style.backgroundColor = '#eee';event.srcElement.style.cursor = 'pointer';}
  101. , false);
  102. menuitem.attachEvent("onmouseout", function () {event.srcElement.style.backgroundColor = 'inherit'; event.srcElement.style.cursor = 'default';}, false);
  103. }
  104. } else {
  105. if (menuitem.addEventListener) {
  106. menuitem.addEventListener("mouseover", function (e) {e.target.style.cursor = 'default';}, false);
  107. menuitem.addEventListener("mouseout", function (e) {e.target.style.cursor = 'default';}, false);
  108. } else {
  109. menuitem.attachEvent("onmouseover", function () {event.srcElement.style.cursor = 'default'}, false);
  110. menuitem.attachEvent("onmouseout", function () {event.srcElement.style.cursor = 'default';}, false);
  111. }
  112. }
  113. } else {
  114. menuitem.style.borderBottom = '1px solid #ddd';
  115. menuitem.style.marginLeft = '25px';
  116. }
  117. div.appendChild(menuitem);
  118. /**
  119. * Install the event handler that calls the menuitem
  120. */
  121. if (menuitems[i] && menuitems[i][1] && typeof(menuitems[i][1]) == 'function') {
  122. menuitem.addEventListener('click', menuitems[i][1], false);
  123. // Submenu
  124. } else if (menuitems[i] && menuitems[i][1] && RGraph.is_array(menuitems[i][1])) {
  125. (function ()
  126. {
  127. var tmp = menuitems[i][1]; // This is here because of "references vs primitives" and how they're passed around in Javascript
  128. // TODO This may need attention
  129. menuitem.addEventListener('mouseover', function (e) {RGraph.Contextmenu_submenu(obj, tmp, e.target);}, false);
  130. })();
  131. }
  132. }
  133. /**
  134. * Now all the menu items have been added, set the shadow width
  135. * Shadow now handled by CSS3?
  136. */
  137. div.style.width = (div.offsetWidth + 10) + 'px';
  138. div.style.height = (div.offsetHeight - 2) + 'px';
  139. // Show the menu to the left or the right (normal) of the cursor?
  140. if (x + div.offsetWidth > document.body.offsetWidth) {
  141. x -= div.offsetWidth;
  142. }
  143. // Reposition the menu (now we have the real offsetWidth)
  144. div.style.left = x + 'px';
  145. div.style.top = y + 'px';
  146. /**
  147. * Do a little fade in effect
  148. */
  149. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 0.2", 50);
  150. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 0.4", 100);
  151. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 0.6", 150);
  152. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 0.8", 200);
  153. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 1", 250);
  154. // The fade in effect on the left gray bar
  155. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 0.2", 50);
  156. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 0.4", 100);
  157. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 0.6", 150);
  158. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 0.8", 200);
  159. setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 1", 250);
  160. // Store the context menu in the registry
  161. RGraph.Registry.Set('chart.contextmenu', div);
  162. RGraph.Registry.Set('chart.contextmenu.bg', bg);
  163. RGraph.Registry.Get('chart.contextmenu').oncontextmenu = function () {return false;};
  164. RGraph.Registry.Get('chart.contextmenu.bg').oncontextmenu = function () {return false;};
  165. /**
  166. * Install the event handlers that hide the context menu
  167. */
  168. canvas.addEventListener('click', function () {RGraph.HideContext();}, false);
  169. window.addEventListener('click', function ()
  170. {
  171. RGraph.HideContext();
  172. }, false);
  173. window.addEventListener('resize', function ()
  174. {
  175. RGraph.HideContext();
  176. }, false);
  177. /**
  178. * Add the __shape__ object to the context menu
  179. */
  180. /**
  181. * Set the shape coords from the .getShape() method
  182. */
  183. if (typeof(obj.getShape) == 'function') {
  184. RGraph.Registry.Get('chart.contextmenu').__shape__ = obj.getShape(e);
  185. }
  186. e.stopPropagation();
  187. /**
  188. * Fire the (RGraph) oncontextmenu event
  189. */
  190. RGraph.FireCustomEvent(obj, 'oncontextmenu');
  191. return false;
  192. }
  193. /**
  194. * Hides the context menu if it's currently visible
  195. */
  196. RGraph.HideContext = function ()
  197. {
  198. var cm = RGraph.Registry.Get('chart.contextmenu');
  199. var cmbg = RGraph.Registry.Get('chart.contextmenu.bg');
  200. //Hide any submenu currently being displayed
  201. RGraph.HideContextSubmenu();
  202. if (cm) {
  203. cm.parentNode.removeChild(cm);
  204. cmbg.parentNode.removeChild(cmbg);
  205. cm.style.visibility = 'hidden';
  206. cm.style.display = 'none';
  207. RGraph.Registry.Set('chart.contextmenu', null);
  208. cmbg.style.visibility = 'hidden';
  209. cmbg.style.display = 'none';
  210. RGraph.Registry.Set('chart.contextmenu.bg', null);
  211. }
  212. }
  213. /**
  214. * Hides the context menus SUBMENU if it's currently visible
  215. */
  216. RGraph.HideContextSubmenu = function ()
  217. {
  218. var sub = RGraph.Registry.Get('chart.contextmenu.submenu');
  219. if (sub) {
  220. sub.style.visibility = 'none';
  221. sub.style.display = 'none';
  222. RGraph.Registry.Set('chart.contextmenu.submenu', null);
  223. }
  224. }
  225. /**
  226. * Shows the context menu after making a few checks - not opera (doesn't support oncontextmenu,
  227. * not safari (tempermentality), not chrome (hmmm)
  228. */
  229. RGraph.ShowContext = function (obj)
  230. {
  231. RGraph.HidePalette();
  232. if (obj.Get('chart.contextmenu') && obj.Get('chart.contextmenu').length) {
  233. var isOpera = navigator.userAgent.indexOf('Opera') >= 0;
  234. var isSafari = navigator.userAgent.indexOf('Safari') >= 0;
  235. var isChrome = navigator.userAgent.indexOf('Chrome') >= 0;
  236. var isMacFirefox = navigator.userAgent.indexOf('Firefox') > 0 && navigator.userAgent.indexOf('Mac') > 0;
  237. var isIE9 = navigator.userAgent.indexOf('MSIE 9') >= 0;
  238. if (((!isOpera && !isSafari) || isChrome) && !isMacFirefox) {
  239. obj.canvas.oncontextmenu = function (e)
  240. {
  241. e = RGraph.FixEventObject(e);
  242. if (e.ctrlKey) return true;
  243. RGraph.Contextmenu(obj, obj.Get('chart.contextmenu'), e);
  244. return false;
  245. }
  246. // Accomodate Opera and Safari - use double click event
  247. } else {
  248. obj.canvas.addEventListener('dblclick', function (e)
  249. {
  250. if (e.ctrlKey) return true;
  251. if (!RGraph.Registry.Get('chart.contextmenu')) {
  252. RGraph.Contextmenu(obj, obj.Get('chart.contextmenu'), e);
  253. }
  254. }, false);
  255. }
  256. }
  257. }
  258. /**
  259. * This draws a submenu should it be necessary
  260. *
  261. * @param object obj The graph object
  262. * @param object menu The context menu
  263. */
  264. RGraph.Contextmenu_submenu = function (obj, menuitems, parentMenuItem)
  265. {
  266. RGraph.HideContextSubmenu();
  267. var canvas = obj.canvas;
  268. var context = obj.context;
  269. var menu = parentMenuItem.parentNode;
  270. var subMenu = document.createElement('DIV');
  271. subMenu.style.position = 'absolute';
  272. subMenu.style.width = '100px';
  273. subMenu.style.top = menu.offsetTop + parentMenuItem.offsetTop + 'px';
  274. subMenu.style.left = (menu.offsetLeft + menu.offsetWidth - (RGraph.isOld() ? 9 : 0)) + 'px';
  275. subMenu.style.backgroundColor = 'white';
  276. subMenu.style.border = '1px solid black';
  277. subMenu.className = 'RGraph_contextmenu';
  278. subMenu.__contextmenu__ = menu;
  279. subMenu.style.boxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
  280. subMenu.style.MozBoxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
  281. subMenu.style.WebkitBoxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
  282. subMenu.style.filter = 'progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa,direction=135)';
  283. document.body.appendChild(subMenu);
  284. for (var i=0; i<menuitems.length; ++i) {
  285. var menuitem = document.createElement('DIV');
  286. menuitem.__canvas__ = canvas;
  287. menuitem.__contextmenu__ = menu;
  288. menuitem.className = 'RGraph_contextmenu_item';
  289. if (menuitems[i]) {
  290. menuitem.style.padding = '2px 5px 2px 23px';
  291. menuitem.style.fontFamily = 'Arial';
  292. menuitem.style.fontSize = '10pt';
  293. menuitem.style.fontWeight = 'normal';
  294. menuitem.innerHTML = menuitems[i][0];
  295. if (menuitems[i][1]) {
  296. if (menuitem.addEventListener) {
  297. menuitem.addEventListener("mouseover", function (e) {e.target.style.backgroundColor = 'rgba(0,0,0,0.2)'; e.target.style.cursor = 'pointer';}, false);
  298. menuitem.addEventListener("mouseout", function (e) {e.target.style.backgroundColor = 'inherit'; e.target.style.cursor = 'default';}, false);
  299. } else {
  300. menuitem.attachEvent("onmouseover", function () {event.srcElement.style.backgroundColor = 'rgba(0,0,0,0.2)'; event.srcElement.style.cursor = 'pointer'}, false);
  301. menuitem.attachEvent("onmouseout", function () {event.srcElement.style.backgroundColor = 'inherit'; event.srcElement.style.cursor = 'default';}, false);
  302. }
  303. } else {
  304. if (menuitem.addEventListener) {
  305. menuitem.addEventListener("mouseover", function (e) {e.target.style.cursor = 'default';}, false);
  306. menuitem.addEventListener("mouseout", function (e) {e.target.style.cursor = 'default';}, false);
  307. } else {
  308. menuitem.attachEvent("onmouseover", function () {event.srcElement.style.cursor = 'default'}, false);
  309. menuitem.attachEvent("onmouseout", function () {event.srcElement.style.cursor = 'default';}, false);
  310. }
  311. }
  312. } else {
  313. menuitem.style.borderBottom = '1px solid #ddd';
  314. menuitem.style.marginLeft = '25px';
  315. }
  316. subMenu.appendChild(menuitem);
  317. if (menuitems[i] && menuitems[i][1]) {
  318. if (document.all) {
  319. menuitem.attachEvent('onclick', menuitems[i][1]);
  320. } else {
  321. menuitem.addEventListener('click', menuitems[i][1], false);
  322. }
  323. }
  324. }
  325. var bg = document.createElement('DIV');
  326. bg.className = 'RGraph_contextmenu_background';
  327. bg.style.position = 'absolute';
  328. bg.style.backgroundColor = '#ccc';
  329. bg.style.borderRight = '1px solid #aaa';
  330. bg.style.top = 0;
  331. bg.style.left = 0;
  332. bg.style.width = '18px';
  333. bg.style.height = '100%';
  334. bg = subMenu.appendChild(bg);
  335. RGraph.Registry.Set('chart.contextmenu.submenu', subMenu);
  336. }
  337. /**
  338. * A function designed to be used in conjunction with thed context menu
  339. * to allow people to get image versions of canvases.
  340. *
  341. * @param canvas Optionally you can pass in the canvas, which will be used
  342. */
  343. RGraph.showPNG = function ()
  344. {
  345. if (RGraph.isIE8()) {
  346. alert('[RGRAPH PNG] Sorry, showing a PNG is not supported on MSIE8.');
  347. return;
  348. }
  349. if (arguments[0] && arguments[0].id) {
  350. var canvas = arguments[0];
  351. var event = arguments[1];
  352. } else if (RGraph.Registry.Get('chart.contextmenu')) {
  353. var canvas = RGraph.Registry.Get('chart.contextmenu').__canvas__;
  354. } else {
  355. alert('[RGRAPH SHOWPNG] Could not find canvas!');
  356. }
  357. var obj = canvas.__object__;
  358. /**
  359. * Create the gray background DIV to cover the page
  360. */
  361. var bg = document.createElement('DIV');
  362. bg.id = '__rgraph_image_bg__';
  363. bg.style.position = 'fixed';
  364. bg.style.top = '-10px';
  365. bg.style.left = '-10px';
  366. bg.style.width = '5000px';
  367. bg.style.height = '5000px';
  368. bg.style.backgroundColor = 'rgb(204,204,204)';
  369. bg.style.opacity = 0;
  370. document.body.appendChild(bg);
  371. /**
  372. * Create the div that the graph sits in
  373. */
  374. var div = document.createElement('DIV');
  375. div.style.backgroundColor = 'white';
  376. div.style.opacity = 0;
  377. div.style.border = '1px solid black';
  378. div.style.position = 'fixed';
  379. div.style.top = '20%';
  380. div.style.width = canvas.width + 'px';
  381. div.style.height = canvas.height + 35 + 'px';
  382. div.style.left = (document.body.clientWidth / 2) - (canvas.width / 2) + 'px';
  383. div.style.padding = '5px';
  384. div.style.borderRadius = '10px';
  385. div.style.MozBorderRadius = '10px';
  386. div.style.WebkitBorderRadius = '10px';
  387. div.style.boxShadow = '0 0 15px rgba(96,96,96,0.5)';
  388. div.style.MozBoxShadow = '0 0 15px rgba(96,96,96,0.5)';
  389. div.style.WebkitBoxShadow = 'rgba(96,96,96,0.5) 0 0 15px';
  390. div.__canvas__ = canvas;
  391. div.__object__ = obj;
  392. div.id = '__rgraph_image_div__';
  393. document.body.appendChild(div);
  394. /**
  395. * Add the HTML text inputs
  396. */
  397. div.innerHTML += '<div style="position: absolute; margin-left: 10px; top: ' + canvas.height + 'px; width: ' + (canvas.width - 50) + 'px; height: 25px"><span style="font-size: 12pt;display: inline; display: inline-block; width: 65px; text-align: right">URL:</span><textarea style="float: right; overflow: hidden; height: 20px; width: ' + (canvas.width - obj.gutterLeft - obj.gutterRight - 80) + 'px" onclick="this.select()" readonly="readonly" id="__rgraph_dataurl__">' + canvas.toDataURL() + '</textarea></div>';
  398. div.innerHTML += '<div style="position: absolute; top: ' + (canvas.height + 25) + 'px; left: ' + (obj.gutterLeft - 65 + (canvas.width / 2)) + 'px; width: ' + (canvas.width - obj.gutterRight) + 'px; font-size: 65%">A link using the URL: <a href="' + canvas.toDataURL() + '">View</a></div>'
  399. /**
  400. * Create the image rendition of the graph
  401. */
  402. var img = document.createElement('IMG');
  403. RGraph.Registry.Set('chart.png', img);
  404. img.__canvas__ = canvas;
  405. img.__object__ = obj;
  406. img.id = '__rgraph_image_img__';
  407. img.className = 'RGraph_png';
  408. img.src = canvas.toDataURL();
  409. div.appendChild(img);
  410. setTimeout(function () {document.getElementById("__rgraph_dataurl__").select();}, 50);
  411. window.addEventListener('resize', function (e){var img = RGraph.Registry.Get('chart.png');img.style.left = (document.body.clientWidth / 2) - (img.width / 2) + 'px';}, false);
  412. bg.onclick = function (e)
  413. {
  414. var div = document.getElementById("__rgraph_image_div__");
  415. var bg = document.getElementById("__rgraph_image_bg__");
  416. if (div) {
  417. div.style.opacity = 0;
  418. div.parentNode.removeChild(div);
  419. div.id = '';
  420. div.style.display = 'none';
  421. div = null;
  422. }
  423. if (bg) {
  424. bg.style.opacity = 0;
  425. bg.id = '';
  426. bg.style.display = 'none';
  427. bg = null;
  428. }
  429. }
  430. window.addEventListener('resize', function (e) {bg.onclick(e);}, false)
  431. /**
  432. * This sets the image as a global variable, circumventing repeated calls to document.getElementById()
  433. */
  434. __rgraph_image_bg__ = bg;
  435. __rgraph_image_div__ = div;
  436. setTimeout('__rgraph_image_div__.style.opacity = 0.2', 50);
  437. setTimeout('__rgraph_image_div__.style.opacity = 0.4', 100);
  438. setTimeout('__rgraph_image_div__.style.opacity = 0.6', 150);
  439. setTimeout('__rgraph_image_div__.style.opacity = 0.8', 200);
  440. setTimeout('__rgraph_image_div__.style.opacity = 1', 250);
  441. setTimeout('__rgraph_image_bg__.style.opacity = 0.1', 50);
  442. setTimeout('__rgraph_image_bg__.style.opacity = 0.2', 100);
  443. setTimeout('__rgraph_image_bg__.style.opacity = 0.3', 150);
  444. setTimeout('__rgraph_image_bg__.style.opacity = 0.4', 200);
  445. setTimeout('__rgraph_image_bg__.style.opacity = 0.5', 250);
  446. img.onclick = function (e)
  447. {
  448. if (e.stopPropagation) e.stopPropagation();
  449. else event.cancelBubble = true;
  450. }
  451. if (event && event.stopPropagation) {
  452. event.stopPropagation();
  453. }
  454. }