目标:
这个想法是创建一个元素网格(例如图像库),它将在两个轴上滚动无限循环。 应该没有洞也没有太多的随机性(避免让相同的元素随机掉落)。而且无论一开始有多少元素(通过16(4 * 4)个元素的网格看起来很容易无限循环,而不是超过17(17 * 1)那么多。(我的猜测是任何素数)根据定义,元素的数量是制作网格的痛苦。
所以我实际上找到了一个很好的工作例子: http://www.benstockley.com/
它实际上非常接近(可能更好),而不是我想象的那样。现在它使用画布,我尝试查看javascript,它是一个30000缩小行长脚本,所以我真的无法读取它背后的任何核心逻辑。
数学方面/解决问题:
这是问题背后的逻辑和理论,涉及的数学和心态。 程序应该如何处理元素列表,这样我们就没有孔,无限网格,所有轴上元素的最佳重现。
我的猜测是,某种程度上必须是程序性的。我不确定是否应该在每个轴上创建网格或循环列表(有点像数独?我不知道);
实用方/ UI / UX:
对所涉及的技术,代码片段的任何建议。我猜它经典的DOM是不合适的,并且某种方式画布或2D webgl将是强制性的。但我很乐意听到这方面的任何建议。
除了所有元素网格处理。在DOM或渲染器中探索2D无限或大型布局所涉及的UI和UX在某种程度上并不经典。欢迎提供最好的技术或建议。
例子:
我欢迎任何有点与此问题有关的工作例子。
答案 0 :(得分:1)
我已经设置fiddle来安排您的2D网格。
它通过使用水平和垂直"步长"起作用。因此,在网格中向右移动一步可以提高列表中的水平步长。向下移动一步可以提升列表中的垂直步长(并累积)。
我们允许列表中的进展在到达结束时循环回零。
使用水平步长1可能是有意义的(因此网格的一行将保持您的列表顺序)。对于垂直步长,您需要一个不与列表长度共享公约数的整数。虽然不能保证,但我使用列表长度的(圆形)平方根作为可以在很多情况下工作的东西。
我会在这里重现小提琴:
var list = ['red','green','blue','cyan','orange','yellow','pink'];
var hstep = 1;
var vstep = Math.ceil(Math.sqrt(list.length));
function getListItem(x,y) {
var index = x * hstep + y * vstep;
return list[index % list.length];
}
var elementSize = 30;
var gutterSize = 10;
function getOffset(x,y) {
return [10 + (elementSize + gutterSize) * x, 10 + (elementSize + gutterSize) * y];
}
var frame = $('.frame');
function drawElement(x,y) {
var listItem = getListItem(x,y);
var offsets = getOffset(x,y);
var element = $('<div></div>').addClass('element').css({
left: offsets[0] + 'px',
top: offsets[1] + 'px',
'background-color': listItem
});
frame.append(element);
}
function drawElements() {
var x = 0, y = 0;
while (10 + (elementSize + gutterSize) * x < frame.width()) {
while (10 + (elementSize + gutterSize) * y < frame.height()) {
drawElement(x,y);
y++;
}
y = 0;
x++;
}
}
drawElements();
&#13;
.frame {
border: 2px solid black;
margin: 40px auto;
height: 300px;
width: 300px;
position: relative;
overflow: hidden;
}
.frame .element {
position: absolute;
width: 30px;
height: 30px;
}
.buttons {
position: absolute;
top: 0px;
width: 100%;
}
.buttons button {
position: absolute;
width: 30px;
height: 30px;
padding: 5px;
}
button.up {top: 0px; left: 46%;}
button.down {top: 355px; left: 46%;}
button.left {top: 160px; left: 15px;}
button.right {top: 160px; right: 15px;}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="frame">
</div>
<div class="buttons">
<button class="up">↑</button>
<button class="down">↓</button>
<button class="left">←</button>
<button class="right">→</button>
</div>
&#13;
你可以看到我留下了一些简单的按钮来实现动作,但它们还没有发挥作用。如果你想按照我在这里完成的工作继续实现,你可以将元素渲染到可见帧之外的某个范围,然后实现某种动画重新定位。这里的renderElements
函数只渲染可见的东西,所以你可以使用类似的东西而不会陷入渲染无限元素的过程中,即使你可以在多大程度上没有理论限制&#34;滚动& #34;
答案 1 :(得分:1)
@arbuthnott我编辑了你的代码,通过递减relativeX和relativeY变量来实现探索。我还插入了一个“原点”div(1x1 px,溢出可见)。此DOM元素将表示X和Y原点。我不确定它是否必不可少但是非常方便。
现在我的函数当前删除所有元素并重新插入每个更新的所有元素(现在每500毫秒)。
理想是找到一种方法来比较我需要的元素与已存在的元素。 可能将现有元素存储到数组中,并将数组与“查询”数组进行比较。只看到缺少的元素。
这是理想的,不确定实现(我很擅长处理数组)。
https://jsfiddle.net/bnv6mumd/64/
var sources = ['red','green','blue','cyan','orange','yellow','pink','purple'];
var frame = $('.frame'),
origin = $('.origin');
var fWidth = 600,
fHeight = 300,
srcTotal = sources.length,
srcSquare = Math.ceil(Math.sqrt(srcTotal)),
rX = 0,
rY = 0;
var gridSize = 30,
gutterSize = 5,
elementSize = gridSize - gutterSize;
function getSourceItem(x,y) {
var index = x + y * srcSquare;
return sources[Math.abs(index) % srcTotal];
}
function getOffset(x,y) {
return [gridSize * x,gridSize * y];
}
function drawElement(x,y) {
var sourceItem = getSourceItem(x,y);
var offsets = getOffset(x,y);
var element = $('<div></div>').addClass('element').css({
left: offsets[0] + 'px',
top: offsets[1] + 'px',
'background-color': sourceItem,
});
origin.append(element);
}
function init() {
var x = 0, y = 0;
while ( gridSize * x < fWidth) {
while ( gridSize * y < fHeight) {
drawElement(x,y);
y++;
}
y = 0;
x++;
}
}
function updateElements() {
origin.empty();
var x = -Math.trunc(rX / gridSize) -1, y = - Math.trunc(rY / gridSize) -1;
while ( gridSize * x + rX < fWidth) {
while ( gridSize * y + rY < fHeight) {
drawElement(x,y);
y++;
}
y = -Math.ceil(rY / gridSize);
x++;
}
}
function animate() {
rX -= 5;
rY -= 5;
origin.css({left: rX, top: rY})
updateElements();
console.log("relative X : " + rX + " | relative Y : " + rY);
}
setInterval(animate, 500)
init();
.frame {
border: 2px solid black;
margin: 40px auto;
height: 300px;
width: 600px;
position: relative;
overflow: hidden;
}
.origin {
height: 1px;
width: 1px;
position: absolute;
overflow: visible;
}
.frame .element {
position: absolute;
width: 25px;
height: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="frame">
<div class="origin" style="top:0;left:0;"></div>
</div>
答案 2 :(得分:0)
这是我的最终片段版本(我现在将开始针对我的案例进行实际实现)。
我认为我以一种体面的方式优化了DOM操作,代码结构等(尽管我很乐意接受建议)。
我现在只更新需要更新的元素(点击框架附近显示溢出)
https://jsfiddle.net/bnv6mumd/81/
var sources = ['red', 'green', 'blue', 'cyan', 'orange', 'yellow', 'pink', 'purple'];
var frame = $('.frame'),
origin = $('.origin');
var srcTotal = sources.length,
srcSquare = Math.round(Math.sqrt(srcTotal)),
fWidth = 200,
fHeight = 200,
cellSize = 50,
gutterSize = 20,
gridSize = [Math.floor(fWidth / cellSize) + 1, Math.floor(fHeight / cellSize) + 1],
aX = 0, // Absolute/Applied Coordinates
aY = 0,
rX = 0, // Relative/frame Coordinates
rY = 0;
function getSrcItem(x, y) {
var index = x + y * srcSquare;
return sources[Math.abs(index) % srcTotal];
}
function getOffset(x, y) {
return [cellSize * x, cellSize * y];
}
function getY() {
return Math.floor(-rY / cellSize);
}
function getX() {
return Math.floor(-rX / cellSize);
}
function drawElement(x, y) {
var srcItem = getSrcItem(x, y),
offsets = getOffset(x, y),
element = $('<div></div>').addClass('element').css({
left: offsets[0] + 'px',
top: offsets[1] + 'px',
'background-color': srcItem,
}).attr({
"X": x,
"Y": y
});
origin.append(element);
}
function drawCol(x, y) {
var maxY = y + gridSize[1];
while (y <= maxY + 1) {
drawElement(x - 1, y - 1);
y++;
}
}
function drawLign(x, y) {
var maxX = x + gridSize[0];
while (x <= maxX + 1) {
drawElement(x - 1, y - 1);
x++;
}
}
function drawGrid() {
origin.empty();
var x = getX(),
y = getY(),
maxX = x + gridSize[0],
maxY = y + gridSize[1];
while (y <= maxY + 1) {
drawLign(x, y);
x = getX();
y++;
}
}
function updateX(x, y, diffX, diffY) {
if (Math.sign(diffX) == -1) {
drawCol(aX - 1, y);
$('[x=' + (aX + gridSize[0]) + ']').remove();
aX--;
} else if (Math.sign(diffY) == 1) {
drawCol(aX + gridSize[0] + 2, y);
$('[x=' + (aX - 1) + ']').remove();
aX++;
}
}
function updateY(x, y, diffX, diffY) {
if (Math.sign(diffY) == -1) {
drawLign(x, aY - 1);
$('[y=' + (aY + gridSize[0]) + ']').remove();
aY--;
} else if (Math.sign(diffY) == 1) {
drawLign(x, aY + gridSize[0] + 2);
$('[y=' + (aY - 1) + ']').remove();
aY++;
}
}
function animate() {
rX += 1;
rY += 1;
origin.css({
left: rX,
top: rY
});
var x = getX(),
y = getY(),
diffX = x - aX,
diffY = y - aY;
if (diffX) {
updateX(x, y, diffX, diffY)
};
if (diffY) {
updateY(x, y, diffX, diffY)
};
requestAnimationFrame(animate);
}
$('body').click(function() {
$(frame).toggleClass("overflow");
})
drawGrid();
animate();
.frame {
border: 2px solid black;
margin: 100px auto;
height: 200px;
width: 200px;
position: relative;
}
.overflow{
overflow:hidden;
}
.origin {
height: 1px;
width: 1px;
position: absolute;
overflow: visible;
}
.frame .element {
position: absolute;
width: 30px;
height: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="frame overflow">
<div class="origin" style="top:0;left:0;"></div>
</div>