diff --git a/package.json b/package.json
index 5422d2386050f..b16b2761c7c5d 100644
--- a/package.json
+++ b/package.json
@@ -91,6 +91,7 @@
"bootstrap": "3.3.6",
"brace": "0.5.1",
"bunyan": "1.7.1",
+ "chart.js": "2.1.3",
"clipboard": "1.5.5",
"commander": "2.8.1",
"css-loader": "0.17.0",
diff --git a/src/ui/public/vislib/styles/_legend.less b/src/ui/public/vislib/styles/_legend.less
index ddd2ae39d7785..fcfa67cae294d 100644
--- a/src/ui/public/vislib/styles/_legend.less
+++ b/src/ui/public/vislib/styles/_legend.less
@@ -20,6 +20,10 @@ visualize-legend {
flex-direction: row;
padding-top: 5px;
+ &.fixed-width {
+ width: 200px;
+ }
+
.header {
cursor: pointer;
width: 15px;
diff --git a/src/ui/public/visualize/visualize.html b/src/ui/public/visualize/visualize.html
index 5d8f7763033bb..895457a142d21 100644
--- a/src/ui/public/visualize/visualize.html
+++ b/src/ui/public/visualize/visualize.html
@@ -13,5 +13,10 @@
No results found
class="visualize-chart">
+
diff --git a/src/ui/public/visualize/visualize.js b/src/ui/public/visualize/visualize.js
index 86c9a5beae6be..a546400f2f823 100644
--- a/src/ui/public/visualize/visualize.js
+++ b/src/ui/public/visualize/visualize.js
@@ -6,6 +6,7 @@ import _ from 'lodash';
import RegistryVisTypesProvider from 'ui/registry/vis_types';
import uiModules from 'ui/modules';
import visualizeTemplate from 'ui/visualize/visualize.html';
+import Chart from 'chart';
uiModules
.get('kibana/directive')
.directive('visualize', function (Notifier, SavedVis, indexPatterns, Private, config, $timeout) {
@@ -17,6 +18,130 @@ uiModules
location: 'Visualize'
});
+ function esRespConvertorFactory($el, $legend, chartType) {
+ chartType = {
+ pie: 'pie',
+ line: 'line',
+ area: 'line',
+ histogram: 'bar'
+ }[chartType];
+ let myChart;
+ function makeColor(num) {
+ let hexStr = Math.round(num).toString(16);
+ while (hexStr.length / 6 !== 1) {
+ hexStr = '0' + hexStr;
+ }
+ return '#' + hexStr;
+ }
+ const isPieChart = (chartType === 'pie');
+ function decodeBucketData(aggConfigs, aggregations) {
+ const datasetMap = {};
+ const xAxisLabels = [];
+ // If there is no data
+ if (!aggConfigs) { return datasetMap; }
+
+ const maxAggDepth = aggConfigs.length - 1;
+ let currDepth = 0;
+ // meant to recursively crawl through es aggregations
+ // to make sense of the data for a charting library
+ function decodeBucket(aggConfig, aggResp) {
+ aggResp.buckets.forEach((bucket) => {
+ const isFirstAggConfig = currDepth === 0;
+
+ if (isFirstAggConfig) { // Sets the labels for the X-Axis
+ xAxisLabels.push(bucket.key);
+ }
+ if (currDepth < maxAggDepth) { // Crawl through the structure if we should
+ const nextAggConfig = aggConfigs[++currDepth];
+ decodeBucket(nextAggConfig, bucket[nextAggConfig.id]);
+ currDepth--;
+ } else {
+ const isDateBucket = aggConfig.__type.dslName === 'date_histogram';
+ const legendLabel = (isFirstAggConfig && isDateBucket && !isPieChart) ? 'Count' : bucket.key;
+ const dataset = datasetMap[legendLabel] || [];
+ dataset.push(bucket.doc_count);
+ datasetMap[legendLabel] = dataset;
+ }
+ });
+ }
+ const firstAggConfig = aggConfigs[0];
+ decodeBucket(firstAggConfig, aggregations[firstAggConfig.id]);
+ const legendLabels = [];
+ const arrDatasets = _.map(datasetMap, (val, key) => {
+ legendLabels.push(key);
+ return {
+ data: val,
+ label: key,
+ backgroundColor: []
+ };
+ });
+ // Make some colors for all of the data points.
+ // This need to be different, instead of looking at all the colors
+ // you should look at RGB separate and limit the number from there
+ // then multiply to get your result
+ arrDatasets.forEach(set => {
+ const allTheColors = Math.pow(16, 6);
+ const colorOffset = allTheColors / 8;
+ let numDataPoints = set.data.length;
+ const maxColors = allTheColors - (colorOffset * 2);
+ const difference = maxColors / numDataPoints;
+ let currColor = colorOffset;
+ while (numDataPoints-- > 0) {
+ if (isPieChart) {
+ set.backgroundColor.push(makeColor(currColor));
+ }
+ currColor += difference;
+ }
+ if (!isPieChart) {
+ set.backgroundColor = set.backgroundColor[0];
+ }
+ });
+
+ return {
+ legend: legendLabels,
+ labels: xAxisLabels,
+ dataConfigs: arrDatasets
+ };
+ }
+ return function convertEsRespAndAggConfig(esResp, aggConfigs) {
+ const aggConfigMap = aggConfigs.byId;
+ const decodedData = decodeBucketData(aggConfigs.bySchemaGroup.buckets, esResp.aggregations);
+ if (myChart) { // Not a fan of this, i should be using update
+ myChart.destroy();
+ }
+ myChart = new Chart($el, {
+ type: chartType,
+ data: {
+ labels: decodedData.labels,
+ datasets: decodedData.dataConfigs
+ },
+ fill: false,
+ options: {
+ legendCallback: function (chartObj) {
+ const multipleBuckets = aggConfigs.bySchemaGroup.buckets.length > 1;
+ const legendItems = multipleBuckets || isPieChart ? decodedData.legend : [aggConfigs.bySchemaGroup.metrics[0]._opts.type];
+ const itemsHtmlArr = legendItems.map(item => { return '' + item + ''; });
+ return '' + itemsHtmlArr.join('') + '
';
+ },
+ legend: {
+ display: false
+ },
+ tooltips: {
+ callbacks: {
+ title: function () { return 'hello world'; },
+ label: function (item, data) {
+ const dataset = data.datasets[item.datasetIndex];
+ return dataset.label + ': ' + dataset.data[item.index];
+ }
+ }
+ }
+ }
+ });
+
+ $legend.html(myChart.generateLegend());
+ };
+ }
+
return {
restrict: 'E',
scope : {
@@ -29,6 +154,7 @@ uiModules
},
template: visualizeTemplate,
link: function ($scope, $el, attr) {
+ const esRespConvertor = esRespConvertorFactory($el.find('#canvas-chart'), $el.find('#chart-legend'), $scope.vis.type.name);
let chart; // set in "vis" watcher
let minVisChartHeight = 180;
@@ -148,6 +274,7 @@ uiModules
$scope.$watch('esResp', prereq(function (resp, prevResp) {
if (!resp) return;
+ esRespConvertor(resp, $scope.vis.aggs);
$scope.renderbot.render(resp);
}));
diff --git a/webpackShims/chart.js b/webpackShims/chart.js
new file mode 100644
index 0000000000000..ff6f875a02346
--- /dev/null
+++ b/webpackShims/chart.js
@@ -0,0 +1,9 @@
+/**
+ * THESE ARE AUTOMATICALLY INCLUDED IN LODASH
+ *
+ * use:
+ * var _ = require('lodash');
+ */
+
+var Chart = require('node_modules/chart.js/src/chart.js');
+module.exports = Chart;