initial commit
[home-automation.git] / libraries / RGraph.common.context.js
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.txt                       |
12     * o------------------------------------------------------------------------------o
13     */
14
15     if (typeof(RGraph) == 'undefined') RGraph = {isRGraph:true,type:'common'};
16
17
18     /**
19     * This gunction shows a context menu containing the parameters
20     * provided to it
21     * 
22     * @param object canvas    The canvas object
23     * @param array  menuitems The context menu menuitems
24     * @param object e         The event object
25     */
26     RGraph.Contextmenu = function (canvas, menuitems, e)
27     {
28         e = RGraph.FixEventObject(e);
29
30         /**
31         * Hide any existing menu
32         */
33         if (RGraph.Registry.Get('chart.contextmenu')) {
34             RGraph.HideContext();
35         }
36         
37         // Hide any zoomed canvas
38         RGraph.HideZoomedCanvas();
39
40         /**
41         * Hide the palette if necessary
42         */
43         RGraph.HidePalette();
44         
45         /**
46         * This is here to ensure annotating is OFF
47         */
48         canvas.__object__.Set('chart.mousedown', false);
49
50         var x      = e.pageX;
51         var y      = e.pageY;
52         var div    = document.createElement('div');
53         var bg     = document.createElement('div');
54
55         div.className             = 'RGraph_contextmenu';
56         div.__canvas__            = canvas; /* Store a reference to the canvas on the contextmenu object */
57         div.style.position        = 'absolute';
58         div.style.left            = 0;
59         div.style.top             = 0;
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;
67
68         bg.className             = 'RGraph_contextmenu_background';
69         bg.style.position        = 'absolute';
70         bg.style.backgroundColor = '#ccc';
71         bg.style.borderRight     = '1px solid #aaa';
72         bg.style.top             = 0;
73         bg.style.left            = 0;
74         bg.style.width           = '18px';
75         bg.style.height          = '100%';
76         bg.style.opacity         = 0;
77
78
79         div = document.body.appendChild(div);
80         bg  = div.appendChild(bg);
81
82
83         /**
84         * Now add the context menu items
85         */
86         for (i=0; i<menuitems.length; ++i) {
87             
88             var menuitem = document.createElement('div');
89             
90             menuitem.__canvas__      = canvas;
91             menuitem.__contextmenu__ = div;
92             menuitem.className       = 'RGraph_contextmenu_item';
93             
94             if (menuitems[i]) {
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];
100
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';
105                 }
106
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);
112                     } else  {
113                         menuitem.attachEvent("onmouseover", function () {RGraph.HideContextSubmenu();event.srcElement.style.backgroundColor = '#eee';event.srcElement.style.cursor = 'pointer';}
114                     , false);
115                         menuitem.attachEvent("onmouseout", function () {event.srcElement.style.backgroundColor = 'inherit'; event.srcElement.style.cursor = 'default';}, false);
116                     }
117                 } else {
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);
121                     } else  {
122                         menuitem.attachEvent("onmouseover", function () {event.srcElement.style.cursor = 'default'}, false);
123                         menuitem.attachEvent("onmouseout", function () {event.srcElement.style.cursor = 'default';}, false);
124                     }
125                 }
126
127             } else {
128                 menuitem.style.borderBottom = '1px solid #ddd';
129                 menuitem.style.marginLeft = '25px';
130             }
131
132             div.appendChild(menuitem);
133
134             /**
135             * Install the event handler that calls the menuitem
136             */
137             if (menuitems[i] && menuitems[i][1] && typeof(menuitems[i][1]) == 'function') {
138                 if (document.all) {
139                     menuitem.attachEvent('onclick', menuitems[i][1]);
140                     menuitem.attachEvent('onclick', function () {RGraph.HideContext();});
141                 } else {
142                     menuitem.addEventListener('click', menuitems[i][1], false);
143                 }
144             
145             // Submenu
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);
149             }
150         }
151
152         /**
153         * Now all the menu items have been added, set the shadow width
154         * Shadow now handled by CSS3?
155         */
156         div.style.width = (div.offsetWidth + 10) + 'px';
157         div.style.height = (div.offsetHeight - (RGraph.isIE9up() ? 10 : 2)) + 'px';
158
159         /**
160         * Set the background (the left bar) width if it's MSIE
161         */
162         if (document.all) {
163             bg.style.height = (div.offsetHeight - 10) + 'px';
164         }
165
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;
169         }
170         
171         // Reposition the menu (now we have the real offsetWidth)
172         div.style.left = x + 'px';
173         div.style.top = y + 'px';
174
175         /**
176         * Do a little fade in effect
177         */
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);
183
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);
190
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;};
196
197         /**
198         * Install the event handlers that hide the context menu
199         */
200         canvas.addEventListener('click', function () {RGraph.HideContext();}, false);
201
202         window.onclick = function (e)
203         {
204             RGraph.HideContext();
205             
206             // Removed on 3/7/10 - stops a bug in conjunction with annotating which presents itself on the Rscatter
207             //RGraph.Redraw();
208             
209             // Fire the onclick event again
210             if (e.target.onclick && e.button == 0) {
211                 e.target.onclick(e);
212             }
213         }
214
215         window.onresize = function () {RGraph.HideContext();}
216
217         e.stopPropagation();
218
219         /**
220         * Fire the (RGraph) oncontextmenu event
221         */
222         RGraph.FireCustomEvent(canvas.__object__, 'oncontextmenu');
223
224         return false;
225     }
226
227
228     /**
229     * Hides the context menu if it's currently visible
230     */
231     RGraph.HideContext = function ()
232     {
233         var cm   = RGraph.Registry.Get('chart.contextmenu');
234         var cmbg = RGraph.Registry.Get('chart.contextmenu.bg');
235         
236         //Hide any submenu currently being displayed
237         RGraph.HideContextSubmenu();
238
239         if (cm) {
240             cm.parentNode.removeChild(cm);
241             cmbg.parentNode.removeChild(cmbg);
242
243             cm.style.visibility = 'hidden';
244             cm.style.display = 'none';
245             RGraph.Registry.Set('chart.contextmenu', null);
246             
247             cmbg.style.visibility = 'hidden';
248             cmbg.style.display = 'none';
249             RGraph.Registry.Set('chart.contextmenu.bg', null);
250         }
251     }
252
253
254     /**
255     * Hides the context menus SUBMENU if it's currently visible
256     */
257     RGraph.HideContextSubmenu = function ()
258     {
259         var sub  = RGraph.Registry.Get('chart.contextmenu.submenu');
260
261         if (sub) {
262             sub.style.visibility = 'none';
263             sub.style.display    = 'none';
264             RGraph.Registry.Set('chart.contextmenu.submenu', null);
265         }
266     }
267
268
269     /**
270     * Shows the context menu after making a few checks - not opera (doesn't support oncontextmenu,
271     * not safari (tempermentality), not chrome (hmmm)
272     */
273     RGraph.ShowContext = function (obj)
274     {
275         RGraph.HidePalette();
276
277         if (obj.Get('chart.contextmenu') && obj.Get('chart.contextmenu').length) {
278
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;
284
285             if (((!isOpera && !isSafari) || isChrome) && !isMacFirefox && !isIE9) {
286
287                 obj.canvas.oncontextmenu = function (e)
288                 {
289                      e = RGraph.FixEventObject(e);
290
291                     if (e.ctrlKey) return true;
292
293                     RGraph.Contextmenu(obj.canvas, obj.Get('chart.contextmenu'), e);
294
295                     return false;
296                 }
297
298             // Accomodate Opera, IE9 and Safari - use double click event
299             } else {
300
301                 obj.canvas.addEventListener('dblclick', function (e)
302                 {
303                     if (e.ctrlKey) return true;
304
305                     if (!RGraph.Registry.Get('chart.contextmenu')) {
306                         RGraph.Contextmenu(obj.canvas, obj.Get('chart.contextmenu'), e);
307                     }
308                 }, false);
309             }
310         }
311     }
312
313
314     /**
315     * This draws a submenu should it be necessary
316     * 
317     * @param object obj  The graph object
318     * @param object menu The context menu
319     */
320     RGraph.Contextmenu_submenu = function (obj, menuitems, parentMenuItem)
321     {
322         RGraph.HideContextSubmenu();
323
324         var canvas  = obj.canvas;
325         var context = obj.context;
326         var menu    = parentMenuItem.parentNode;
327
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);
342         
343         for (var i=0; i<menuitems.length; ++i) {
344                     
345             var menuitem = document.createElement('DIV');
346             
347             menuitem.__canvas__      = canvas;
348             menuitem.__contextmenu__ = menu;
349             menuitem.className       = 'RGraph_contextmenu_item';
350             
351             if (menuitems[i]) {
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];
357         
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);
362                     } else  {
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);
365                     }
366                 } else {
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);
370                     } else  {
371                         menuitem.attachEvent("onmouseover", function () {event.srcElement.style.cursor = 'default'}, false);
372                         menuitem.attachEvent("onmouseout", function () {event.srcElement.style.cursor = 'default';}, false);
373                     }
374                 }
375             } else {
376                 menuitem.style.borderBottom = '1px solid #ddd';
377                 menuitem.style.marginLeft = '25px';
378             }
379             
380             subMenu.appendChild(menuitem);
381         
382             if (menuitems[i] && menuitems[i][1]) {
383                 if (document.all) {
384                     menuitem.attachEvent('onclick', menuitems[i][1]);
385                 } else {
386                     menuitem.addEventListener('click', menuitems[i][1], false);
387                 }
388             }
389         }
390
391
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';
397         bg.style.top             = 0;
398         bg.style.left            = 0;
399         bg.style.width           = '18px';
400         bg.style.height          = '100%';
401
402         bg  = subMenu.appendChild(bg);
403
404         RGraph.Registry.Set('chart.contextmenu.submenu', subMenu);
405     }
406
407
408     /**
409     * A function designed to be used in conjunction with thed context menu
410     * to allow people to get image versions of canvases.
411     * 
412     * @param      canvas Optionally you can pass in the canvas, which will be used
413     */
414     RGraph.showPNG = function ()
415     {
416         if (RGraph.isIE8()) {
417             alert('[RGRAPH PNG] Sorry, showing a PNG is not supported on MSIE8.');
418             return;
419         }
420
421         if (arguments[0] && arguments[0].id) {
422             var canvas = arguments[0];
423             var event  = arguments[1];
424         
425         } else if (RGraph.Registry.Get('chart.contextmenu')) {
426             var canvas = RGraph.Registry.Get('chart.contextmenu').__canvas__;
427         
428         } else {
429             alert('[RGRAPH SHOWPNG] Could not find canvas!');
430         }
431
432         var obj = canvas.__object__;
433
434         /**
435         * Create the gray background DIV to cover the page
436         */
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);
447         
448         
449         /**
450         * Create the div that the graph sits in
451         */
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';
462
463             div.style.borderRadius = '10px';
464             div.style.MozBorderRadius = '10px';
465             div.style.WebkitBorderRadius = '10px';
466
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';
470
471             div.__canvas__ = canvas;
472             div.__object__ = obj;
473             div.id = '__rgraph_image_div__';
474         document.body.appendChild(div);
475
476         
477         /**
478         * Add the HTML text inputs
479         */
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>'
482
483         
484         
485         /**
486         * Create the image rendition of the graph
487         */
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';
494
495         img.src = canvas.toDataURL();
496
497         div.appendChild(img);
498         
499         setTimeout(function () {document.getElementById("__rgraph_dataurl__").select();}, 50);
500         
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);
502         
503         bg.onclick = function (e)
504         {
505             var div = document.getElementById("__rgraph_image_div__");
506             var bg = document.getElementById("__rgraph_image_bg__");
507
508             if (div) {
509                 div.style.opacity = 0;
510
511                 div.parentNode.removeChild(div);
512
513                 div.id = '';
514                 div.style.display = 'none';
515                 div = null;
516             }
517
518             if (bg) {
519                 bg.style.opacity = 0;
520
521                 bg.id = '';
522                 bg.style.display = 'none';
523                 bg = null;
524             }
525         }
526         
527         window.addEventListener('resize', function (e) {bg.onclick(e);}, false)
528         
529         /**
530         * This sets the image as a global variable, circumventing repeated calls to document.getElementById()
531         */
532         __rgraph_image_bg__  = bg;
533         __rgraph_image_div__ = div;
534
535
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);
541
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);
547
548
549         
550         img.onclick = function (e)
551         {
552             if (e.stopPropagation) e.stopPropagation();
553             else event.cancelBubble = true;
554         }
555         
556         if (event && event.stopPropagation) {
557             event.stopPropagation();
558         }
559     }