ManageIQ/manageiq-ui-classic

View on GitHub
app/javascript/oldjs/miq_c3.js

Summary

Maintainability
C
7 hrs
Test Coverage
/* global ManageIQ chartData miqBuildChartMenuEx miqSparkleOff */

window.load_c3_charts = function() {
  for (var set in ManageIQ.charts.chartData) {
    for (var i = 0; i < ManageIQ.charts.chartData[set].length; i++) {
      var chart_id = 'miq_chart_' + set + '_' + i.toString();
      var data = ManageIQ.charts.chartData[set][i];
      if (data != null) {
        load_c3_chart(data.data, chart_id);

        chart_id += '_2';
        if (typeof (data.data2) !== 'undefined') {
          data.data2.miq.flat_chart = true;
          load_c3_chart(data.data2, chart_id, 100);
        }
      }
    }
  }
  miqSparkleOff();
}

window.load_c3_chart = function(data, chart_id, height) {
  if (typeof (data.miqChart) === 'undefined') {
    data.miqChart = 'Line';
  }

  var generate_args = chartData(data.miqChart, data, { bindto: '#' + chart_id, size: {height: height}});

  generate_args.data.onclick = function(data, _i) {
    var index = _.findIndex(generate_args.data.columns, function(col) {
      return col[0] === data.id;
    });
    // when not Pie/Donut chart, first column doesn't contain actual data.
    var seriesIndex = ['Pie', 'Donut'].includes(generate_args.miqChart) ? index : index - 1;
    var pointIndex = ['Pie', 'Donut'].includes(generate_args.miqChart) ? index : data.index;
    var value = data.value;

    var parts = chart_id.split('_'); // miq_chart_candu_2
    var chart_set   = parts[2];
    var chart_index = parts[3];

    miqBuildChartMenuEx(pointIndex, seriesIndex, value, data.name, data.id, chart_set, chart_index);

    // This is to allow the bootstrap pop-up to be manually fired from the chart's click event
    // and have it closed by clicking outside of the pop-up menu.
    setTimeout(function() {
      $(document).on('click.close_popup', function() {
        $('.chart_parent.open').removeClass('open').trigger(
          $.Event('hidden.bs.dropdown'), { relatedTarget: this });

        $('.chart_parent .overlay').hide();

        $(document).off('click.close_popup');
      });
    });

    return false;
  };
  var chart = c3.generate(generate_args);

  ManageIQ.charts.c3[chart_id] = chart;
}


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

  var minMax = getMinMaxFromChart(this);

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

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

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

window.validatePrecision = function(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,
    'function': ManageIQ.charts.formatters[recalculated.format.function].c3(recalculated.format.options),
    'format': recalculated.format,
  };
}

window.recalculatePrecision = function(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};
}

window.getMinMaxFromChart = function(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 === undefined || min === undefined) {
    return false;
  }
  return [min, max];
}

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

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

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

window.validateMinMax = function(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;
  var categoryIndex = Math.ceil(i);
  return i < config.axis_x_categories.length ? config.axis_x_categories[categoryIndex] : i;
};