我不确定标题是否正确。
我有几个标签在y范围内设置了它们的位置:
range = [0, 100px]
例如:5个标签位置:
positions = [5px, 6px, 8px, 72px, 76px]
现在我希望我的算法能够纠正这些位置,使它们彼此之间的距离不超过10px,并进行最小的修正。
我期待这样调用我的函数:
result = calculateNewPositions(range, positions, min(10px, 100px / positions.length))
并且这种情况的结果应该是:
[0px, 10px, 20px, 69px, 79px]
这个alghoritm的名称是什么或如何实现?
答案 0 :(得分:2)
这是一种适用于大多数情况的算法,并且尝试根据原始值进行必要的最小调整。
这是一个示例实现:
function calculateNewPositions(positions, minSpacing, rangeMin, rangeMax) {
var temp = positions.slice(0);
var madeChange;
do {
madeChange = false;
for (var i = 0; i < temp.length - 1; i++)
if (temp[i + 1] - temp[i] < minSpacing) {
if (temp[i] > rangeMin) { temp[i]--; madeChange = true; }
if (temp[i + 1] < rangeMax) { temp[i + 1]++; madeChange = true; }
}
} while (madeChange);
return temp;
}
演示:https://jsfiddle.net/aaxmuw2t/
示例结果:[0,10,20,69,79]
请注意,此算法非常简单,并且对于具有大量紧密数字的真正复杂数组而言,可能无法始终产生最佳结果。例如,如果您输入[33, 34, 35, 36]
,则会获得[19, 29, 40, 50]
,这会占用额外的空间。
答案 1 :(得分:1)
calculateNewPositions = function(positions, minDelta) {
var newPositions = [0]
positions.slice(1).forEach(function(pos, index) {
var delta = positions[index + 1] - positions[index]
newPositions.push(newPositions[index] + Math.max(delta, minDelta))
})
return newPositions
}
答案 2 :(得分:1)
我终于做了这样的事情:
var fixPositions = function(range, pos, delta, strict) {
var i;
var leftSpaces = [];
var halfDelta = strict ? delta / 2 : 0;
delta = Math.min(delta, (range[1] - range[0] / (pos.length + (strict ? 0 : 1))));
// calculate all spaces that are greater than delta
leftSpaces.push(Math.max(pos[0] - range[0] - halfDelta, 0));
for (i = 1; i < pos.length; i++) {
leftSpaces.push(Math.max(pos[i] - pos[i-1] - delta, 0));
}
leftSpaces.push(Math.max(range[1] - pos[pos.length-1] - halfDelta, 0));
// save indexes of big spaces
var nonZeroSpacesIdx = [];
leftSpaces.map(function(space, i) {
if (space > 0) {
nonZeroSpacesIdx.push(i);
}
});
// sort indexes by spaces sizes (start from smaller)
nonZeroSpacesIdx.sort(function(a, b) {
return leftSpaces[a] - leftSpaces[b];
});
// loop until spaces sum are greater than range
var spacesSum = Infinity;
while (nonZeroSpacesIdx.length > 0 && spacesSum > 0) {
spacesSum = 0;
for (i = 0; i < nonZeroSpacesIdx.length; i++) {
spacesSum += leftSpaces[nonZeroSpacesIdx[i]];
}
var missingDiff = (spacesSum + (pos.length - 1) * delta + halfDelta * 2) - (range[1] - range[0]);
if (missingDiff <= 0) {
break;
}
// find min diff which can be substracted from all spaces
var minDiff = Math.min(missingDiff / nonZeroSpacesIdx.length, leftSpaces[nonZeroSpacesIdx[0]]);
for (i = 0; i < nonZeroSpacesIdx.length; i++) {
leftSpaces[nonZeroSpacesIdx[i]] -= minDiff;
}
// remove index of first space if its equal zero
if (leftSpaces[nonZeroSpacesIdx[0]] <= 0) {
nonZeroSpacesIdx.shift();
}
}
// reconstruct new positions
var newPos = [];
newPos.push(range[0] + leftSpaces[0] + halfDelta);
for (i = 1; i < leftSpaces.length - 1; i++) {
newPos[i] = newPos[i-1] + leftSpaces[i] + delta;
}
return newPos;
};
// result should be from range: [5, 95]
console.log(fixPositions([0, 100], [5, 6, 8, 72, 76], 10, true));
// result should be from range: [0, 100]
console.log(fixPositions([0, 100], [5, 6, 8, 72, 76], 10, false));
https://jsfiddle.net/fcwu1oyu/14/
它没有为我的输入提供完全相同的值,但它完成了我的饼图的工作:
答案 3 :(得分:0)
正在进行的工作解决方案
代码推动两个太近的情侣appart,每边一个。这是对称的,并且有时会导致很大的推动值,这可以得到纠正。
function disperse(values, threshold, range) {
var delta = Array.apply(null, { length: values.length }).map(function () { return 0; }),
converged = false;
while (!converged) {
converged = true;
delta = delta.map(function (d, i, dd) {
if (i < dd.length - 1 && dd.length > 1 && values[i + 1] + dd[i + 1] - values[i] - d < threshold) {
converged = false;
dd[i + 1] += 1;
return d - 1;
}
return d;
});
}
converged = false;
// try to minimise difference
while (!converged) {
converged = true;
delta = delta.map(function (d, i) {
var space;
if (i < delta.length - 2) {
space = values[i + 1] + delta[i + 1] - values[i] - d;
if (d < 0 && space > threshold) {
converged = false;
return d + space - threshold;
}
}
return d;
});
}
// respect lower range
delta.reduce(function (r, d, i, dd) {
if (values[i] + d < r) {
dd[i] = r - values[i];
return r + threshold;
}
return values[i] + threshold + d;
}, range[0]);
// respect upper range
delta.reduceRight(function (r, d, i, dd) {
if (values[i] + d > r) {
dd[i] = r - values[i];
return r - threshold;
}
return values[i] + d;
}, range[1]);
return values.map(function (v, i) {
return v + delta[i];
});
}
document.write('<pre>' + JSON.stringify(disperse([5, 6, 8, 72, 76], 10, [0, 100]), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(disperse([5, 6, 7, 8, 72, 76], 10, [0, 100]), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(disperse([24, 28, 92, 94, 95], 10, [0, 100]), 0, 4) + '</pre>');
&#13;