Skip to content

Commit

Permalink
Merge pull request #40 from PanSpagetka/miq_pr_13289
Browse files Browse the repository at this point in the history
Fix repeating values on Y-axis of C&U charts
(cherry picked from commit 9cb01d3)

https://bugzilla.redhat.com/show_bug.cgi?id=1416093
  • Loading branch information
himdel authored and simaishi committed Jan 24, 2017
1 parent b32eddb commit 8a5f4d5
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 6 deletions.
27 changes: 23 additions & 4 deletions app/assets/javascripts/miq_application.js
Original file line number Diff line number Diff line change
Expand Up @@ -1685,7 +1685,7 @@ function chartData(type, data, data2) {

// small C&U charts have very limited height
if (data.miq.flat_chart) {
var max = _.max(_.flatten(_.tail(data.data.columns).map(_.tail)));
var max = _.max(getChartColumnDataValues(data.data.columns));
data.axis.y.tick.values = [0, max];
}

Expand All @@ -1706,13 +1706,32 @@ function chartData(type, data, data2) {
_.isObject(data.axis.y.tick) &&
_.isObject(data.axis.y.tick.format) &&
data.axis.y.tick.format.function) {

var format = data.axis.y.tick.format;
var max = _.max(getChartColumnDataValues(data.data.columns));
var min = _.min(getChartColumnDataValues(data.data.columns));
var maxShowed = getChartFormatedValue(format, max);
var minShowed = getChartFormatedValue(format, min);
var changeFormat = true;

var tmp = validateMinMax(min, max, minShowed, maxShowed);
changeFormat = !tmp.invalid;
min = tmp.min;

if (changeFormat) {
// if min and max are close, labels should be more precise
var recalculated = recalculatePrecision(minShowed, maxShowed, format, min, max);
format = recalculated.format;
}
data.axis.y.tick.format = ManageIQ.charts.formatters[format.function].c3(format.options);
data.legend.item = {
onclick: recalculateChartYAxisLabels
}

var title_format = _.cloneDeep(format);
title_format.options.precision += 2;
var titleFormat = _.cloneDeep(format);
titleFormat.options.precision += 1;
data.tooltip.format.value = function (value, _ratio, _id) {
var format = ManageIQ.charts.formatters[title_format.function].c3(title_format.options);
var format = ManageIQ.charts.formatters[titleFormat.function].c3(titleFormat.options);
return format(value);
}
}
Expand Down
117 changes: 117 additions & 0 deletions app/assets/javascripts/miq_c3.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,123 @@ function load_c3_chart(data, chart_id, height) {
ManageIQ.charts.c3[chart_id] = chart;
};


function recalculateChartYAxisLabels (id) {
// hide/show chart with id
this.api.toggle(id);

var minMax = getMinMaxFromChart(this);

if (minMax) {
var columnsData = validateMinMax(minMax[0], minMax[1], minShowed, maxShowed);
if (columnsData.invalid) {
return;
}
minMax[0] = columnsData.min;
} else {
return;
}

var format = ManageIQ.charts.chartData.candu[this.config.bindto.split('_').pop()].xml.miq.format;
var tmpMin = getChartFormatedValueWithFormat(format, minMax[0]);
var tmpMax = getChartFormatedValueWithFormat(format, minMax[1]);
var minShowed = tmpMin[0];
var maxShowed = tmpMax[0];
var min_units = tmpMin[1];
var max_units = tmpMax[1];
if (min_units !== max_units) {
return;
}

var o = validatePrecision(minShowed, maxShowed, format, minMax[0], minMax[1]);
if (o.changed) {
this.config.axis_y_tick_format = o.format;
this.api.flush();
}
}

function validatePrecision(minShowed, maxShowed, format, min, max) {
if (min === max) {
return {'changed' : false, 'format' : ManageIQ.charts.formatters[format.function].c3(format.options)}
}
var recalculated = recalculatePrecision(minShowed, maxShowed, format, min, max);
return {
'changed' : recalculated.changed,
'format' : ManageIQ.charts.formatters[recalculated.format.function].c3(recalculated.format.options)
}
}

function recalculatePrecision(minShowed, maxShowed, format, min, max) {
var changed = false;
if (maxShowed - minShowed <= Math.pow(10, 1 - format.options.precision)) {
// if min and max are close, labels should be more precise
changed = true;
while (((maxShowed - minShowed ) * Math.pow(10, format.options.precision)) < 9.9) {
format.options.precision += 1;
minShowed = getChartFormatedValue(format, min);
maxShowed = getChartFormatedValue(format, max);
}
} else if ((maxShowed - minShowed) >= Math.pow(10, 2 - format.options.precision)) {
changed = true;
// if min and max are not, labels should be less precise
while (((maxShowed - minShowed ) * Math.pow(10, format.options.precision)) > 99) {
if (format.options.precision < 1) {
break;
}
format.options.precision -= 1;
minShowed = getChartFormatedValue(format, min);
maxShowed = getChartFormatedValue(format, max);
}
}
return {'changed' : changed, 'format' : format};
}

function getMinMaxFromChart(chart) {
var data = [];
_.forEach(chart.api.data.shown(), function(o) {
_.forEach(o.values, function(elem) {
data.push(elem.value);
});
});

var max = _.max(_.filter(data, function(o) { return o !== null; }));
var min = _.min(_.filter(data, function(o) { return o !== null; }));
if (max === -Infinity || min === Infinity) {
return false;
}
return [min, max];
}

function getChartColumnDataValues(columns) {
return _.filter(_.flatten(_.tail(columns).map(_.tail)), function(o) { return o !== null; })
}

function getChartFormatedValue(format, value) {
return numeral(ManageIQ.charts.formatters[format.function].c3(format.options)(value).split(/[^0-9\,\.]/)[0]).value();
}

function getChartFormatedValueWithFormat(format, value) {
var tmp = /^([0-9\,\.]+)(.*)/.exec(ManageIQ.charts.formatters[format.function].c3(format.options)(value));
return [numeral(tmp[1]).value(), tmp[2]];
}

function validateMinMax(min, max, minShowed, maxShowed) {
var invalid = false;
// if there are no valid values or there is only single values big enough, then not change formating function
if (max <= min || maxShowed <= minShowed) {
if (max < min || max > 10) {
invalid = true;
} else if (max > 0){
min = 0;
} else if (min === 0 && max === 0){
invalid = true;
}
}

return {'invalid' : invalid, 'min' : min };
}


c3.chart.internal.fn.categoryName = function (i) {
var config = this.config, categoryIndex = Math.ceil(i);
return i < config.axis_x_categories.length ? config.axis_x_categories[categoryIndex] : i;
Expand Down
6 changes: 4 additions & 2 deletions lib/report_formatter/c3.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ def build_document_header
:data => {:columns => [], :names => {}},
:axis => {:x => {:tick => {}}, :y => {:tick => {}}},
:tooltip => {:format => {}},
:miq => {:name_table => {}, :category_table => {}}
:miq => {:name_table => {}, :category_table => {}},
:legend => {}
}

if chart_is_2d?
Expand Down Expand Up @@ -94,6 +95,7 @@ def build_document_header

axis_formatter = {:function => format, :options => options}
mri.chart[:axis][:y] = {:tick => {:format => axis_formatter}}
mri.chart[:miq][:format] = axis_formatter
end
end

Expand Down Expand Up @@ -141,7 +143,7 @@ def change_structure_to_timeseries
# set x axis type to timeseries and remove categories
mri.chart[:axis][:x] = {:type => 'timeseries', :tick => {}}
# set flag for performance chart
mri.chart[:miq] = {:performance_chart => true}
mri.chart[:miq][:performance_chart] = true
# this conditions are taken from build_performance_chart_area method from chart_commons.rb
if mri.db.include?("Daily") || (mri.where_clause && mri.where_clause.include?("daily"))
# set format for parsing
Expand Down

0 comments on commit 8a5f4d5

Please sign in to comment.