diff --git a/src/fixtures/mock_ui_state.js b/src/fixtures/mock_ui_state.js
new file mode 100644
index 0000000000000..b0e794722f794
--- /dev/null
+++ b/src/fixtures/mock_ui_state.js
@@ -0,0 +1,15 @@
+define(function (require) {
+ var _ = require('lodash');
+ var keys = {};
+ return {
+ get: function (path, def) {
+ return keys[path] == null ? def : keys[path];
+ },
+ set: function (path, val) {
+ keys[path] = val;
+ return val;
+ },
+ on: _.noop,
+ off: _.noop
+ }
+})
\ No newline at end of file
diff --git a/src/plugins/kbn_vislib_vis_types/public/controls/vislib_basic_options.html b/src/plugins/kbn_vislib_vis_types/public/controls/vislib_basic_options.html
index 5a694765f77e5..cfc12aae2631f 100644
--- a/src/plugins/kbn_vislib_vis_types/public/controls/vislib_basic_options.html
+++ b/src/plugins/kbn_vislib_vis_types/public/controls/vislib_basic_options.html
@@ -5,10 +5,4 @@
Show Tooltip
-
-
-
diff --git a/src/plugins/table_vis/public/__tests__/_table_vis.js b/src/plugins/table_vis/public/__tests__/_table_vis.js
index e2068932f61cc..14790fbe83fd1 100644
--- a/src/plugins/table_vis/public/__tests__/_table_vis.js
+++ b/src/plugins/table_vis/public/__tests__/_table_vis.js
@@ -30,7 +30,8 @@ describe('Integration', function () {
$rootScope.vis = vis;
$rootScope.esResponse = esResponse;
- $el = $('');
+ $rootScope.uiState = require('fixtures/mock_ui_state');
+ $el = $('');
$compile($el)($rootScope);
$rootScope.$apply();
diff --git a/src/ui/public/filter_bar/filter_bar_click_handler.js b/src/ui/public/filter_bar/filter_bar_click_handler.js
index 6a5c7bbf18854..59844f9207bf7 100644
--- a/src/ui/public/filter_bar/filter_bar_click_handler.js
+++ b/src/ui/public/filter_bar/filter_bar_click_handler.js
@@ -2,21 +2,11 @@ define(function (require) {
var _ = require('lodash');
var dedupFilters = require('./lib/dedupFilters');
var uniqFilters = require('./lib/uniqFilters');
-
- // given an object or array of objects, return the value of the passed param
- // if the param is missing, return undefined
- function findByParam(values, param) {
- if (_.isArray(values)) { // point series chart
- var index = _.findIndex(values, param);
- if (index === -1) return;
- return values[index][param];
- }
- return values[param]; // pie chart
- }
+ var findByParam = require('ui/utils/find_by_param');
return function (Notifier) {
return function ($state) {
- return function (event) {
+ return function (event, simulate) {
var notify = new Notifier({
location: 'Filter bar'
});
@@ -58,9 +48,20 @@ define(function (require) {
if (!filters.length) return;
+ if (event.negate) {
+ _.each(filters, function (filter) {
+ filter.meta = filter.meta || {};
+ filter.meta.negate = true;
+ });
+ }
+
filters = dedupFilters($state.filters, uniqFilters(filters));
// We need to add a bunch of filter deduping here.
- $state.$newFilters = filters;
+ if (!simulate) {
+ $state.$newFilters = filters;
+ }
+
+ return filters;
}
};
};
diff --git a/src/ui/public/utils/find_by_param.js b/src/ui/public/utils/find_by_param.js
new file mode 100644
index 0000000000000..c22a5c6ed00f7
--- /dev/null
+++ b/src/ui/public/utils/find_by_param.js
@@ -0,0 +1,13 @@
+define(function (require) {
+ var _ = require('lodash');
+ // given an object or array of objects, return the value of the passed param
+ // if the param is missing, return undefined
+ return function findByParam(values, param) {
+ if (_.isArray(values)) { // point series chart
+ var index = _.findIndex(values, param);
+ if (index === -1) return;
+ return values[index][param];
+ }
+ return values[param]; // pie chart
+ };
+});
\ No newline at end of file
diff --git a/src/ui/public/vislib/__tests__/lib/layout/layout.js b/src/ui/public/vislib/__tests__/lib/layout/layout.js
index 7b07b929c8f33..f10949009c951 100644
--- a/src/ui/public/vislib/__tests__/lib/layout/layout.js
+++ b/src/ui/public/vislib/__tests__/lib/layout/layout.js
@@ -52,7 +52,6 @@ dateHistogramArray.forEach(function (data, i) {
expect($(vis.el).find('.vis-wrapper').length).to.be(1);
expect($(vis.el).find('.y-axis-col-wrapper').length).to.be(1);
expect($(vis.el).find('.vis-col-wrapper').length).to.be(1);
- expect($(vis.el).find('.legend-col-wrapper').length).to.be(1);
expect($(vis.el).find('.y-axis-col').length).to.be(1);
expect($(vis.el).find('.y-axis-title').length).to.be(1);
expect($(vis.el).find('.y-axis-div-wrapper').length).to.be(1);
diff --git a/src/ui/public/vislib/__tests__/lib/legend.js b/src/ui/public/vislib/__tests__/lib/legend.js
deleted file mode 100644
index 2d80681dde185..0000000000000
--- a/src/ui/public/vislib/__tests__/lib/legend.js
+++ /dev/null
@@ -1,129 +0,0 @@
-var d3 = require('d3');
-var angular = require('angular');
-var _ = require('lodash');
-var $ = require('jquery');
-var ngMock = require('ngMock');
-var expect = require('expect.js');
-
-var slices = require('fixtures/vislib/mock_data/histogram/_slices');
-var stackedSeries = require('fixtures/vislib/mock_data/date_histogram/_stacked_series');
-var histogramSlices = require('fixtures/vislib/mock_data/histogram/_slices');
-
-var dataArray = [
- stackedSeries,
- slices,
- histogramSlices,
- stackedSeries,
- stackedSeries
-];
-
-var chartTypes = [
- 'histogram',
- 'pie',
- 'pie',
- 'area',
- 'line'
-];
-
-var chartSelectors = {
- histogram: '.chart rect',
- pie: '.chart path',
- area: '.chart path',
- line: '.chart circle'
-};
-
-describe('Vislib Legend Class', function () {
- dataArray.forEach(function (data, i) {
- describe(chartTypes[i] + ' data', function () {
- var visLibParams = {
- type: chartTypes[i],
- addLegend: true
- };
- var Legend;
- var vis;
- var persistedState;
- var $el;
-
- beforeEach(ngMock.module('kibana'));
- beforeEach(ngMock.inject(function (Private) {
- vis = Private(require('fixtures/vislib/_vis_fixture'))(visLibParams);
- persistedState = new (Private(require('ui/persisted_state/persisted_state')))();
- Legend = Private(require('ui/vislib/lib/legend'));
- $el = d3.select('body').append('div').attr('class', 'fake-legend');
- vis.render(data, persistedState);
- }));
-
- afterEach(function () {
- $(vis.el).remove();
- $('.fake-legend').remove();
- vis = null;
- });
-
- describe('legend item label matches vis item label', function () {
- it('should match the slice label', function () {
- var chartType = chartTypes[i];
- var paths = $(vis.el).find(chartSelectors[chartType]).toArray();
- var items = vis.handler.legend.labels;
-
- items.forEach(function (d) {
- var path = _.find(paths, function (path) {
- return path.getAttribute('data-label') === String(d.label);
- });
-
- expect(path).to.be.ok();
- });
- });
- });
-
- describe('header method', function () {
- it('should append the legend header', function () {
- expect($(vis.el).find('.header').length).to.be(1);
- expect($(vis.el).find('.column-labels').length).to.be(1);
- });
- });
-
- describe('list method', function () {
- it('should append the legend list', function () {
- expect($(vis.el).find('.legend-ul').length).to.be(1);
- });
-
- it('should contain a list of items', function () {
- expect($(vis.el).find('li').length).to.be.greaterThan(1);
- });
-
- it('should not return an undefined value', function () {
- var emptyObject = {
- label: ''
- };
- var labels = [emptyObject, emptyObject, emptyObject];
- var args = {
- _attr: {isOpen: true},
- color: function () { return 'blue'; }
- };
-
- Legend.prototype._list($el, labels, args);
-
- $el.selectAll('li').each(function (d) {
- expect(d.label).not.to.be(undefined);
- });
- });
- });
-
- describe('render method', function () {
- it('should create a legend toggle', function () {
- expect($('.legend-toggle').length).to.be(1);
- });
-
- it('should have an onclick listener', function () {
- expect(!!$('.legend-toggle')[0].__onclick).to.be(true);
- expect(!!$('li.color')[0].__onclick).to.be(true);
- });
-
- it('should attach onmouseover listener', function () {
- expect(!!$('li.color')[0].__onmouseover).to.be(true);
- });
- });
- });
- });
-});
-
diff --git a/src/ui/public/vislib/lib/dispatch.js b/src/ui/public/vislib/lib/dispatch.js
index fb13291d038d7..68de13d3f46f9 100644
--- a/src/ui/public/vislib/lib/dispatch.js
+++ b/src/ui/public/vislib/lib/dispatch.js
@@ -226,16 +226,8 @@ define(function (require) {
*/
Dispatch.prototype.highlightLegend = function (element) {
var label = this.getAttribute('data-label');
-
if (!label) return;
-
- d3.select(element)
- .select('.legend-ul')
- .selectAll('li.color')
- .filter(function (d, i) {
- return String(d.label) !== label;
- })
- .classed('blur_shape', true);
+ $('[data-label]', element.parentNode).not('[data-label="' + label + '"]').css('opacity', 0.5);
};
/**
@@ -245,10 +237,7 @@ define(function (require) {
* @method unHighlightLegend
*/
Dispatch.prototype.unHighlightLegend = function (element) {
- d3.select(element)
- .select('.legend-ul')
- .selectAll('li.color')
- .classed('blur_shape', false);
+ $('[data-label]', element.parentNode).css('opacity', 1);
};
/**
diff --git a/src/ui/public/vislib/lib/handler/handler.js b/src/ui/public/vislib/lib/handler/handler.js
index 9892268db9019..8b7ba300bdbcd 100644
--- a/src/ui/public/vislib/lib/handler/handler.js
+++ b/src/ui/public/vislib/lib/handler/handler.js
@@ -7,7 +7,6 @@ define(function (require) {
var Data = Private(require('ui/vislib/lib/data'));
var Layout = Private(require('ui/vislib/lib/layout/layout'));
- var Legend = Private(require('ui/vislib/lib/legend'));
/**
* Handles building all the components of the visualization
@@ -39,15 +38,10 @@ define(function (require) {
this.axisTitle = opts.axisTitle;
this.alerts = opts.alerts;
- if (this._attr.addLegend) {
- this.legend = opts.legend;
- }
-
this.layout = new Layout(vis.el, vis.data, vis._attr.type, opts);
this.binder = new Binder();
this.renderArray = _.filter([
this.layout,
- this.legend,
this.axisTitle,
this.chartTitle,
this.alerts,
@@ -96,12 +90,6 @@ define(function (require) {
this._validateData();
this.renderArray.forEach(function (property) {
- if (property instanceof Legend) {
- self.vis.activeEvents().forEach(function (event) {
- self.enable(event, property);
- });
- }
-
if (typeof property.render === 'function') {
property.render();
}
diff --git a/src/ui/public/vislib/lib/handler/types/pie.js b/src/ui/public/vislib/lib/handler/types/pie.js
index 33a29c81257c4..09f8d9cc6c65f 100644
--- a/src/ui/public/vislib/lib/handler/types/pie.js
+++ b/src/ui/public/vislib/lib/handler/types/pie.js
@@ -2,7 +2,6 @@ define(function (require) {
return function PieHandler(Private) {
var Handler = Private(require('ui/vislib/lib/handler/handler'));
var Data = Private(require('ui/vislib/lib/data'));
- var Legend = Private(require('ui/vislib/lib/legend'));
var ChartTitle = Private(require('ui/vislib/lib/chart_title'));
/*
@@ -11,7 +10,6 @@ define(function (require) {
return function (vis) {
return new Handler(vis, {
- legend: new Legend(vis),
chartTitle: new ChartTitle(vis.el)
});
};
diff --git a/src/ui/public/vislib/lib/handler/types/point_series.js b/src/ui/public/vislib/lib/handler/types/point_series.js
index ff3fb08a3b911..69c345ccaefb3 100644
--- a/src/ui/public/vislib/lib/handler/types/point_series.js
+++ b/src/ui/public/vislib/lib/handler/types/point_series.js
@@ -3,7 +3,6 @@ define(function (require) {
var injectZeros = Private(require('ui/vislib/components/zero_injection/inject_zeros'));
var Handler = Private(require('ui/vislib/lib/handler/handler'));
var Data = Private(require('ui/vislib/lib/data'));
- var Legend = Private(require('ui/vislib/lib/legend'));
var XAxis = Private(require('ui/vislib/lib/x_axis'));
var YAxis = Private(require('ui/vislib/lib/y_axis'));
var AxisTitle = Private(require('ui/vislib/lib/axis_title'));
@@ -29,7 +28,6 @@ define(function (require) {
return new Handler(vis, {
data: data,
- legend: new Legend(vis, vis.data),
axisTitle: new AxisTitle(vis.el, data.get('xAxisLabel'), data.get('yAxisLabel')),
chartTitle: new ChartTitle(vis.el),
xAxis: new XAxis({
diff --git a/src/ui/public/vislib/lib/layout/types/column_layout.js b/src/ui/public/vislib/lib/layout/types/column_layout.js
index 0dfea45abfc28..0caa60c5b0299 100644
--- a/src/ui/public/vislib/lib/layout/types/column_layout.js
+++ b/src/ui/public/vislib/lib/layout/types/column_layout.js
@@ -100,10 +100,6 @@ define(function (require) {
]
}
]
- },
- {
- type: 'div',
- class: 'legend-col-wrapper'
}
]
}
diff --git a/src/ui/public/vislib/lib/legend.js b/src/ui/public/vislib/lib/legend.js
deleted file mode 100644
index 5d976d4554d01..0000000000000
--- a/src/ui/public/vislib/lib/legend.js
+++ /dev/null
@@ -1,246 +0,0 @@
-define(function (require) {
- return function LegendFactory(Private) {
- var d3 = require('d3');
- var _ = require('lodash');
- var Dispatch = Private(require('ui/vislib/lib/dispatch'));
- var Data = Private(require('ui/vislib/lib/data'));
- var legendHeaderTemplate = _.template(require('ui/vislib/partials/legend_header.html'));
- var dataLabel = require('ui/vislib/lib/_data_label');
- var color = Private(require('ui/vislib/components/color/color'));
-
- const NUM_COLORS = 5 * 5; // rows x columns
- const colorPalette = Private(require('ui/vislib/components/color/color_palette'))(NUM_COLORS);
-
- /**
- * Appends legend to the visualization
- *
- * @class Legend
- * @constructor
- * @param vis {Object} Reference to Vis Constructor
- */
- function Legend(vis) {
- if (!(this instanceof Legend)) {
- return new Legend(vis);
- }
-
- var data = vis.data.columns || vis.data.rows || [vis.data];
- var type = vis._attr.type;
- var labels = this.labels = this._getLabels(data, type);
- var labelsArray = labels.map(function (obj) { return obj.label; });
-
- this.events = new Dispatch();
- this.vis = vis;
- this.el = vis.el;
- this.color = color(labelsArray, vis.uiState.get('vis.colors'));
- this._attr = _.defaults({}, vis._attr || {}, {
- 'legendClass' : 'legend-col-wrapper',
- 'blurredOpacity' : 0.3,
- 'focusOpacity' : 1,
- 'defaultOpacity' : 1,
- 'legendDefaultOpacity': 1
- });
- }
-
- Legend.prototype._getPieLabels = function (data) {
- return Data.prototype.pieNames(data);
- };
-
- Legend.prototype._getSeriesLabels = function (data) {
- var isOneSeries = data.every(function (chart) {
- return chart.series.length === 1;
- });
-
- var values = data.map(function (chart) {
- var yLabel = isOneSeries ? chart.yAxisLabel : undefined;
-
- return chart.series.map(function (series) {
- if (yLabel) series.label = yLabel;
- return series;
- });
- })
- .reduce(function (a, b) {
- return a.concat(b);
- }, []);
-
- return _.uniq(values, 'label');
- };
-
- Legend.prototype._getLabels = function (data, type) {
- if (type === 'pie') return this._getPieLabels(data);
- return this._getSeriesLabels(data);
- };
-
- /**
- * Adds legend header
- *
- * @method header
- * @param el {HTMLElement} Reference to DOM element
- * @param args {Object|*} Legend options
- * @returns {*} HTML element
- */
- Legend.prototype._header = function (el, args) {
- var self = this;
- return el.append('div')
- .attr('class', 'header')
- .append('div')
- .attr('class', 'column-labels')
- .html(function () {
- return legendHeaderTemplate({ isOpen: self.vis.get('legendOpen') });
- });
- };
-
- Legend.prototype._colorPicker = function (el, label) {
- const self = this;
-
- const container = el.selectAll('div');
- if (!container.empty()) return container.remove();
-
- return el
- .append('div')
- .attr('class', 'color-selector')
- .selectAll('i').data(colorPalette)
- .enter()
- .append('i')
- .attr('class', 'fa fa-circle dots')
- .attr('style', function (d) {
- return `color: ${d};`;
- }).on('click', function (d) {
- const colors = self.vis.uiState.get('vis.colors') || {};
- colors[label] = d;
- self.vis.uiState.set('vis.colors', colors);
- });
- };
-
- /**
- * Adds list to legend
- *
- * @method list
- * @param el {HTMLElement} Reference to DOM element
- * @param arrOfLabels {Array} Array of labels
- * @param args {Object|*} Legend options
- * @returns {D3.Selection} HTML element with list of labels attached
- */
- Legend.prototype._list = function (el, data, args) {
- var self = this;
-
- return el.append('ul')
- .attr('class', function () {
- var className = 'legend-ul';
- if (self.vis && !self.vis.get('legendOpen')) className += ' hidden';
- return className;
- })
- .selectAll('li')
- .data(data)
- .enter()
- .append('li')
- .attr('class', 'color')
- .each(function (d) {
- var li = d3.select(this);
- self._addIdentifier.call(this, d);
-
- li.append('i')
- .attr('class', 'fa fa-circle dots')
- .attr('style', 'color:' + args.color(d.label));
-
- li.append('span').text(d.label);
- });
- };
-
- /**
- * Append the data label to the element
- *
- * @method _addIdentifier
- * @param label {string} label to use
- */
- Legend.prototype._addIdentifier = function (d) {
- dataLabel(this, d.label);
- };
-
- /**
- * Renders legend
- *
- * @method render
- * @return {HTMLElement} Legend
- */
- Legend.prototype.render = function () {
- var self = this;
- var visEl = d3.select(this.el);
- var legendDiv = visEl.select('.' + this._attr.legendClass);
- var items = this.labels;
- this._header(legendDiv, this);
- this._list(legendDiv, items, this);
-
- var headerIcon = visEl.select('.legend-toggle');
-
- // toggle legend open and closed
- headerIcon
- .on('click', function legendClick() {
- var legendOpen = !self.vis.get('legendOpen');
- self.vis.set('legendOpen', legendOpen);
-
- visEl.select('ul.legend-ul').classed('hidden', legendOpen);
- self.vis.resize();
- });
-
- legendDiv.select('.legend-ul').selectAll('li')
- .on('mouseover', function (d) {
- var label = d.label;
- var charts = visEl.selectAll('.chart');
-
- function filterLabel() {
- var pointLabel = this.getAttribute('data-label');
- return pointLabel !== label.toString();
- }
-
- if (label && label !== 'Count') {
- d3.select(this).style('cursor', 'pointer');
- }
-
- // legend
- legendDiv.selectAll('li')
- .filter(filterLabel)
- .classed('blur_shape', true);
-
- // all data-label attribute
- charts.selectAll('[data-label]')
- .filter(filterLabel)
- .classed('blur_shape', true);
-
- var eventEl = d3.select(this);
- eventEl.style('white-space', 'inherit');
- eventEl.style('word-break', 'break-all');
- })
- .on('mouseout', function () {
- /*
- * The default opacity of elements in charts may be modified by the
- * chart constructor, and so may differ from that of the legend
- */
-
- var charts = visEl.selectAll('.chart');
-
- // legend
- legendDiv.selectAll('li')
- .classed('blur_shape', false);
-
- // all data-label attribute
- charts.selectAll('[data-label]')
- .classed('blur_shape', false);
-
- var eventEl = d3.select(this);
- eventEl.style('white-space', 'nowrap');
- eventEl.style('word-break', 'inherit');
- });
-
- legendDiv.selectAll('li.color').each(function (d) {
- d3.select(this).on('click', function (d) {
- self._colorPicker(d3.select(this), d.label);
- });
- //if (label !== undefined && label !== 'Count') {
- // d3.select(this).call(self.events.addClickEvent());
- //}
- });
- };
-
- return Legend;
- };
-});
diff --git a/src/ui/public/vislib/partials/legend_header.html b/src/ui/public/vislib/partials/legend_header.html
deleted file mode 100644
index 7c909bcee9920..0000000000000
--- a/src/ui/public/vislib/partials/legend_header.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- <%= (isOpen) ?
- 'Legend ' :
- ''
- %>
-
-
\ No newline at end of file
diff --git a/src/ui/public/vislib/styles/_legend.less b/src/ui/public/vislib/styles/_legend.less
index b7d6d89fc35b8..2422aa7cd5db9 100644
--- a/src/ui/public/vislib/styles/_legend.less
+++ b/src/ui/public/vislib/styles/_legend.less
@@ -1,25 +1,33 @@
@import "~ui/styles/mixins";
@import "~ui/styles/variables";
+visualize-legend {
+ display: flex;
+ flex-direction: row;
+}
+
.legend-col-wrapper {
.flex-parent(0, 0, auto);
+ flex-direction: row;
z-index: 10;
min-height: 0;
- .legend-toggle {
+ .header {
cursor: pointer;
- opacity: 0.75;
- white-space: nowrap;
- font-size: 0.9em;
+ width: 15px;
+ }
- .legend-open {
- margin-right: 20px;
+ .legend-toggle {
+ &:hover {
+ color: @sidebar-hover-color;
+ background-color: @sidebar-hover-bg;
}
- .legend-closed {
- font-size: 1.5em;
- padding-left: 5px;
- }
+ background-color: @sidebar-bg;
+ font-size: 10px;
+ height: 30px;
+ padding: 8px 3px;
+ border-bottom-left-radius: @border-radius-small;
}
.column-labels {
@@ -27,46 +35,85 @@
}
.legend-ul {
+ border-left: 1px solid @sidebar-bg;
+ width: 150px;
flex: 1 1 1px;
overflow-x: hidden;
- overflow-y: auto;
-
+ overflow-y: scroll;
+ color: @legend-item-color;
list-style-type: none;
padding: 0;
+ margin-bottom: 0;
visibility: visible;
min-height: 0;
- min-width: 60px;
- margin-right: 5px;
-
- li.color {
- min-height: 22px;
- padding: 3px 0 3px 0;
- text-align: left;
- font-size: 12px;
- line-height: 13px;
- color: @legend-item-color;
- cursor: default;
- text-align: left;
- white-space: nowrap;
- overflow-x: hidden;
- text-overflow: ellipsis;
- max-width: 150px;
-
- .dots {
- padding-right: 5px;
- cursor: pointer;
- }
- }
+ font-size: 12px;
+ line-height: 13px;
+ text-align: left;
- .color-selector {
- width: 80px;
- }
+ display: flex;
+ flex-direction: column;
}
.legend-ul.hidden {
visibility: hidden;
}
+}
- .legend-toggle {
+.legend-value {
+ &-title {
+ padding: 3px;
+
+ &:hover {
+ background-color: @sidebar-hover-bg;
+ }
+ }
+
+ &-truncate {
+ overflow-x: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+
+ &-full {
+ white-space: normal;
+ word-break: break-all;
+ background-color: @sidebar-hover-bg;
+ }
+
+ &-details {
+ border-bottom: 1px solid @sidebar-bg;
+
+ .filter-button {
+ display: block;
+ float: left;
+ width: 50%;
+ border-radius: 0px;
+ background-color: @sidebar-bg;
+
+ &:hover {
+ background-color: @sidebar-hover-bg;
+ }
+ }
+ }
+
+ &-color-picker {
+ width: 130px;
+
+ .dot {
+ line-height: 14px;
+ margin: 2px;
+ font-size: 14px;
+ }
+
+ .dot:hover {
+ margin: 0px;
+ font-size: 18px
+ }
}
}
+
+.legend-value:hover {
+ cursor: pointer;
+}
+
+
diff --git a/src/ui/public/visualize/visualize.html b/src/ui/public/visualize/visualize.html
index 6b105e5c8fab9..9a307ead8e583 100644
--- a/src/ui/public/visualize/visualize.html
+++ b/src/ui/public/visualize/visualize.html
@@ -7,9 +7,12 @@ No results found
-
+
diff --git a/src/ui/public/visualize/visualize.js b/src/ui/public/visualize/visualize.js
index fa4dffe04cb88..89ed633d4df6b 100644
--- a/src/ui/public/visualize/visualize.js
+++ b/src/ui/public/visualize/visualize.js
@@ -1,10 +1,12 @@
define(function (require) {
require('ui/modules')
.get('kibana/directive')
- .directive('visualize', function (Notifier, SavedVis, indexPatterns, Private, config) {
+ .directive('visualize', function (Notifier, SavedVis, indexPatterns, Private, config, $timeout) {
require('ui/visualize/spy');
require('ui/visualize/visualize.less');
+ require('ui/visualize/visualize_legend');
+
var $ = require('jquery');
var _ = require('lodash');
var visTypes = Private(require('ui/registry/vis_types'));
@@ -40,6 +42,7 @@ define(function (require) {
}
var getVisEl = getter('.visualize-chart');
+ var getVisContainer = getter('.vis-container');
var getSpyEl = getter('visualize-spy');
$scope.fullScreenSpy = false;
@@ -47,19 +50,16 @@ define(function (require) {
$scope.spy.mode = ($scope.uiState) ? $scope.uiState.get('spy.mode', {}) : {};
var applyClassNames = function () {
- var $spyEl = getSpyEl();
- var $visEl = getVisEl();
+ var $visEl = getVisContainer();
var fullSpy = ($scope.spy.mode && ($scope.spy.mode.fill || $scope.fullScreenSpy));
- // external
- $el.toggleClass('only-visualization', !$scope.spy.mode);
- $el.toggleClass('visualization-and-spy', $scope.spy.mode && !fullSpy);
- $el.toggleClass('only-spy', Boolean(fullSpy));
- if ($spyEl) $spyEl.toggleClass('only', Boolean(fullSpy));
-
- // internal
- $visEl.toggleClass('spy-visible', Boolean($scope.spy.mode));
$visEl.toggleClass('spy-only', Boolean(fullSpy));
+
+ $timeout(function () {
+ if ($visEl.height() < 100) {
+ $visEl.addClass('spy-only');
+ };
+ }, 0);
};
// we need to wait for some watchers to fire at least once
diff --git a/src/ui/public/visualize/visualize.less b/src/ui/public/visualize/visualize.less
index 6290045efcdcc..6879cf173d088 100644
--- a/src/ui/public/visualize/visualize.less
+++ b/src/ui/public/visualize/visualize.less
@@ -12,20 +12,20 @@ visualize {
white-space: pre-line;
}
- .visualize-chart {
+ .vis-container {
+ height: 1px;
+ display: flex;
+ flex-direction: row;
+
flex: 1 1 auto;
overflow: auto;
-webkit-transition: opacity 0.01s;
transition: opacity 0.01s;
- &.spy-visible {
- margin-bottom: 10px;
- height: 0px;
- }
-
&.spy-only {
display: none;
}
+
}
.loading {
@@ -181,3 +181,4 @@ visualize-spy {
white-space: pre-wrap;
}
}
+
diff --git a/src/ui/public/visualize/visualize_legend.html b/src/ui/public/visualize/visualize_legend.html
new file mode 100644
index 0000000000000..4abb1493e4a97
--- /dev/null
+++ b/src/ui/public/visualize/visualize_legend.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ -
+
+
+
+ {{legendData.label}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ui/public/visualize/visualize_legend.js b/src/ui/public/visualize/visualize_legend.js
new file mode 100644
index 0000000000000..a3c60e9c5f86f
--- /dev/null
+++ b/src/ui/public/visualize/visualize_legend.js
@@ -0,0 +1,103 @@
+define(function (require) {
+ var _ = require('lodash');
+ var html = require('ui/visualize/visualize_legend.html');
+
+ var $ = require('jquery');
+ var d3 = require('d3');
+ var findByParam = require('ui/utils/find_by_param');
+
+ require('ui/modules').get('kibana')
+ .directive('visualizeLegend', function (Private, getAppState) {
+ var Data = Private(require('ui/vislib/lib/data'));
+ var colorPalette = Private(require('ui/vislib/components/color/color'));
+ var filterBarClickHandler = Private(require('ui/filter_bar/filter_bar_click_handler'));
+
+ return {
+ restrict: 'E',
+ template: html,
+ link: function ($scope, $elem) {
+ var $state = getAppState();
+ var clickHandler = filterBarClickHandler($state);
+ $scope.open = $scope.uiState.get('vis.legendOpen', true);
+
+ $scope.$watch('renderbot.chartData', function (data) {
+ if (!data) return;
+ $scope.data = data;
+ refresh();
+ });
+
+ $scope.highlightSeries = function (label) {
+ $('[data-label]', $elem.siblings()).not('[data-label="' + label + '"]').css('opacity', 0.5);
+ };
+
+ $scope.unhighlightSeries = function () {
+ $('[data-label]', $elem.siblings()).css('opacity', 1);
+ };
+
+ $scope.setColor = function (label, color) {
+ var colors = $scope.uiState.get('vis.colors') || {};
+ colors[label] = color;
+ $scope.uiState.set('vis.colors', colors);
+ refresh();
+ };
+
+ $scope.toggleLegend = function () {
+ var bwcAddLegend = $scope.renderbot.vislibVis._attr.addLegend;
+ var bwcLegendStateDefault = bwcAddLegend == null ? true : bwcAddLegend;
+ $scope.open = !$scope.uiState.get('vis.legendOpen', bwcLegendStateDefault);
+ $scope.uiState.set('vis.legendOpen', $scope.open);
+ };
+
+ $scope.filter = function (legendData, negate) {
+ clickHandler({point: legendData, negate: negate});
+ };
+
+ $scope.canFilter = function (legendData) {
+ var filters = clickHandler({point: legendData}, true) || [];
+ return filters.length;
+ };
+
+ $scope.colors = [
+ '#3F6833', '#967302', '#2F575E', '#99440A', '#58140C', '#052B51', '#511749', '#3F2B5B', //6
+ '#508642', '#CCA300', '#447EBC', '#C15C17', '#890F02', '#0A437C', '#6D1F62', '#584477', //2
+ '#629E51', '#E5AC0E', '#64B0C8', '#E0752D', '#BF1B00', '#0A50A1', '#962D82', '#614D93', //4
+ '#7EB26D', '#EAB839', '#6ED0E0', '#EF843C', '#E24D42', '#1F78C1', '#BA43A9', '#705DA0', // Normal
+ '#9AC48A', '#F2C96D', '#65C5DB', '#F9934E', '#EA6460', '#5195CE', '#D683CE', '#806EB7', //5
+ '#B7DBAB', '#F4D598', '#70DBED', '#F9BA8F', '#F29191', '#82B5D8', '#E5A8E2', '#AEA2E0', //3
+ '#E0F9D7', '#FCEACA', '#CFFAFF', '#F9E2D2', '#FCE2DE', '#BADFF4', '#F9D9F9', '#DEDAF7' //7
+ ];
+
+ function refresh() {
+ var vislibVis = $scope.renderbot.vislibVis;
+
+ if ($scope.uiState.get('vis.legendOpen') == null && vislibVis._attr.addLegend != null) {
+ $scope.open = vislibVis._attr.addLegend;
+ }
+
+ $scope.labels = getLabels($scope.data, vislibVis._attr.type);
+ $scope.getColor = colorPalette(_.pluck($scope.labels, 'label'), $scope.uiState.get('vis.colors'));
+ }
+
+ // Most of these functions were moved directly from the old Legend class. Not a fan of this.
+ function getLabels(data, type) {
+ if (!data) return [];
+ var data = data.columns || data.rows || [data];
+ if (type === 'pie') return Data.prototype.pieNames(data);
+ return getSeriesLabels(data);
+ };
+
+ function getSeriesLabels(data) {
+ var values = data.map(function (chart) {
+ return chart.series;
+ })
+ .reduce(function (a, b) {
+ return a.concat(b);
+ }, []);
+ return _.compact(_.uniq(values, 'label'));
+ }
+
+
+ }
+ };
+ });
+});