使用JavaScript创建随机颜色的随机矩形,而且不能重叠

7
我该如何使用 JavaScript 在 HTML 中创建类似这样的东西? enter image description here 实际上,我知道如何在 HTML 中创建矩形,但想要做类似于这个的东西。HTML 画布可以是任何大小,但每当页面加载时,会生成多个随机大小和颜色的正方形而不重叠。当我尝试做到这一点时,矩形以列表形式生成。我是一个 Web 开发人员(以 Ruby on Rails 为导向),但对这种 JavaScript 的东西还很新。任何帮助将不胜感激。
HTML:
<body>
    <div id="randBlock" >
    </div>
</body>

JavaScript:

(function makeDiv(){
    var divsize = ((Math.random()*100) + 50).toFixed();
    var color = '#'+ Math.round(0xffffff * Math.random()).toString(16);
    $newdiv = $('#randBlock').css({
        'width':divsize+'px',
        'height':divsize+'px',
        'background-color': color
    });

    var posx = (Math.random() * ($(document).width() - divsize)).toFixed();
    var posy = (Math.random() * ($(document).height() - divsize)).toFixed();

    $newdiv.css({
        'position':'absolute',
        'left':posx+'px',
        'top':posy+'px',
        'display':'none'
    }).appendTo( 'body' ).fadeIn(100).delay(300).fadeOut(200, function(){
       $(this).remove();
       makeDiv(); 
    }); 
})();

@Paulie_D 这个问题非常具体。每当页面加载时,都会创建一个宽度等于屏幕的 div。这个 div 需要包含像图片中那样随机位置和颜色的块,但不重叠。我是一名 Ruby on Rails 开发者,对这种 JavaScript 编码经验较少。任何帮助将不胜感激。 - Amarjeet Singh
@Paulie_D 对不起,我没有分享代码。 - Amarjeet Singh
好的...已经投票重新开放。 - Paulie_D
你需要特定数量的正方形吗?你想要淡入/淡出做什么?所有正方形一起,还是逐个淡出淡入?如果需要非重叠,则会给算法增加很多复杂性;这是严格要求吗? - Scott Mermelstein
@ScottMermelstein 数字不需要超过10。所有块都需要同时出现和消失。实际上,现在在代码中它们是自动出现和消失的,它们需要是静态的,因为我将为一个按钮分配随机化的东西。但是,是的,它们不需要重叠。 - Amarjeet Singh
2个回答

4
一种使用canvas的解决方案(据我理解这个问题)。
内置碰撞检测isInside()
编辑:更好的随机支持,不会无限运行,来自在canvas上绘制1px宽线条会创建2px宽线条的提示和一些来自此答案的东西。JavaScript中的随机颜色生成器

function getRandomColor() {
    var color = '#';
    for (var i = 0; i < 6; i++) {
        color += (Math.random() * 16 | 0).toString(16);
    }
    return color;
}

function Point(x, y) {
    this.x = x;
    this.y = y;
}

function Rectangle(p1, p2) {
    this.p1 = p1;
    this.p2 = p2;
}

Rectangle.prototype.isInside = function (r) {
    function check(a, b) {
        return (
            a.p1.x <= b.p1.x && b.p1.x <= a.p2.x && a.p1.y <= b.p1.y && b.p1.y <= a.p2.y ||
            a.p1.x <= b.p2.x && b.p2.x <= a.p2.x && a.p1.y <= b.p2.y && b.p2.y <= a.p2.y ||
            a.p1.x <= b.p2.x && b.p2.x <= a.p2.x && a.p1.y <= b.p1.y && b.p1.y <= a.p2.y ||
            a.p1.x <= b.p1.x && b.p1.x <= a.p2.x && a.p1.y <= b.p2.y && b.p2.y <= a.p2.y
        );
    }
    return check(this, r) || check(r, this);
}

function generateRectangles() {
    function p() { return Math.random() * 300 | 0; }
    function s() { return 50 + Math.random() * 150 | 0; }

    var rectangles = [],
        r, size, x, y, isInside, i, counter = 0;

    for (i = 0; i < 20; i++) {
        counter = 0;
        do {
            counter++;
            x = p();
            y = p();
            size = s();
            r = new Rectangle(new Point(x, y), new Point(x + size, y + size));
            isInside = rectangles.some(function (a) {
                return a.isInside(r);
            });
        } while (isInside && counter < 1000);
        counter < 1000 && rectangles.push(r);
    }
    return rectangles;
}

function drawRectangles(rectangles) {
    var canvas = document.getElementById("canvas"),
        ctx = canvas.getContext("2d");

    rectangles.forEach(function (a) {
        ctx.lineWidth = 1;
        ctx.strokeRect(a.p1.x + 0.5, a.p1.y + 0.5, a.p2.x - a.p1.x - 1, a.p2.y - a.p1.y - 1);
        ctx.fillStyle = getRandomColor();
        ctx.fillRect(a.p1.x + 0.5, a.p1.y + 0.5, a.p2.x - a.p1.x - 1, a.p2.y - a.p1.y - 1);
    });
}

var rectangles = generateRectangles();
drawRectangles(rectangles);
<canvas id="canvas" width="500" height="500"></canvas>


1
谢谢!这正是我所需要的。 :) - Amarjeet Singh
我可能引入了一个错误,但我几乎可以确定当边框对齐时,您有一个边缘情况(双关语)。我看到内部正方形 https://jsfiddle.net/Victornpb/3hc0j5pd/ - Vitim.us
在这里,我看不到重叠... - Nina Scholz
我会编辑它并用它来生成我的墙饰图案。lmao - Persk

1
你已经可以画出一个随机位置的正方形。要画多个正方形也很容易,只需使用循环添加多个div即可。当然,这时需要给每个正方形分配一个随机id,但这也很容易。问题在于这样会允许重叠。

Simplest case: allowing overlap

function makeDiv(i) {
  var divsize = ((Math.random() * 100) + 50).toFixed();
  var color = '#' + Math.round(0xffffff * Math.random()).toString(16);
  var posx = (Math.random() * ($(document).width() - divsize)).toFixed();
  var posy = (Math.random() * ($(document).height() - divsize)).toFixed();
  var divid = 'randBlock' + i;

  $('#randBlock').append("<div id='" + divid + "'>");
  $('#' + divid).css({
    'width': divsize + 'px',
    'height': divsize + 'px',
    'background-color': color,
    'position': 'absolute',
    'left': posx + 'px',
    'top': posy + 'px'
  });
}

for (var i = 0; i < 10; ++i) {
  makeDiv(i);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>
  <div id="randBlock">
  </div>
</body>

如果您想保证它不重叠,除非有一些CSS魔法可以做到这一点(这是很可能的),否则您需要做更多的工作,但我不知道。您将不得不跟踪每个正方形的位置和大小,并仅将结果适配到清晰的区域中。
根据您的确切要求,您的算法将有所不同。您将不得不有一些限制 - 要么是正方形的最大尺寸,要么是重叠的要求,要么是您想要适合的最大正方形数量,或者允许正方形变得越来越小。我将为其中两个提供口头演示。网格想法有一个工作代码片段。根据您在评论中添加的内容,那可能已经足够了。
您已经建立了一个固定的大小,所以也许最好的想法是以此大小为基础,创建一个网格。在这种情况下,您将知道每个网格中可以有一个正方形。有一个存储每个网格位置的数组,并随机选择从(1到该数组的长度)- 1。在该网格中,适配一个正方形,非常类似于您当前拥有的函数。它的大小是您已经设置的最大值,其在该框内的位置可以基于大小随机。
网格化案例。

var fixedScale = 100;
var fixedConstant = 50;
var fixedMax = fixedScale + fixedConstant;
var gridCols = (($(document).width() / fixedMax) + 1).toFixed();
var gridRows = (($(document).height() / fixedMax) + 1).toFixed();
var grid = [];
for (var row = 0; row < gridRows; ++row) {
  for (var col = 0; col < gridCols; ++col) {
    var index = row * gridCols + col;
    grid[index] = {row: row, col: col};
  }
}

function makeDiv(i) {
  var gridId = Math.floor(Math.random() * grid.length);
  
  var divsize = ((Math.random() * fixedScale) + fixedConstant).toFixed();
  console.log(gridId + ", grid.length = " + grid.length);
  var color = '#' + Math.round(0xffffff * Math.random()).toString(16);
  var posx = grid[gridId].col * fixedMax;
  var posy = grid[gridId].row * fixedMax;
  var offsetx = (Math.random() * (fixedMax - divsize)).toFixed();
  var offsety = (Math.random() * (fixedMax - divsize)).toFixed();
  posx = +posx + +offsetx;
  posy = +posy + +offsety;
  var divid = 'randBlock' + i;

  grid.splice(gridId, 1);
  
  $('#randBlock').append("<div id='" + divid + "'>");
  $('#' + divid).css({
    'width': divsize + 'px',
    'height': divsize + 'px',
    'background-color': color,
    'position': 'absolute',
    'left': posx + 'px',
    'top': posy + 'px'
  });
}

for (var i = 0; i < 10; ++i) {
  makeDiv(i);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>
  <div id="randBlock">
  </div>
</body>

你可以使用以下事实来拥有无限的(但递减的)正方形:每当你将一个正方形添加到一个空区域时,它将在该区域留下四个剩余空间的矩形。每当你制作一个彩色正方形时,你实际上可以制作5个div:彩色正方形,其顶部,右侧,底部和左侧的空白区域。将空白区域分配给特定的类。然后,查看所有具有“空”类的div,并将最大大小设置为空div的最大值。当你创建下一个彩色正方形时,请选择一个至少与正方形一样大的随机div。
显然,这些代码并不是完全琐碎的。你在需求和约束方面所做的选择将对你的编码工作产生巨大影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接