jquery.flot.events.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. define([
  2. 'jquery',
  3. 'lodash',
  4. 'angular',
  5. 'tether-drop',
  6. ],
  7. function ($, _, angular, Drop) {
  8. 'use strict';
  9. function createAnnotationToolip(element, event) {
  10. var injector = angular.element(document).injector();
  11. var content = document.createElement('div');
  12. content.innerHTML = '<annotation-tooltip></annotation-tooltip>';
  13. injector.invoke(["$compile", "$rootScope", function($compile, $rootScope) {
  14. var tmpScope = $rootScope.$new(true);
  15. tmpScope.event = event;
  16. $compile(content)(tmpScope);
  17. tmpScope.$digest();
  18. tmpScope.$destroy();
  19. var drop = new Drop({
  20. target: element[0],
  21. content: content,
  22. position: "bottom center",
  23. classes: 'drop-popover',
  24. openOn: 'hover',
  25. hoverCloseDelay: 200,
  26. tetherOptions: {
  27. constraints: [{to: 'window', pin: true, attachment: "both"}]
  28. }
  29. });
  30. drop.open();
  31. drop.on('close', function() {
  32. setTimeout(function() {
  33. drop.destroy();
  34. });
  35. });
  36. }]);
  37. }
  38. /*
  39. * jquery.flot.events
  40. *
  41. * description: Flot plugin for adding events/markers to the plot
  42. * version: 0.2.5
  43. * authors:
  44. * Alexander Wunschik <alex@wunschik.net>
  45. * Joel Oughton <joeloughton@gmail.com>
  46. * Nicolas Joseph <www.nicolasjoseph.com>
  47. *
  48. * website: https://github.com/mojoaxel/flot-events
  49. *
  50. * released under MIT License and GPLv2+
  51. */
  52. /**
  53. * A class that allows for the drawing an remove of some object
  54. */
  55. var DrawableEvent = function(object, drawFunc, clearFunc, moveFunc, left, top, width, height) {
  56. var _object = object;
  57. var _drawFunc = drawFunc;
  58. var _clearFunc = clearFunc;
  59. var _moveFunc = moveFunc;
  60. var _position = { left: left, top: top };
  61. var _width = width;
  62. var _height = height;
  63. this.width = function() { return _width; };
  64. this.height = function() { return _height; };
  65. this.position = function() { return _position; };
  66. this.draw = function() { _drawFunc(_object); };
  67. this.clear = function() { _clearFunc(_object); };
  68. this.getObject = function() { return _object; };
  69. this.moveTo = function(position) {
  70. _position = position;
  71. _moveFunc(_object, _position);
  72. };
  73. };
  74. /**
  75. * Event class that stores options (eventType, min, max, title, description) and the object to draw.
  76. */
  77. var VisualEvent = function(options, drawableEvent) {
  78. var _parent;
  79. var _options = options;
  80. var _drawableEvent = drawableEvent;
  81. var _hidden = false;
  82. this.visual = function() { return _drawableEvent; };
  83. this.getOptions = function() { return _options; };
  84. this.getParent = function() { return _parent; };
  85. this.isHidden = function() { return _hidden; };
  86. this.hide = function() { _hidden = true; };
  87. this.unhide = function() { _hidden = false; };
  88. };
  89. /**
  90. * A Class that handles the event-markers inside the given plot
  91. */
  92. var EventMarkers = function(plot) {
  93. var _events = [];
  94. this._types = [];
  95. this._plot = plot;
  96. this.eventsEnabled = false;
  97. this.getEvents = function() {
  98. return _events;
  99. };
  100. this.setTypes = function(types) {
  101. return this._types = types;
  102. };
  103. /**
  104. * create internal objects for the given events
  105. */
  106. this.setupEvents = function(events) {
  107. var that = this;
  108. $.each(events, function(index, event) {
  109. var ve = new VisualEvent(event, that._buildDiv(event));
  110. _events.push(ve);
  111. });
  112. _events.sort(function(a, b) {
  113. var ao = a.getOptions(), bo = b.getOptions();
  114. if (ao.min > bo.min) { return 1; }
  115. if (ao.min < bo.min) { return -1; }
  116. return 0;
  117. });
  118. };
  119. /**
  120. * draw the events to the plot
  121. */
  122. this.drawEvents = function() {
  123. var that = this;
  124. // var o = this._plot.getPlotOffset();
  125. $.each(_events, function(index, event) {
  126. // check event is inside the graph range
  127. if (that._insidePlot(event.getOptions().min) && !event.isHidden()) {
  128. event.visual().draw();
  129. } else {
  130. event.visual().getObject().hide();
  131. }
  132. });
  133. };
  134. /**
  135. * update the position of the event-markers (e.g. after scrolling or zooming)
  136. */
  137. this.updateEvents = function() {
  138. var that = this;
  139. var o = this._plot.getPlotOffset(), left, top;
  140. var xaxis = this._plot.getXAxes()[this._plot.getOptions().events.xaxis - 1];
  141. $.each(_events, function(index, event) {
  142. top = o.top + that._plot.height() - event.visual().height();
  143. left = xaxis.p2c(event.getOptions().min) + o.left - event.visual().width() / 2;
  144. event.visual().moveTo({ top: top, left: left });
  145. });
  146. };
  147. /**
  148. * remove all events from the plot
  149. */
  150. this._clearEvents = function() {
  151. $.each(_events, function(index, val) {
  152. val.visual().clear();
  153. });
  154. _events = [];
  155. };
  156. /**
  157. * create a DOM element for the given event
  158. */
  159. this._buildDiv = function(event) {
  160. var that = this;
  161. var container = this._plot.getPlaceholder();
  162. var o = this._plot.getPlotOffset();
  163. var axes = this._plot.getAxes();
  164. var xaxis = this._plot.getXAxes()[this._plot.getOptions().events.xaxis - 1];
  165. var yaxis, top, left, color, markerSize, markerShow, lineStyle, lineWidth;
  166. var markerTooltip;
  167. // determine the y axis used
  168. if (axes.yaxis && axes.yaxis.used) { yaxis = axes.yaxis; }
  169. if (axes.yaxis2 && axes.yaxis2.used) { yaxis = axes.yaxis2; }
  170. // map the eventType to a types object
  171. var eventTypeId = event.eventType;
  172. if (this._types === null || !this._types[eventTypeId] || !this._types[eventTypeId].color) {
  173. color = '#666';
  174. } else {
  175. color = this._types[eventTypeId].color;
  176. }
  177. if (this._types === null || !this._types[eventTypeId] || !this._types[eventTypeId].markerSize) {
  178. markerSize = 8; //default marker size
  179. } else {
  180. markerSize = this._types[eventTypeId].markerSize;
  181. }
  182. if (this._types === null || !this._types[eventTypeId] || this._types[eventTypeId].markerShow === undefined) {
  183. markerShow = true;
  184. } else {
  185. markerShow = this._types[eventTypeId].markerShow;
  186. }
  187. if (this._types === null || !this._types[eventTypeId] || this._types[eventTypeId].markerTooltip === undefined) {
  188. markerTooltip = true;
  189. } else {
  190. markerTooltip = this._types[eventTypeId].markerTooltip;
  191. }
  192. if (this._types == null || !this._types[eventTypeId] || !this._types[eventTypeId].lineStyle) {
  193. lineStyle = 'dashed'; //default line style
  194. } else {
  195. lineStyle = this._types[eventTypeId].lineStyle.toLowerCase();
  196. }
  197. if (this._types == null || !this._types[eventTypeId] || this._types[eventTypeId].lineWidth === undefined) {
  198. lineWidth = 1; //default line width
  199. } else {
  200. lineWidth = this._types[eventTypeId].lineWidth;
  201. }
  202. top = o.top + this._plot.height();
  203. left = xaxis.p2c(event.min) + o.left;
  204. var line = $('<div class="events_line"></div>').css({
  205. "position": "absolute",
  206. "opacity": 0.8,
  207. "left": left + 'px',
  208. "top": 8,
  209. "width": lineWidth + "px",
  210. "height": this._plot.height(),
  211. "border-left-width": lineWidth + "px",
  212. "border-left-style": lineStyle,
  213. "border-left-color": color
  214. })
  215. .appendTo(container);
  216. if (markerShow) {
  217. var marker = $('<div class="events_marker"></div>').css({
  218. "position": "absolute",
  219. "left": (-markerSize-Math.round(lineWidth/2)) + "px",
  220. "font-size": 0,
  221. "line-height": 0,
  222. "width": 0,
  223. "height": 0,
  224. "border-left": markerSize+"px solid transparent",
  225. "border-right": markerSize+"px solid transparent"
  226. })
  227. .appendTo(line);
  228. if (this._types[eventTypeId] && this._types[eventTypeId].position && this._types[eventTypeId].position.toUpperCase() === 'BOTTOM') {
  229. marker.css({
  230. "top": top-markerSize-8 +"px",
  231. "border-top": "none",
  232. "border-bottom": markerSize+"px solid " + color
  233. });
  234. } else {
  235. marker.css({
  236. "top": "0px",
  237. "border-top": markerSize+"px solid " + color,
  238. "border-bottom": "none"
  239. });
  240. }
  241. marker.data({
  242. "event": event
  243. });
  244. var mouseenter = function() {
  245. createAnnotationToolip(marker, $(this).data("event"));
  246. };
  247. var mouseleave = function() {
  248. that._plot.clearSelection();
  249. };
  250. if (markerTooltip) {
  251. marker.css({ "cursor": "help" });
  252. marker.hover(mouseenter, mouseleave);
  253. }
  254. }
  255. var drawableEvent = new DrawableEvent(
  256. line,
  257. function drawFunc(obj) { obj.show(); },
  258. function(obj) { obj.remove(); },
  259. function(obj, position) {
  260. obj.css({
  261. top: position.top,
  262. left: position.left
  263. });
  264. },
  265. left,
  266. top,
  267. line.width(),
  268. line.height()
  269. );
  270. return drawableEvent;
  271. };
  272. /**
  273. * check if the event is inside visible range
  274. */
  275. this._insidePlot = function(x) {
  276. var xaxis = this._plot.getXAxes()[this._plot.getOptions().events.xaxis - 1];
  277. var xc = xaxis.p2c(x);
  278. return xc > 0 && xc < xaxis.p2c(xaxis.max);
  279. };
  280. };
  281. /**
  282. * initialize the plugin for the given plot
  283. */
  284. function init(plot) {
  285. /*jshint validthis:true */
  286. var that = this;
  287. var eventMarkers = new EventMarkers(plot);
  288. plot.getEvents = function() {
  289. return eventMarkers._events;
  290. };
  291. plot.hideEvents = function() {
  292. $.each(eventMarkers._events, function(index, event) {
  293. event.visual().getObject().hide();
  294. });
  295. };
  296. plot.showEvents = function() {
  297. plot.hideEvents();
  298. $.each(eventMarkers._events, function(index, event) {
  299. event.hide();
  300. });
  301. that.eventMarkers.drawEvents();
  302. };
  303. // change events on an existing plot
  304. plot.setEvents = function(events) {
  305. if (eventMarkers.eventsEnabled) {
  306. eventMarkers.setupEvents(events);
  307. }
  308. };
  309. plot.hooks.processOptions.push(function(plot, options) {
  310. // enable the plugin
  311. if (options.events.data != null) {
  312. eventMarkers.eventsEnabled = true;
  313. }
  314. });
  315. plot.hooks.draw.push(function(plot) {
  316. var options = plot.getOptions();
  317. if (eventMarkers.eventsEnabled) {
  318. // check for first run
  319. if (eventMarkers.getEvents().length < 1) {
  320. eventMarkers.setTypes(options.events.types);
  321. eventMarkers.setupEvents(options.events.data);
  322. } else {
  323. eventMarkers.updateEvents();
  324. }
  325. }
  326. eventMarkers.drawEvents();
  327. });
  328. }
  329. var defaultOptions = {
  330. events: {
  331. data: null,
  332. types: null,
  333. xaxis: 1,
  334. position: 'BOTTOM'
  335. }
  336. };
  337. $.plot.plugins.push({
  338. init: init,
  339. options: defaultOptions,
  340. name: "events",
  341. version: "0.2.5"
  342. });
  343. });