+ *
+ * website: https://github.com/mojoaxel/flot-events
+ *
+ * released under MIT License and GPLv2+
+ */
+
+ /**
+ * A class that allows for the drawing an remove of some object
+ */
+ var DrawableEvent = function(object, drawFunc, clearFunc, moveFunc, left, top, width, height) {
+ var _object = object;
+ var _drawFunc = drawFunc;
+ var _clearFunc = clearFunc;
+ var _moveFunc = moveFunc;
+ var _position = { left: left, top: top };
+ var _width = width;
+ var _height = height;
+
+ this.width = function() { return _width; };
+ this.height = function() { return _height; };
+ this.position = function() { return _position; };
+ this.draw = function() { _drawFunc(_object); };
+ this.clear = function() { _clearFunc(_object); };
+ this.getObject = function() { return _object; };
+ this.moveTo = function(position) {
+ _position = position;
+ _moveFunc(_object, _position);
+ };
+ };
+
+ /**
+ * Event class that stores options (eventType, min, max, title, description) and the object to draw.
+ */
+ var VisualEvent = function(options, drawableEvent) {
+ var _parent;
+ var _options = options;
+ var _drawableEvent = drawableEvent;
+ var _hidden = false;
+
+ this.visual = function() { return _drawableEvent; };
+ this.getOptions = function() { return _options; };
+ this.getParent = function() { return _parent; };
+ this.isHidden = function() { return _hidden; };
+ this.hide = function() { _hidden = true; };
+ this.unhide = function() { _hidden = false; };
+ };
+
+ /**
+ * A Class that handles the event-markers inside the given plot
+ */
+ var EventMarkers = function(plot) {
+ var _events = [];
+
+ this._types = [];
+ this._plot = plot;
+ this.eventsEnabled = false;
+
+ this.getEvents = function() {
+ return _events;
+ };
+
+ this.setTypes = function(types) {
+ return this._types = types;
+ };
+
+ /**
+ * create internal objects for the given events
+ */
+ this.setupEvents = function(events) {
+ var that = this;
+ $.each(events, function(index, event) {
+ var ve = new VisualEvent(event, that._buildDiv(event));
+ _events.push(ve);
+ });
+
+ _events.sort(function(a, b) {
+ var ao = a.getOptions(), bo = b.getOptions();
+ if (ao.min > bo.min) { return 1; }
+ if (ao.min < bo.min) { return -1; }
+ return 0;
+ });
+ };
+
+ /**
+ * draw the events to the plot
+ */
+ this.drawEvents = function() {
+ var that = this;
+ // var o = this._plot.getPlotOffset();
+
+ $.each(_events, function(index, event) {
+ // check event is inside the graph range
+ if (that._insidePlot(event.getOptions().min) && !event.isHidden()) {
+ event.visual().draw();
+ } else {
+ event.visual().getObject().hide();
+ }
+ });
+ };
+
+ /**
+ * update the position of the event-markers (e.g. after scrolling or zooming)
+ */
+ this.updateEvents = function() {
+ var that = this;
+ var o = this._plot.getPlotOffset(), left, top;
+ var xaxis = this._plot.getXAxes()[this._plot.getOptions().events.xaxis - 1];
+
+ $.each(_events, function(index, event) {
+ top = o.top + that._plot.height() - event.visual().height();
+ left = xaxis.p2c(event.getOptions().min) + o.left - event.visual().width() / 2;
+ event.visual().moveTo({ top: top, left: left });
+ });
+ };
+
+ /**
+ * remove all events from the plot
+ */
+ this._clearEvents = function() {
+ $.each(_events, function(index, val) {
+ val.visual().clear();
+ });
+ _events = [];
+ };
+
+ /**
+ * create a DOM element for the given event
+ */
+ this._buildDiv = function(event) {
+ var that = this;
+
+ var container = this._plot.getPlaceholder();
+ var o = this._plot.getPlotOffset();
+ var axes = this._plot.getAxes();
+ var xaxis = this._plot.getXAxes()[this._plot.getOptions().events.xaxis - 1];
+ var yaxis, top, left, color, markerSize, markerShow, lineStyle, lineWidth;
+ var markerTooltip;
+
+ // determine the y axis used
+ if (axes.yaxis && axes.yaxis.used) { yaxis = axes.yaxis; }
+ if (axes.yaxis2 && axes.yaxis2.used) { yaxis = axes.yaxis2; }
+
+ // map the eventType to a types object
+ var eventTypeId = event.eventType;
+
+ if (this._types === null || !this._types[eventTypeId] || !this._types[eventTypeId].color) {
+ color = '#666';
+ } else {
+ color = this._types[eventTypeId].color;
+ }
+
+ if (this._types === null || !this._types[eventTypeId] || !this._types[eventTypeId].markerSize) {
+ markerSize = 8; //default marker size
+ } else {
+ markerSize = this._types[eventTypeId].markerSize;
+ }
+
+ if (this._types === null || !this._types[eventTypeId] || this._types[eventTypeId].markerShow === undefined) {
+ markerShow = true;
+ } else {
+ markerShow = this._types[eventTypeId].markerShow;
+ }
+
+ if (this._types === null || !this._types[eventTypeId] || this._types[eventTypeId].markerTooltip === undefined) {
+ markerTooltip = true;
+ } else {
+ markerTooltip = this._types[eventTypeId].markerTooltip;
+ }
+
+ if (this._types == null || !this._types[eventTypeId] || !this._types[eventTypeId].lineStyle) {
+ lineStyle = 'dashed'; //default line style
+ } else {
+ lineStyle = this._types[eventTypeId].lineStyle.toLowerCase();
+ }
+
+ if (this._types == null || !this._types[eventTypeId] || this._types[eventTypeId].lineWidth === undefined) {
+ lineWidth = 1; //default line width
+ } else {
+ lineWidth = this._types[eventTypeId].lineWidth;
+ }
+
+ top = o.top + this._plot.height();
+ left = xaxis.p2c(event.min) + o.left;
+
+ var line = $('').css({
+ "position": "absolute",
+ "opacity": 0.8,
+ "left": left + 'px',
+ "top": 8,
+ "width": lineWidth + "px",
+ "height": this._plot.height(),
+ "border-left-width": lineWidth + "px",
+ "border-left-style": lineStyle,
+ "border-left-color": color
+ })
+ .appendTo(container);
+
+ if (markerShow) {
+ var marker = $('').css({
+ "position": "absolute",
+ "left": (-markerSize-Math.round(lineWidth/2)) + "px",
+ "font-size": 0,
+ "line-height": 0,
+ "width": 0,
+ "height": 0,
+ "border-left": markerSize+"px solid transparent",
+ "border-right": markerSize+"px solid transparent"
+ })
+ .appendTo(line);
+
+ if (this._types[eventTypeId] && this._types[eventTypeId].position && this._types[eventTypeId].position.toUpperCase() === 'BOTTOM') {
+ marker.css({
+ "top": top-markerSize-8 +"px",
+ "border-top": "none",
+ "border-bottom": markerSize+"px solid " + color
+ });
+ } else {
+ marker.css({
+ "top": "0px",
+ "border-top": markerSize+"px solid " + color,
+ "border-bottom": "none"
+ });
+ }
+
+ marker.data({
+ "event": event
+ });
+
+ var mouseenter = function() {
+ createAnnotationToolip(marker, $(this).data("event"));
+ };
+
+ var mouseleave = function() {
+ that._plot.clearSelection();
+ };
+
+ if (markerTooltip) {
+ marker.css({ "cursor": "help" });
+ marker.hover(mouseenter, mouseleave);
+ }
+ }
+
+ var drawableEvent = new DrawableEvent(
+ line,
+ function drawFunc(obj) { obj.show(); },
+ function(obj) { obj.remove(); },
+ function(obj, position) {
+ obj.css({
+ top: position.top,
+ left: position.left
+ });
+ },
+ left,
+ top,
+ line.width(),
+ line.height()
+ );
+
+ return drawableEvent;
+ };
+
+ /**
+ * check if the event is inside visible range
+ */
+ this._insidePlot = function(x) {
+ var xaxis = this._plot.getXAxes()[this._plot.getOptions().events.xaxis - 1];
+ var xc = xaxis.p2c(x);
+ return xc > 0 && xc < xaxis.p2c(xaxis.max);
+ };
+ };
+
+ /**
+ * initialize the plugin for the given plot
+ */
+ function init(plot) {
+ /*jshint validthis:true */
+ var that = this;
+ var eventMarkers = new EventMarkers(plot);
+
+ plot.getEvents = function() {
+ return eventMarkers._events;
+ };
+
+ plot.hideEvents = function() {
+ $.each(eventMarkers._events, function(index, event) {
+ event.visual().getObject().hide();
+ });
+ };
+
+ plot.showEvents = function() {
+ plot.hideEvents();
+ $.each(eventMarkers._events, function(index, event) {
+ event.hide();
+ });
+
+ that.eventMarkers.drawEvents();
+ };
+
+ // change events on an existing plot
+ plot.setEvents = function(events) {
+ if (eventMarkers.eventsEnabled) {
+ eventMarkers.setupEvents(events);
+ }
+ };
+
+ plot.hooks.processOptions.push(function(plot, options) {
+ // enable the plugin
+ if (options.events.data != null) {
+ eventMarkers.eventsEnabled = true;
+ }
+ });
+
+ plot.hooks.draw.push(function(plot) {
+ var options = plot.getOptions();
+
+ if (eventMarkers.eventsEnabled) {
+ // check for first run
+ if (eventMarkers.getEvents().length < 1) {
+ eventMarkers.setTypes(options.events.types);
+ eventMarkers.setupEvents(options.events.data);
+ } else {
+ eventMarkers.updateEvents();
+ }
+ }
+
+ eventMarkers.drawEvents();
+ });
+ }
+
+ var defaultOptions = {
+ events: {
+ data: null,
+ types: null,
+ xaxis: 1,
+ position: 'BOTTOM'
+ }
+ };
+
+ $.plot.plugins.push({
+ init: init,
+ options: defaultOptions,
+ name: "events",
+ version: "0.2.5"
+ });
+
+});
diff --git a/public/app/system.conf.js b/public/app/system.conf.js
index 9e68baa8588..86c00995403 100644
--- a/public/app/system.conf.js
+++ b/public/app/system.conf.js
@@ -20,7 +20,6 @@ System.config({
"bootstrap-tagsinput": "vendor/tagsinput/bootstrap-tagsinput.js",
"jquery.flot": "vendor/flot/jquery.flot",
"jquery.flot.pie": "vendor/flot/jquery.flot.pie",
- "jquery.flot.events": "vendor/flot/jquery.flot.events",
"jquery.flot.selection": "vendor/flot/jquery.flot.selection",
"jquery.flot.stack": "vendor/flot/jquery.flot.stack",
"jquery.flot.stackpercent": "vendor/flot/jquery.flot.stackpercent",
diff --git a/public/sass/components/_panel_graph.scss b/public/sass/components/_panel_graph.scss
index b51ac317043..3f0e104e48c 100644
--- a/public/sass/components/_panel_graph.scss
+++ b/public/sass/components/_panel_graph.scss
@@ -232,11 +232,6 @@
opacity: 0.7;
}
- .label-tag {
- margin-right: 4px;
- margin-top: 8px;
- }
-
.graph-tooltip-list-item {
display: table-row;
}
@@ -253,6 +248,31 @@
}
}
+.graph-annotation {
+
+ .label-tag {
+ margin-right: 4px;
+ margin-top: 8px;
+ }
+
+ .graph-annotation-title {
+ font-weight: $font-weight-semi-bold;
+ position: relative;
+ top: -0.4rem;
+ }
+
+ a {
+ color: $blue;
+ text-decoration: underline;
+ }
+
+ .graph-annotation-time {
+ position: relative;
+ text-align: center;
+ top: 0.6rem;
+ }
+}
+
.left-yaxis-label {
top: 50%;
left: -5px;
diff --git a/public/test/test-main.js b/public/test/test-main.js
index 608305e46e7..5cc7b25dd6c 100644
--- a/public/test/test-main.js
+++ b/public/test/test-main.js
@@ -29,7 +29,6 @@
"bootstrap-tagsinput": "vendor/tagsinput/bootstrap-tagsinput.js",
"jquery.flot": "vendor/flot/jquery.flot",
"jquery.flot.pie": "vendor/flot/jquery.flot.pie",
- "jquery.flot.events": "vendor/flot/jquery.flot.events",
"jquery.flot.selection": "vendor/flot/jquery.flot.selection",
"jquery.flot.stack": "vendor/flot/jquery.flot.stack",
"jquery.flot.stackpercent": "vendor/flot/jquery.flot.stackpercent",
diff --git a/public/vendor/flot/jquery.flot.events.js b/public/vendor/flot/jquery.flot.events.js
deleted file mode 100644
index 6d8a0cf3c42..00000000000
--- a/public/vendor/flot/jquery.flot.events.js
+++ /dev/null
@@ -1,610 +0,0 @@
-/**
- * Flot plugin for adding 'events' to the plot.
- *
- * Events are small icons drawn onto the graph that represent something happening at that time.
- *
- * This plugin adds the following options to flot:
- *
- * options = {
- * events: {
- * levels: int // number of hierarchy levels
- * data: [], // array of event objects
- * types: [] // array of icons
- * xaxis: int // the x axis to attach events to
- * }
- * };
- *
- *
- * An event is a javascript object in the following form:
- *
- * {
- * min: startTime,
- * max: endTime,
- * eventType: "type",
- * title: "event title",
- * description: "event description"
- * }
- *
- * Types is an array of javascript objects in the following form:
- *
- * types: [
- * {
- * eventType: "eventType",
- * level: hierarchicalLevel,
- * icon: {
- image: "eventImage1.png",
- * width: 10,
- * height: 10
- * }
- * }
- * ]
- *
- * @author Joel Oughton
- */
-(function($){
- function init(plot){
- var DEFAULT_ICON = {
- icon: "icon-caret-up",
- size: 20,
- width: 19,
- height: 10
- };
-
- var _events = [], _types, _eventsEnabled = false;
-
- plot.getEvents = function(){
- return _events;
- };
-
- plot.hideEvents = function(levelRange){
-
- $.each(_events, function(index, event){
- if (_withinHierarchy(event.level(), levelRange)) {
- event.visual().getObject().hide();
- }
- });
-
- };
-
- plot.showEvents = function(levelRange){
- plot.hideEvents();
-
- $.each(_events, function(index, event){
- if (!_withinHierarchy(event.level(), levelRange)) {
- event.hide();
- }
- });
-
- _drawEvents();
- };
-
- plot.hooks.processOptions.push(function(plot, options){
- // enable the plugin
- if (options.events.data != null) {
- _eventsEnabled = true;
- }
- });
-
- plot.hooks.draw.push(function(plot, canvascontext){
- var options = plot.getOptions();
- var xaxis = plot.getXAxes()[options.events.xaxis - 1];
-
- if (_eventsEnabled) {
-
- // check for first run
- if (_events.length < 1) {
-
- // check for clustering
- if (options.events.clustering) {
- var ed = _clusterEvents(options.events.types, options.events.data, xaxis.max - xaxis.min);
- _types = ed.types;
- _setupEvents(ed.data);
- } else {
- _types = options.events.types;
- _setupEvents(options.events.data);
- }
-
- } else {
- /*if (options.events.clustering) {
- _clearEvents();
- var ed = _clusterEvents(options.events.types, options.events.data, xaxis.max - xaxis.min);
- _types = ed.types;
- _setupEvents(ed.data);
- }*/
- _updateEvents();
- }
- }
-
- _drawEvents();
- });
-
- var _drawEvents = function() {
- var o = plot.getPlotOffset();
- var pleft = o.left, pright = plot.width() - o.right;
-
- $.each(_events, function(index, event){
-
- // check event is inside the graph range and inside the hierarchy level
- if (_insidePlot(event.getOptions().min) &&
- !event.isHidden()) {
- event.visual().draw();
- } else {
- event.visual().getObject().hide();
- }
- });
-
- _identicalStarts();
- _overlaps();
- };
-
- var _withinHierarchy = function(level, levelRange){
- var range = {};
-
- if (!levelRange) {
- range.start = 0;
- range.end = _events.length - 1;
- } else {
- range.start = (levelRange.min == undefined) ? 0 : levelRange.min;
- range.end = (levelRange.max == undefined) ? _events.length - 1 : levelRange.max;
- }
-
- if (level >= range.start && level <= range.end) {
- return true;
- }
- return false;
- };
-
- var _clearEvents = function(){
- $.each(_events, function(index, val) {
- val.visual().clear();
- });
-
- _events = [];
- };
-
- var _updateEvents = function() {
- var o = plot.getPlotOffset(), left, top;
- var xaxis = plot.getXAxes()[plot.getOptions().events.xaxis - 1];
-
- $.each(_events, function(index, event) {
- top = o.top + plot.height() - event.visual().height();
- left = xaxis.p2c(event.getOptions().min) + o.left - event.visual().width() / 2;
-
- event.visual().moveTo({ top: top, left: left });
- });
- };
-
- var _showTooltip = function(x, y, event){
- /*
- var tooltip = $('').appendTo('body').fadeIn(200);
-
- $('' + event.title + '
').appendTo(tooltip);
- $('Type: ' + event.eventType + '
').appendTo(tooltip);
- $('' + event.description + '
').appendTo(tooltip);
-
- tooltip.css({
- top: y - tooltip.height() - 5,
- left: x
- });
- console.log(tooltip);
- */
-
- // grafana addition
- var $tooltip = $('');
- if (event) {
- $tooltip
- .html(event.description)
- .place_tt(x, y, {offset: 10, compile: true, scopeData: {event: event}});
- } else {
- $tooltip.remove();
- }
- };
-
- var _setupEvents = function(events){
-
- $.each(events, function(index, event){
- var level = (plot.getOptions().events.levels == null || !_types || !_types[event.eventType]) ? 0 : _types[event.eventType].level;
-
- if (level > plot.getOptions().events.levels) {
- throw "A type's level has exceeded the maximum. Level=" +
- level +
- ", Max levels:" +
- (plot.getOptions().events.levels);
- }
-
- _events.push(new VisualEvent(event, _buildDiv(event), level));
- });
-
- _events.sort(compareEvents);
- };
-
- var _identicalStarts = function() {
- var ranges = [], range = {}, event, prev, offset = 0;
-
- $.each(_events, function(index, val) {
-
- if (prev) {
- if (val.getOptions().min == prev.getOptions().min) {
-
- if (!range.min) {
- range.min = index;
- }
- range.max = index;
- } else {
- if (range.min) {
- ranges.push(range);
- range = {};
- }
- }
- }
-
- prev = val;
- });
-
- if (range.min) {
- ranges.push(range);
- }
-
- $.each(ranges, function(index, val) {
- var removed = _events.splice(val.min - offset, val.max - val.min + 1);
-
- $.each(removed, function(index, val) {
- val.visual().clear();
- });
-
- offset += val.max - val.min + 1;
- });
- };
-
- var _overlaps = function() {
- var xaxis = plot.getXAxes()[plot.getOptions().events.xaxis - 1];
- var range, diff, cmid, pmid, left = 0, right = -1;
- pright = plot.width() - plot.getPlotOffset().right;
-
- // coverts a clump of events into a single vertical line
- var processClump = function() {
- // find the middle x value
- pmid = _events[right].getOptions().min -
- (_events[right].getOptions().min - _events[left].getOptions().min) / 2;
-
- cmid = xaxis.p2c(pmid);
-
- // hide the events between the discovered range
- while (left <= right) {
- _events[left++].visual().getObject().hide();
- }
-
- // draw a vertical line in the middle of where they are
- if (_insidePlot(pmid)) {
- _drawLine('#000', 1, { x: cmid, y: 0 }, { x: cmid, y: plot.height() });
-
- }
- };
-
- if (xaxis.min && xaxis.max) {
- range = xaxis.max - xaxis.min;
-
- for (var i = 1; i < _events.length; i++) {
- diff = _events[i].getOptions().min - _events[i - 1].getOptions().min;
-
- if (diff / range > 0.007) { //enough variance
- // has a clump has been found
- if (right != -1) {
- //processClump();
- }
- right = -1;
- left = i;
- } else { // not enough variance
- right = i;
- // handle to final case
- if (i == _events.length - 1) {
- //processClump();
- }
- }
- }
- }
- };
-
- var _buildDiv = function(event){
- //var po = plot.pointOffset({ x: 450, y: 1});
- var container = plot.getPlaceholder(), o = plot.getPlotOffset(), yaxis,
- xaxis = plot.getXAxes()[plot.getOptions().events.xaxis - 1], axes = plot.getAxes();
- var top, left, div, icon, level, drawableEvent;
-
- // determine the y axis used
- if (axes.yaxis && axes.yaxis.used) yaxis = axes.yaxis;
- if (axes.yaxis2 && axes.yaxis2.used) yaxis = axes.yaxis2;
-
- // use the default icon and level
- if (_types == null || !_types[event.eventType] || !_types[event.eventType].icon) {
- icon = DEFAULT_ICON;
- level = 0;
- } else {
- icon = _types[event.eventType].icon;
- level = _types[event.eventType].level;
- }
-
- div = $('').appendTo(container);
-
- top = o.top + plot.height() - icon.size + 1;
- left = xaxis.p2c(event.min) + o.left - icon.size / 2;
-
- div.css({
- left: left + 'px',
- top: top,
- color: icon.color,
- "text-shadow" : "1px 1px "+icon.outline+", -1px -1px "+icon.outline+", -1px 1px "+icon.outline+", 1px -1px "+icon.outline,
- 'font-size': icon['size']+'px',
- });
- div.hide();
- div.data({
- "event": event
- });
- div.hover(
- // mouseenter
- function(){
- var pos = $(this).offset();
-
- _showTooltip(pos.left + $(this).width() / 2, pos.top, $(this).data("event"));
- },
- // mouseleave
- function(){
- //$(this).data("bouncing", false);
- $('#tooltip').remove();
- plot.clearSelection();
- });
-
- drawableEvent = new DrawableEvent(
- div,
- function(obj){
- obj.show();
- },
- function(obj){
- obj.remove();
- },
- function(obj, position){
- obj.css({
- top: position.top,
- left: position.left
- });
- },
- left, top, div.width(), div.height());
-
- return drawableEvent;
- };
-
- var _getEventsAtPos = function(x, y){
- var found = [], left, top, width, height;
-
- $.each(_events, function(index, val){
-
- left = val.div.offset().left;
- top = val.div.offset().top;
- width = val.div.width();
- height = val.div.height();
-
- if (x >= left && x <= left + width && y >= top && y <= top + height) {
- found.push(val);
- }
-
- return found;
- });
- };
-
- var _insidePlot = function(x) {
- var xaxis = plot.getXAxes()[plot.getOptions().events.xaxis - 1];
- var xc = xaxis.p2c(x);
-
- return xc > 0 && xc < xaxis.p2c(xaxis.max);
- };
-
- var _drawLine = function(color, lineWidth, from, to) {
- var ctx = plot.getCanvas().getContext("2d");
- var plotOffset = plot.getPlotOffset();
-
- ctx.save();
- ctx.translate(plotOffset.left, plotOffset.top);
-
- ctx.beginPath();
- ctx.strokeStyle = color;
- ctx.lineWidth = lineWidth;
- ctx.moveTo(from.x, from.y);
- ctx.lineTo(to.x, to.y);
- ctx.stroke();
-
- ctx.restore();
- };
-
-
- /**
- * Runs over the given 2d array of event objects and returns an object
- * containing:
- *
- * {
- * types {}, // An array containing all the different event types
- * data [], // An array of the clustered events
- * }
- *
- * @param {Object} types
- * an object containing event types
- * @param {Object} events
- * an array of event to cluster
- * @param {Object} range
- * the current graph range
- */
- var _clusterEvents = function(types, events, range) {
- //TODO: support custom types
- var groups, clusters = [], newEvents = [];
-
- // split into same evenType groups
- groups = _groupEvents(events);
-
- $.each(groups.eventTypes, function(index, val) {
- clusters.push(_varianceAlgorithm(groups.groupedEvents[val], 1, range));
- });
-
- // summarise clusters
- $.each(clusters, function(index, eventType) {
-
- // each cluser of each event type
- $.each(eventType, function(index, cluster) {
-
- var newEvent = {
- min: cluster[0].min,
- max: cluster[cluster.length - 1].min, //TODO: needs to be max of end event if it exists
- eventType: cluster[0].eventType + ",cluster",
- title: "Cluster of: " + cluster[0].title,
- description: cluster[0].description + ", Number of events in the cluster: " + cluster.length
- };
-
- newEvents.push(newEvent);
- });
- });
-
- return { types: types, data: newEvents };
- };
-
- /**
- * Runs over the given 2d array of event objects and returns an object
- * containing:
- *
- * {
- * eventTypes [], // An array containing all the different event types
- * groupedEvents {}, // An object containing all the grouped events
- * }
- *
- * @param {Object} events
- * an array of event objects
- */
- var _groupEvents = function(events) {
- var eventTypes = [], groupedEvents = {};
-
- $.each(events, function(index, val) {
- if (!groupedEvents[val.eventType]) {
- groupedEvents[val.eventType] = [];
- eventTypes.push(val.eventType);
- }
-
- groupedEvents[val.eventType].push(val);
- });
-
- return { eventTypes: eventTypes, groupedEvents: groupedEvents };
- };
-
- /**
- * Runs over the given 2d array of event objects and returns a 3d array of
- * the same events,but clustered into groups with similar x deltas.
- *
- * This function assumes that the events are related. So it must be run on
- * each set of related events.
- *
- * @param {Object} events
- * an array of event objects
- * @param {Object} sens
- * a measure of the level of grouping tolerance
- * @param {Object} space
- * the size of the space we have to place clusters within
- */
- var _varianceAlgorithm = function(events, sens, space) {
- var cluster, clusters = [], sum = 0, avg, density;
-
- // find the average x delta
- for (var i = 1; i < events.length - 1; i++) {
- sum += events[i].min - events[i - 1].min;
- }
- avg = sum / (events.length - 2);
-
- // first point
- cluster = [ events[0] ];
-
- // middle points
- for (var i = 1; i < events.length; i++) {
- var leftDiff = events[i].min - events[i - 1].min;
-
- density = leftDiff / space;
-
- if (leftDiff > avg * sens && density > 0.05) {
- clusters.push(cluster);
- cluster = [ events[i] ];
- } else {
- cluster.push(events[i]);
- }
- }
-
- clusters.push(cluster);
-
- return clusters;
- };
- }
-
- var options = {
- events: {
- levels: null,
- data: null,
- types: null,
- xaxis: 1,
- clustering: false
- }
- };
-
- $.plot.plugins.push({
- init: init,
- options: options,
- name: "events",
- version: "0.20"
- });
-
- /**
- * A class that allows for the drawing an remove of some object
- *
- * @param {Object} object
- * the drawable object
- * @param {Object} drawFunc
- * the draw function
- * @param {Object} clearFunc
- * the clear function
- */
- function DrawableEvent(object, drawFunc, clearFunc, moveFunc, left, top, width, height){
- var _object = object, _drawFunc = drawFunc, _clearFunc = clearFunc, _moveFunc = moveFunc,
- _position = { left: left, top: top }, _width = width, _height = height;
-
- this.width = function() { return _width; };
- this.height = function() { return _height };
- this.position = function() { return _position; };
- this.draw = function() { _drawFunc(_object); };
- this.clear = function() { _clearFunc(_object); };
- this.getObject = function() { return _object; };
- this.moveTo = function(position) {
- _position = position;
- _moveFunc(_object, _position);
- };
- }
-
- /**
- * Event class that stores options (eventType, min, max, title, description) and the object to draw.
- *
- * @param {Object} options
- * @param {Object} drawableEvent
- */
- function VisualEvent(options, drawableEvent, level){
- var _parent, _options = options, _drawableEvent = drawableEvent,
- _level = level, _hidden = false;
-
- this.visual = function() { return _drawableEvent; }
- this.level = function() { return _level; };
- this.getOptions = function() { return _options; };
- this.getParent = function() { return _parent; };
-
- this.isHidden = function() { return _hidden; };
- this.hide = function() { _hidden = true; };
- this.unhide = function() { _hidden = false; };
- }
-
- function compareEvents(a, b) {
- var ao = a.getOptions(), bo = b.getOptions();
-
- if (ao.min > bo.min) return 1;
- if (ao.min < bo.min) return -1;
- return 0;
- };
-})(jQuery);