2 * o------------------------------------------------------------------------------o
3 * | This file is part of the RGraph package - you can learn more at: |
5 * | http://www.rgraph.net |
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: |
11 * | http://www.rgraph.net/LICENSE.txt |
12 * o------------------------------------------------------------------------------o
15 if (typeof(RGraph) == 'undefined') RGraph = {isRGraph:true,type:'common'};
19 * This gunction shows a context menu containing the parameters
22 * @param object canvas The canvas object
23 * @param array menuitems The context menu menuitems
24 * @param object e The event object
26 RGraph.Contextmenu = function (canvas, menuitems, e)
28 e = RGraph.FixEventObject(e);
31 * Hide any existing menu
33 if (RGraph.Registry.Get('chart.contextmenu')) {
37 // Hide any zoomed canvas
38 RGraph.HideZoomedCanvas();
41 * Hide the palette if necessary
46 * This is here to ensure annotating is OFF
48 canvas.__object__.Set('chart.mousedown', false);
52 var div = document.createElement('div');
53 var bg = document.createElement('div');
55 div.className = 'RGraph_contextmenu';
56 div.__canvas__ = canvas; /* Store a reference to the canvas on the contextmenu object */
57 div.style.position = 'absolute';
60 div.style.border = '1px solid black';
61 div.style.backgroundColor = 'white';
62 div.style.boxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
63 div.style.MozBoxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
64 div.style.WebkitBoxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
65 div.style.filter = 'progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa,direction=135)';
66 div.style.opacity = 0;
68 bg.className = 'RGraph_contextmenu_background';
69 bg.style.position = 'absolute';
70 bg.style.backgroundColor = '#ccc';
71 bg.style.borderRight = '1px solid #aaa';
74 bg.style.width = '18px';
75 bg.style.height = '100%';
79 div = document.body.appendChild(div);
80 bg = div.appendChild(bg);
84 * Now add the context menu items
86 for (i=0; i<menuitems.length; ++i) {
88 var menuitem = document.createElement('div');
90 menuitem.__canvas__ = canvas;
91 menuitem.__contextmenu__ = div;
92 menuitem.className = 'RGraph_contextmenu_item';
95 menuitem.style.padding = '2px 5px 2px 23px';
96 menuitem.style.fontFamily = 'Arial';
97 menuitem.style.fontSize = '10pt';
98 menuitem.style.fontWeight = 'normal';
99 menuitem.innerHTML = menuitems[i][0];
101 if (RGraph.is_array(menuitems[i][1])) {
102 menuitem.style.backgroundImage = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAQUlEQVQImY3NoQ2AMABE0ZewABMyGQ6mqWODzlAclBSFO8HZl8uf0FFxCHtwYkt4Y6ChYE44cGH9/fyae2p2LAleW9oVTQuVf6gAAAAASUVORK5CYII=)';
103 menuitem.style.backgroundRepeat = 'no-repeat';
104 menuitem.style.backgroundPosition = '97% center';
107 // Add the mouseover event
108 if (menuitems[i][1]) {
109 if (menuitem.addEventListener) {
110 menuitem.addEventListener("mouseover", function (e) {RGraph.HideContextSubmenu(); e.target.style.backgroundColor = 'rgba(0,0,0,0.2)'; e.target.style.cursor = 'pointer';}, false);
111 menuitem.addEventListener("mouseout", function (e) {e.target.style.backgroundColor = 'inherit'; e.target.style.cursor = 'default';}, false);
113 menuitem.attachEvent("onmouseover", function () {RGraph.HideContextSubmenu();event.srcElement.style.backgroundColor = '#eee';event.srcElement.style.cursor = 'pointer';}
115 menuitem.attachEvent("onmouseout", function () {event.srcElement.style.backgroundColor = 'inherit'; event.srcElement.style.cursor = 'default';}, false);
118 if (menuitem.addEventListener) {
119 menuitem.addEventListener("mouseover", function (e) {e.target.style.cursor = 'default';}, false);
120 menuitem.addEventListener("mouseout", function (e) {e.target.style.cursor = 'default';}, false);
122 menuitem.attachEvent("onmouseover", function () {event.srcElement.style.cursor = 'default'}, false);
123 menuitem.attachEvent("onmouseout", function () {event.srcElement.style.cursor = 'default';}, false);
128 menuitem.style.borderBottom = '1px solid #ddd';
129 menuitem.style.marginLeft = '25px';
132 div.appendChild(menuitem);
135 * Install the event handler that calls the menuitem
137 if (menuitems[i] && menuitems[i][1] && typeof(menuitems[i][1]) == 'function') {
139 menuitem.attachEvent('onclick', menuitems[i][1]);
140 menuitem.attachEvent('onclick', function () {RGraph.HideContext();});
142 menuitem.addEventListener('click', menuitems[i][1], false);
146 } else if (menuitems[i] && menuitems[i][1] && RGraph.is_array(menuitems[i][1])) {
147 var tmp = menuitems[i][1]; // This is here because of "references vs primitives" and how they're passed around in Javascript
148 menuitem.addEventListener('mouseover', function (e) {RGraph.Contextmenu_submenu(canvas.__object__, tmp, e.target);}, false);
153 * Now all the menu items have been added, set the shadow width
154 * Shadow now handled by CSS3?
156 div.style.width = (div.offsetWidth + 10) + 'px';
157 div.style.height = (div.offsetHeight - (RGraph.isIE9up() ? 10 : 2)) + 'px';
160 * Set the background (the left bar) width if it's MSIE
163 bg.style.height = (div.offsetHeight - 10) + 'px';
166 // Show the menu to the left or the right (normal) of the cursor?
167 if (x + div.offsetWidth > document.body.offsetWidth) {
168 x -= div.offsetWidth;
171 // Reposition the menu (now we have the real offsetWidth)
172 div.style.left = x + 'px';
173 div.style.top = y + 'px';
176 * Do a little fade in effect
178 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 0.2", 50);
179 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 0.4", 100);
180 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 0.6", 150);
181 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 0.8", 200);
182 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu')) obj.style.opacity = 1", 250);
184 // The fade in effect on the left gray bar
185 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 0.2", 50);
186 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 0.4", 100);
187 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 0.6", 150);
188 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 0.8", 200);
189 setTimeout("if (obj = RGraph.Registry.Get('chart.contextmenu.bg')) obj.style.opacity = 1", 250);
191 // Store the context menu in the registry
192 RGraph.Registry.Set('chart.contextmenu', div);
193 RGraph.Registry.Set('chart.contextmenu.bg', bg);
194 RGraph.Registry.Get('chart.contextmenu').oncontextmenu = function () {return false;};
195 RGraph.Registry.Get('chart.contextmenu.bg').oncontextmenu = function () {return false;};
198 * Install the event handlers that hide the context menu
200 canvas.addEventListener('click', function () {RGraph.HideContext();}, false);
202 window.onclick = function (e)
204 RGraph.HideContext();
206 // Removed on 3/7/10 - stops a bug in conjunction with annotating which presents itself on the Rscatter
209 // Fire the onclick event again
210 if (e.target.onclick && e.button == 0) {
215 window.onresize = function () {RGraph.HideContext();}
220 * Fire the (RGraph) oncontextmenu event
222 RGraph.FireCustomEvent(canvas.__object__, 'oncontextmenu');
229 * Hides the context menu if it's currently visible
231 RGraph.HideContext = function ()
233 var cm = RGraph.Registry.Get('chart.contextmenu');
234 var cmbg = RGraph.Registry.Get('chart.contextmenu.bg');
236 //Hide any submenu currently being displayed
237 RGraph.HideContextSubmenu();
240 cm.parentNode.removeChild(cm);
241 cmbg.parentNode.removeChild(cmbg);
243 cm.style.visibility = 'hidden';
244 cm.style.display = 'none';
245 RGraph.Registry.Set('chart.contextmenu', null);
247 cmbg.style.visibility = 'hidden';
248 cmbg.style.display = 'none';
249 RGraph.Registry.Set('chart.contextmenu.bg', null);
255 * Hides the context menus SUBMENU if it's currently visible
257 RGraph.HideContextSubmenu = function ()
259 var sub = RGraph.Registry.Get('chart.contextmenu.submenu');
262 sub.style.visibility = 'none';
263 sub.style.display = 'none';
264 RGraph.Registry.Set('chart.contextmenu.submenu', null);
270 * Shows the context menu after making a few checks - not opera (doesn't support oncontextmenu,
271 * not safari (tempermentality), not chrome (hmmm)
273 RGraph.ShowContext = function (obj)
275 RGraph.HidePalette();
277 if (obj.Get('chart.contextmenu') && obj.Get('chart.contextmenu').length) {
279 var isOpera = navigator.userAgent.indexOf('Opera') >= 0;
280 var isSafari = navigator.userAgent.indexOf('Safari') >= 0;
281 var isChrome = navigator.userAgent.indexOf('Chrome') >= 0;
282 var isMacFirefox = navigator.userAgent.indexOf('Firefox') > 0 && navigator.userAgent.indexOf('Mac') > 0;
283 var isIE9 = navigator.userAgent.indexOf('MSIE 9') >= 0;
285 if (((!isOpera && !isSafari) || isChrome) && !isMacFirefox && !isIE9) {
287 obj.canvas.oncontextmenu = function (e)
289 e = RGraph.FixEventObject(e);
291 if (e.ctrlKey) return true;
293 RGraph.Contextmenu(obj.canvas, obj.Get('chart.contextmenu'), e);
298 // Accomodate Opera, IE9 and Safari - use double click event
301 obj.canvas.addEventListener('dblclick', function (e)
303 if (e.ctrlKey) return true;
305 if (!RGraph.Registry.Get('chart.contextmenu')) {
306 RGraph.Contextmenu(obj.canvas, obj.Get('chart.contextmenu'), e);
315 * This draws a submenu should it be necessary
317 * @param object obj The graph object
318 * @param object menu The context menu
320 RGraph.Contextmenu_submenu = function (obj, menuitems, parentMenuItem)
322 RGraph.HideContextSubmenu();
324 var canvas = obj.canvas;
325 var context = obj.context;
326 var menu = parentMenuItem.parentNode;
328 var subMenu = document.createElement('DIV');
329 subMenu.style.position = 'absolute';
330 subMenu.style.width = '100px';
331 subMenu.style.top = menu.offsetTop + parentMenuItem.offsetTop + 'px';
332 subMenu.style.left = (menu.offsetLeft + menu.offsetWidth - (document.all ? 9 : 0)) + 'px';
333 subMenu.style.backgroundColor = 'white';
334 subMenu.style.border = '1px solid black';
335 subMenu.className = 'RGraph_contextmenu';
336 subMenu.__contextmenu__ = menu;
337 subMenu.style.boxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
338 subMenu.style.MozBoxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
339 subMenu.style.WebkitBoxShadow = '3px 3px 3px rgba(96,96,96,0.5)';
340 subMenu.style.filter = 'progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa,direction=135)';
341 document.body.appendChild(subMenu);
343 for (var i=0; i<menuitems.length; ++i) {
345 var menuitem = document.createElement('DIV');
347 menuitem.__canvas__ = canvas;
348 menuitem.__contextmenu__ = menu;
349 menuitem.className = 'RGraph_contextmenu_item';
352 menuitem.style.padding = '2px 5px 2px 23px';
353 menuitem.style.fontFamily = 'Arial';
354 menuitem.style.fontSize = '10pt';
355 menuitem.style.fontWeight = 'normal';
356 menuitem.innerHTML = menuitems[i][0];
358 if (menuitems[i][1]) {
359 if (menuitem.addEventListener) {
360 menuitem.addEventListener("mouseover", function (e) {e.target.style.backgroundColor = 'rgba(0,0,0,0.2)'; e.target.style.cursor = 'pointer';}, false);
361 menuitem.addEventListener("mouseout", function (e) {e.target.style.backgroundColor = 'inherit'; e.target.style.cursor = 'default';}, false);
363 menuitem.attachEvent("onmouseover", function () {event.srcElement.style.backgroundColor = 'rgba(0,0,0,0.2)'; event.srcElement.style.cursor = 'pointer'}, false);
364 menuitem.attachEvent("onmouseout", function () {event.srcElement.style.backgroundColor = 'inherit'; event.srcElement.style.cursor = 'default';}, false);
367 if (menuitem.addEventListener) {
368 menuitem.addEventListener("mouseover", function (e) {e.target.style.cursor = 'default';}, false);
369 menuitem.addEventListener("mouseout", function (e) {e.target.style.cursor = 'default';}, false);
371 menuitem.attachEvent("onmouseover", function () {event.srcElement.style.cursor = 'default'}, false);
372 menuitem.attachEvent("onmouseout", function () {event.srcElement.style.cursor = 'default';}, false);
376 menuitem.style.borderBottom = '1px solid #ddd';
377 menuitem.style.marginLeft = '25px';
380 subMenu.appendChild(menuitem);
382 if (menuitems[i] && menuitems[i][1]) {
384 menuitem.attachEvent('onclick', menuitems[i][1]);
386 menuitem.addEventListener('click', menuitems[i][1], false);
392 var bg = document.createElement('DIV');
393 bg.className = 'RGraph_contextmenu_background';
394 bg.style.position = 'absolute';
395 bg.style.backgroundColor = '#ccc';
396 bg.style.borderRight = '1px solid #aaa';
399 bg.style.width = '18px';
400 bg.style.height = '100%';
402 bg = subMenu.appendChild(bg);
404 RGraph.Registry.Set('chart.contextmenu.submenu', subMenu);
409 * A function designed to be used in conjunction with thed context menu
410 * to allow people to get image versions of canvases.
412 * @param canvas Optionally you can pass in the canvas, which will be used
414 RGraph.showPNG = function ()
416 if (RGraph.isIE8()) {
417 alert('[RGRAPH PNG] Sorry, showing a PNG is not supported on MSIE8.');
421 if (arguments[0] && arguments[0].id) {
422 var canvas = arguments[0];
423 var event = arguments[1];
425 } else if (RGraph.Registry.Get('chart.contextmenu')) {
426 var canvas = RGraph.Registry.Get('chart.contextmenu').__canvas__;
429 alert('[RGRAPH SHOWPNG] Could not find canvas!');
432 var obj = canvas.__object__;
435 * Create the gray background DIV to cover the page
437 var bg = document.createElement('DIV');
438 bg.id = '__rgraph_image_bg__';
439 bg.style.position = 'fixed';
440 bg.style.top = '-10px';
441 bg.style.left = '-10px';
442 bg.style.width = '5000px';
443 bg.style.height = '5000px';
444 bg.style.backgroundColor = 'rgb(204,204,204)';
445 bg.style.opacity = 0;
446 document.body.appendChild(bg);
450 * Create the div that the graph sits in
452 var div = document.createElement('DIV');
453 div.style.backgroundColor = 'white';
454 div.style.opacity = 0;
455 div.style.border = '1px solid black';
456 div.style.position = 'fixed';
457 div.style.top = '20%';
458 div.style.width = canvas.width + 'px';
459 div.style.height = canvas.height + 35 + 'px';
460 div.style.left = (document.body.clientWidth / 2) - (canvas.width / 2) + 'px';
461 div.style.padding = '5px';
463 div.style.borderRadius = '10px';
464 div.style.MozBorderRadius = '10px';
465 div.style.WebkitBorderRadius = '10px';
467 div.style.boxShadow = '0 0 15px rgba(96,96,96,0.5)';
468 div.style.MozBoxShadow = '0 0 15px rgba(96,96,96,0.5)';
469 div.style.WebkitBoxShadow = 'rgba(96,96,96,0.5) 0 0 15px';
471 div.__canvas__ = canvas;
472 div.__object__ = obj;
473 div.id = '__rgraph_image_div__';
474 document.body.appendChild(div);
478 * Add the HTML text inputs
480 div.innerHTML += '<div style="position: absolute; margin-left: 10px; top: ' + canvas.height + 'px; width: ' + (canvas.width - 50) + 'px; height: 25px"><span style="display: inline; display: inline-block; width: 65px; text-align: right">URL:</span><textarea style="float: right; overflow: hidden; height: 15px; width: ' + (canvas.width - (2 * obj.Get('chart.gutter')) - 80) + 'px" onclick="this.select()" readonly="readonly" id="__rgraph_dataurl__">' + canvas.toDataURL() + '</textarea></div>';
481 div.innerHTML += '<div style="position: absolute; top: ' + (canvas.height + 25) + 'px; left: ' + (obj.Get('chart.gutter') - 65 + (canvas.width / 2)) + 'px; width: ' + (canvas.width - obj.Get('chart.gutter')) + 'px; font-size: 65%">A link using the URL: <a href="' + canvas.toDataURL() + '">View</a></div>'
486 * Create the image rendition of the graph
488 var img = document.createElement('IMG');
489 RGraph.Registry.Set('chart.png', img);
490 img.__canvas__ = canvas;
491 img.__object__ = obj;
492 img.id = '__rgraph_image_img__';
493 img.className = 'RGraph_png';
495 img.src = canvas.toDataURL();
497 div.appendChild(img);
499 setTimeout(function () {document.getElementById("__rgraph_dataurl__").select();}, 50);
501 window.addEventListener('resize', function (e){var img = RGraph.Registry.Get('chart.png');img.style.left = (document.body.clientWidth / 2) - (img.width / 2) + 'px';}, false);
503 bg.onclick = function (e)
505 var div = document.getElementById("__rgraph_image_div__");
506 var bg = document.getElementById("__rgraph_image_bg__");
509 div.style.opacity = 0;
511 div.parentNode.removeChild(div);
514 div.style.display = 'none';
519 bg.style.opacity = 0;
522 bg.style.display = 'none';
527 window.addEventListener('resize', function (e) {bg.onclick(e);}, false)
530 * This sets the image as a global variable, circumventing repeated calls to document.getElementById()
532 __rgraph_image_bg__ = bg;
533 __rgraph_image_div__ = div;
536 setTimeout('__rgraph_image_div__.style.opacity = 0.2', 50);
537 setTimeout('__rgraph_image_div__.style.opacity = 0.4', 100);
538 setTimeout('__rgraph_image_div__.style.opacity = 0.6', 150);
539 setTimeout('__rgraph_image_div__.style.opacity = 0.8', 200);
540 setTimeout('__rgraph_image_div__.style.opacity = 1', 250);
542 setTimeout('__rgraph_image_bg__.style.opacity = 0.1', 50);
543 setTimeout('__rgraph_image_bg__.style.opacity = 0.2', 100);
544 setTimeout('__rgraph_image_bg__.style.opacity = 0.3', 150);
545 setTimeout('__rgraph_image_bg__.style.opacity = 0.4', 200);
546 setTimeout('__rgraph_image_bg__.style.opacity = 0.5', 250);
550 img.onclick = function (e)
552 if (e.stopPropagation) e.stopPropagation();
553 else event.cancelBubble = true;
556 if (event && event.stopPropagation) {
557 event.stopPropagation();