universal y intervals, min limit in case of line chart
This commit is contained in:
parent
ebfd6bd8dc
commit
3de049c451
319
dist/frappe-charts.min.cjs.js
vendored
319
dist/frappe-charts.min.cjs.js
vendored
@ -671,9 +671,176 @@ function runSVGAnimation(svg_container, elements) {
|
||||
return anim_svg;
|
||||
}
|
||||
|
||||
// export function calc_intervals() {
|
||||
// //
|
||||
// }
|
||||
function normalize(x) {
|
||||
// Calculates mantissa and exponent of a number
|
||||
// Returns normalized number and exponent
|
||||
// https://stackoverflow.com/q/9383593/6495043
|
||||
|
||||
if (x === 0) {
|
||||
return [0, 0];
|
||||
}
|
||||
if (isNaN(x)) {
|
||||
return { mantissa: -6755399441055744, exponent: 972 };
|
||||
}
|
||||
var sig = x > 0 ? 1 : -1;
|
||||
if (!isFinite(x)) {
|
||||
return { mantissa: sig * 4503599627370496, exponent: 972 };
|
||||
}
|
||||
|
||||
x = Math.abs(x);
|
||||
var exp = Math.floor(Math.log10(x));
|
||||
var man = x / Math.pow(10, exp);
|
||||
|
||||
return [sig * man, exp];
|
||||
}
|
||||
|
||||
// function get_commafied_or_powered_number(number) {}
|
||||
|
||||
function get_actual_pretty_num(number, exponent) {
|
||||
return number;
|
||||
}
|
||||
|
||||
function get_range_intervals(max) {
|
||||
var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
|
||||
var upper_bound = Math.ceil(max);
|
||||
var lower_bound = Math.floor(min);
|
||||
var range = upper_bound - lower_bound;
|
||||
|
||||
var no_of_parts = range;
|
||||
var part_size = 1;
|
||||
|
||||
if (range > 5) {
|
||||
if (range % 2 !== 0) {
|
||||
upper_bound++;
|
||||
// Recalc range
|
||||
range = upper_bound - lower_bound;
|
||||
}
|
||||
no_of_parts = range / 2;
|
||||
part_size = 2;
|
||||
}
|
||||
|
||||
if (range <= 2) {
|
||||
no_of_parts = 4;
|
||||
part_size = range / no_of_parts;
|
||||
}
|
||||
|
||||
var intervals = [];
|
||||
for (var i = 0; i <= no_of_parts; i++) {
|
||||
intervals.push(lower_bound + part_size * i);
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function get_intervals(max_value) {
|
||||
var min_value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
|
||||
var _normalize = normalize(max_value),
|
||||
_normalize2 = slicedToArray(_normalize, 2),
|
||||
normal_max_value = _normalize2[0],
|
||||
exponent = _normalize2[1];
|
||||
|
||||
var normal_min_value = min_value ? min_value / Math.pow(10, exponent) : 0;
|
||||
|
||||
// Allow only 7 significant digits
|
||||
normal_max_value = normal_max_value.toFixed(6);
|
||||
|
||||
var intervals = get_range_intervals(normal_max_value, normal_min_value);
|
||||
intervals = intervals.map(function (value) {
|
||||
return value * Math.pow(10, exponent);
|
||||
});
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function calc_intervals(values) {
|
||||
var with_minimum = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
|
||||
//*** Where the magic happens ***
|
||||
|
||||
// Calculates best-fit y intervals from given values
|
||||
// and returns the interval array
|
||||
|
||||
var max_value = Math.max.apply(Math, toConsumableArray(values));
|
||||
var min_value = Math.min.apply(Math, toConsumableArray(values));
|
||||
|
||||
var exponent = 0,
|
||||
intervals = [];
|
||||
|
||||
// CASE I: Both non-negative
|
||||
|
||||
if (max_value >= 0 && min_value >= 0) {
|
||||
exponent = normalize(max_value)[1];
|
||||
if (!with_minimum) {
|
||||
intervals = get_intervals(max_value);
|
||||
} else {
|
||||
intervals = get_intervals(max_value, min_value);
|
||||
}
|
||||
}
|
||||
|
||||
// CASE II: Only min_value negative
|
||||
|
||||
if (max_value > 0 && min_value < 0) {
|
||||
// `with_minimum` irrelevant in this case,
|
||||
// We'll be handling both sides of zero separately
|
||||
// (both starting from zero)
|
||||
// Because ceil() and floor() behave differently
|
||||
// in those two regions
|
||||
|
||||
var get_positive_first_intervals = function get_positive_first_intervals(max_value, abs_min_value) {
|
||||
var intervals = get_intervals(max_value);
|
||||
|
||||
var interval_size = intervals[1] - intervals[0];
|
||||
|
||||
// Then unshift the negative values
|
||||
var value = 0;
|
||||
for (var i = 1; value < abs_min_value; i++) {
|
||||
value += interval_size;
|
||||
intervals.unshift(-1 * value);
|
||||
}
|
||||
return intervals;
|
||||
};
|
||||
|
||||
var abs_min_value = Math.abs(min_value);
|
||||
|
||||
if (max_value >= abs_min_value) {
|
||||
exponent = normalize(max_value)[1];
|
||||
intervals = get_positive_first_intervals(max_value, abs_min_value);
|
||||
} else {
|
||||
// Mirror: max_value => abs_min_value, then change sign
|
||||
exponent = normalize(abs_min_value)[1];
|
||||
var pos_intervals = get_positive_first_intervals(abs_min_value, max_value);
|
||||
intervals = pos_intervals.map(function (d) {
|
||||
return d * -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// CASE III: Both non-positive
|
||||
|
||||
if (max_value <= 0 && min_value <= 0) {
|
||||
// Mirrored Case I:
|
||||
// Work with positives, then reverse the sign and array
|
||||
|
||||
var pseudo_max_value = Math.abs(min_value);
|
||||
var pseudo_min_value = Math.abs(max_value);
|
||||
|
||||
exponent = normalize(pseudo_max_value)[1];
|
||||
if (!with_minimum) {
|
||||
intervals = get_intervals(pseudo_max_value);
|
||||
} else {
|
||||
intervals = get_intervals(pseudo_max_value, pseudo_min_value);
|
||||
}
|
||||
|
||||
intervals = intervals.reverse().map(function (d) {
|
||||
return d * -1;
|
||||
});
|
||||
}
|
||||
|
||||
intervals = intervals.map(function (value) {
|
||||
return get_actual_pretty_num(value, exponent);
|
||||
});
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function calc_distribution(values, distribution_size) {
|
||||
// Assume non-negative values,
|
||||
@ -698,137 +865,6 @@ function get_max_checkpoint(value, distribution) {
|
||||
}).length;
|
||||
}
|
||||
|
||||
function calc_y_intervals(array) {
|
||||
//*** Where the magic happens ***
|
||||
|
||||
// Calculates best-fit y intervals from given values
|
||||
// and returns the interval array
|
||||
|
||||
// TODO: Fractions
|
||||
|
||||
var max_bound = void 0,
|
||||
min_bound = void 0,
|
||||
pos_no_of_parts = void 0,
|
||||
neg_no_of_parts = void 0,
|
||||
part_size = void 0; // eslint-disable-line no-unused-vars
|
||||
|
||||
// Critical values
|
||||
var max_val = parseInt(Math.max.apply(Math, toConsumableArray(array)));
|
||||
var min_val = parseInt(Math.min.apply(Math, toConsumableArray(array)));
|
||||
if (min_val >= 0) {
|
||||
min_val = 0;
|
||||
}
|
||||
|
||||
var get_params = function get_params(value1, value2) {
|
||||
var bound1 = void 0,
|
||||
bound2 = void 0,
|
||||
no_of_parts_1 = void 0,
|
||||
no_of_parts_2 = void 0,
|
||||
interval_size = void 0;
|
||||
if ((value1 + "").length <= 1) {
|
||||
bound1 = 10;
|
||||
no_of_parts_1 = 5;
|
||||
} else {
|
||||
var _calc_upper_bound_and = calc_upper_bound_and_no_of_parts(value1);
|
||||
|
||||
var _calc_upper_bound_and2 = slicedToArray(_calc_upper_bound_and, 2);
|
||||
|
||||
bound1 = _calc_upper_bound_and2[0];
|
||||
no_of_parts_1 = _calc_upper_bound_and2[1];
|
||||
}
|
||||
|
||||
interval_size = bound1 / no_of_parts_1;
|
||||
no_of_parts_2 = calc_no_of_parts(value2, interval_size);
|
||||
bound2 = no_of_parts_2 * interval_size;
|
||||
|
||||
return [bound1, bound2, no_of_parts_1, no_of_parts_2, interval_size];
|
||||
};
|
||||
|
||||
var abs_min_val = min_val * -1;
|
||||
if (abs_min_val <= max_val) {
|
||||
var _get_params = get_params(max_val, abs_min_val);
|
||||
// Get the positive region intervals
|
||||
// then calc negative ones accordingly
|
||||
|
||||
|
||||
var _get_params2 = slicedToArray(_get_params, 5);
|
||||
|
||||
min_bound = _get_params2[1];
|
||||
pos_no_of_parts = _get_params2[2];
|
||||
neg_no_of_parts = _get_params2[3];
|
||||
part_size = _get_params2[4];
|
||||
|
||||
if (abs_min_val === 0) {
|
||||
min_bound = 0;neg_no_of_parts = 0;
|
||||
}
|
||||
} else {
|
||||
var _get_params3 = get_params(abs_min_val, max_val);
|
||||
// Get the negative region here first
|
||||
|
||||
|
||||
var _get_params4 = slicedToArray(_get_params3, 5);
|
||||
|
||||
min_bound = _get_params4[0];
|
||||
neg_no_of_parts = _get_params4[2];
|
||||
pos_no_of_parts = _get_params4[3];
|
||||
part_size = _get_params4[4];
|
||||
}
|
||||
|
||||
// Make both region parts even
|
||||
if (pos_no_of_parts % 2 !== 0 && neg_no_of_parts > 0) pos_no_of_parts++;
|
||||
if (neg_no_of_parts % 2 !== 0) {
|
||||
// every increase in no_of_parts entails an increase in corresponding bound
|
||||
// except here, it happens implicitly after every calc_no_of_parts() call
|
||||
neg_no_of_parts++;
|
||||
min_bound += part_size;
|
||||
}
|
||||
|
||||
var no_of_parts = pos_no_of_parts + neg_no_of_parts;
|
||||
if (no_of_parts > 5) {
|
||||
no_of_parts /= 2;
|
||||
part_size *= 2;
|
||||
|
||||
pos_no_of_parts /= 2;
|
||||
}
|
||||
|
||||
if (max_val < (pos_no_of_parts - 1) * part_size) {
|
||||
no_of_parts--;
|
||||
}
|
||||
|
||||
return get_intervals(-1 * min_bound, part_size, no_of_parts);
|
||||
}
|
||||
|
||||
function get_intervals(start, interval_size, count) {
|
||||
var intervals = [];
|
||||
for (var i = 0; i <= count; i++) {
|
||||
intervals.push(start);
|
||||
start += interval_size;
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function calc_upper_bound_and_no_of_parts(max_val) {
|
||||
// Given a positive value, calculates a nice-number upper bound
|
||||
// and a consequent optimal number of parts
|
||||
|
||||
var part_size = Math.pow(10, (max_val + "").length - 1);
|
||||
var no_of_parts = calc_no_of_parts(max_val, part_size);
|
||||
|
||||
// Use it to get a nice even upper bound
|
||||
var upper_bound = part_size * no_of_parts;
|
||||
|
||||
return [upper_bound, no_of_parts];
|
||||
}
|
||||
|
||||
function calc_no_of_parts(value, divisor) {
|
||||
// value should be a positive number, divisor should be greater than 0
|
||||
// returns an even no of parts
|
||||
var no_of_parts = Math.ceil(value / divisor);
|
||||
if (no_of_parts % 2 !== 0) no_of_parts++; // Make it an even number
|
||||
|
||||
return no_of_parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a number upto 2 decimal places.
|
||||
* @param {Number} d Any number
|
||||
@ -1385,7 +1421,7 @@ var AxisChart = function (_BaseChart) {
|
||||
values = values.concat(this.y_sums);
|
||||
}
|
||||
|
||||
this.y_axis_values = calc_y_intervals(values);
|
||||
this.y_axis_values = calc_intervals(values, this.type === 'line');
|
||||
|
||||
if (!this.y_old_axis_values) {
|
||||
this.y_old_axis_values = this.y_axis_values.slice();
|
||||
@ -1398,10 +1434,21 @@ var AxisChart = function (_BaseChart) {
|
||||
this.multiplier = this.height / value_range;
|
||||
if (!this.old_multiplier) this.old_multiplier = this.multiplier;
|
||||
|
||||
var zero_index = y_pts.indexOf(0);
|
||||
var interval = y_pts[1] - y_pts[0];
|
||||
var interval_height = interval * this.multiplier;
|
||||
|
||||
var zero_index = void 0;
|
||||
|
||||
if (y_pts.indexOf(0) >= 0) {
|
||||
zero_index = y_pts.indexOf(0);
|
||||
} else if (y_pts[0] > 0) {
|
||||
var min = y_pts[0];
|
||||
zero_index = -1 * min / interval;
|
||||
} else {
|
||||
var max = y_pts[y_pts.length - 1];
|
||||
zero_index = -1 * max / interval + (y_pts.length - 1);
|
||||
}
|
||||
|
||||
if (this.zero_line) this.old_zero_line = this.zero_line;
|
||||
this.zero_line = this.height - zero_index * interval_height;
|
||||
if (!this.old_zero_line) this.old_zero_line = this.zero_line;
|
||||
|
||||
319
dist/frappe-charts.min.esm.js
vendored
319
dist/frappe-charts.min.esm.js
vendored
@ -669,9 +669,176 @@ function runSVGAnimation(svg_container, elements) {
|
||||
return anim_svg;
|
||||
}
|
||||
|
||||
// export function calc_intervals() {
|
||||
// //
|
||||
// }
|
||||
function normalize(x) {
|
||||
// Calculates mantissa and exponent of a number
|
||||
// Returns normalized number and exponent
|
||||
// https://stackoverflow.com/q/9383593/6495043
|
||||
|
||||
if (x === 0) {
|
||||
return [0, 0];
|
||||
}
|
||||
if (isNaN(x)) {
|
||||
return { mantissa: -6755399441055744, exponent: 972 };
|
||||
}
|
||||
var sig = x > 0 ? 1 : -1;
|
||||
if (!isFinite(x)) {
|
||||
return { mantissa: sig * 4503599627370496, exponent: 972 };
|
||||
}
|
||||
|
||||
x = Math.abs(x);
|
||||
var exp = Math.floor(Math.log10(x));
|
||||
var man = x / Math.pow(10, exp);
|
||||
|
||||
return [sig * man, exp];
|
||||
}
|
||||
|
||||
// function get_commafied_or_powered_number(number) {}
|
||||
|
||||
function get_actual_pretty_num(number, exponent) {
|
||||
return number;
|
||||
}
|
||||
|
||||
function get_range_intervals(max) {
|
||||
var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
|
||||
var upper_bound = Math.ceil(max);
|
||||
var lower_bound = Math.floor(min);
|
||||
var range = upper_bound - lower_bound;
|
||||
|
||||
var no_of_parts = range;
|
||||
var part_size = 1;
|
||||
|
||||
if (range > 5) {
|
||||
if (range % 2 !== 0) {
|
||||
upper_bound++;
|
||||
// Recalc range
|
||||
range = upper_bound - lower_bound;
|
||||
}
|
||||
no_of_parts = range / 2;
|
||||
part_size = 2;
|
||||
}
|
||||
|
||||
if (range <= 2) {
|
||||
no_of_parts = 4;
|
||||
part_size = range / no_of_parts;
|
||||
}
|
||||
|
||||
var intervals = [];
|
||||
for (var i = 0; i <= no_of_parts; i++) {
|
||||
intervals.push(lower_bound + part_size * i);
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function get_intervals(max_value) {
|
||||
var min_value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
|
||||
var _normalize = normalize(max_value),
|
||||
_normalize2 = slicedToArray(_normalize, 2),
|
||||
normal_max_value = _normalize2[0],
|
||||
exponent = _normalize2[1];
|
||||
|
||||
var normal_min_value = min_value ? min_value / Math.pow(10, exponent) : 0;
|
||||
|
||||
// Allow only 7 significant digits
|
||||
normal_max_value = normal_max_value.toFixed(6);
|
||||
|
||||
var intervals = get_range_intervals(normal_max_value, normal_min_value);
|
||||
intervals = intervals.map(function (value) {
|
||||
return value * Math.pow(10, exponent);
|
||||
});
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function calc_intervals(values) {
|
||||
var with_minimum = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
|
||||
//*** Where the magic happens ***
|
||||
|
||||
// Calculates best-fit y intervals from given values
|
||||
// and returns the interval array
|
||||
|
||||
var max_value = Math.max.apply(Math, toConsumableArray(values));
|
||||
var min_value = Math.min.apply(Math, toConsumableArray(values));
|
||||
|
||||
var exponent = 0,
|
||||
intervals = [];
|
||||
|
||||
// CASE I: Both non-negative
|
||||
|
||||
if (max_value >= 0 && min_value >= 0) {
|
||||
exponent = normalize(max_value)[1];
|
||||
if (!with_minimum) {
|
||||
intervals = get_intervals(max_value);
|
||||
} else {
|
||||
intervals = get_intervals(max_value, min_value);
|
||||
}
|
||||
}
|
||||
|
||||
// CASE II: Only min_value negative
|
||||
|
||||
if (max_value > 0 && min_value < 0) {
|
||||
// `with_minimum` irrelevant in this case,
|
||||
// We'll be handling both sides of zero separately
|
||||
// (both starting from zero)
|
||||
// Because ceil() and floor() behave differently
|
||||
// in those two regions
|
||||
|
||||
var get_positive_first_intervals = function get_positive_first_intervals(max_value, abs_min_value) {
|
||||
var intervals = get_intervals(max_value);
|
||||
|
||||
var interval_size = intervals[1] - intervals[0];
|
||||
|
||||
// Then unshift the negative values
|
||||
var value = 0;
|
||||
for (var i = 1; value < abs_min_value; i++) {
|
||||
value += interval_size;
|
||||
intervals.unshift(-1 * value);
|
||||
}
|
||||
return intervals;
|
||||
};
|
||||
|
||||
var abs_min_value = Math.abs(min_value);
|
||||
|
||||
if (max_value >= abs_min_value) {
|
||||
exponent = normalize(max_value)[1];
|
||||
intervals = get_positive_first_intervals(max_value, abs_min_value);
|
||||
} else {
|
||||
// Mirror: max_value => abs_min_value, then change sign
|
||||
exponent = normalize(abs_min_value)[1];
|
||||
var pos_intervals = get_positive_first_intervals(abs_min_value, max_value);
|
||||
intervals = pos_intervals.map(function (d) {
|
||||
return d * -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// CASE III: Both non-positive
|
||||
|
||||
if (max_value <= 0 && min_value <= 0) {
|
||||
// Mirrored Case I:
|
||||
// Work with positives, then reverse the sign and array
|
||||
|
||||
var pseudo_max_value = Math.abs(min_value);
|
||||
var pseudo_min_value = Math.abs(max_value);
|
||||
|
||||
exponent = normalize(pseudo_max_value)[1];
|
||||
if (!with_minimum) {
|
||||
intervals = get_intervals(pseudo_max_value);
|
||||
} else {
|
||||
intervals = get_intervals(pseudo_max_value, pseudo_min_value);
|
||||
}
|
||||
|
||||
intervals = intervals.reverse().map(function (d) {
|
||||
return d * -1;
|
||||
});
|
||||
}
|
||||
|
||||
intervals = intervals.map(function (value) {
|
||||
return get_actual_pretty_num(value, exponent);
|
||||
});
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function calc_distribution(values, distribution_size) {
|
||||
// Assume non-negative values,
|
||||
@ -696,137 +863,6 @@ function get_max_checkpoint(value, distribution) {
|
||||
}).length;
|
||||
}
|
||||
|
||||
function calc_y_intervals(array) {
|
||||
//*** Where the magic happens ***
|
||||
|
||||
// Calculates best-fit y intervals from given values
|
||||
// and returns the interval array
|
||||
|
||||
// TODO: Fractions
|
||||
|
||||
var max_bound = void 0,
|
||||
min_bound = void 0,
|
||||
pos_no_of_parts = void 0,
|
||||
neg_no_of_parts = void 0,
|
||||
part_size = void 0; // eslint-disable-line no-unused-vars
|
||||
|
||||
// Critical values
|
||||
var max_val = parseInt(Math.max.apply(Math, toConsumableArray(array)));
|
||||
var min_val = parseInt(Math.min.apply(Math, toConsumableArray(array)));
|
||||
if (min_val >= 0) {
|
||||
min_val = 0;
|
||||
}
|
||||
|
||||
var get_params = function get_params(value1, value2) {
|
||||
var bound1 = void 0,
|
||||
bound2 = void 0,
|
||||
no_of_parts_1 = void 0,
|
||||
no_of_parts_2 = void 0,
|
||||
interval_size = void 0;
|
||||
if ((value1 + "").length <= 1) {
|
||||
bound1 = 10;
|
||||
no_of_parts_1 = 5;
|
||||
} else {
|
||||
var _calc_upper_bound_and = calc_upper_bound_and_no_of_parts(value1);
|
||||
|
||||
var _calc_upper_bound_and2 = slicedToArray(_calc_upper_bound_and, 2);
|
||||
|
||||
bound1 = _calc_upper_bound_and2[0];
|
||||
no_of_parts_1 = _calc_upper_bound_and2[1];
|
||||
}
|
||||
|
||||
interval_size = bound1 / no_of_parts_1;
|
||||
no_of_parts_2 = calc_no_of_parts(value2, interval_size);
|
||||
bound2 = no_of_parts_2 * interval_size;
|
||||
|
||||
return [bound1, bound2, no_of_parts_1, no_of_parts_2, interval_size];
|
||||
};
|
||||
|
||||
var abs_min_val = min_val * -1;
|
||||
if (abs_min_val <= max_val) {
|
||||
var _get_params = get_params(max_val, abs_min_val);
|
||||
// Get the positive region intervals
|
||||
// then calc negative ones accordingly
|
||||
|
||||
|
||||
var _get_params2 = slicedToArray(_get_params, 5);
|
||||
|
||||
min_bound = _get_params2[1];
|
||||
pos_no_of_parts = _get_params2[2];
|
||||
neg_no_of_parts = _get_params2[3];
|
||||
part_size = _get_params2[4];
|
||||
|
||||
if (abs_min_val === 0) {
|
||||
min_bound = 0;neg_no_of_parts = 0;
|
||||
}
|
||||
} else {
|
||||
var _get_params3 = get_params(abs_min_val, max_val);
|
||||
// Get the negative region here first
|
||||
|
||||
|
||||
var _get_params4 = slicedToArray(_get_params3, 5);
|
||||
|
||||
min_bound = _get_params4[0];
|
||||
neg_no_of_parts = _get_params4[2];
|
||||
pos_no_of_parts = _get_params4[3];
|
||||
part_size = _get_params4[4];
|
||||
}
|
||||
|
||||
// Make both region parts even
|
||||
if (pos_no_of_parts % 2 !== 0 && neg_no_of_parts > 0) pos_no_of_parts++;
|
||||
if (neg_no_of_parts % 2 !== 0) {
|
||||
// every increase in no_of_parts entails an increase in corresponding bound
|
||||
// except here, it happens implicitly after every calc_no_of_parts() call
|
||||
neg_no_of_parts++;
|
||||
min_bound += part_size;
|
||||
}
|
||||
|
||||
var no_of_parts = pos_no_of_parts + neg_no_of_parts;
|
||||
if (no_of_parts > 5) {
|
||||
no_of_parts /= 2;
|
||||
part_size *= 2;
|
||||
|
||||
pos_no_of_parts /= 2;
|
||||
}
|
||||
|
||||
if (max_val < (pos_no_of_parts - 1) * part_size) {
|
||||
no_of_parts--;
|
||||
}
|
||||
|
||||
return get_intervals(-1 * min_bound, part_size, no_of_parts);
|
||||
}
|
||||
|
||||
function get_intervals(start, interval_size, count) {
|
||||
var intervals = [];
|
||||
for (var i = 0; i <= count; i++) {
|
||||
intervals.push(start);
|
||||
start += interval_size;
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function calc_upper_bound_and_no_of_parts(max_val) {
|
||||
// Given a positive value, calculates a nice-number upper bound
|
||||
// and a consequent optimal number of parts
|
||||
|
||||
var part_size = Math.pow(10, (max_val + "").length - 1);
|
||||
var no_of_parts = calc_no_of_parts(max_val, part_size);
|
||||
|
||||
// Use it to get a nice even upper bound
|
||||
var upper_bound = part_size * no_of_parts;
|
||||
|
||||
return [upper_bound, no_of_parts];
|
||||
}
|
||||
|
||||
function calc_no_of_parts(value, divisor) {
|
||||
// value should be a positive number, divisor should be greater than 0
|
||||
// returns an even no of parts
|
||||
var no_of_parts = Math.ceil(value / divisor);
|
||||
if (no_of_parts % 2 !== 0) no_of_parts++; // Make it an even number
|
||||
|
||||
return no_of_parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a number upto 2 decimal places.
|
||||
* @param {Number} d Any number
|
||||
@ -1383,7 +1419,7 @@ var AxisChart = function (_BaseChart) {
|
||||
values = values.concat(this.y_sums);
|
||||
}
|
||||
|
||||
this.y_axis_values = calc_y_intervals(values);
|
||||
this.y_axis_values = calc_intervals(values, this.type === 'line');
|
||||
|
||||
if (!this.y_old_axis_values) {
|
||||
this.y_old_axis_values = this.y_axis_values.slice();
|
||||
@ -1396,10 +1432,21 @@ var AxisChart = function (_BaseChart) {
|
||||
this.multiplier = this.height / value_range;
|
||||
if (!this.old_multiplier) this.old_multiplier = this.multiplier;
|
||||
|
||||
var zero_index = y_pts.indexOf(0);
|
||||
var interval = y_pts[1] - y_pts[0];
|
||||
var interval_height = interval * this.multiplier;
|
||||
|
||||
var zero_index = void 0;
|
||||
|
||||
if (y_pts.indexOf(0) >= 0) {
|
||||
zero_index = y_pts.indexOf(0);
|
||||
} else if (y_pts[0] > 0) {
|
||||
var min = y_pts[0];
|
||||
zero_index = -1 * min / interval;
|
||||
} else {
|
||||
var max = y_pts[y_pts.length - 1];
|
||||
zero_index = -1 * max / interval + (y_pts.length - 1);
|
||||
}
|
||||
|
||||
if (this.zero_line) this.old_zero_line = this.zero_line;
|
||||
this.zero_line = this.height - zero_index * interval_height;
|
||||
if (!this.old_zero_line) this.old_zero_line = this.zero_line;
|
||||
|
||||
2
dist/frappe-charts.min.iife.js
vendored
2
dist/frappe-charts.min.iife.js
vendored
File diff suppressed because one or more lines are too long
2
docs/assets/js/frappe-charts.min.js
vendored
2
docs/assets/js/frappe-charts.min.js
vendored
File diff suppressed because one or more lines are too long
@ -20,6 +20,8 @@ let line_composite_data = {
|
||||
datasets: [{
|
||||
"color": "green",
|
||||
"values": [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 0, 0],
|
||||
// "values": [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 40, 40],
|
||||
// "values": [-36, -46, -45, -32, -27, -31, -30, -36, -39, -49, -40, -40],
|
||||
// "formatted": ["₹ 0.00", "₹ 0.00", "₹ 0.00", "₹ 61,500.00", "₹ 82,936.88", "₹ 24,010.00", "₹ 0.00", "₹ 0.00", "₹ 25,840.00", "₹ 5,08,048.82", "₹ 1,16,820.00", "₹ 0.00"],
|
||||
}]
|
||||
};
|
||||
@ -36,6 +38,8 @@ let more_line_data = {
|
||||
8: {values: [36, 24, 38, 27, 15, 22, 24, 38, 32, 57, 139, 26]},
|
||||
9: {values: [37, 36, 32, 33, 12, 34, 52, 45, 58, 57, 64, 35]},
|
||||
10: {values: [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 0, 0]}
|
||||
// 10: {values: [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 40, 40]}
|
||||
// 10: {values: [-36, -46, -45, -32, -27, -31, -30, -36, -39, -49, -40, -40]}
|
||||
};
|
||||
|
||||
let c1 = document.querySelector("#chart-composite-1");
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import $ from '../utils/dom';
|
||||
import { UnitRenderer, make_x_line, make_y_line } from '../utils/draw';
|
||||
import { runSVGAnimation } from '../utils/animate';
|
||||
import { calc_y_intervals } from '../utils/intervals';
|
||||
import { calc_intervals } from '../utils/intervals';
|
||||
import { float_2, arrays_equal, get_string_width } from '../utils/helpers';
|
||||
import BaseChart from './BaseChart';
|
||||
|
||||
@ -56,7 +56,7 @@ export default class AxisChart extends BaseChart {
|
||||
values = values.concat(this.y_sums);
|
||||
}
|
||||
|
||||
this.y_axis_values = calc_y_intervals(values);
|
||||
this.y_axis_values = calc_intervals(values, this.type === 'line');
|
||||
|
||||
if(!this.y_old_axis_values) {
|
||||
this.y_old_axis_values = this.y_axis_values.slice();
|
||||
@ -69,10 +69,21 @@ export default class AxisChart extends BaseChart {
|
||||
this.multiplier = this.height / value_range;
|
||||
if(!this.old_multiplier) this.old_multiplier = this.multiplier;
|
||||
|
||||
const zero_index = y_pts.indexOf(0);
|
||||
const interval = y_pts[1] - y_pts[0];
|
||||
const interval_height = interval * this.multiplier;
|
||||
|
||||
let zero_index;
|
||||
|
||||
if(y_pts.indexOf(0) >= 0) {
|
||||
zero_index = y_pts.indexOf(0);
|
||||
} else if(y_pts[0] > 0) {
|
||||
let min = y_pts[0];
|
||||
zero_index = (-1) * min / interval;
|
||||
} else {
|
||||
let max = y_pts[y_pts.length - 1];
|
||||
zero_index = (-1) * max / interval + (y_pts.length - 1);
|
||||
}
|
||||
|
||||
if(this.zero_line) this.old_zero_line = this.zero_line;
|
||||
this.zero_line = this.height - (zero_index * interval_height);
|
||||
if(!this.old_zero_line) this.old_zero_line = this.zero_line;
|
||||
|
||||
@ -1,36 +1,155 @@
|
||||
export function divide_if_more_than_five(number) {
|
||||
return (number < 5) ? number : number / 2;
|
||||
function normalize(x) {
|
||||
// Calculates mantissa and exponent of a number
|
||||
// Returns normalized number and exponent
|
||||
// https://stackoverflow.com/q/9383593/6495043
|
||||
|
||||
if(x===0) {
|
||||
return [0, 0];
|
||||
}
|
||||
if(isNaN(x)) {
|
||||
return {mantissa: -6755399441055744, exponent: 972};
|
||||
}
|
||||
var sig = x > 0 ? 1 : -1;
|
||||
if(!isFinite(x)) {
|
||||
return {mantissa: sig * 4503599627370496, exponent: 972};
|
||||
}
|
||||
|
||||
x = Math.abs(x);
|
||||
var exp = Math.floor(Math.log10(x));
|
||||
var man = x/Math.pow(10, exp);
|
||||
|
||||
return [sig * man, exp];
|
||||
}
|
||||
|
||||
export function calc_whole_parts(value, divisor) {
|
||||
return Math.ceil(value / divisor);
|
||||
// function get_commafied_or_powered_number(number) {}
|
||||
|
||||
function get_actual_pretty_num(number, exponent) {
|
||||
return number;
|
||||
}
|
||||
|
||||
export function make_even(number) {
|
||||
return (number % 2 !== 0) ? ++number : number;
|
||||
}
|
||||
function get_range_intervals(max, min=0) {
|
||||
let upper_bound = Math.ceil(max);
|
||||
let lower_bound = Math.floor(min);
|
||||
let range = upper_bound - lower_bound;
|
||||
|
||||
export function calc_part_size(value) {
|
||||
// take care of fractions
|
||||
return Math.pow(10, ((value+"").length - 1));
|
||||
}
|
||||
let no_of_parts = range;
|
||||
let part_size = 1;
|
||||
|
||||
export function calc_upper_bound(value) {
|
||||
//
|
||||
}
|
||||
if(range > 5) {
|
||||
if(range % 2 !== 0) {
|
||||
upper_bound++;
|
||||
// Recalc range
|
||||
range = upper_bound - lower_bound;
|
||||
}
|
||||
no_of_parts = range/2;
|
||||
part_size = 2;
|
||||
}
|
||||
|
||||
if(range <= 2) {
|
||||
no_of_parts = 4;
|
||||
part_size = range/no_of_parts;
|
||||
}
|
||||
|
||||
export function clump_intervals(start, interval_size, count) {
|
||||
let intervals = [];
|
||||
for(var i = 0; i <= count; i++){
|
||||
intervals.push(start);
|
||||
start += interval_size;
|
||||
for(var i = 0; i <= no_of_parts; i++){
|
||||
intervals.push(lower_bound + part_size * i);
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
// export function calc_intervals() {
|
||||
// //
|
||||
// }
|
||||
function get_intervals(max_value, min_value=0) {
|
||||
let [normal_max_value, exponent] = normalize(max_value);
|
||||
let normal_min_value = min_value ? min_value/Math.pow(10, exponent): 0;
|
||||
|
||||
// Allow only 7 significant digits
|
||||
normal_max_value = normal_max_value.toFixed(6);
|
||||
|
||||
let intervals = get_range_intervals(normal_max_value, normal_min_value);
|
||||
intervals = intervals.map(value => value * Math.pow(10, exponent));
|
||||
return intervals;
|
||||
}
|
||||
|
||||
export function calc_intervals(values, with_minimum=false) {
|
||||
//*** Where the magic happens ***
|
||||
|
||||
// Calculates best-fit y intervals from given values
|
||||
// and returns the interval array
|
||||
|
||||
let max_value = Math.max(...values);
|
||||
let min_value = Math.min(...values);
|
||||
|
||||
let exponent = 0, intervals = [];
|
||||
|
||||
// CASE I: Both non-negative
|
||||
|
||||
if(max_value >= 0 && min_value >= 0) {
|
||||
exponent = normalize(max_value)[1];
|
||||
if(!with_minimum) {
|
||||
intervals = get_intervals(max_value);
|
||||
} else {
|
||||
intervals = get_intervals(max_value, min_value);
|
||||
}
|
||||
}
|
||||
|
||||
// CASE II: Only min_value negative
|
||||
|
||||
if(max_value > 0 && min_value < 0) {
|
||||
// `with_minimum` irrelevant in this case,
|
||||
// We'll be handling both sides of zero separately
|
||||
// (both starting from zero)
|
||||
// Because ceil() and floor() behave differently
|
||||
// in those two regions
|
||||
|
||||
function get_positive_first_intervals(max_value, abs_min_value) {
|
||||
let intervals = get_intervals(max_value);
|
||||
|
||||
let interval_size = intervals[1] - intervals[0];
|
||||
|
||||
// Then unshift the negative values
|
||||
let value = 0;
|
||||
for(var i = 1; value < abs_min_value; i++) {
|
||||
value += interval_size;
|
||||
intervals.unshift((-1) * value)
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
let abs_min_value = Math.abs(min_value);
|
||||
|
||||
if(max_value >= abs_min_value) {
|
||||
exponent = normalize(max_value)[1];
|
||||
intervals = get_positive_first_intervals(max_value, abs_min_value);
|
||||
} else {
|
||||
// Mirror: max_value => abs_min_value, then change sign
|
||||
exponent = normalize(abs_min_value)[1];
|
||||
let pos_intervals = get_positive_first_intervals(abs_min_value, max_value);
|
||||
intervals = pos_intervals.map(d => d * (-1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CASE III: Both non-positive
|
||||
|
||||
if(max_value <= 0 && min_value <= 0) {
|
||||
// Mirrored Case I:
|
||||
// Work with positives, then reverse the sign and array
|
||||
|
||||
let pseudo_max_value = Math.abs(min_value);
|
||||
let pseudo_min_value = Math.abs(max_value);
|
||||
|
||||
exponent = normalize(pseudo_max_value)[1];
|
||||
if(!with_minimum) {
|
||||
intervals = get_intervals(pseudo_max_value);
|
||||
} else {
|
||||
intervals = get_intervals(pseudo_max_value, pseudo_min_value);
|
||||
}
|
||||
|
||||
intervals = intervals.reverse().map(d => d * (-1));
|
||||
}
|
||||
|
||||
intervals = intervals.map(value => get_actual_pretty_num(value, exponent));
|
||||
return intervals;
|
||||
}
|
||||
|
||||
export function calc_distribution(values, distribution_size) {
|
||||
// Assume non-negative values,
|
||||
@ -52,114 +171,3 @@ export function calc_distribution(values, distribution_size) {
|
||||
export function get_max_checkpoint(value, distribution) {
|
||||
return distribution.filter(d => d < value).length;
|
||||
}
|
||||
|
||||
export function calc_y_intervals(array) {
|
||||
//*** Where the magic happens ***
|
||||
|
||||
// Calculates best-fit y intervals from given values
|
||||
// and returns the interval array
|
||||
|
||||
// TODO: Fractions
|
||||
|
||||
let max_bound, min_bound, pos_no_of_parts, neg_no_of_parts, part_size; // eslint-disable-line no-unused-vars
|
||||
|
||||
// Critical values
|
||||
let max_val = parseInt(Math.max(...array));
|
||||
let min_val = parseInt(Math.min(...array));
|
||||
if(min_val >= 0) {
|
||||
min_val = 0;
|
||||
}
|
||||
|
||||
let get_params = (value1, value2) => {
|
||||
let bound1, bound2, no_of_parts_1, no_of_parts_2, interval_size;
|
||||
if((value1+"").length <= 1) {
|
||||
[bound1, no_of_parts_1] = [10, 5];
|
||||
} else {
|
||||
[bound1, no_of_parts_1] = calc_upper_bound_and_no_of_parts(value1);
|
||||
}
|
||||
|
||||
interval_size = bound1 / no_of_parts_1;
|
||||
no_of_parts_2 = calc_no_of_parts(value2, interval_size);
|
||||
bound2 = no_of_parts_2 * interval_size;
|
||||
|
||||
return [bound1, bound2, no_of_parts_1, no_of_parts_2, interval_size];
|
||||
};
|
||||
|
||||
const abs_min_val = min_val * -1;
|
||||
if(abs_min_val <= max_val) {
|
||||
// Get the positive region intervals
|
||||
// then calc negative ones accordingly
|
||||
[max_bound, min_bound, pos_no_of_parts, neg_no_of_parts, part_size]
|
||||
= get_params(max_val, abs_min_val);
|
||||
if(abs_min_val === 0) {
|
||||
min_bound = 0; neg_no_of_parts = 0;
|
||||
}
|
||||
} else {
|
||||
// Get the negative region here first
|
||||
[min_bound, max_bound, neg_no_of_parts, pos_no_of_parts, part_size]
|
||||
= get_params(abs_min_val, max_val);
|
||||
}
|
||||
|
||||
// Make both region parts even
|
||||
if(pos_no_of_parts % 2 !== 0 && neg_no_of_parts > 0) pos_no_of_parts++;
|
||||
if(neg_no_of_parts % 2 !== 0) {
|
||||
// every increase in no_of_parts entails an increase in corresponding bound
|
||||
// except here, it happens implicitly after every calc_no_of_parts() call
|
||||
neg_no_of_parts++;
|
||||
min_bound += part_size;
|
||||
}
|
||||
|
||||
let no_of_parts = pos_no_of_parts + neg_no_of_parts;
|
||||
if(no_of_parts > 5) {
|
||||
no_of_parts /= 2;
|
||||
part_size *= 2;
|
||||
|
||||
pos_no_of_parts /=2;
|
||||
}
|
||||
|
||||
if (max_val < (pos_no_of_parts - 1) * part_size) {
|
||||
no_of_parts--;
|
||||
}
|
||||
|
||||
return get_intervals(
|
||||
(-1) * min_bound,
|
||||
part_size,
|
||||
no_of_parts
|
||||
);
|
||||
}
|
||||
|
||||
function get_intervals(start, interval_size, count) {
|
||||
let intervals = [];
|
||||
for(var i = 0; i <= count; i++){
|
||||
intervals.push(start);
|
||||
start += interval_size;
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
function calc_upper_bound_and_no_of_parts(max_val) {
|
||||
// Given a positive value, calculates a nice-number upper bound
|
||||
// and a consequent optimal number of parts
|
||||
|
||||
const part_size = Math.pow(10, ((max_val+"").length - 1));
|
||||
const no_of_parts = calc_no_of_parts(max_val, part_size);
|
||||
|
||||
// Use it to get a nice even upper bound
|
||||
const upper_bound = part_size * no_of_parts;
|
||||
|
||||
return [upper_bound, no_of_parts];
|
||||
}
|
||||
|
||||
function calc_no_of_parts(value, divisor) {
|
||||
// value should be a positive number, divisor should be greater than 0
|
||||
// returns an even no of parts
|
||||
let no_of_parts = Math.ceil(value / divisor);
|
||||
if(no_of_parts % 2 !== 0) no_of_parts++; // Make it an even number
|
||||
|
||||
return no_of_parts;
|
||||
}
|
||||
|
||||
function get_optimal_no_of_parts(no_of_parts) {
|
||||
// aka Divide by 2 if too large
|
||||
return (no_of_parts < 5) ? no_of_parts : no_of_parts / 2;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user