mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
commit
860e9d27c3
9 changed files with 98 additions and 130 deletions
15
src/kibana/components/vislib/lib/_data_label.js
Normal file
15
src/kibana/components/vislib/lib/_data_label.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
define(function (require) {
|
||||
var d3 = require('d3');
|
||||
/**
|
||||
* Creates a string based on the hex color passed in
|
||||
*
|
||||
* @method dataLabel
|
||||
* @param d {Object} object to wrap in d3.select
|
||||
* @returns {string} label value
|
||||
*/
|
||||
function dataLabel(selection, label) {
|
||||
d3.select(selection).attr('data-label', label);
|
||||
}
|
||||
|
||||
return dataLabel;
|
||||
});
|
|
@ -227,14 +227,15 @@ define(function (require) {
|
|||
* @method highlightLegend
|
||||
*/
|
||||
Dispatch.prototype.highlightLegend = function (element) {
|
||||
var classList = d3.select(this).node().classList;
|
||||
var liClass = d3.select(this).node().classList[1];
|
||||
var label = this.getAttribute('data-label');
|
||||
|
||||
if (!label) return;
|
||||
|
||||
d3.select(element)
|
||||
.select('.legend-ul')
|
||||
.selectAll('li.color')
|
||||
.filter(function (d, i) {
|
||||
return d3.select(this).node().classList[1] !== liClass;
|
||||
return this.getAttribute('data-label') !== label;
|
||||
})
|
||||
.classed('blur_shape', true);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@ define(function (require) {
|
|||
return function LegendFactory(d3) {
|
||||
var _ = require('lodash');
|
||||
var legendHeaderTemplate = _.template(require('text!components/vislib/partials/legend_header.html'));
|
||||
var dataLabel = require('components/vislib/lib/_data_label');
|
||||
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
|
@ -76,27 +77,24 @@ define(function (require) {
|
|||
.data(arrOfLabels)
|
||||
.enter()
|
||||
.append('li')
|
||||
.attr('class', function (d) {
|
||||
return 'color ' + self.colorToClass(args.color(d));
|
||||
})
|
||||
.attr('class', 'color')
|
||||
.each(self._addIdentifier)
|
||||
.html(function (d) {
|
||||
return '<i class="fa fa-circle dots" style="color:' + args.color(d) + '"></i>' + d;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a class name based on the hexColor assigned to each label
|
||||
* Append the data label to the element
|
||||
*
|
||||
* @method colorToClass
|
||||
* @param hexColor {String} Label
|
||||
* @returns {string} CSS class name
|
||||
* @method _addIdentifier
|
||||
* @param label {string} label to use
|
||||
*/
|
||||
Legend.prototype.colorToClass = function (hexColor) {
|
||||
if (hexColor) {
|
||||
return 'c' + hexColor.replace(/[#]/g, '');
|
||||
}
|
||||
Legend.prototype._addIdentifier = function (label) {
|
||||
dataLabel(this, label);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Renders legend
|
||||
*
|
||||
|
@ -134,35 +132,20 @@ define(function (require) {
|
|||
});
|
||||
|
||||
legendDiv.select('.legend-ul').selectAll('li')
|
||||
.on('mouseover', function (d) {
|
||||
var liClass = self.colorToClass(self.color(d));
|
||||
.on('mouseover', function (label) {
|
||||
var charts = visEl.selectAll('.chart');
|
||||
|
||||
// legend
|
||||
legendDiv.selectAll('li')
|
||||
.filter(function (d) {
|
||||
return d3.select(this).node().classList[1] !== liClass;
|
||||
return this.getAttribute('data-label') !== label;
|
||||
})
|
||||
.classed('blur_shape', true);
|
||||
|
||||
// lines/area
|
||||
charts.selectAll('.color')
|
||||
// all data-label attribute
|
||||
charts.selectAll('[data-label]')
|
||||
.filter(function (d) {
|
||||
return d3.select(this).node().classList[1] !== liClass;
|
||||
})
|
||||
.classed('blur_shape', true);
|
||||
|
||||
// circles
|
||||
charts.selectAll('.line circle')
|
||||
.filter(function (d) {
|
||||
return d3.select(this).node().classList[1] !== liClass;
|
||||
})
|
||||
.classed('blur_shape', true);
|
||||
|
||||
// pie slices
|
||||
charts.selectAll('.slice')
|
||||
.filter(function (d) {
|
||||
return d3.select(this).node().classList[1] !== liClass;
|
||||
return this.getAttribute('data-label') !== label;
|
||||
})
|
||||
.classed('blur_shape', true);
|
||||
|
||||
|
@ -182,16 +165,8 @@ define(function (require) {
|
|||
legendDiv.selectAll('li')
|
||||
.classed('blur_shape', false);
|
||||
|
||||
// lines/areas
|
||||
charts.selectAll('.color')
|
||||
.classed('blur_shape', false);
|
||||
|
||||
// circles
|
||||
charts.selectAll('.line circle')
|
||||
.classed('blur_shape', false);
|
||||
|
||||
// pie slices
|
||||
charts.selectAll('.slice')
|
||||
// all data-label attribute
|
||||
charts.selectAll('[data-label]')
|
||||
.classed('blur_shape', false);
|
||||
|
||||
var eventEl = d3.select(this);
|
||||
|
|
|
@ -2,9 +2,9 @@ define(function (require) {
|
|||
return function ChartBaseClass(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
|
||||
var Legend = Private(require('components/vislib/lib/legend'));
|
||||
var Dispatch = Private(require('components/vislib/lib/dispatch'));
|
||||
var Tooltip = Private(require('components/vislib/components/tooltip/tooltip'));
|
||||
var dataLabel = require('components/vislib/lib/_data_label');
|
||||
|
||||
/**
|
||||
* The Base Class for all visualizations.
|
||||
|
@ -48,14 +48,18 @@ define(function (require) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Returns a CSS class name
|
||||
* Append the data label to the element
|
||||
*
|
||||
* @method colorToClass
|
||||
* @param label {String} Data point label
|
||||
* @returns {String} CSS class name
|
||||
* @method _addIdentifier
|
||||
* @param selection {Object} d3 select object
|
||||
*/
|
||||
Chart.prototype.colorToClass = function (label) {
|
||||
return Legend.prototype.colorToClass.call(null, label);
|
||||
Chart.prototype._addIdentifier = function (selection, labelProp) {
|
||||
labelProp = labelProp || 'label';
|
||||
selection.each(function (datum) {
|
||||
var label = datum[0] ? datum[0][labelProp] : datum[labelProp];
|
||||
if (label == null) return;
|
||||
dataLabel(this, label);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -82,22 +82,18 @@ define(function (require) {
|
|||
})
|
||||
.interpolate(interpolate);
|
||||
|
||||
var layer;
|
||||
var path;
|
||||
|
||||
// Data layers
|
||||
layer = svg.selectAll('.layer')
|
||||
var layer = svg.selectAll('.layer')
|
||||
.data(layers)
|
||||
.enter().append('g')
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', function (d, i) {
|
||||
return i;
|
||||
return 'pathgroup ' + i;
|
||||
});
|
||||
|
||||
// Append path
|
||||
path = layer.append('path')
|
||||
.attr('class', function (d) {
|
||||
return 'color ' + self.colorToClass(color(d[0].label));
|
||||
})
|
||||
var path = layer.append('path')
|
||||
.call(this._addIdentifier)
|
||||
.style('fill', function (d) {
|
||||
return color(d[0].label);
|
||||
})
|
||||
|
@ -151,7 +147,7 @@ define(function (require) {
|
|||
var yScale = this.handler.yAxis.yScale;
|
||||
var ordered = this.handler.data.get('ordered');
|
||||
var circleRadius = 12;
|
||||
var circleStrokeWidth = 1;
|
||||
var circleStrokeWidth = 0;
|
||||
var tooltip = this.tooltip;
|
||||
var isTooltip = this._attr.addTooltip;
|
||||
var isOverlapping = this.isOverlapping;
|
||||
|
@ -180,9 +176,7 @@ define(function (require) {
|
|||
circles
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('class', function circleClass(d) {
|
||||
return d.label + ' ' + self.colorToClass(color(d.label));
|
||||
})
|
||||
.call(this._addIdentifier)
|
||||
.attr('stroke', function strokeColor(d) {
|
||||
return color(d.label);
|
||||
})
|
||||
|
|
|
@ -68,9 +68,7 @@ define(function (require) {
|
|||
bars
|
||||
.enter()
|
||||
.append('rect')
|
||||
.attr('class', function (d) {
|
||||
return 'color ' + self.colorToClass(color(d.label));
|
||||
})
|
||||
.call(this._addIdentifier)
|
||||
.attr('fill', function (d) {
|
||||
return color(d.label);
|
||||
});
|
||||
|
|
|
@ -144,9 +144,8 @@ define(function (require) {
|
|||
.attr('cx', cx)
|
||||
.attr('cy', cy)
|
||||
.attr('fill', colorCircle)
|
||||
.attr('class', function circleClass(d) {
|
||||
return 'circle-decoration ' + self.colorToClass(color(d.label));
|
||||
});
|
||||
.attr('class', 'circle-decoration')
|
||||
.call(this._addIdentifier);
|
||||
|
||||
circles
|
||||
.enter()
|
||||
|
@ -155,9 +154,8 @@ define(function (require) {
|
|||
.attr('cx', cx)
|
||||
.attr('cy', cy)
|
||||
.attr('fill', 'transparent')
|
||||
.attr('class', function circleClass(d) {
|
||||
return 'circle ' + self.colorToClass(color(d.label));
|
||||
})
|
||||
.attr('class', 'circle')
|
||||
.call(this._addIdentifier)
|
||||
.attr('stroke', cColor)
|
||||
.attr('stroke-width', 0);
|
||||
|
||||
|
@ -202,12 +200,10 @@ define(function (require) {
|
|||
.data(data)
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', 'lines');
|
||||
.attr('class', 'pathgroup lines');
|
||||
|
||||
lines.append('path')
|
||||
.attr('class', function lineClass(d) {
|
||||
return 'color ' + self.colorToClass(color(d.label));
|
||||
})
|
||||
.call(this._addIdentifier)
|
||||
.attr('d', function lineD(d) {
|
||||
return line(d.values);
|
||||
})
|
||||
|
|
|
@ -83,10 +83,19 @@ define(function (require) {
|
|||
* @returns {D3.Selection} SVG with paths attached
|
||||
*/
|
||||
PieChart.prototype.addPath = function (width, height, svg, slices) {
|
||||
var self = this;
|
||||
var marginFactor = 0.95;
|
||||
var isDonut = this._attr.isDonut;
|
||||
var isDonut = self._attr.isDonut;
|
||||
var radius = (Math.min(width, height) / 2) * marginFactor;
|
||||
var color = this.handler.data.getPieColorFunc();
|
||||
var color = self.handler.data.getPieColorFunc();
|
||||
var tooltip = self.tooltip;
|
||||
var isTooltip = self._attr.addTooltip;
|
||||
|
||||
var format = function (d, label) {
|
||||
var formatter = d.aggConfig ? d.aggConfig.fieldFormatter() : String;
|
||||
return formatter(label);
|
||||
};
|
||||
|
||||
var partition = d3.layout.partition()
|
||||
.sort(null)
|
||||
.value(function (d) {
|
||||
|
@ -115,16 +124,8 @@ define(function (require) {
|
|||
.outerRadius(function (d) {
|
||||
return Math.max(0, y(d.y + d.dy));
|
||||
});
|
||||
var tooltip = this.tooltip;
|
||||
var isTooltip = this._attr.addTooltip;
|
||||
var self = this;
|
||||
var path;
|
||||
var format = function (d, label) {
|
||||
var formatter = d.aggConfig ? d.aggConfig.fieldFormatter() : String;
|
||||
return formatter(label);
|
||||
};
|
||||
|
||||
path = svg
|
||||
var path = svg
|
||||
.datum(slices)
|
||||
.selectAll('path')
|
||||
.data(partition.nodes)
|
||||
|
@ -133,8 +134,9 @@ define(function (require) {
|
|||
.attr('d', arc)
|
||||
.attr('class', function (d) {
|
||||
if (d.depth === 0) { return; }
|
||||
return 'slice ' + self.colorToClass(color(format(d, d.name)));
|
||||
return 'slice';
|
||||
})
|
||||
.call(self._addIdentifier, 'name')
|
||||
.style('stroke', '#fff')
|
||||
.style('fill', function (d) {
|
||||
if (d.depth === 0) { return 'none'; }
|
||||
|
|
|
@ -20,6 +20,13 @@ define(function (require) {
|
|||
'line'
|
||||
];
|
||||
|
||||
var chartSelectors = {
|
||||
histogram: '.chart rect',
|
||||
pie: '.chart path',
|
||||
area: '.chart path',
|
||||
line: '.chart circle',
|
||||
};
|
||||
|
||||
angular.module('LegendFactory', ['kibana']);
|
||||
|
||||
dataArray.forEach(function (data, i) {
|
||||
|
@ -48,31 +55,25 @@ define(function (require) {
|
|||
vis = null;
|
||||
});
|
||||
|
||||
describe('legend item color matches slice color', function () {
|
||||
var items;
|
||||
var paths;
|
||||
var getColor;
|
||||
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;
|
||||
|
||||
if (chartTypes[i] === 'pie') {
|
||||
it('should match the slice color', function () {
|
||||
paths = $(vis.el).find('path').toArray();
|
||||
items = vis.handler.legend.labels;
|
||||
getColor = vis.handler.legend.color;
|
||||
items.forEach(function (label) {
|
||||
var path = _(paths)
|
||||
.map(function (path) {
|
||||
return path.getAttribute('data-label');
|
||||
})
|
||||
.filter(function (dataLabel) {
|
||||
return dataLabel === label;
|
||||
})
|
||||
.value();
|
||||
|
||||
items.forEach(function (label) {
|
||||
var slices = paths.filter(function (path) {
|
||||
if (path.__data__.name === undefined) return false;
|
||||
return path.__data__.name.toString() === label;
|
||||
}).map(function (path) {
|
||||
return $(path).attr('class').split(/\s+/)[1].replace('c', '#');
|
||||
});
|
||||
|
||||
slices.forEach(function (hex) {
|
||||
expect(hex).to.be(getColor(label));
|
||||
});
|
||||
});
|
||||
expect(path.length).to.be.greaterThan(0);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('header method', function () {
|
||||
|
@ -91,24 +92,6 @@ define(function (require) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('colorToClass method', function () {
|
||||
var labels;
|
||||
var color;
|
||||
var colorToClass;
|
||||
|
||||
beforeEach(function () {
|
||||
labels = vis.handler.legend.labels;
|
||||
color = vis.handler.legend.color;
|
||||
colorToClass = vis.handler.legend.colorToClass;
|
||||
});
|
||||
|
||||
it('should create a class label from the labels hex color', function () {
|
||||
labels.forEach(function (label) {
|
||||
expect(colorToClass(color(label))).to.be('c' + color(label).replace(/[#]/g, ''));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('render method', function () {
|
||||
it('should create a legend toggle', function () {
|
||||
expect($('.legend-toggle').length).to.be(1);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue