You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

527 lines
18 KiB

'use strict';
System.register(['./libs/d3/d3', 'app/core/time_series2', 'app/core/utils/kbn', 'app/plugins/sdk', './properties', 'lodash', 'moment', './series_overrides_heatmap_ctrl', './css/heatmap.css!'], function (_export, _context) {
"use strict";
var TimeSeries, kbn, MetricsPanelCtrl, heatmapEditor, displayEditor, pluginName, _, moment, _createClass, panelOptions, panelDefaults, HeatmapCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
function ensureArrayContains(array, value) {
if (array.indexOf(value) == -1) {
array.push(value);
}
}
function colorToHex(color) {
if (color.substr(0, 1) === '#') {
return color;
}
var digits = color.replace(/[rgba\(\)\ ]/g, '').split(',');
while (digits.length < 3) {
digits.push(255);
}
var red = parseInt(digits[0]);
var green = parseInt(digits[1]);
var blue = parseInt(digits[2]);
var rgba = blue | green << 8 | red << 16;
return '#' + rgba.toString(16);
}
function getColorByXPercentage(canvas, xPercent) {
var x = canvas.width * xPercent || 0;
var context = canvas.getContext("2d");
var p = context.getImageData(x, 1, 1, 1).data;
var color = 'rgba(' + [p[0] + ',' + p[1] + ',' + p[2] + ',' + p[3]] + ')';
return color;
}
return {
setters: [function (_libsD3D) {}, function (_appCoreTime_series) {
TimeSeries = _appCoreTime_series.default;
}, function (_appCoreUtilsKbn) {
kbn = _appCoreUtilsKbn.default;
}, function (_appPluginsSdk) {
MetricsPanelCtrl = _appPluginsSdk.MetricsPanelCtrl;
}, function (_properties) {
heatmapEditor = _properties.heatmapEditor;
displayEditor = _properties.displayEditor;
pluginName = _properties.pluginName;
}, function (_lodash) {
_ = _lodash.default;
}, function (_moment) {
moment = _moment.default;
}, function (_series_overrides_heatmap_ctrl) {}, function (_cssHeatmapCss) {}],
execute: function () {
_createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
panelOptions = {
aggregationFunctions: ['avg', 'min', 'max', 'total', 'current', 'count'],
treeMap: {
modes: ['squarify', 'slice', 'dice', 'slice-dice'],
aggregationFunctions: ['sum', 'min', 'max', 'extent', 'mean', 'median', 'quantile', 'variance', 'deviation'],
timestampFormats: ['YYYY-MM-DDTHH', 'YYYY-MM-DDTHH:mm', 'YYYY-MM-DDTHH:mm:ss', 'YYYY-MM-DDTHH:mm:ss.sssZ']
}
};
panelDefaults = {
// other style overrides
seriesOverrides: [],
thresholds: '0,10',
colors: ['rgba(50, 172, 45, 1)', 'rgba(241, 255, 0, 1)', 'rgba(245, 54, 54, 1)'],
legend: {
show: true,
min: true,
max: true,
avg: true,
current: true,
total: true
},
maxDataPoints: 100,
mappingType: 1,
nullPointMode: 'connected',
format: 'none',
valueMaps: [{ value: 'null', op: '=', text: 'N/A' }],
treeMap: {
mode: 'squarify',
groups: [{ key: 'server', value: '/^.*\./g' }],
colorByFunction: 'max',
sizeByFunction: 'constant',
enableTimeBlocks: false,
enableGrouping: true,
debug: false,
depth: 0,
ids: ['alias'],
nodeSizeProperty: "value"
}
};
_export('MetricsPanelCtrl', _export('HeatmapCtrl', HeatmapCtrl = function (_MetricsPanelCtrl) {
_inherits(HeatmapCtrl, _MetricsPanelCtrl);
function HeatmapCtrl($scope, $injector, $sce) {
_classCallCheck(this, HeatmapCtrl);
var _this2 = _possibleConstructorReturn(this, (HeatmapCtrl.__proto__ || Object.getPrototypeOf(HeatmapCtrl)).call(this, $scope, $injector));
_.defaults(_this2.panel, panelDefaults);
_this2.options = panelOptions;
_this2.panel.chartId = 'chart_' + _this2.panel.id;
_this2.containerDivId = 'container_' + _this2.panel.chartId;
_this2.$sce = $sce;
_this2.events.on('init-edit-mode', _this2.onInitEditMode.bind(_this2));
_this2.events.on('data-received', _this2.onDataReceived.bind(_this2));
_this2.events.on('data-snapshot-load', _this2.onDataReceived.bind(_this2));
_this2.initializePanel();
return _this2;
}
_createClass(HeatmapCtrl, [{
key: 'initializePanel',
value: function initializePanel() {
var d3plusPath = 'plugins/' + pluginName + '/libs/d3plus/d3plus.full.js';
var _this = this;
var meta = {};
meta[d3plusPath] = {
format: 'global'
};
SystemJS.config({
meta: meta
});
SystemJS.import(d3plusPath).then(function d3plusLoaded() {
console.log('d3plus is loaded');
_this.events.emit('data-received');
});
}
}, {
key: 'handleError',
value: function handleError(err) {
this.getPanelContainer().html('<p>Error:</p><pre>' + err + '</pre>');
}
}, {
key: 'onInitEditMode',
value: function onInitEditMode() {
this.addEditorTab('Heatmap', heatmapEditor, 2);
this.addEditorTab('Display', displayEditor, 3);
}
}, {
key: 'getPanelContainer',
value: function getPanelContainer() {
return $(document.getElementById(this.containerDivId));
}
}, {
key: 'onDataReceived',
value: function onDataReceived(dataList) {
console.info('received data');
console.debug(dataList);
if (undefined != dataList) {
this.series = dataList.map(this.seriesHandler.bind(this));
console.info('mapped dataList to series');
}
var preparedData = this.d3plusDataProcessor(this.series);
this.render(preparedData);
}
}, {
key: 'getGroupKeys',
value: function getGroupKeys() {
return this.panel.treeMap.groups.map(function (group) {
return group.key;
});
}
}, {
key: 'd3plusDataProcessor',
value: function d3plusDataProcessor(dataArray) {
var resultArray = [];
var hasGroups = this.panel.treeMap.groups.length > 0;
if (!hasGroups) {
// just add the original items since there are no groups
for (var dataIndex = 0; dataIndex < dataArray.length; dataIndex++) {
var newDataItem = Object.assign({}, dataArray[dataIndex], dataArray[dataIndex].stats);
resultArray.push(newDataItem);
}
} else {
// Process Groups
var groupArray = [];
for (var groupIndex = 0; groupIndex < this.panel.treeMap.groups.length; groupIndex++) {
groupArray.push({
key: this.panel.treeMap.groups[groupIndex].key,
regex: kbn.stringToJsRegex(this.panel.treeMap.groups[groupIndex].value)
});
}
for (var dataIndex = 0; dataIndex < dataArray.length; dataIndex++) {
var newDataItem = Object.assign({}, dataArray[dataIndex]);
// only add the stats if we arent using granular timeblock data
if (!this.panel.treeMap.enableTimeBlocks) {
Object.assign(newDataItem, dataArray[dataIndex].stats);
}
delete newDataItem.stats;
for (var groupIndex = 0; groupIndex < groupArray.length; groupIndex++) {
var key = groupArray[groupIndex].key;
var regex = groupArray[groupIndex].regex;
var matches = newDataItem.alias.match(regex);
if (matches && matches.length > 0) {
newDataItem[key] = matches[0];
} else {
newDataItem[key] = 'NA';
}
}
resultArray.push(newDataItem);
}
}
// If we're using timeBlocks mode
// replace the aggregated series with individual records
if (this.panel.treeMap.enableTimeBlocks) {
console.info('creating timeblock records');
var timeBlockArray = [];
for (var dataIndex = 0; dataIndex < resultArray.length; dataIndex++) {
console.debug('dataIndex:' + dataIndex + ', alias:' + resultArray[dataIndex].alias);
var dataSeries = resultArray[dataIndex];
for (var dataPointIndex = 0; dataPointIndex < dataSeries.flotpairs.length; dataPointIndex++) {
var dataSeriesCopy = Object.assign({}, dataSeries);
delete dataSeriesCopy.datapoints;
delete dataSeriesCopy.flotpairs;
dataSeriesCopy.count = 1;
dataSeriesCopy.timestamp = dataSeries.flotpairs[dataPointIndex][0];
dataSeriesCopy.value = dataSeries.flotpairs[dataPointIndex][1];
timeBlockArray.push(dataSeriesCopy);
}
}
resultArray = timeBlockArray;
}
return resultArray;
}
}, {
key: 'seriesHandler',
value: function seriesHandler(seriesData) {
var series = new TimeSeries({
datapoints: seriesData.datapoints,
alias: seriesData.target.replace(/"|,|;|=|:|{|}/g, '_')
});
series.flotpairs = series.getFlotPairs(this.panel.nullPointMode);
return series;
}
}, {
key: 'addSeriesOverride',
value: function addSeriesOverride(override) {
this.panel.seriesOverrides.push(override || {});
}
}, {
key: 'addTreeMapGroup',
value: function addTreeMapGroup(group) {
this.panel.treeMap.groups.push(group || {});
}
}, {
key: 'removeSeriesOverride',
value: function removeSeriesOverride(override) {
this.panel.seriesOverrides = _.without(this.panel.seriesOverrides, override);
this.render();
}
}, {
key: 'removeTreeMapGroup',
value: function removeTreeMapGroup(group) {
this.panel.treeMap.groups = _.without(this.panel.treeMap.groups, group);
this.render();
}
}, {
key: 'updateThresholds',
value: function updateThresholds() {
var thresholdCount = this.panel.thresholds.length;
var colorCount = this.panel.colors.length;
this.refresh();
}
}, {
key: 'changeColor',
value: function changeColor(colorIndex, color) {
this.panel.colors[colorIndex] = color;
}
}, {
key: 'removeColor',
value: function removeColor(colorIndex) {
this.panel.colors.splice(colorIndex, 1);
}
}, {
key: 'addColor',
value: function addColor() {
this.panel.colors.push('rgba(255, 255, 255, 1)');
}
}, {
key: 'getGradientForValue',
value: function getGradientForValue(data, value) {
var min = Math.min.apply(Math, data.thresholds);
var max = Math.max.apply(Math, data.thresholds);
var absoluteDistance = max - min;
var valueDistanceFromMin = value - min;
var xPercent = valueDistanceFromMin / absoluteDistance;
// Get the smaller number to clamp at 0.99 max
xPercent = Math.min(0.99, xPercent);
// Get the larger number to clamp at 0.01 min
xPercent = Math.max(0.01, xPercent);
return getColorByXPercentage(this.canvas, xPercent);
}
}, {
key: 'applyOverrides',
value: function applyOverrides(seriesItemAlias) {
var seriesItem = {},
colorData = {},
overrides = {};
console.info('applying overrides for seriesItem');
console.debug(seriesItemAlias);
console.debug(this.panel.seriesOverrides);
for (var i = 0; i <= this.panel.seriesOverrides.length; i++) {
console.debug('comparing:');
console.debug(this.panel.seriesOverrides[i]);
if (this.panel.seriesOverrides[i] && this.panel.seriesOverrides[i].alias == seriesItemAlias) {
overrides = this.panel.seriesOverrides[i];
}
}
colorData.thresholds = (overrides.thresholds || this.panel.thresholds).split(',').map(function (strVale) {
return Number(strVale.trim());
});
colorData.colorMap = this.panel.colors;
seriesItem.colorData = colorData;
seriesItem.valueName = overrides.valueName || this.panel.valueName;
return seriesItem;
}
}, {
key: 'invertColorOrder',
value: function invertColorOrder() {
this.panel.colors.reverse();
this.refresh();
}
}, {
key: 'addTreeMapId',
value: function addTreeMapId() {
this.panel.treeMap.ids.push('');
this.refresh();
}
}, {
key: 'removeTreeMapId',
value: function removeTreeMapId(pos) {
this.panel.treeMap.ids.splice(pos, 1);
this.refresh();
}
}, {
key: 'changeTreeMapId',
value: function changeTreeMapId(idString, pos) {
this.panel.treeMap.ids[pos] = idString;
}
}, {
key: 'link',
value: function link(scope, elem, attrs, ctrl) {
var chartElement = elem.find('.heatmap');
chartElement.append('<div id="' + ctrl.containerDivId + '"></div>');
var chartContainer = $(document.getElementById(ctrl.containerDivId));
console.debug('found chartContainer');
console.debug(chartContainer);
elem.css('height', ctrl.height + 'px');
var canvas = elem.find('.canvas')[0];
ctrl.canvas = canvas;
var gradientValueMax = elem.find('.gradient-value-max')[0];
var gradientValueMin = elem.find('.gradient-value-min')[0];
var visFormat = {
"text": function text(_text, opts) {
if (opts.key == 'timestamp') {
var timestamp = moment(Number(_text));
return timestamp.format(ctrl.panel.treeMap.timestampFormat);
} else if (ctrl.getGroupKeys().indexOf(opts.key) > -1) {
return _text;
} else {
return d3plus.string.title(_text, opts);
}
}
};
function render(data) {
updateSize();
updateCanvasStyle();
updateChart(data);
}
function updateCanvasStyle() {
canvas.width = Math.max(chartElement[0].clientWidth, 100);
var canvasContext = canvas.getContext("2d");
canvasContext.clearRect(0, 0, canvas.width, canvas.height);
var grd = canvasContext.createLinearGradient(0, 0, canvas.width, 0);
var colorWidth = 1 / Math.max(ctrl.panel.colors.length, 1);
for (var i = 0; i < ctrl.panel.colors.length; i++) {
var currentColor = ctrl.panel.colors[i];
grd.addColorStop(Math.min(colorWidth * i, 1), currentColor);
}
canvasContext.fillStyle = grd;
canvasContext.fillRect(0, 0, canvas.width, 3);
ctrl.canvasContext = canvasContext;
gradientValueMax.innerText = Math.max.apply(Math, ctrl.panel.thresholds.split(','));
gradientValueMin.innerText = Math.min.apply(Math, ctrl.panel.thresholds.split(','));
}
function updateSize() {
elem.css('height', ctrl.height + 'px');
}
function getVisSize(dataPoint) {
if (ctrl.panel.treeMap.sizeByFunction == 'constant') return 1;else {
return dataPoint[ctrl.panel.treeMap.sizeByFunction] || dataPoint.value;
}
}
function getVisColor(dataPoint) {
var value = dataPoint[ctrl.panel.treeMap.colorByFunction] || dataPoint.value;
var rgbColor = ctrl.getGradientForValue({ thresholds: ctrl.panel.thresholds.split(',') }, value);
var hexColor = colorToHex(rgbColor);
return hexColor;
}
function updateChart(data) {
d3.select("#" + ctrl.containerDivId).selectAll('*').remove();
// Make sure the necessary IDs are added
var idKeys = Array.from(ctrl.panel.treeMap.ids);
if (idKeys.length == 0) {
ensureArrayContains(idKeys, 'alias');
}
if (ctrl.panel.treeMap.enableTimeBlocks) {
ensureArrayContains(idKeys, 'timestamp');
}
// Setup Aggregations
var aggs = {};
aggs.value = ctrl.panel.treeMap.aggregationFunction;
aggs.current = ctrl.panel.treeMap.aggregationFunction;
aggs.count = 'sum';
aggs.total = 'sum';
aggs.avg = 'mean';
aggs.min = 'min';
aggs.max = 'max';
d3plus.viz().dev(ctrl.panel.treeMap.debug).aggs(aggs).container("#" + ctrl.containerDivId).legend(ctrl.panel.treeMap.showLegend).data(data)
//.type("tree_map")
.type({ "mode": ctrl.panel.treeMap.mode }) // sets the mode of visualization display based on type
.id({
"value": _.uniq(idKeys),
"grouping": ctrl.panel.treeMap.enableGrouping
}).depth(Number(ctrl.panel.treeMap.depth)).size(getVisSize).height(ctrl.height).width(ctrl.width).color(getVisColor).format(visFormat).draw();
}
this.events.on('render', function onRender(data) {
if (typeof d3plus !== 'undefined' && data) {
render(data);
ctrl.renderingCompleted();
} else {
console.info('d3plus is not loaded yet');
}
});
}
}]);
return HeatmapCtrl;
}(MetricsPanelCtrl)));
;HeatmapCtrl.templateUrl = 'module.html';
_export('HeatmapCtrl', HeatmapCtrl);
_export('MetricsPanelCtrl', HeatmapCtrl);
}
};
});
//# sourceMappingURL=heatmapControl.js.map