在javascript数组中分散数字
Dispersing numbers in a javascript array
我有一个10+
数字数组。它们以度表示圆上的坐标,即每个数字都在0
和359.999999...
之间
我试图解决的问题是,当我在圆圈上绘制项目时(通过html5 canvas api),有时它们会聚集在一起,导致项目相互绘制。
所以我想创建一个算法,将项目均匀地分散在它们的初始聚类位置。假设(我希望这是一个可配置的选项)两个项目之间的最小距离是5
度。
因此,如果初始数组是[5, 41, 97, 101, 103, 158, 201, 214, 216, 217, 320]
,那么我希望算法能得出类似[5,41,95,100和105的结果,158201,2211216221320](粗体项目分散在其初始"重心"周围,无论是2个还是更多项目)。
同样必要的是,该算法识别出0和359仅相距1个单位(度),并且还将这些项目均匀地分布在周围。
有人创建过这样的算法吗?或者知道如何实现它吗甚至一些一般性的想法也是受欢迎的。我相信我可以通过大量的尝试和错误来实现这一点,但如果你愿意的话,我想先听听一些有根据的猜测。
var val = [5, 41, 96, 101, 103, 158, 201, 214, 216, 217, 320, 1201, 1213, 1214, 1216, 1217, 1320],
delta = Array.apply(null, { length: val.length }).map(function () { return 0 }),
result,
threshold = 5,
converged = false;
document.write('val: ' + val + '<br>');
while (!converged) {
converged = true;
delta = delta.map(function (d, i) {
if (i < delta.length - 1 && delta.length > 1) {
if (val[i + 1] + delta[i + 1] - val[i] - d < threshold) {
converged = false;
delta[i + 1] += 1;
return d - 1;
}
}
return d;
});
document.write('delta: ' + delta + '<br>');
}
result = val.map(function (v, i) {
return v + delta[i];
});
document.write('result: ' + result + '<br>');
// try to minimise difference
converged = false;
while (!converged) {
converged = true;
delta = delta.map(function (d, i) {
if (i < delta.length - 2) {
var space = val[i + 1] + delta[i + 1] - val[i] - d;
if (d < 0 && space > threshold) {
converged = false;
return d + space - threshold;
}
}
return d;
});
document.write('delta min: ' + delta + '<br>');
}
result = val.map(function (v, i) {
return v + delta[i];
});
document.write('result: ' + result + '<br>');
代码推送两对过于亲密的情侣,两边各有一对。这是对称的,有时会导致推得更远的值,可以进行校正。
[未实现!]如果你的值的空间不够,[0..360[或超过72个元素的差值为5,while循环可能不会结束。
edit:最小化块应该迭代,直到所有值都被更正。
要得到"均匀随机"分布,假设你有N个数字-将圆分成N段,然后将每个数字随机放入其段中。
这样,您甚至不需要关心0和359之间只有1个单元的间隔。
这里有一个想法:
var numbers = 5;
var segment = 360/numbers;
var result = [];
for(var i = 0; i < numbers; i++) {
result.push(Math.round((Math.random() + i) * segment));
}
alert(result.join(','));
这里有一个更图形化的想法(想象一下将矩形折叠成圆柱体):
var numbers = 5;
var segment = 360 / numbers;
var minimum = 15;
var div = document.getElementById('r');
function build() {
var result = [];
div.innerHTML = '';
for (var i = 0; i < numbers; i++) {
var current = 0;
while(current < minimum + (result[result.length - 1] || 0)) {
current = Math.round((Math.random() + i) * segment);
}
result.push(current);
var d = document.createElement('div');
d.className = 'segment';
d.style.left = (result[result.length - 2] || 0) + 'px';
d.style.width = (current - (result[result.length - 2] || 0) - 1) + 'px';
d.textContent = current;
div.appendChild(d);
}
console.log(result.join(','));
}
build();
.segment {
height: 100%;
position: absolute;
font-size: 12px;
text-align: right;
border-right: 1px solid black;
}
#r {
height: 100%;
width: 360px;
background: #eee;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
button {
position: absolute;
right: 4px;
margin: 0;
}
<button onclick="build()">Rebuild</button>
<div id="r"></div>
漂亮打印图形的算法使用弹簧系统在顶点重叠时将它们相互移开。在这里,您只处理一个维度,并且可以迭代调整附近的角度,直到所有节点相距至少5度。
您可以通过创建一个辅助工作数组来处理循环值,以便在最大间隙之后对元素进行重新排序。这允许您将数组视为线性值,而不必关心包装:
[2, 7, 320, 359] -> [-40, -1, 2, 7]
下面的代码可以执行此操作。不过,节点的移动方式相当粗糙:代码只查看距离太近的节点对。代码可能可以通过锁定两个或多个节点的集群来改进,这些节点彼此距离太近:
function adjust(arr, dist)
{
var offset = 0;
var max = 360.0 + arr[0] - arr[arr.length - 1];
var min = max;
var mix = 0; // index of first elment after largest gap
// exit early if array can't be adjusted
if (dist * arr.length > 240.0) return arr;
// find largest gap
for (var i = 1; i < arr.length; i++) {
var d = arr[i] - arr[i - 1];
if (d > max) {
max = d;
mix = i;
}
if (d < min) min = d;
}
var x = []; // working array
var adj = []; // final, adjusted array
// create working array on greatest gap
for (var i = 0; i < arr.length; i++) {
if (i + mix < arr.length) {
x.push(arr[i + mix] - 360);
} else {
x.push(arr[i + mix - arr.length]);
}
}
// iteratively adjust angles
while (min < dist) {
min = dist;
for (var i = 1; i < x.length; i++) {
var d = x[i] - x[i - 1];
if (d < dist) {
if (d < min) min = d;
x[i - 1] -= (dist - d) / 2;
x[i] += (dist - d) / 2;
}
}
}
// create final array
for (var i = 0; i < x.length; i++) {
if (i - mix < 0) {
adj.push(x[i - mix + x.length]);
} else {
adj.push(x[i - mix] + 360);
}
}
return adj;
}
- 通过单击表单中的按钮,在代码生成中使用javascript生成字母数字代码
- 测试索引值是否等于某个数字的倍数
- 将数字转换为一定数量的硬币
- 键入最后一位数字后自动提交
- 如何在javascript中迭代数字列表
- Javascript逻辑运算符和字符串/数字
- 如何在javascript中获得与特定数字相等的随机数
- 如果元素's的ID以数字开头
- 递增一个数字而不去掉前导零
- 如何使用JavaScript查找1和N之间的所有数字的总和
- 如何在这里将两个值最低的数字相加
- 如何删除除冒号、数字和'上午'或者'下午'
- 如何为jQuery屏蔽输入插件创建一个允许字母数字、空格和重音字符的掩码
- Javascript排序字符串或数字
- 我想在AngularJS应用程序中创建一个输入数字框,用户不应该在该框上键入十进制数字.(一个整数输入框)
- 将数字四舍五入到小数点后两位
- 我如何在数字插入中使用逗号,这样它就不会'不要破坏我的输入字段
- 正则表达式与数字中的第二个点匹配
- 在javascript数组中分散数字
- AngularJS如何获取一个数组,该数组将数字添加到函数中的元素,然后用另一个函数分散其注意力