From a70958ff0f4d8b6aa48b0f75ac9478e67ba111ec Mon Sep 17 00:00:00 2001 From: Trevan Richins Date: Wed, 8 Apr 2015 14:07:57 -0600 Subject: [PATCH 1/3] Add the hierarchy to legends --- .../vislib/components/color/color.js | 8 +- src/kibana/components/vislib/lib/data.js | 129 ++++++++---------- src/kibana/components/vislib/lib/dispatch.js | 4 +- .../vislib/lib/handler/types/pie.js | 2 +- src/kibana/components/vislib/lib/legend.js | 62 +++++++-- .../components/vislib/styles/_legend.less | 3 + .../vislib/visualizations/area_chart.js | 4 +- .../vislib/visualizations/column_chart.js | 2 +- .../vislib/visualizations/line_chart.js | 4 +- .../vislib/visualizations/pie_chart.js | 2 +- .../fixture/mock_data/histogram/_slices.js | 30 +++- test/unit/specs/vislib/lib/legend.js | 11 +- 12 files changed, 163 insertions(+), 98 deletions(-) diff --git a/src/kibana/components/vislib/components/color/color.js b/src/kibana/components/vislib/components/color/color.js index ecaa02ebe5baaf..d89d97bf18380d 100644 --- a/src/kibana/components/vislib/components/color/color.js +++ b/src/kibana/components/vislib/components/color/color.js @@ -9,9 +9,10 @@ define(function (require) { * a lookup table that associates the values (key) with a hex color (value). * Returns a function that accepts a value (i.e. a string or number) * and returns a hex color associated with that value. + * Allows an empty value to match to the first color. */ - return function (arrayOfStringsOrNumbers) { + return function (arrayOfStringsOrNumbers, matchEmptyToFirst) { if (!_.isArray(arrayOfStringsOrNumbers)) { throw new Error('ColorUtil expects an array'); } @@ -26,8 +27,11 @@ define(function (require) { var colorObj = _.zipObject(arrayOfStringsOrNumbers, createColorPalette(arrayLength)); return function (value) { + if (matchEmptyToFirst && value === '') { + value = _.first(arrayOfStringsOrNumbers); + } return colorObj[value]; }; }; }; -}); \ No newline at end of file +}); diff --git a/src/kibana/components/vislib/lib/data.js b/src/kibana/components/vislib/lib/data.js index f5c72a5791599e..541cc1e81769c2 100644 --- a/src/kibana/components/vislib/lib/data.js +++ b/src/kibana/components/vislib/lib/data.js @@ -39,19 +39,24 @@ define(function (require) { this.type = this.getDataType(); this.labels; + this.color; if (this.type === 'series') { - if (getLabels(data).length === 1 && getLabels(data)[0] === '') { + var labels = getLabels(data); + var matchEmptyToFirst = false; + if (labels.length === 1 && labels[0] === '') { this.labels = [(this.get('yAxisLabel'))]; + matchEmptyToFirst = true; } else { - this.labels = getLabels(data); + this.labels = labels; } + this.color = this.labels ? color(this.labels, matchEmptyToFirst) : undefined; } else if (this.type === 'slices') { - this.labels = this.pieNames(); + var flatAndNested = this.pieNames(); + this.labels = flatAndNested.nestedNames; + this.color = color(flatAndNested.flatNames); } - this.color = this.labels ? color(this.labels) : undefined; - this._normalizeOrdered(); this._attr = _.defaults(attr || {}, { @@ -456,29 +461,28 @@ define(function (require) { /** * Helper function for getNames - * Returns an array of objects with a name (key) value and an index value. - * The index value allows us to sort the names in the correct nested order. + * Returns a nested set of objects that contain the hierarchical relationship. Each object contains + * the name, the children, and a data object that has the size and depth for sorting + * purposes. * * @method returnNames * @param array {Array} Array of data objects * @param index {Number} Number of times the object is nested - * @param columns {Object} Contains name formatter information - * @returns {Array} Array of labels (strings) + * @returns {Object} Nested set of objects */ - Data.prototype.returnNames = function (array, index, columns) { - var names = []; + Data.prototype.returnNames = function (array, index) { + var names = {}; var self = this; _.forEach(array, function (obj) { var fieldFormatter = obj.aggConfig ? obj.aggConfig.fieldFormatter() : String; - names.push({ key: fieldFormatter(obj.name), index: index }); + var name = fieldFormatter(obj.name); + names[name] = {name: name, data: {name: name, amount: obj.size, depth: index}, children: {}}; if (obj.children) { var plusIndex = index + 1; - _.forEach(self.returnNames(obj.children, plusIndex, columns), function (namedObj) { - names.push(namedObj); - }); + names[name].children = self.returnNames(obj.children, plusIndex); } }); @@ -486,28 +490,19 @@ define(function (require) { }; /** - * Flattens hierarchical data into an array of objects with a name and index value. - * The indexed value determines the order of nesting in the data. - * Returns an array with names sorted by the index value. + * Returns a nested set of objects that contain the hierarchical relationship. Each object contains + * the name, the children, and a data object that has the size and depth for sorting + * purposes. * * @method getNames * @param data {Object} Chart data object - * @param columns {Object} Contains formatter information - * @returns {Array} Array of names (strings) + * @returns {Object} Nested set of objects */ - Data.prototype.getNames = function (data, columns) { + Data.prototype.getNames = function (data) { var slices = data.slices; if (slices.children) { - var namedObj = this.returnNames(slices.children, 0, columns); - - return _(namedObj) - .sortBy(function (obj) { - return obj.index; - }) - .pluck('key') - .unique() - .value(); + return this.returnNames(slices.children, 0); } }; @@ -539,27 +534,51 @@ define(function (require) { }; /** - * Returns an array of names ordered by appearance in the nested array - * of objects + * Returns an array of names and an object hierarchy of names ordered by size * * @method pieNames - * @returns {Array} Array of unique names (strings) + * @returns {Object} Object that contains array of names and hierarchy of names */ Data.prototype.pieNames = function () { var self = this; - var names = []; + var hierarchy = {}; + var nestedNames = {}; + var flatNames = []; this._validatePieData(); _.forEach(this.getVisData(), function (obj) { - var columns = obj.raw ? obj.raw.columns : undefined; - - _.forEach(self.getNames(obj, columns), function (name) { - names.push(name); + var namedObj = []; + _.merge(hierarchy, self.getNames(obj), function (resultValue, sourceValue) { + // current version of lodash doesn't pass in the key name so use duck-typing to determine + // if this is the correct valur + if (_.isPlainObject(sourceValue) && _.has(sourceValue, 'amount')) { + namedObj.push({name: sourceValue.name, depth: sourceValue.depth}); + if (_.has(resultValue, 'amount')) { + resultValue.amount += sourceValue.amount; + return resultValue; + } else { + return sourceValue; + } + } }); + flatNames.push(_(namedObj) + .sortBy(function (obj) { + return obj.depth; + }) + .pluck('name') + .unique() + .value()); }); + var recursiveSort = function (obj) { + obj.children = _.sortBy(obj.children, function (child) { + return recursiveSort(child); + }); + return -1 * obj.data.amount; + }; + nestedNames = _.sortBy(hierarchy, recursiveSort); - return _.uniq(names); + return {flatNames: _(flatNames).flatten().unique().value(), nestedNames: nestedNames}; }; /** @@ -582,38 +601,6 @@ define(function (require) { return orderKeys(this.data); }; - /** - * Return an array of unique labels - * Curently, only used for vertical bar and line charts, - * or any data object with series values - * - * @method getLabels - * @returns {Array} Array of labels (strings) - */ - Data.prototype.getLabels = function () { - return getLabels(this.data); - }; - - /** - * Returns a function that does color lookup on labels - * - * @method getColorFunc - * @returns {Function} Performs lookup on string and returns hex color - */ - Data.prototype.getColorFunc = function () { - return color(this.getLabels()); - }; - - /** - * Returns a function that does color lookup on names for pie charts - * - * @method getPieColorFunc - * @returns {Function} Performs lookup on string and returns hex color - */ - Data.prototype.getPieColorFunc = function () { - return color(this.pieNames()); - }; - /** * ensure that the datas ordered property has a min and max * if the data represents an ordered date range. diff --git a/src/kibana/components/vislib/lib/dispatch.js b/src/kibana/components/vislib/lib/dispatch.js index f59694dfb8b78a..f9c09d9dfbf741 100644 --- a/src/kibana/components/vislib/lib/dispatch.js +++ b/src/kibana/components/vislib/lib/dispatch.js @@ -233,7 +233,7 @@ define(function (require) { d3.select(element) .select('.legend-ul') - .selectAll('li.color') + .selectAll('li span.color') .filter(function (d, i) { return this.getAttribute('data-label') !== label; }) @@ -249,7 +249,7 @@ define(function (require) { Dispatch.prototype.unHighlightLegend = function (element) { d3.select(element) .select('.legend-ul') - .selectAll('li.color') + .selectAll('li span.color.blur_shape') .classed('blur_shape', false); }; diff --git a/src/kibana/components/vislib/lib/handler/types/pie.js b/src/kibana/components/vislib/lib/handler/types/pie.js index 4bcb4a3c7d9238..d1562e34e7934e 100644 --- a/src/kibana/components/vislib/lib/handler/types/pie.js +++ b/src/kibana/components/vislib/lib/handler/types/pie.js @@ -13,7 +13,7 @@ define(function (require) { var data = new Data(vis.data, vis._attr); return new Handler(vis, { - legend: new Legend(vis, vis.el, data.pieNames(), data.getPieColorFunc(), vis._attr), + legend: new Legend(vis, vis.el, data.labels, data.color, vis._attr), chartTitle: new ChartTitle(vis.el) }); }; diff --git a/src/kibana/components/vislib/lib/legend.js b/src/kibana/components/vislib/lib/legend.js index 90e027bf2bc5d4..f886b67123ab23 100644 --- a/src/kibana/components/vislib/lib/legend.js +++ b/src/kibana/components/vislib/lib/legend.js @@ -25,6 +25,11 @@ define(function (require) { this.vis = vis; this.el = el; this.labels = labels; + if (!_.isPlainObject(_.first(this.labels))) { + this.labels = _.map(this.labels, function (label) { + return {name: label, children: []}; + }); + } this.color = color; this._attr = _.defaults(_attr || {}, { 'legendClass' : 'legend-col-wrapper', @@ -66,6 +71,41 @@ define(function (require) { Legend.prototype.list = function (el, arrOfLabels, args) { var self = this; + function recurseLabels(li) { + li.attr('class', 'color'); + var label = li.append('span') + .attr('class', 'color') + .each(self._addIdentifier); + + label.append('i') + .attr('class', 'fa fa-circle dots') + .attr('style', function (d) { + return 'color:' + args.color(d.name); + }); + + label.append('span') + .text(function (d) { + return d.name; + }); + + var hasChildSelection = li.filter(function (d) { + return d.children.length > 0; + }); + if (hasChildSelection.empty()) { + return; + } + + // add children + hasChildSelection.append('ul') + .selectAll('li') + .data(function (d) { + return d.children; + }) + .enter() + .append('li') + .call(recurseLabels); + } + return el.append('ul') .attr('class', function () { if (args._attr.isOpen) { @@ -77,11 +117,7 @@ define(function (require) { .data(arrOfLabels) .enter() .append('li') - .attr('class', 'color') - .each(self._addIdentifier) - .html(function (d) { - return '' + d; - }); + .call(recurseLabels); }; /** @@ -91,7 +127,7 @@ define(function (require) { * @param label {string} label to use */ Legend.prototype._addIdentifier = function (label) { - dataLabel(this, label); + dataLabel(this, label.name); }; @@ -131,12 +167,14 @@ define(function (require) { } }); - legendDiv.select('.legend-ul').selectAll('li') - .on('mouseover', function (label) { + legendDiv.select('.legend-ul').selectAll('li > span') + .on('mouseover', function (d) { + // data-label's are strings so make sure the label is a string + var label = '' + d.name; var charts = visEl.selectAll('.chart'); // legend - legendDiv.selectAll('li') + legendDiv.selectAll('li span.color') .filter(function (d) { return this.getAttribute('data-label') !== label; }) @@ -162,11 +200,11 @@ define(function (require) { var charts = visEl.selectAll('.chart'); // legend - legendDiv.selectAll('li') + legendDiv.selectAll('li span.blur_shape') .classed('blur_shape', false); - // all data-label attribute - charts.selectAll('[data-label]') + // all blur'ed elements with data-label attribute + charts.selectAll('.blur_shape[data-label]') .classed('blur_shape', false); var eventEl = d3.select(this); diff --git a/src/kibana/components/vislib/styles/_legend.less b/src/kibana/components/vislib/styles/_legend.less index 322c0927868402..2221688881a6d6 100644 --- a/src/kibana/components/vislib/styles/_legend.less +++ b/src/kibana/components/vislib/styles/_legend.less @@ -54,6 +54,9 @@ padding-right: 5px; } } + ul { + padding-left: 15px; + } } .legend-ul.hidden { diff --git a/src/kibana/components/vislib/visualizations/area_chart.js b/src/kibana/components/vislib/visualizations/area_chart.js index 0636f163ebac75..bda45a0c2184df 100644 --- a/src/kibana/components/vislib/visualizations/area_chart.js +++ b/src/kibana/components/vislib/visualizations/area_chart.js @@ -55,7 +55,7 @@ define(function (require) { var ordered = this.handler.data.get('ordered'); var isTimeSeries = (ordered && ordered.date); var isOverlapping = this.isOverlapping; - var color = this.handler.data.getColorFunc(); + var color = this.handler.data.color; var xScale = this.handler.xAxis.xScale; var yScale = this.handler.yAxis.yScale; var interpolate = (this._attr.smoothLines) ? 'cardinal' : this._attr.interpolate; @@ -142,7 +142,7 @@ define(function (require) { */ AreaChart.prototype.addCircles = function (svg, data) { var self = this; - var color = this.handler.data.getColorFunc(); + var color = this.handler.data.color; var xScale = this.handler.xAxis.xScale; var yScale = this.handler.yAxis.yScale; var ordered = this.handler.data.get('ordered'); diff --git a/src/kibana/components/vislib/visualizations/column_chart.js b/src/kibana/components/vislib/visualizations/column_chart.js index 7d8ca05eacba90..c9464bb7f9d05a 100644 --- a/src/kibana/components/vislib/visualizations/column_chart.js +++ b/src/kibana/components/vislib/visualizations/column_chart.js @@ -43,7 +43,7 @@ define(function (require) { */ ColumnChart.prototype.addBars = function (svg, layers) { var self = this; - var color = this.handler.data.getColorFunc(); + var color = this.handler.data.color; var tooltip = this.tooltip; var isTooltip = this._attr.addTooltip; var layer; diff --git a/src/kibana/components/vislib/visualizations/line_chart.js b/src/kibana/components/vislib/visualizations/line_chart.js index 2d1fb561eef75d..14c16490c615d9 100644 --- a/src/kibana/components/vislib/visualizations/line_chart.js +++ b/src/kibana/components/vislib/visualizations/line_chart.js @@ -67,7 +67,7 @@ define(function (require) { LineChart.prototype.addCircles = function (svg, data) { var self = this; var showCircles = this._attr.showCircles; - var color = this.handler.data.getColorFunc(); + var color = this.handler.data.color; var xScale = this.handler.xAxis.xScale; var yScale = this.handler.yAxis.yScale; var ordered = this.handler.data.get('ordered'); @@ -179,7 +179,7 @@ define(function (require) { var xScale = this.handler.xAxis.xScale; var yScale = this.handler.yAxis.yScale; var xAxisFormatter = this.handler.data.get('xAxisFormatter'); - var color = this.handler.data.getColorFunc(); + var color = this.handler.data.color; var ordered = this.handler.data.get('ordered'); var interpolate = (this._attr.smoothLines) ? 'cardinal' : this._attr.interpolate; var line = d3.svg.line() diff --git a/src/kibana/components/vislib/visualizations/pie_chart.js b/src/kibana/components/vislib/visualizations/pie_chart.js index 3990bbc501f840..fc5160fa5fcb65 100644 --- a/src/kibana/components/vislib/visualizations/pie_chart.js +++ b/src/kibana/components/vislib/visualizations/pie_chart.js @@ -87,7 +87,7 @@ define(function (require) { var marginFactor = 0.95; var isDonut = self._attr.isDonut; var radius = (Math.min(width, height) / 2) * marginFactor; - var color = self.handler.data.getPieColorFunc(); + var color = this.handler.data.color; var tooltip = self.tooltip; var isTooltip = self._attr.addTooltip; diff --git a/test/unit/specs/vislib/fixture/mock_data/histogram/_slices.js b/test/unit/specs/vislib/fixture/mock_data/histogram/_slices.js index f41013da80f873..5a9e906ec4f587 100644 --- a/test/unit/specs/vislib/fixture/mock_data/histogram/_slices.js +++ b/test/unit/specs/vislib/fixture/mock_data/histogram/_slices.js @@ -16,7 +16,35 @@ define(function () { 'interval': 1000, 'extended_bounds': {} } - } + }, + 'children': [ + { + 'name': '0-inner0', + 'size': 378611, + 'aggConfig': { + 'type': 'histogram', + 'schema': 'segment', + 'fieldFormatter': _.constant(String), + 'params': { + 'interval': 1000, + 'extended_bounds': {} + } + } + }, + { + 'name': '0-inner1', + 'size': 378610, + 'aggConfig': { + 'type': 'histogram', + 'schema': 'segment', + 'fieldFormatter': _.constant(String), + 'params': { + 'interval': 1000, + 'extended_bounds': {} + } + } + } + ] }, { 'name': 1000, diff --git a/test/unit/specs/vislib/lib/legend.js b/test/unit/specs/vislib/lib/legend.js index 53763f0d71557e..4ea49266921d69 100644 --- a/test/unit/specs/vislib/lib/legend.js +++ b/test/unit/specs/vislib/lib/legend.js @@ -61,13 +61,13 @@ define(function (require) { var paths = $(vis.el).find(chartSelectors[chartType]).toArray(); var items = vis.handler.legend.labels; - items.forEach(function (label) { + items.forEach(function (item) { var path = _(paths) .map(function (path) { return path.getAttribute('data-label'); }) .filter(function (dataLabel) { - return dataLabel === label; + return dataLabel === item.name; }) .value(); @@ -90,6 +90,11 @@ define(function (require) { it('should contain a list of items', function () { expect($(vis.el).find('li').length).to.be.greaterThan(1); }); + if (chartTypes[i] === 'pie') { + it('should contain a nested list of items', function () { + expect($(vis.el).find('li ul li').length).to.be.greaterThan(1); + }); + } }); describe('render method', function () { @@ -102,7 +107,7 @@ define(function (require) { }); it('should attach onmouseover listener', function () { - expect(!!$('li.color')[0].__onmouseover).to.be(true); + expect(!!$('li > span')[0].__onmouseover).to.be(true); }); }); }); From 08244946a6ca9254f7aefaa496c8c8a76ccb44fe Mon Sep 17 00:00:00 2001 From: Trevan Richins Date: Mon, 20 Apr 2015 16:37:14 -0600 Subject: [PATCH 2/3] Make sure that the legend order stays the same as the data order. lodash's merge requires an object which isn't guarenteed to keep an order. So write a custom merge function that works on arrays. --- src/kibana/components/vislib/lib/data.js | 106 +++++++++++++++-------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/src/kibana/components/vislib/lib/data.js b/src/kibana/components/vislib/lib/data.js index 541cc1e81769c2..547495a9ec6e41 100644 --- a/src/kibana/components/vislib/lib/data.js +++ b/src/kibana/components/vislib/lib/data.js @@ -460,33 +460,34 @@ define(function (require) { }; /** - * Helper function for getNames + * Helper function for getHierarchyNames * Returns a nested set of objects that contain the hierarchical relationship. Each object contains * the name, the children, and a data object that has the size and depth for sorting * purposes. * - * @method returnNames + * @method returnHierarchyNames * @param array {Array} Array of data objects - * @param index {Number} Number of times the object is nested - * @returns {Object} Nested set of objects + * @param depth {Number} Number of times the object is nested + * @returns {Array} Array of objects with children */ - Data.prototype.returnNames = function (array, index) { - var names = {}; + Data.prototype.returnHierarchyNames = function (array, depth) { + var hierarchyNames = []; var self = this; _.forEach(array, function (obj) { var fieldFormatter = obj.aggConfig ? obj.aggConfig.fieldFormatter() : String; var name = fieldFormatter(obj.name); - names[name] = {name: name, data: {name: name, amount: obj.size, depth: index}, children: {}}; + var hierarchyName = {name: name, depth: depth, children: []}; if (obj.children) { - var plusIndex = index + 1; + var plusDepth = depth + 1; - names[name].children = self.returnNames(obj.children, plusIndex); + hierarchyName.children = self.returnHierarchyNames(obj.children, plusDepth); } + hierarchyNames.push(hierarchyName); }); - return names; + return hierarchyNames; }; /** @@ -494,15 +495,15 @@ define(function (require) { * the name, the children, and a data object that has the size and depth for sorting * purposes. * - * @method getNames + * @method getHierarchyNames * @param data {Object} Chart data object * @returns {Object} Nested set of objects */ - Data.prototype.getNames = function (data) { + Data.prototype.getHierarchyNames = function (data) { var slices = data.slices; if (slices.children) { - return this.returnNames(slices.children, 0); + return this.returnHierarchyNames(slices.children, 0); } }; @@ -533,6 +534,54 @@ define(function (require) { }); }; + /** + * Merges two object hierarchy of names into finalHierarchyNames. + * Also grabs a list of names and depth pairs + * + * @method _mergeHierarchyNames + * @param finalHierarchyNames {Object} Object hierarchy of names destination + * @param newHierarchyNames {Object} Object hierarchy of names source + * @param namesWithDepth {Array} Array of name/depth pairs + */ + Data.prototype._mergeHierarchyNames = function (finalHierarchyNames, newHierarchyNames, namesWithDepth) { + var self = this; + + _.each(newHierarchyNames, function (hierarchy) { + var name = hierarchy.name; + namesWithDepth.push({name: name, depth: hierarchy.depth}); + var wasMerged = false; + _.each(finalHierarchyNames, function (finalHierarchy) { + if (finalHierarchy.name === name) { + // merge together + wasMerged = true; + self._mergeHierarchyNames(finalHierarchy.children, hierarchy.children, namesWithDepth); + } + }); + if (!wasMerged) { + finalHierarchyNames.push(hierarchy); + self._getNamesWithDepth(hierarchy.children, namesWithDepth); + } + }); + }; + + /** + * Helper function for _mergeHierarchyNames to grab just the name/depth pairs when there is + * no destination merge location. + * + * @method _getNamesWithDepth + * @param hierarchyNames {Object} Object hierarchy of names + * @param namesWithDepth {Array} Array of name/depth pairs + */ + Data.prototype._getNamesWithDepth = function (hierarchyNames, namesWithDepth) { + var self = this; + + _.each(hierarchyNames, function (hierarchy) { + var name = hierarchy.name; + namesWithDepth.push({name: name, depth: hierarchy.depth}); + self._getNamesWithDepth(hierarchy.children, namesWithDepth); + }); + }; + /** * Returns an array of names and an object hierarchy of names ordered by size * @@ -541,28 +590,16 @@ define(function (require) { */ Data.prototype.pieNames = function () { var self = this; - var hierarchy = {}; - var nestedNames = {}; + var mergedHierarchyNames = []; var flatNames = []; this._validatePieData(); _.forEach(this.getVisData(), function (obj) { - var namedObj = []; - _.merge(hierarchy, self.getNames(obj), function (resultValue, sourceValue) { - // current version of lodash doesn't pass in the key name so use duck-typing to determine - // if this is the correct valur - if (_.isPlainObject(sourceValue) && _.has(sourceValue, 'amount')) { - namedObj.push({name: sourceValue.name, depth: sourceValue.depth}); - if (_.has(resultValue, 'amount')) { - resultValue.amount += sourceValue.amount; - return resultValue; - } else { - return sourceValue; - } - } - }); - flatNames.push(_(namedObj) + var namesWithDepth = []; + self._mergeHierarchyNames(mergedHierarchyNames, self.getHierarchyNames(obj), namesWithDepth); + + flatNames.push(_(namesWithDepth) .sortBy(function (obj) { return obj.depth; }) @@ -570,15 +607,8 @@ define(function (require) { .unique() .value()); }); - var recursiveSort = function (obj) { - obj.children = _.sortBy(obj.children, function (child) { - return recursiveSort(child); - }); - return -1 * obj.data.amount; - }; - nestedNames = _.sortBy(hierarchy, recursiveSort); - return {flatNames: _(flatNames).flatten().unique().value(), nestedNames: nestedNames}; + return {flatNames: _(flatNames).flatten().unique().value(), nestedNames: mergedHierarchyNames}; }; /** From 41fc305a4b4ab1011cb847302773b6744f4e9a6c Mon Sep 17 00:00:00 2001 From: Trevan Richins Date: Mon, 20 Apr 2015 17:01:48 -0600 Subject: [PATCH 3/3] Fix expansion of truncated legend values Switched to a div block container and moved the text-overflow styling there. --- src/kibana/components/vislib/lib/dispatch.js | 4 ++-- src/kibana/components/vislib/lib/legend.js | 8 ++++---- src/kibana/components/vislib/styles/_legend.less | 7 +++++-- test/unit/specs/vislib/lib/legend.js | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/kibana/components/vislib/lib/dispatch.js b/src/kibana/components/vislib/lib/dispatch.js index f9c09d9dfbf741..a7fccc8182364d 100644 --- a/src/kibana/components/vislib/lib/dispatch.js +++ b/src/kibana/components/vislib/lib/dispatch.js @@ -233,7 +233,7 @@ define(function (require) { d3.select(element) .select('.legend-ul') - .selectAll('li span.color') + .selectAll('li div.color') .filter(function (d, i) { return this.getAttribute('data-label') !== label; }) @@ -249,7 +249,7 @@ define(function (require) { Dispatch.prototype.unHighlightLegend = function (element) { d3.select(element) .select('.legend-ul') - .selectAll('li span.color.blur_shape') + .selectAll('li div.color.blur_shape') .classed('blur_shape', false); }; diff --git a/src/kibana/components/vislib/lib/legend.js b/src/kibana/components/vislib/lib/legend.js index f886b67123ab23..e4ab65ea59e10b 100644 --- a/src/kibana/components/vislib/lib/legend.js +++ b/src/kibana/components/vislib/lib/legend.js @@ -73,7 +73,7 @@ define(function (require) { function recurseLabels(li) { li.attr('class', 'color'); - var label = li.append('span') + var label = li.append('div') .attr('class', 'color') .each(self._addIdentifier); @@ -167,14 +167,14 @@ define(function (require) { } }); - legendDiv.select('.legend-ul').selectAll('li > span') + legendDiv.select('.legend-ul').selectAll('li > div') .on('mouseover', function (d) { // data-label's are strings so make sure the label is a string var label = '' + d.name; var charts = visEl.selectAll('.chart'); // legend - legendDiv.selectAll('li span.color') + legendDiv.selectAll('li div.color') .filter(function (d) { return this.getAttribute('data-label') !== label; }) @@ -200,7 +200,7 @@ define(function (require) { var charts = visEl.selectAll('.chart'); // legend - legendDiv.selectAll('li span.blur_shape') + legendDiv.selectAll('li div.blur_shape') .classed('blur_shape', false); // all blur'ed elements with data-label attribute diff --git a/src/kibana/components/vislib/styles/_legend.less b/src/kibana/components/vislib/styles/_legend.less index 2221688881a6d6..cf033bd81e88ca 100644 --- a/src/kibana/components/vislib/styles/_legend.less +++ b/src/kibana/components/vislib/styles/_legend.less @@ -45,10 +45,13 @@ cursor: default; text-align: left; .flex-grow(2); - white-space: nowrap; overflow-x: hidden; - text-overflow: ellipsis; max-width: 150px; + & > div { + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; + } .dots { padding-right: 5px; diff --git a/test/unit/specs/vislib/lib/legend.js b/test/unit/specs/vislib/lib/legend.js index 4ea49266921d69..aed405c1105db0 100644 --- a/test/unit/specs/vislib/lib/legend.js +++ b/test/unit/specs/vislib/lib/legend.js @@ -107,7 +107,7 @@ define(function (require) { }); it('should attach onmouseover listener', function () { - expect(!!$('li > span')[0].__onmouseover).to.be(true); + expect(!!$('li > div')[0].__onmouseover).to.be(true); }); }); });