Closes issue #340. Legend now has human readable date formats. I've passed in the field formatters to format the values. The solution however is not ideal as I have had to duplicate code in several places. This fix should work without fault, but it needs to be revised in the future.

This commit is contained in:
Shelby Sturgis 2014-10-03 21:49:30 +03:00
parent eeb94f03ff
commit 8c9a36f91e
9 changed files with 66 additions and 32 deletions

View file

@ -25,7 +25,7 @@ Kibana is an open source (Apache Licensed), browser based analytics and search d
You're up and running! Fantastic! Kibana is now running on port 5601, so point your browser at http://YOURDOMAIN.com:5601.
The first screen you arrive at will ask you to configure an **index pattern**. An index pattern describes to Kibana how to access your data. We make the guess that you're working with log data, and we hope (because it's awesome) that you're working with Logstash. By default, we fill in `logstash-*` as your index pattern, thus the only thing you need to do is select which field contains the timestamp you'd like to use. Kibana reads your Elasticsearch mapping to find your time fields - select one from the list and hit *Create*.
The first screen you arrive at will ask you to configure an **index pattern**. An index pattern describes to kibana how to access your data. We make the guess that you're working with log data, and we hope (because it's awesome) that you're working with Logstash. By default, we fill in `logstash-*` as your index pattern, thus the only thing you need to do is select which field contains the timestamp you'd like to use. Kibana reads your Elasticsearch mapping to find your time fields - select one from the list and hit *Create*.
**Tip:** there's an optimization in the way of the *Use event times to create index names* option. Since Logstash creates an index every day, Kibana uses that fact to only search indices that could possibly contain data in your selected time range.
@ -128,7 +128,7 @@ Or HTML
status:[400 TO 499] AND (extension:php OR extension:html)
```
While Lucene query syntax is simple and very powerful, Kibana also supports the full Elasticsearch, JSON based, Query DSL. See the [Elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax) for usage and examples.
While lucene query syntax is simple and very powerful, Kibana also supports the full elasticsearch, JSON based, query DSL. See the [Elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax) for usage and examples.
<!-- /include -->
<!-- include {"path":"docs/visualize.md"} -->
## Visualize
@ -163,7 +163,7 @@ To the right of the search box there are a row of icons for creating new visuali
#### Aggregation Builder
The aggregation builder on the left of the screen is used for configuring the [metric](http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/search-aggregations.html#_metrics_aggregations) and [bucket](http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/search-aggregations.html#_bucket_aggregations) aggregations used to create a visualization. (If you are coming from the SQL world, buckets are similar to group-bys. Check out the [Elasticsearch docs](http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/search-aggregations.html) for more info) For a bar chart or line chart the *metric* is used for the y-axis and the *buckets* are used for the x-axis, segment bar colors, and row/column splits. For pie charts the "metric" is used for the size of the slice and the *bucket* is used for the number of slices. Other visualizations may use these in new and different ways.
The aggregation builder on the left of the screen is used for configuring the [metric](http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/search-aggregations.html#_metrics_aggregations) and [bucket](http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/search-aggregations.html#_bucket_aggregations) aggregations used to create a visualization. (If you are coming from the SQL world, buckets are similar to group-bys. Check out the [elasticsearch docs](http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/search-aggregations.html) for more info) For a bar chart or line chart the *metric* is used for the y-axis and the *buckets* are used for the x-axis, segment bar colors, and row/column splits. For pie charts the "metric" is used for the size of the slice and the *bucket* is used for the number of slices. Other visualizations may use these in new and different ways.
For the remainder of this documentation we are going to use the bar chart as our example when discussing the features of the aggregation panel. The same concepts apply to the other visualizations but the bar chart is the workhorse of the visualization world.
@ -314,4 +314,4 @@ Clicking on the *View* action loads that item in the associated applications. Re
Clicking *Edit* will allow you to change the title, description and other settings of the saved object. You can also edit the schema of the stored object.
*Note:* this operation is for advanced users only - making changes here can break large portions of the application.
<!-- /include -->
<!-- /include -->

View file

@ -20,8 +20,17 @@ define(function (require) {
throw new Error('LabelUtil expects an object');
}
var raw;
var fieldIndex;
if (obj.raw) {
raw = obj.raw.columns;
fieldIndex = _.findIndex(raw, {'categoryName': 'group'});
}
var fieldFormatter = raw && raw[fieldIndex] ? raw[fieldIndex].field.format.convert : function (d) { return d; };
// Returns an array of unique chart labels
return getArrOfUniqLabels(getArr(obj));
return getArrOfUniqLabels(getArr(obj), fieldFormatter);
};
};
});

View file

@ -3,13 +3,19 @@ define(function (require) {
var _ = require('lodash');
// Takes an array of objects
return function (arr) {
return function (arr, formatter) {
if (!_.isArray(arr)) {
throw TypeError('UniqLabelUtil expects an array of objects');
}
// Returns a array of unique chart labels
return _.uniq(_.pluck(arr, 'label'));
return _(arr)
.pluck('label')
.unique()
.map(function (d) {
return formatter(d);
})
.value();
};
};
});

View file

@ -170,17 +170,18 @@ 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.
Data.prototype.returnNames = function (array, index) {
Data.prototype.returnNames = function (array, index, columns) {
var names = [];
var self = this;
_.forEach(array, function (obj) {
names.push({ key: obj.name, index: index });
var fieldFormatter = columns[index].field.format.convert;
names.push({ key: fieldFormatter(obj.name), index: index });
if (obj.children) {
var plusIndex = index + 1;
_.forEach(self.returnNames(obj.children, plusIndex), function (namedObj) {
_.forEach(self.returnNames(obj.children, plusIndex, columns), function (namedObj) {
names.push(namedObj);
});
}
@ -194,9 +195,10 @@ define(function (require) {
// Returns an array with names sorted by the index value.
Data.prototype.getNames = function () {
var data = this.data.slices;
var columns = this.data.raw.columns;
if (data.children) {
var namedObj = this.returnNames(data.children, 0);
var namedObj = this.returnNames(data.children, 0, columns);
return _(namedObj)
.sortBy(function (obj) {

View file

@ -33,16 +33,6 @@ define(function (require) {
'defaultOpacity' : 1,
'isOpen' : true
});
// Adding field formatter for formatting legend labels
var raw;
var fieldIndex;
if (this.vis.data.raw) {
raw = this.vis.data.raw.columns;
fieldIndex = _.findIndex(raw, {'categoryName': 'group'});
}
this.fieldFormatter = raw && raw[fieldIndex] ? raw[fieldIndex].field.format.convert : function (d) { return d; };
}
// Add legend header
@ -77,7 +67,7 @@ define(function (require) {
})
.html(function (d) {
// return the appropriate color for each dot
return '<span class="dots" style="background:' + args.color(d) + '"></span>' + self.fieldFormatter(d);
return '<span class="dots" style="background:' + args.color(d) + '"></span>' + d;
});
};

View file

@ -18,6 +18,16 @@ define(function (require) {
return new ColumnChart(handler, chartEl, chartData);
}
var raw;
var fieldIndex;
if (chartData.raw) {
raw = chartData.raw.columns;
fieldIndex = _.findIndex(raw, {'categoryName': 'group'});
}
this.fieldFormatter = raw && raw[fieldIndex] ? raw[fieldIndex].field.format.convert : function (d) { return d; };
ColumnChart.Super.apply(this, arguments);
// Column chart specific attributes
this._attr = _.defaults(handler._attr || {}, {
@ -75,10 +85,10 @@ define(function (require) {
bars.enter()
.append('rect')
.attr('class', function (d) {
return self.colorToClass(color(d.label));
return self.colorToClass(color(self.fieldFormatter(d.label)));
})
.attr('fill', function (d) {
return color(d.label);
return color(self.fieldFormatter(d.label));
});
// update

View file

@ -14,6 +14,16 @@ define(function (require) {
return new LineChart(handler, chartEl, chartData);
}
var raw;
var fieldIndex;
if (chartData.raw) {
raw = chartData.raw.columns;
fieldIndex = _.findIndex(raw, {'categoryName': 'group'});
}
this.fieldFormatter = raw && raw[fieldIndex] ? raw[fieldIndex].field.format.convert : function (d) { return d; };
LineChart.Super.apply(this, arguments);
// Line chart specific attributes
this._attr = _.defaults(handler._attr || {}, {
@ -88,13 +98,13 @@ define(function (require) {
.enter()
.append('circle')
.attr('class', function circleClass(d) {
return self.colorToClass(color(d.label));
return self.colorToClass(color(self.fieldFormatter(d.label)));
})
.attr('fill', function (d) {
return color(d.label);
return color(self.fieldFormatter(d.label));
})
.attr('stroke', function strokeColor(d) {
return color(d.label);
return color(self.fieldFormatter(d.label));
})
.attr('stroke-width', circleStrokeWidth);
@ -149,14 +159,14 @@ define(function (require) {
lines.append('path')
.attr('class', function lineClass(d) {
return self.colorToClass(color(d.label));
return self.colorToClass(color(self.fieldFormatter(d.label)));
})
.attr('d', function lineD(d) {
return line(d.values);
})
.attr('fill', 'none')
.attr('stroke', function lineStroke(d) {
return color(d.label);
return color(self.fieldFormatter(d.label));
})
.attr('stroke-width', 2);

View file

@ -19,6 +19,8 @@ define(function (require) {
}
PieChart.Super.apply(this, arguments);
this.columns = chartData.raw.columns;
this._attr = _.defaults(handler._attr || {}, {
getSize: function (d) { return d.size; },
dispatch: d3.dispatch('brush', 'click', 'hover', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout')
@ -84,6 +86,7 @@ define(function (require) {
var isTooltip = this._attr.addTooltip;
var self = this;
var path;
var fieldFormatter;
path = svg
.datum(slices)
@ -94,12 +97,16 @@ define(function (require) {
.attr('d', arc)
.attr('class', function (d) {
if (d.depth === 0) { return; }
return self.colorToClass(color(d.name));
fieldFormatter = self.columns[d.depth - 1].field.format.convert;
return self.colorToClass(color(fieldFormatter(d.name)));
})
.style('stroke', '#fff')
.style('fill', function (d) {
if (d.depth === 0) { return 'none'; }
return color(d.name);
fieldFormatter = self.columns[d.depth - 1].field.format.convert;
return color(fieldFormatter(d.name));
});
// Add tooltip

View file

@ -224,7 +224,7 @@ define(function (require) {
beforeEach(function () {
inject(function (d3, Private) {
uniqLabels = Private(require('components/vislib/components/labels/uniq_labels'));
uniq = uniqLabels(arrObj);
uniq = uniqLabels(arrObj, function (d) { return d; });
testArr = _.isArray(uniq);
});
});