basicprimitives
Version:
Basic Primitives Diagrams for JavaScript - data visualization components library that implements organizational chart and multi-parent dependency diagrams, contains implementations of JavaScript Controls and PDF rendering plugins.
79 lines (63 loc) • 2.49 kB
JavaScript
import binarySearch from './binarySearch';
/**
* Breaks collection of values into 3 intervals, so values stay close to each other within interval.
*
* @param {number[]} values Array of values
* @returns {number[]} Returns array containing 3 indexes. The first 2 break values into 3 intervals,
* the last index is actual index of the last element in the values collection.
*/
export default function getLiniarBreaks(values) {
var _leftTotal = [],
_len = values.length;
// Sum up values from left to right
var total = 0;
for (var index = 0; index < _len; index += 1) {
total += values[index];
_leftTotal[index] = total;
}
function getLinearDeviation(leftIndex, rightIndex) {
var result = 0;
var avg = (_leftTotal[rightIndex] - _leftTotal[leftIndex] + values[leftIndex]) / (rightIndex - leftIndex + 1);
var median = binarySearch(values, function (item) {
return avg - item;
}, leftIndex, rightIndex);
if (median.item <= avg) {
result += (avg * (median.index + 1 - leftIndex) - (_leftTotal[median.index] - _leftTotal[leftIndex] + values[leftIndex]));
result += (_leftTotal[rightIndex] - _leftTotal[median.index] - avg * (rightIndex - median.index));
} else {
result += (avg * (median.index - leftIndex) - (_leftTotal[median.index] - _leftTotal[leftIndex] - values[median.index] + values[leftIndex]));
result += (_leftTotal[rightIndex] - _leftTotal[median.index] + values[median.index] - avg * (rightIndex - median.index + 1));
}
return result;
}
function getScore(leftIndex, rightIndex) {
var score = 0;
score += getLinearDeviation(0, leftIndex);
if (rightIndex > leftIndex + 1) {
score += getLinearDeviation(leftIndex + 1, rightIndex - 1);
}
score += getLinearDeviation(rightIndex, _len - 1);
return score;
}
var leftIndex = 0,
rightIndex = _len - 1;
var score = getScore(leftIndex, rightIndex);
while (leftIndex < rightIndex + 1) {
var leftScore = getScore(leftIndex + 1, rightIndex);
var rightScore = getScore(leftIndex, rightIndex - 1);
if (leftScore < rightScore) {
if (leftScore >= score) {
break;
}
leftIndex += 1;
score = leftScore;
} else {
if (rightScore >= score) {
break;
}
rightIndex -= 1;
score = rightScore;
}
}
return [leftIndex, rightIndex - 1, _len - 1];
};