diff --git a/package.json b/package.json
index 6b13820..5d2c8ae 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "prelert_swimlane_vis",
- "version": "0.1.1",
+ "version": "5.0.0",
"description": "Prelert swimlane visualization plugin",
"license": "Apache-2.0"
}
diff --git a/public/prelert_swimlane_vis.html b/public/prelert_swimlane_vis.html
index edcfb8d..d6edd27 100644
--- a/public/prelert_swimlane_vis.html
+++ b/public/prelert_swimlane_vis.html
@@ -11,12 +11,12 @@
info="This interval creates {{ vis.params.interval.scale > 1 ? 'buckets that are too large' : 'too many buckets' }} to show in the selected time range, so it has been scaled to {{ vis.params.interval.description }}">
-
+
-
+
-
+
+
diff --git a/public/prelert_swimlane_vis.js b/public/prelert_swimlane_vis.js
index d3d4b58..93bd1e8 100644
--- a/public/prelert_swimlane_vis.js
+++ b/public/prelert_swimlane_vis.js
@@ -18,79 +18,76 @@
****************************************************************************
*/
-define(function(require) {
+import 'plugins/prelert_swimlane_vis/prelert_swimlane_vis_controller.js';
+import 'plugins/prelert_swimlane_vis/prelert_swimlane_vis.less';
- require('plugins/prelert_swimlane_vis/prelert_swimlane_vis_controller.js');
- require('plugins/prelert_swimlane_vis/prelert_swimlane_vis.less');
+import visTypes from 'ui/registry/vis_types';
+import TemplateVisTypeProvider from 'ui/template_vis_type/template_vis_type';
+import VisSchemasProvider from 'ui/vis/schemas';
- // Register the PrelertSwimlaneVisProvider with the visualization registry.
- require('ui/registry/vis_types').register(PrelertSwimlaneVisProvider);
+// Register the PrelertSwimlaneVisProvider with the visualization registry.
+visTypes.register(PrelertSwimlaneVisProvider);
- function PrelertSwimlaneVisProvider(Private) {
- var TemplateVisType = Private(require('ui/template_vis_type/TemplateVisType'));
- var Schemas = Private(require('ui/Vis/Schemas'));
+function PrelertSwimlaneVisProvider(Private) {
+ const TemplateVisType = Private(TemplateVisTypeProvider);
+ const Schemas = Private(VisSchemasProvider);
- // Return a new instance describing this visualization.
- return new TemplateVisType({
- name : 'prelert_swimlane',
- title : 'Swimlane',
- icon : 'fa-bars',
- description : 'Swimlane visualization displaying the behavior of a metric ' +
- 'over time across a field from the results. ' +
- 'Each lane displays a different value of the field, with the ' +
- 'relative size of the metric over each interval indicated ' +
- 'by the color of the symbol at that time. ' +
- 'Created by Prelert for Behavioral Analytics www.prelert.com',
- template : require('plugins/prelert_swimlane_vis/prelert_swimlane_vis.html'),
- params : {
- editor : require('plugins/prelert_swimlane_vis/prelert_swimlane_vis_params.html'),
- defaults : {
- interval : { display : 'Auto', val : 'auto' },
- lowThreshold: 0,
- warningThreshold: 3,
- minorThreshold: 25,
- majorThreshold: 50,
- criticalThreshold: 75,
- tooltipNumberFormat: '0.0'
- },
- intervalOptions: [{display:'Auto', val:'auto'},
- {display:'5 minutes', val:'custom', customInterval:'5m'},
- {display:'10 minutes', val:'custom', customInterval:'10m'},
- {display:'30 minutes', val:'custom', customInterval:'30m'},
- {display:'1 hour', val:'h'},
- {display:'3 hours', val:'custom', customInterval:'3h'},
- {display:'12 hours', val:'custom', customInterval:'12h'},
- {display:'1 day', val:'d'}]
+ // Return a new instance describing this visualization.
+ return new TemplateVisType({
+ name : 'prelert_swimlane',
+ title : 'Swimlane',
+ icon : 'fa-bars',
+ description : 'Swimlane visualization displaying the behavior of a metric ' +
+ 'over time across a field from the results. ' +
+ 'Each lane displays a different value of the field, with the ' +
+ 'relative size of the metric over each interval indicated ' +
+ 'by the color of the symbol at that time. ' +
+ 'Created by Prelert for Behavioral Analytics www.prelert.com',
+ template : require('plugins/prelert_swimlane_vis/prelert_swimlane_vis.html'),
+ params : {
+ editor : require('plugins/prelert_swimlane_vis/prelert_swimlane_vis_params.html'),
+ defaults : {
+ interval : { display : 'Auto', val : 'auto' },
+ lowThreshold: 0,
+ warningThreshold: 3,
+ minorThreshold: 25,
+ majorThreshold: 50,
+ criticalThreshold: 75,
+ tooltipNumberFormat: '0.0'
},
- schemas : new Schemas([ {
- group : 'metrics',
- name : 'metric',
- title : 'Value',
- min : 1,
- max : 1,
- aggFilter : [ 'count', 'avg', 'sum', 'min', 'max' ]
- }, {
- group : 'buckets',
- name : 'viewBy',
- icon : 'fa fa-eye',
- title : 'View by',
- mustBeFirst : true,
- min : 0,
- max : 1,
- aggFilter : 'terms'
- }, {
- group : 'buckets',
- name : 'timeSplit',
- icon : 'fa fa-th',
- title : 'Time field',
- min : 1,
- max : 1,
- aggFilter : 'date_histogram'
- } ])
- });
- }
-
- // export the provider so that the visType can be required with Private()
- return PrelertSwimlaneVisProvider;
-
-});
+ intervalOptions: [{display:'Auto', val:'auto'},
+ {display:'5 minutes', val:'custom', customInterval:'5m'},
+ {display:'10 minutes', val:'custom', customInterval:'10m'},
+ {display:'30 minutes', val:'custom', customInterval:'30m'},
+ {display:'1 hour', val:'h'},
+ {display:'3 hours', val:'custom', customInterval:'3h'},
+ {display:'12 hours', val:'custom', customInterval:'12h'},
+ {display:'1 day', val:'d'}]
+ },
+ schemas : new Schemas([ {
+ group : 'metrics',
+ name : 'metric',
+ title : 'Value',
+ min : 1,
+ max : 1,
+ aggFilter : [ 'count', 'avg', 'sum', 'min', 'max', 'cardinality' ]
+ }, {
+ group : 'buckets',
+ name : 'viewBy',
+ icon : 'fa fa-eye',
+ title : 'View by',
+ mustBeFirst : true,
+ min : 0,
+ max : 1,
+ aggFilter : 'terms'
+ }, {
+ group : 'buckets',
+ name : 'timeSplit',
+ icon : 'fa fa-th',
+ title : 'Time field',
+ min : 1,
+ max : 1,
+ aggFilter : 'date_histogram'
+ } ])
+ });
+};
diff --git a/public/prelert_swimlane_vis.less b/public/prelert_swimlane_vis.less
index 2e6469b..77c2240 100644
--- a/public/prelert_swimlane_vis.less
+++ b/public/prelert_swimlane_vis.less
@@ -15,7 +15,7 @@
padding-right: 5px;
padding-left: 5px;
}
-
+
.flot-y-axis {
.flot-tick-label {
@@ -28,7 +28,7 @@
z-index: 1;
}
}
-
+
.prl-swimlane-vis-point-over {
cursor: pointer !important;
}
@@ -36,14 +36,14 @@
.prl-swimlane-vis-options {
div.threshold-input-container {
- display: block;
+ display: block;
padding-bottom: 7px;
-
+
.fa-circle {
- display:inline;
+ display:inline;
font-size:16px;
}
-
+
.icon-severity-critical {
color: #fe5050;
}
@@ -59,7 +59,7 @@
.icon-severity-warning {
color: #8bc8fb;
}
-
+
.icon-severity-low {
color: #d2e9f7;
}
@@ -67,12 +67,12 @@
.icon-severity-unknown {
color: #e6e6e6;
}
-
+
input[type="number"] {
display:inline;
width: 110px;
font-size: 12px;
- }
+ }
}
}
@@ -86,7 +86,7 @@
background-color: #303030;
font-family: Roboto, Droid, Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 12px;
-
+
hr {
margin-top: 3px;
margin-bottom: 3px;
@@ -98,9 +98,8 @@
.prl-swimlane-vis {
color: #cecece;
}
-
+
.flot-tick-label {
color: #cecece;
}
}
-
diff --git a/public/prelert_swimlane_vis_controller.js b/public/prelert_swimlane_vis_controller.js
index 57112c7..189c798 100644
--- a/public/prelert_swimlane_vis_controller.js
+++ b/public/prelert_swimlane_vis_controller.js
@@ -18,21 +18,24 @@
****************************************************************************
*/
-var _ = require('lodash');
-var $ = require('jquery');
-var moment = require('moment');
-var numeral = require('numeral');
-var flot = require("imports?$=jquery!./lib/bower_components/flot/jquery.flot");
-require("imports?$=jquery!./lib/bower_components/flot/jquery.flot.selection");
-require("imports?$=jquery!./lib/bower_components/flot/jquery.flot.time");
-require("imports?$=jquery,this=>window!./lib/bower_components/flot/jquery.flot.resize");
-require('ui/courier');
-require('ui/timefilter');
-require('ui/directives/inequality');
-
-var module = require('ui/modules').get('prelert_swimlane_vis/prelert_swimlane_vis', ['kibana']);
-
-module.controller('PrelertSwimlaneVisController', function($scope, courier) {
+import angular from 'angular';
+import _ from 'lodash';
+import $ from 'jquery';
+import moment from 'moment';
+import numeral from 'numeral';
+require('imports?$=jquery!./lib/bower_components/flot/jquery.flot');
+require('imports?$=jquery!./lib/bower_components/flot/jquery.flot.selection');
+require('imports?$=jquery!./lib/bower_components/flot/jquery.flot.time');
+require('imports?$=jquery,this=>window!./lib/bower_components/flot/jquery.flot.resize');
+
+import 'ui/courier';
+import 'ui/timefilter';
+import 'ui/directives/inequality';
+import chrome from 'ui/chrome';
+import uiModules from 'ui/modules';
+
+const module = uiModules.get('prelert_swimlane_vis/prelert_swimlane_vis', ['kibana']);
+module.controller('PrelertSwimlaneVisController', function ($scope, courier) {
$scope.$watch('esResponse', function (resp) {
@@ -44,8 +47,8 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
if (resp.hits.total !== 0) {
// Remove ng-hide from the parent div as that has display:none,
// resulting in the flot chart labels falling inside the chart area on first render.
- var ngHideContainer = $("prl-swimlane-vis").closest( ".ng-hide" );
- ngHideContainer.removeClass("ng-hide");
+ let ngHideContainer = $('prl-swimlane-vis').closest('.ng-hide');
+ ngHideContainer.removeClass('ng-hide');
}
// Process the aggregations in the ES response.
@@ -53,49 +56,49 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
syncViewControls();
- // Tell the swimlane directive to render.
+ // Tell the swimlane directive to render.
$scope.$emit('render');
});
- $scope.processAggregations = function(aggregations) {
- var dataByViewBy = {};
+ $scope.processAggregations = function (aggregations) {
+ let dataByViewBy = {};
- if (aggregations &&
- ($scope.vis.aggs.bySchemaName['metric'] !== undefined) &&
- ($scope.vis.aggs.bySchemaName['timeSplit'] !== undefined) ) {
+ if (aggregations &&
+ ($scope.vis.aggs.bySchemaName.metric !== undefined) &&
+ ($scope.vis.aggs.bySchemaName.timeSplit !== undefined)) {
// Retrieve the visualization aggregations.
- var metricsAgg = $scope.vis.aggs.bySchemaName['metric'][0];
- var timeAgg = $scope.vis.aggs.bySchemaName['timeSplit'][0];
- var timeAggId = timeAgg.id;
-
- if ($scope.vis.aggs.bySchemaName['viewBy'] !== undefined) {
+ let metricsAgg = $scope.vis.aggs.bySchemaName.metric[0];
+ let timeAgg = $scope.vis.aggs.bySchemaName.timeSplit[0];
+ let timeAggId = timeAgg.id;
+
+ if ($scope.vis.aggs.bySchemaName.viewBy !== undefined) {
// Get the buckets of the viewBy aggregation.
- var viewByAgg = $scope.vis.aggs.bySchemaName['viewBy'][0];
- var buckets = aggregations[viewByAgg.id].buckets;
- _.each(buckets, function(bucket){
+ let viewByAgg = $scope.vis.aggs.bySchemaName.viewBy[0];
+ let viewByBuckets = aggregations[viewByAgg.id].buckets;
+ _.each(viewByBuckets, function (bucket) {
// There will be 1 bucket for each 'view by' value.
- var viewByValue = bucket.key;
- var timesForViewBy = {};
+ let viewByValue = bucket.key;
+ let timesForViewBy = {};
dataByViewBy[viewByValue] = timesForViewBy;
- var bucketsForViewByValue = bucket[timeAggId].buckets;
- _.each(bucketsForViewByValue, function(valueBucket) {
+ let bucketsForViewByValue = bucket[timeAggId].buckets;
+ _.each(bucketsForViewByValue, function (valueBucket) {
// time is the 'valueBucket' key.
timesForViewBy[valueBucket.key] = {
- value: metricsAgg.getValue(valueBucket)
+ value: metricsAgg.getValue(valueBucket)
};
});
});
} else {
// No 'View by' selected - compile data for a single swimlane
// showing the time bucketed metric value.
- var timesForViewBy = {};
- var buckets = aggregations[timeAggId].buckets;
- _.each(buckets, function(bucket){
+ let timesForViewBy = {};
+ let buckets = aggregations[timeAggId].buckets;
+ _.each(buckets, function (bucket) {
timesForViewBy[bucket.key] = { value: metricsAgg.getValue(bucket) };
});
-
+
// Use the metric label as the swimlane label.
dataByViewBy[metricsAgg.makeLabel()] = timesForViewBy;
}
@@ -109,25 +112,25 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
function syncViewControls() {
// Synchronize the Interval control to match the aggregation run in the view,
// e.g. if being edited via the Kibana Visualization tab sidebar.
- if ($scope.vis.aggs.length === 0 || $scope.vis.aggs.bySchemaName['timeSplit'] === undefined) {
+ if ($scope.vis.aggs.length === 0 || $scope.vis.aggs.bySchemaName.timeSplit === undefined) {
return;
}
// Retrieve the visualization aggregations.
- var timeAgg = $scope.vis.aggs.bySchemaName['timeSplit'][0];
+ let timeAgg = $scope.vis.aggs.bySchemaName.timeSplit[0];
// Update the scope 'interval' field.
- var aggInterval = _.get(timeAgg, ['params', 'interval', 'val']);
+ let aggInterval = _.get(timeAgg, ['params', 'interval', 'val']);
if (aggInterval === 'custom') {
aggInterval = _.get(timeAgg, ['params', 'customInterval']);
- }
+ }
- var scopeInterval = $scope.vis.params.interval.val;
+ let scopeInterval = $scope.vis.params.interval.val;
if (scopeInterval && scopeInterval === 'custom') {
scopeInterval = $scope.vis.params.interval.customInterval;
}
- var setToInterval = _.findWhere($scope.vis.type.params.intervalOptions, {val: aggInterval});
+ let setToInterval = _.findWhere($scope.vis.type.params.intervalOptions, {val: aggInterval});
if (!setToInterval) {
setToInterval = _.findWhere($scope.vis.type.params.intervalOptions, {customInterval: aggInterval});
}
@@ -137,12 +140,12 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
if (_.get(timeAgg, ['params', 'interval', 'val']) !== 'custom') {
setToInterval.val = _.get(timeAgg, ['params', 'interval', 'val']);
- setToInterval.display = "Custom: " + _.get(timeAgg, ['params', 'interval', 'val']);
+ setToInterval.display = 'Custom: ' + _.get(timeAgg, ['params', 'interval', 'val']);
} else {
- setToInterval.val = "custom";
+ setToInterval.val = 'custom';
setToInterval.customInterval = _.get(timeAgg, ['params', 'customInterval']);
- setToInterval.display = "Custom: " + _.get(timeAgg, ['params', 'customInterval']);
- }
+ setToInterval.display = 'Custom: ' + _.get(timeAgg, ['params', 'customInterval']);
+ }
$scope.vis.type.params.intervalOptions.push(setToInterval);
}
@@ -150,32 +153,32 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
// Set the flags which indicate if the interval has been scaled.
// e.g. if requesting points at 5 min interval would result in too many buckets being returned.
- var timeBucketsInterval = timeAgg.buckets.getInterval();
+ let timeBucketsInterval = timeAgg.buckets.getInterval();
setToInterval.scaled = timeBucketsInterval.scaled;
setToInterval.scale = timeBucketsInterval.scale;
setToInterval.description = timeBucketsInterval.description;
- $scope.vis.params.interval = setToInterval;
+ $scope.vis.params.interval = setToInterval;
}
- $scope.updateViewState = function() {
+ $scope.updateViewState = function () {
// Set up the visualization in response to a change in the Interval control.
setupVisualization()
.then(function () {
// Re-run the dashboard search.
return courier.fetch();
})
- .catch(function(error) {
- console.log("Error updating swimlane visualization with new view state.", error);
+ .catch(function (error) {
+ console.log('Error updating swimlane visualization with new view state.', error);
});
};
function setupVisualization() {
// Set the params of the time aggregation to the selected 'interval' field.
- if ($scope.vis) {
+ if ($scope.vis) {
// Set the aggregation interval of the 'timeSplit' aggregation.
- var visState = $scope.vis.getState();
- var timeAgg = _.find(visState.aggs, { 'schema': 'timeSplit' });
+ let visState = $scope.vis.getState();
+ let timeAgg = _.find(visState.aggs, { 'schema': 'timeSplit' });
timeAgg.params.interval = $scope.vis.params.interval.val;
if ($scope.vis.params.interval.val === 'custom') {
timeAgg.params.customInterval = $scope.vis.params.interval.customInterval;
@@ -186,167 +189,166 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
// Update the time interval of the 'editable vis'
// i.e. if visualization is being viewed in the Kibana Visualize view,
// we need to update the configurations for the aggregations in the editor sidebar.
- var editableVis = $scope.vis.getEditableVis();
+ let editableVis = $scope.vis.getEditableVis();
if (editableVis) {
- var editableVisState = editableVis.getState();
- var editableTimeAgg = _.find(editableVisState.aggs, { 'schema': 'timeSplit' });
+ let editableVisState = editableVis.getState();
+ let editableTimeAgg = _.find(editableVisState.aggs, { 'schema': 'timeSplit' });
editableTimeAgg.params.interval = $scope.vis.params.interval.val;
if ($scope.vis.params.interval.val === 'custom') {
editableTimeAgg.params.customInterval = $scope.vis.params.interval.customInterval;
}
editableVis.setState(editableVisState);
- }
+ }
return Promise.resolve($scope.vis);
}
}
+ $scope.prelertLogoSrc = chrome.getBasePath() + '/plugins/prelert_swimlane_vis/prelert_logo_24.png';
+
})
-.directive('prlSwimlaneVis', function($compile, timefilter) {
+.directive('prlSwimlaneVis', function ($compile, timefilter) {
function link(scope, element, attrs) {
scope._previousHoverPoint = null;
scope._influencerHoverScope = null;
- scope.$on('render',function(event, d){
- if (scope.vis.aggs.length !== 0 && scope.vis.aggs.bySchemaName['timeSplit'] !== undefined) {
+ scope.$on('render',function (event, d) {
+ if (scope.vis.aggs.length !== 0 && scope.vis.aggs.bySchemaName.timeSplit !== undefined) {
renderSwimlane();
}
});
-
+
function renderSwimlane() {
- var chartData = scope.metricsData || [];
- var allSeries = [];
+ let chartData = scope.metricsData || [];
+ let allSeries = [];
- // Create a series for each severity color band,
+ // Create a series for each severity color band,
// plus an 'unknown' series for scores less than the 'low' threshold.
- var colorBands = ['#e6e6e6', '#d2e9f7', '#8bc8fb', '#ffdd00', '#ff7e00', '#fe5050'];
- var seriesLabels = ['unknown','low','warning','minor','major','critical'];
- _.each(colorBands, function(color, i){
- var series = {};
+ const colorBands = ['#e6e6e6', '#d2e9f7', '#8bc8fb', '#ffdd00', '#ff7e00', '#fe5050'];
+ const seriesLabels = ['unknown','low','warning','minor','major','critical'];
+ _.each(colorBands, function (color, i) {
+ let series = {};
series.label = seriesLabels[i];
series.color = color;
series.points = { fillColor: color, show: true, radius: 5, symbol: drawChartSymbol, lineWidth: 1 };
series.data = [];
series.shadowSize = 0;
allSeries.push(series);
- });
+ });
// Sort the lane labels in reverse so that the order is a-z from the top.
chartData = sortChartDataByLaneLabel(chartData);
- var laneIds = _.keys(chartData);
+ let laneIds = _.keys(chartData);
- var laneIndex = 0;
- _.each(chartData, function(bucketsForViewByValue, viewByValue) {
+ let laneIndex = 0;
+ _.each(chartData, function (bucketsForViewByValue, viewByValue) {
laneIndex = laneIds.indexOf(viewByValue);
- _.each(bucketsForViewByValue, function(dataForTime, time) {
- var value = dataForTime.value;
-
- var pointData = new Array();
+ _.each(bucketsForViewByValue, function (dataForTime, time) {
+ const value = dataForTime.value;
+
+ const pointData = new Array();
pointData[0] = moment(Number(time));
pointData[1] = laneIndex + 0.5;
// Store the score in an additional object property for each point.
pointData[2] = {score: value};
- var seriesIndex = getSeriesIndex(value);
+ const seriesIndex = getSeriesIndex(value);
allSeries[seriesIndex].data.push(pointData);
-
- });
+ });
});
// Extract the bounds of the time filter so we can set the x-axis min and max.
// If no min/max supplied, Flot will automatically set them according to the data values.
- var bounds = timefilter.getActiveBounds();
- var earliest = null;
- var latest = null;
+ const bounds = timefilter.getActiveBounds();
+ let earliest = null;
+ let latest = null;
if (bounds) {
- var timeAgg = scope.vis.aggs.bySchemaName['timeSplit'][0];
- var aggInterval = timeAgg.buckets.getInterval();
+ let timeAgg = scope.vis.aggs.bySchemaName.timeSplit[0];
+ let aggInterval = timeAgg.buckets.getInterval();
// Elasticsearch aggregation returns points at start of bucket,
// so set the x-axis min to the start of the aggregation interval.
earliest = moment(bounds.min).startOf(aggInterval.description).valueOf();
latest = moment(bounds.max).valueOf();
- }
-
-
- var options = {
- xaxis: {
- mode: "time",
- timeformat: "%d %b %H:%M",
- tickFormatter: function(v, axis) {
- // Only show time if tick spacing is less than a day.
- var tickGap = (axis.max - axis.min)/10000; // Approx 10 ticks, convert to sec.
- if (tickGap < 86400) {
- return moment(v).format('MMM D HH:mm');
- } else {
- return moment(v).format('MMM D YYYY');
- }
- },
- min: _.isUndefined(earliest) ? null : earliest,
- max: _.isUndefined(latest) ? null : latest,
- color: '#d5d5d5'
- },
- yaxis: {
- min: 0,
- color: null,
- tickColor: null,
- tickLength: 0,
- },
- grid: {
- backgroundColor: null,
- borderWidth: 1,
- hoverable: true,
- clickable: false,
- borderColor: '#cccccc',
- color: null,
- },
- legend : {
- show: false
+ }
+
+
+ const options = {
+ xaxis: {
+ mode: 'time',
+ timeformat: '%d %b %H:%M',
+ tickFormatter: function (v, axis) {
+ // Only show time if tick spacing is less than a day.
+ const tickGap = (axis.max - axis.min) / 10000; // Approx 10 ticks, convert to sec.
+ if (tickGap < 86400) {
+ return moment(v).format('MMM D HH:mm');
+ } else {
+ return moment(v).format('MMM D YYYY');
+ }
},
- selection: {
- mode: "x",
- color: '#bbbbbb'
- }
+ min: _.isUndefined(earliest) ? null : earliest,
+ max: _.isUndefined(latest) ? null : latest,
+ color: '#d5d5d5'
+ },
+ yaxis: {
+ min: 0,
+ color: null,
+ tickColor: null,
+ tickLength: 0,
+ },
+ grid: {
+ backgroundColor: null,
+ borderWidth: 1,
+ hoverable: true,
+ clickable: false,
+ borderColor: '#cccccc',
+ color: null,
+ },
+ legend : {
+ show: false
+ },
+ selection: {
+ mode: 'x',
+ color: '#bbbbbb'
+ }
};
// Set the alternate lane marking color depending on whether Kibana dark theme is being used.
- var alternateLaneColor = element.closest('.theme-dark').length === 0 ? '#f5f5f5' : "#4a4a4a";
-
+ const alternateLaneColor = element.closest('.theme-dark').length === 0 ? '#f5f5f5' : '#4a4a4a';
+
options.yaxis.max = laneIds.length;
options.yaxis.ticks = [];
options.grid.markings = [];
- var yaxisMarking;
- _.each(laneIds, function(labelId, i){
- var labelText = labelId;
+ let yaxisMarking;
+ _.each(laneIds, function (labelId, i) {
+ let labelText = labelId;
// Crop 'viewBy' labels over 27 chars of more so that the y-axis labels don't take up too much width.
- var labelText = (labelText.length < 28 ? labelText : labelText.substring(0, 25) + "...");
- var tick = [i+0.5, labelText];
+ labelText = (labelText.length < 28 ? labelText : labelText.substring(0, 25) + '...');
+ let tick = [i + 0.5, labelText];
options.yaxis.ticks.push(tick);
// Set up marking effects for each lane.
if (i > 0) {
yaxisMarking = {};
yaxisMarking.from = i;
- yaxisMarking.to = i+0.03;
- var marking = {yaxis: yaxisMarking, color: "#d5d5d5"};
- options.grid.markings.push(marking);
+ yaxisMarking.to = i + 0.03;
+ options.grid.markings.push({yaxis: yaxisMarking, color: '#d5d5d5'});
}
- if (i % 2 != 0) {
+ if (i % 2 !== 0) {
yaxisMarking = {};
- yaxisMarking.from = i+0.03;
- yaxisMarking.to = i+1;
- var marking = {yaxis: yaxisMarking, color: alternateLaneColor};
- options.grid.markings.push(marking);
+ yaxisMarking.from = i + 0.03;
+ yaxisMarking.to = i + 1;
+ options.grid.markings.push({yaxis: yaxisMarking, color: alternateLaneColor});
}
});
@@ -355,36 +357,36 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
element.height((laneIds.length * 32) + 50);
// Draw the plot.
- var plot = $.plot(element, allSeries, options);
+ const plot = $.plot(element, allSeries, options);
// Add tooltips to the y-axis labels to display the full 'viewBy' field
// - useful for cases where a long text value has been cropped.
// NB. requires z-index set in CSS so that hover is picked up on label.
- var yAxisLabelDivs = $('.flot-y-axis', angular.element(element)).find('.flot-tick-label');
- _.each(laneIds, function(labelId, i) {
- var labelText = labelId;
+ const yAxisLabelDivs = $('.flot-y-axis', angular.element(element)).find('.flot-tick-label');
+ _.each(laneIds, function (labelId, i) {
+ const labelText = labelId;
$(yAxisLabelDivs[i]).attr('title', labelText);
});
// Show tooltips on point hover.
- element.unbind("plothover");
- element.bind("plothover", function (event, pos, item) {
+ element.unbind('plothover');
+ element.bind('plothover', function (event, pos, item) {
if (item) {
element.addClass('prl-swimlane-vis-point-over ');
- if (scope._previousHoverPoint != item.dataIndex) {
+ if (scope._previousHoverPoint !== item.dataIndex) {
scope._previousHoverPoint = item.dataIndex;
- $(".prl-swimlane-vis-tooltip").remove();
+ $('.prl-swimlane-vis-tooltip').remove();
if (scope._influencerHoverScope) {
scope._influencerHoverScope.$destroy();
}
- var laneIndex = item.series.data[item.dataIndex][1] - 0.5;
- var laneLabel = laneIds[laneIndex];
+ const laneIndex = item.series.data[item.dataIndex][1] - 0.5;
+ const laneLabel = laneIds[laneIndex];
showTooltip(item, laneLabel);
}
} else {
element.removeClass('prl-swimlane-vis-point-over ');
- $(".prl-swimlane-vis-tooltip").remove();
+ $('.prl-swimlane-vis-tooltip').remove();
scope._previousHoverPoint = null;
if (scope._influencerHoverScope) {
scope._influencerHoverScope.$destroy();
@@ -393,19 +395,19 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
});
// Set the Kibana timefilter if the user selects a range on the chart.
- element.unbind("plotselected");
- element.bind("plotselected", function (event, ranges) {
- var zoomFrom = ranges.xaxis.from;
- var zoomTo = ranges.xaxis.to;
+ element.unbind('plotselected');
+ element.bind('plotselected', function (event, ranges) {
+ let zoomFrom = ranges.xaxis.from;
+ let zoomTo = ranges.xaxis.to;
// Aggregation returns points at start of bucket, so make sure the time
// range zoomed in to covers the full aggregation interval.
- var timeAgg = scope.vis.aggs.bySchemaName['timeSplit'][0];
- var aggIntervalMs = timeAgg.buckets.getInterval().asMilliseconds();
+ const timeAgg = scope.vis.aggs.bySchemaName.timeSplit[0];
+ const aggIntervalMs = timeAgg.buckets.getInterval().asMilliseconds();
// Add a bit of extra padding before start time.
- zoomFrom = zoomFrom - (aggIntervalMs/4);
- zoomTo = zoomTo+aggIntervalMs;
+ zoomFrom = zoomFrom - (aggIntervalMs / 4);
+ zoomTo = zoomTo + aggIntervalMs;
timefilter.time.from = moment.utc(zoomFrom);
timefilter.time.to = moment.utc(zoomTo);
@@ -413,7 +415,7 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
});
}
-
+
function getSeriesIndex(value) {
// Maps value to the index of the series used for values in that range.
// Uses the five colour bands configured in the visualization options,
@@ -435,15 +437,15 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
}
if (value >= scope.vis.params.criticalThreshold) {
return 5;
- }
+ }
}
-
+
function sortChartDataByLaneLabel(list) {
// Sorts chart data according to lane label.
- var keys = _.sortBy(_.keys(list), function (key) {
+ let keys = _.sortBy(_.keys(list), function (key) {
return key;
});
-
+
// Reverse so that the order is a-z from the top.
keys = keys.reverse();
@@ -453,43 +455,44 @@ module.controller('PrelertSwimlaneVisController', function($scope, courier) {
}
function drawChartSymbol(ctx, x, y, radius, shadow) {
- var size = radius * Math.sqrt(Math.PI) / 2;
+ const size = radius * Math.sqrt(Math.PI) / 2;
ctx.rect(x - size, y - 14, size + size, 28);
}
function showTooltip(item, laneLabel) {
- var pointTime = item.datapoint[0];
- var dataModel = item.series.data[item.dataIndex][2];
- var score = parseInt(dataModel.score);
- var metricsAgg = scope.vis.aggs.bySchemaName['metric'][0];
- var metricLabel = metricsAgg.makeLabel();
- var displayScore = numeral(dataModel.score).format(scope.vis.params.tooltipNumberFormat);
+ const pointTime = item.datapoint[0];
+ const dataModel = item.series.data[item.dataIndex][2];
+ const score = parseInt(dataModel.score);
+ const metricsAgg = scope.vis.aggs.bySchemaName.metric[0];
+ const metricLabel = metricsAgg.makeLabel();
+ const displayScore = numeral(dataModel.score).format(scope.vis.params.tooltipNumberFormat);
// Display date using same format as used in Kibana visualizations.
- var formattedDate = moment(pointTime).format('MMMM Do YYYY, HH:mm');
- var contents = formattedDate + "
";
-
- contents += (metricLabel + ": " + displayScore);
-
- var x = item.pageX;
- var y = item.pageY;
- var offset = 5;
- $("" + contents + "
").css({
- "position": "absolute",
- "display": "none",
- "top": y + offset,
- "left": x + offset
- }).appendTo("body").fadeIn(200);
+ const formattedDate = moment(pointTime).format('MMMM Do YYYY, HH:mm');
+ let contents = formattedDate + '
';
+
+ contents += (metricLabel + ': ' + displayScore);
+
+ const x = item.pageX;
+ const y = item.pageY;
+ const offset = 5;
+ $('' + contents + '
').css({
+ 'position': 'absolute',
+ 'display': 'none',
+ 'z-index': 1,
+ 'top': y + offset,
+ 'left': x + offset
+ }).appendTo('body').fadeIn(200);
// Position the tooltip.
- var $win = $(window);
- var winHeight = $win.height();
- var yOffset = window.pageYOffset;
- var width = $(".prl-swimlane-vis-tooltip").outerWidth(true);
- var height = $(".prl-swimlane-vis-tooltip").outerHeight(true);
-
- $(".prl-swimlane-vis-tooltip").css('left', x + offset + width > $win.width() ? x - offset - width : x + offset);
- $(".prl-swimlane-vis-tooltip").css('top', y + height < winHeight + yOffset ? y : y -height);
+ const $win = $(window);
+ const winHeight = $win.height();
+ const yOffset = window.pageYOffset;
+ const width = $('.prl-swimlane-vis-tooltip').outerWidth(true);
+ const height = $('.prl-swimlane-vis-tooltip').outerHeight(true);
+
+ $('.prl-swimlane-vis-tooltip').css('left', x + offset + width > $win.width() ? x - offset - width : x + offset);
+ $('.prl-swimlane-vis-tooltip').css('top', y + height < winHeight + yOffset ? y : y - height);
}
}