angular-nvd3 content percentage in tooltip - angularjs

I am looking into ways I can display the percent of a slice of pie compared to the current graph in the tooltip.
First I tried looking for something similar to chart.labelType: 'percent' but it looks like there is no such option.
What I am trying to do now is calculate the percentage inside chart.tooltip.contentGenerator according to documentation the function should be passed 5 arguments function (key, x, y, e, series) -> String however I am only receiving the first argument.
I am using angular 1.5.0, d3 3.5.16, nvd3 1.8.2, and angular-nvd3 1.0.5.
What is the best practice for displaying the percentage in the tooltip?

EDIT: You brought up a great point that I didn't account for, that the total (and thus the percentage portion of each pie segment) will change when you remove segments from the pie. Looked into how to account for this, and I discovered you can monitor the chart for a stateChange, and configure what happens when this event is dispatched.
So, what I've done is to update the total when that event is fired by filtering out whatever values are disabled:
chart: {
...,
dispatch: {
stateChange: function(e) {
total = _.reduce(_.filter($scope.data, function(value) {
return !value.disabled;
}), function(result, value, key) {
return result += parseFloat(value.y);
}, 0);
console.log(total);
}
},...
};
I've updated the example pie chart plunker with the new code, but everything else remained the same, except that I added in each key and the updated total into the tooltip so you can verify that it's working. But you'll still initialize the total value when the chart first loads:
var total = _.reduce($scope.data, function(result, value, key) {
return result += parseFloat(value.y);
}, 0);
...And use the chart.tooltip.contentGenerator method to customize the tooltip message, which you can set up to return something like this:
tooltip: {
contentGenerator: function (key, x, y, e, series) {
return '<h4>' + ((key.data.y / total) * 100).toFixed(2) + '% of total</h4>';
}
}
Hope that helps!

Related

Highcharts conditionally disable marker on hover

New to highcharts - I've got a chart that I have markers disabled on series
plotOptions: {
series: {
marker: {
enabled: false
}
}
},
which is great for the drawing of the lines, but, when I hover over the chart the markers are there. this is good, however, I do not want the marker to be present if the y value on the xAxis is 0 (empty) but I do want them when the y value on the xAxis is greater than one.
I was able to do this before by just setting the y value to null, disabling hover for that series, but the nulls present on this series - drawn as a stacked areaspline graph causes the spline to get drawn improperly (no spline, jagged edges when using the connectNulls: true option in series.
So how do I, and/or can I, conditionally disable a marker on hover based on the y value on an xAxis?
I have been looking at wrapping highcharts prototypes, which I am already doing to control some crosshair behavior drawCrosshair(): https://www.highcharts.com/docs/extending-highcharts/extending-highcharts but I can't seem to find anything that controls the drawing of the markers at that level
A very static approach to this is simply addressing each point with Y-value of 0. Then you could disable the hover-marker for each of these. One such point would look like this (JSFiddle demo):
{
y:0,
marker:{
states:{
hover:{
enabled:false
}
}
}
}
And used in a series:
series: [{
marker: {
enabled: false
},
data: [3, {y:0, marker:{states:{hover:{enabled:false}}}}, 3, 5, 1, 2, 12]
}]
As you can see, it's not pretty, but might help those who need an ad-hoc solution.
A dynamic approach to this is intercepting the setState-function of the Point.
For example, wrapping it and preventing the handling if the y-value is 0:
(function (H) {
H.wrap(H.Point.prototype, 'setState', function (proceed, state, move) {
if(this.y === 0) return;
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
});
}(Highcharts));
See this JSFiddle demonstration of it in action.

ExtJs dynamically set axes maximum value

I would like to dynamically change the axis maximum limit of an ExtJS 4.x chart.
I tried using a listener beforerefresh but this has no effect:
var chart = Ext.create('Ext.chart.Chart', {
...
listeners: {
beforerefresh(me, eOpts)
{
// set y-axes to max(raw_value)
console.log('before refresh');
// set maximum axis value of Y axis to 0.1
me.axes.getAt(1).maximum = 0.1;
}
},
The code is reached, but using me.axes does not seem to have any effect at all.
What is the correct way to do it?
Thanks

ui-grid infinite scroll with row processor filtering

I have an angularjs app using ui.grid with the infinite scrolling module. I am using whole row filtering as described in the documentation like so:
function MyController($scope){
var that = this;
var getData = function(){
//logic left out for brevity
};
var onRegisterApi = function(gridApi){
gridApi.grid.registerRowsProcessor(function (rows) {
return that.filterRowProcessor.apply(that, [rows]);
}, 200);
gridApi.infiniteScroll.on.needLoadMoreData($scope, getData);
};
this.options["onRegisterApi"] = onRegisterApi;
}
//...code excluded for brevity...
MyController.prototype.filterRowProcessor = function(renderableRows){
renderableRows.forEach(function(row) {
if (this.selectedMap[row.entity["Id"]]) {
row.visible = false;
}
});
return renderableRows;
}
The idea is to filter out rows which have an Id belonging to a specific collection; which works as designed. My problem is that when I get my first page of data the filter row processor removes enough rows from visibility that my scroll bar disappears. This in turn causes the infinite scroll api to never raise the "needLoadMoreData" event.
Is this uncharted territory, or is there a way around this? I am also open to not filtering by that mechanism if its easier to do another way.
UPDATE (01/08/2016)
I have found a work around that I don't like very much. Essentially I have a known page size and if the data coming in to the grid is less than that page size and my callback returns false for "end of query", I automatically issue a next page query. I would rather find a solution via the grid api, but for now this will work.
if(this.itemsSource.data.length < constants.PAGE_SIZE && !continuation.endOfQuery){
//call get data again
}
After thinking about it for a while I decided on the below method as my solution. I am still open to suggestions if it makes more sense to do it a different way. Rather than relying on a length of data (which only loosely translates to having a scroll bar) I decided to calculate the height of the total rows visible, compared to the viewport of the grid.
//this method get called from the callback from needsMoreData
//hasMoreData is the same boolean flag sent in to dataLoaded
var shouldRetrieveMore = function (gridApi, hasMoreData){
if (!hasMoreData) {
return false;
}
var totalCountOfRows = gridApi.grid.getVisibleRowCount();
if (totalCountOfRows === 0) {
return true;
}
var height = gridApi.grid.getViewportHeight();
var heightOfRow = gridApi.grid.getVisibleRows()[0].$$height;
return ((heightOfRow * totalCountOfRows) <= height);
}
One additional addendum to the solution could be to sum the $$heights of all the rows, but I decided against it since in my uses they are always the same height.

How to calculate total of one field in the store

I have a grid within a form as in the attached image. When the the customer name is changed, then the grid store is loaded with records corresponding to the customer. I want the balance textfield to be populated with the sum of Amount due column.
The image is here.
Use like this:
store.load({
scope : this,
callback: function(records, operation, success) {
//here the store has been loaded so you can use what functions you like.
//This code sum numbers in certain column
sum = 0;
store.each(function (rec) { sum += rec.get('NameColumn'); });
}
});
Use the store summary function:
var sum = grid.getStore().sum('NameColumn');
sencha api: sum store

ext js 4 column chart bug? series remain visible when I hide them

Feeling I had not enough control over the chart if I had used a grouped column chart, I made my own version by just adding different series to the chart. After all the store, the number of series, their colors and such all need to be set dynamically and not hard coded. So basically this is what I have:
chart = Ext.create("Ext.chart.Chart", {
store: dataStore,
axes: dynamicAxes,
series: series
});
I leave out the not interesting stuff such as width, height of the chart etc.
now I have a method whichs returns a series object. This is added to the series array mentioned in the code above. The function has a "item" object parameter and also an idx param which is the index of the item object from the array it comes from, and a max param which is the size of the item array
the function returns something like this:
var w = (typeof (max) !== "undefined" && max !== null) ? this._getWidthByMax(max) : 30;
return {
type: "column",
axis = "left",
xField = "timestamp",
yField = item.id, // store field name equals the id of the item object
style = { stroke: colorCode, "stroke-width": (item.isDefault) ? 2 : 1, fill: colorCode },
width = w,
renderer = function (sprite, rec, attr, bix) {
var nx = idx * w;
return Ext.apply(attr, { translation: { x: nx} });
}
}
now this works fine for the number of columns I want to have. That can be one, two, three... up to seven currently.
However, if I want to hide a series, the following call doesn't work:
chart.series.getAt(idx).hideAll();
while it does work if I render my chart as a line chart.
is this a bug in Ext-js 4 or is it because of how I rendered the series for my column chart?
since nobody has replied to my question and I have found a solution in the meantime, I might as well answer my own question...
the problem occurred in Ext Js 4.0.7.
With version 4.1 RC 2 the hideAll behaved correctly.
So the solution, for anyone who would have the same problem, is to upgrade to 4.1 RC 2 or newer.

Resources