RGraph.common.annotate.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. // version: 2014-06-26
  2. /**
  3. * o--------------------------------------------------------------------------------o
  4. * | This file is part of the RGraph package. RGraph is Free Software, licensed |
  5. * | under the MIT license - so it's free to use for all purposes. If you want to |
  6. * | donate to help keep the project going then you can do so here: |
  7. * | |
  8. * | http://www.rgraph.net/donate |
  9. * o--------------------------------------------------------------------------------o
  10. */
  11. RGraph = window.RGraph || {isRGraph: true};
  12. // Module pattern
  13. (function (win, doc, undefined)
  14. {
  15. var RG = RGraph,
  16. ua = navigator.userAgent,
  17. ma = Math;
  18. /**
  19. * This installs some event handlers
  20. *
  21. * Checking the RGraph.Annotate flag means the annotate code only runs once
  22. */
  23. RG.Annotating_canvas_onmousedown = function (e)
  24. {
  25. if (e.button === 0) {
  26. e.target.__object__.Set('chart.mousedown', true);
  27. // Get the object from the canvas. Annotating must be enabled on the
  28. // last object defined
  29. var obj = e.target.__object__;
  30. // This starts the annotating "path" and set the color
  31. obj.context.beginPath();
  32. obj.context.strokeStyle = obj.Get('chart.annotate.color');
  33. obj.context.lineWidth = obj.Get('chart.annotate.linewidth');
  34. var mouseXY = RG.getMouseXY(e);
  35. var mouseX = mouseXY[0];
  36. var mouseY = mouseXY[1];
  37. // Clear the annotation recording
  38. RG.Registry.Set('annotate.actions', [obj.Get('chart.annotate.color')]);
  39. // This sets the initial X/Y position
  40. obj.context.moveTo(mouseX, mouseY);
  41. RG.Registry.Set('annotate.last.coordinates', [mouseX,mouseY]);
  42. RG.Registry.Set('started.annotating', false);
  43. RG.Registry.Set('chart.annotating', obj);
  44. // Fire the onannotatebegin event.
  45. RG.FireCustomEvent(obj, 'onannotatebegin');
  46. }
  47. return false;
  48. };
  49. /**
  50. * This cancels annotating for ALL canvases
  51. */
  52. RG.Annotating_window_onmouseup = function (e)
  53. {
  54. var obj = RG.Registry.Get('chart.annotating');
  55. if (e.button != 0 || !obj) {
  56. return;
  57. }
  58. // This cancels annotating on ALL canvas tags on the page
  59. var tags = doc.getElementsByTagName('canvas');
  60. for (var i=0; i<tags.length; ++i) {
  61. if (tags[i].__object__) {
  62. tags[i].__object__.Set('chart.mousedown', false);
  63. }
  64. }
  65. // Store the annotations in browser storage if it's available
  66. if (RG.Registry.Get('annotate.actions') && RG.Registry.Get('annotate.actions').length > 0 && win.localStorage) {
  67. var id = '__rgraph_annotations_' + e.target.id + '__';
  68. var annotations = win.localStorage[id] ? win.localStorage[id] + '|' : '';
  69. annotations += RG.Registry.Get('annotate.actions');
  70. // Store the annotations information in HTML5 browser storage here
  71. win.localStorage[id] = annotations;
  72. }
  73. // Clear the recorded annotations
  74. RG.Registry.Set('annotate.actions', []);
  75. // Fire the annotate event
  76. RG.FireCustomEvent(obj, 'onannotateend');
  77. };
  78. /**
  79. * The canvas onmousemove function
  80. */
  81. RGraph.Annotating_canvas_onmousemove = function (e)
  82. {
  83. var obj = e.target.__object__;
  84. var mouseXY = RGraph.getMouseXY(e);
  85. var mouseX = mouseXY[0];
  86. var mouseY = mouseXY[1];
  87. var lastXY = RG.Registry.Get('annotate.last.coordinates');
  88. if (obj.Get('chart.mousedown')) {
  89. obj.context.beginPath();
  90. if (!lastXY) {
  91. obj.context.moveTo(mouseX, mouseY)
  92. } else {
  93. obj.context.strokeStyle = obj.properties['chart.annotate.color'];
  94. obj.context.moveTo(lastXY[0], lastXY[1]);
  95. obj.context.lineTo(mouseX, mouseY);
  96. }
  97. RG.Registry.Set('annotate.actions', RG.Registry.Get('annotate.actions') + '|' + mouseX + ',' + mouseY);
  98. RG.Registry.Set('annotate.last.coordinates', [mouseX,mouseY]);
  99. RG.FireCustomEvent(obj, 'onannotate');
  100. obj.context.stroke();
  101. }
  102. };
  103. /**
  104. * Shows the mini palette used for annotations
  105. *
  106. * @param object e The event object
  107. */
  108. RG.ShowPalette =
  109. RG.Showpalette = function (e)
  110. {
  111. var isSafari = navigator.userAgent.indexOf('Safari') ? true : false;
  112. e = RG.FixEventObject(e);
  113. var canvas = e.target.parentNode.__canvas__;
  114. var context = canvas.getContext('2d');
  115. var obj = canvas.__object__;
  116. var div = document.createElement('DIV');
  117. var coords = RG.getMouseXY(e);
  118. div.__object__ = obj; // The graph object
  119. div.className = 'RGraph_palette';
  120. div.style.position = 'absolute';
  121. div.style.backgroundColor = 'white';
  122. div.style.border = '1px solid black';
  123. div.style.left = 0;
  124. div.style.top = 0;
  125. div.style.padding = '3px';
  126. div.style.opacity = 0;
  127. div.style.boxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px';
  128. div.style.WebkitBoxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px';
  129. div.style.MozBoxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px';
  130. // MUST use named colors that are capitalised
  131. var colors = ['Black', 'Red', 'Yellow','Green','Orange', 'White', 'Magenta', 'Pink'];
  132. // Add the colors to the palette
  133. for (var i=0,len=colors.length; i<len; i+=1) {
  134. var div2 = doc.createElement('DIV');
  135. div2.cssClass = 'RGraph_palette_color';
  136. div2.style.fontSize = '12pt';
  137. div2.style.cursor = 'pointer';
  138. div2.style.padding = '1px';
  139. div2.style.paddingRight = '10px';
  140. var span = document.createElement('SPAN');
  141. span.style.display = 'inline-block';
  142. span.style.marginRight = '3px';
  143. span.style.width = '17px';
  144. span.style.height = '17px';
  145. span.style.top = '2px';
  146. span.style.position = 'relative';
  147. span.style.backgroundColor = colors[i];
  148. div2.appendChild(span);
  149. div2.innerHTML += colors[i];
  150. div2.onmouseover = function ()
  151. {
  152. this.style.backgroundColor = '#eee';
  153. }
  154. div2.onmouseout = function ()
  155. {
  156. this.style.backgroundColor = '';
  157. }
  158. div2.onclick = function (e)
  159. {
  160. var color = this.childNodes[0].style.backgroundColor;
  161. obj.Set('chart.annotate.color', color);
  162. }
  163. div.appendChild(div2);
  164. }
  165. doc.body.appendChild(div);
  166. /**
  167. * Now the div has been added to the document, move it up and left
  168. */
  169. div.style.left = e.pageX + 'px';
  170. div.style.top = e.pageY + 'px';
  171. /**
  172. * Chang the position if the cursor is near the right edge of the browser window
  173. */
  174. if ((e.pageX + (div.offsetWidth + 5) ) > document.body.offsetWidth) {
  175. div.style.left = (e.pageX - div.offsetWidth) + 'px';
  176. }
  177. /**
  178. * Store the palette div in the registry
  179. */
  180. RGraph.Registry.Set('palette', div);
  181. setTimeout(function () {RG.Registry.Get('palette').style.opacity = 0.2;}, 50);
  182. setTimeout(function () {RG.Registry.Get('palette').style.opacity = 0.4;}, 100);
  183. setTimeout(function () {RG.Registry.Get('palette').style.opacity = 0.6;}, 150);
  184. setTimeout(function () {RG.Registry.Get('palette').style.opacity = 0.8;}, 200);
  185. setTimeout(function () {RG.Registry.Get('palette').style.opacity = 1;}, 250);
  186. RGraph.HideContext();
  187. window.onclick = function ()
  188. {
  189. RG.hidePalette();
  190. }
  191. // Should this be here? Yes. This function is being used as an event handler.
  192. e.stopPropagation();
  193. return false;
  194. };
  195. /**
  196. * Clears any annotation data from global storage
  197. *
  198. * @param object canvas The canvas tag object
  199. */
  200. RG.clearAnnotations =
  201. RG.ClearAnnotations = function (canvas)
  202. {
  203. /**
  204. * For BC the argument can also be the ID of the canvas
  205. */
  206. if (typeof canvas === 'string') {
  207. var id = canvas;
  208. canvas = doc.getElementById(id);
  209. } else {
  210. var id = canvas.id
  211. }
  212. var obj = canvas.__object__;
  213. if (win.localStorage && win.localStorage['__rgraph_annotations_' + id + '__'] && win.localStorage['__rgraph_annotations_' + id + '__'].length) {
  214. win.localStorage['__rgraph_annotations_' + id + '__'] = [];
  215. RGraph.FireCustomEvent(obj, 'onannotateclear');
  216. }
  217. };
  218. /**
  219. * Replays stored annotations
  220. *
  221. * @param object obj The graph object
  222. */
  223. RG.replayAnnotations =
  224. RG.ReplayAnnotations = function (obj)
  225. {
  226. // Check for support
  227. if (!win.localStorage) {
  228. return;
  229. }
  230. var context = obj.context;
  231. var annotations = win.localStorage['__rgraph_annotations_' + obj.id + '__'];
  232. var i, len, move, coords;
  233. context.beginPath();
  234. context.lineWidth = obj.Get('annotate.linewidth');
  235. if (annotations && annotations.length) {
  236. annotations = annotations.split('|');
  237. } else {
  238. return;
  239. }
  240. for (i=0,len=annotations.length; i<len; ++i) {
  241. // If the element of the array is a color - finish the path,
  242. // stroke it and start a new one
  243. if (annotations[i].match(/[a-z]+/)) {
  244. context.stroke();
  245. context.beginPath();
  246. context.strokeStyle = annotations[i];
  247. move = true;
  248. continue;
  249. }
  250. coords = annotations[i].split(',');
  251. coords[0] = Number(coords[0]);
  252. coords[1] = Number(coords[1]);
  253. if (move) {
  254. context.moveTo(coords[0], coords[1]);
  255. move = false;
  256. } else {
  257. context.lineTo(coords[0], coords[1]);
  258. }
  259. }
  260. context.stroke();
  261. };
  262. window.addEventListener('load', function (e)
  263. {
  264. // This delay is necessary to allow the window.onload event listener to run
  265. setTimeout(function ()
  266. {
  267. var tags = doc.getElementsByTagName('canvas');
  268. for (var i=0; i<tags.length; ++i) {
  269. if (tags[i].__object__ && tags[i].__object__.isRGraph && tags[i].__object__.Get('chart.annotatable')) {
  270. RG.replayAnnotations(tags[i].__object__);
  271. }
  272. }
  273. }, 100); // This delay is sufficient to wait before replaying the annotations
  274. }, false);
  275. // End module pattern
  276. })(window, document);