javascript - 随机生成 HTML Canva 对象

标签 javascript css html canvas

我正在 HTML Canvas 中创建一个模式以应对挑战。

我将如何随机生成如下编码的形状以形成与图片相似的图案。我通过在 Illustrator 中使用 drawscript 生成代码创建了一个版本,但它远非理想,我怎么能用循环来做同样的事情?

enter image description here

谢谢

//triangles
ctx.fillStyle="rgb(75,128,166)";
ctx.beginPath();
ctx.moveTo(824,92);
ctx.lineTo(796,140);
ctx.lineTo(767,92);
ctx.lineTo(824,92);
ctx.fill();

//circles
ctx.fillStyle="rgba(35,121,67,0.8)";
ctx.beginPath();
ctx.moveTo(869,263);
ctx.bezierCurveTo(869,253,861,244,850,244);
ctx.bezierCurveTo(839,244,831,253,831,263);
ctx.bezierCurveTo(831,274,839,283,850,283);
ctx.bezierCurveTo(861,283,869,274,869,263);
ctx.fill();

最佳答案

您可以为三 Angular 形制作一个倾斜的正方形网格,然后对该矩形进行随机插入和随机对 Angular 线分割,使其显示为三 Angular 形。

对于圆圈,我们可以使用伪六边形系统,这意味着圆圈将被放置在六边形位置,只是补偿圆形而不是真正的六边形。

snap

三 Angular 形

  • 首先定义一个普通网格,但它与绘图区域重叠(这是一种方法,另一种方法是包装坐标,但这需要跟踪变换,因此在本例中为蛮力)
  • 倾斜变换,使垂直对齐变为对 Angular 线
  • 定义覆盖范围,填充单元格,这些单元格依次定义是否拆分、是否位于上部等。

如何用随机单元格覆盖有几种方法,下面只是一种方法。其他人可以使用固定的网格系统并使用基于覆盖率的步骤对其进行迭代(需要跟踪剩余部分以确保准确性)。第三个填充单元格的覆盖范围,然后对数组进行随机排序以随机排列单元格。

圆圈

这里也将使用网格,但由于我们要将垂直空间打包成近似六边形网格,因此我们需要对其进行补偿。布局将根据以下因素完成:

  • 垂直距离 = 直径 x sqrt(3) x 0.5 1)
  • 水平距离 = 半径(偏移量每 2 行切换一次)

(1)感谢@Jason 和他的回答提醒我这一点!)

为了补偿垂直“堆积”的圆圈,因为它们不会填满底部,我们使用 sqrt(3) * 0.5 (1/(sqrt(3) * 0.5) 的倒数).

最终结果

将这两个组合到一个 Canvas 中将导致:

var canvas = document.querySelector("canvas"),
    ctx = canvas.getContext("2d"),
    w = canvas.width,
    h = canvas.height,
    cellsY = 14,                     // cells Y for triangles
    cellsX = cellsY * 2,             // cells X times two to overlap skew
    cw = w / cellsX * 2,             // cell width and height         
    ch = h / cellsY,
    toggle, cx = 0, cy,              // for circles
    cells = 25,                      // cells for cirles + comp. (see below)
    deltaY = 0.8660254037844386,     // = sqrt(3) * 0.5
    deltaYI = 1 / deltaY,            // inverse deltaY
    grid = new Uint8Array((cells * cells * deltaYI)|0), // circles "booleans"
    i;

// Calc and Render Triangles ---

// main transform: skew
ctx.setTransform(1, 0, 0.51, 1, -cellsX * cw * 0.5, 0);
ctx.fillStyle = "rgb(90, 146, 176)";

// fill random cells based on likely cover:
var cover = 0.67,                    // how much of total area to cover
    biasDiv = 0.6,                   // bias for splitting cell
    biasUpper = 0.5,                 // bias for which part to draw
    count = cellsX * cellsY * cover, // coverage
    tris = [],
    x, y, d, u, overlap;             // generate cells

for (i = 0; i < count; i++) {
  overlap = true;
  while (overlap) { // if we have overlapping cells
    x = (Math.random() * cellsX) | 0;
    y = (Math.random() * cellsY) | 0;
    overlap = hasCell(x, y);
    if (!overlap) {
      d = Math.random() < biasDiv;   // divide cell?
      u = Math.random() < biasUpper; // if divided, use upper part?
      tris.push({
        x: x,
        y: y,
        divide: d,
        upper: u
      })
    }
  }
}

function hasCell(x, y) {
  for (var i = 0, c; c = tris[i++];) {
    if (c.x === x && c.y === y) return true;
  }
  return false;
}

// render
for (i = 0; i < tris.length; i++) renderTri(tris[i]);
ctx.fill();  // fill all sub-paths

function renderTri(t) {
  var x = t.x * cw,                  // convert to abs. position
    y = t.y * ch;
  if (t.divide) {                    // create triangle
    ctx.moveTo(x + cw, y);           // define common diagonal
    ctx.lineTo(x, y + ch);
    t.upper ? ctx.lineTo(x, y) : ctx.lineTo(x + cw, y + ch);
  }
  else {
    ctx.rect(x, y, cw, ch);          // fill complete cell
  }
}

// Calc and Render Circles ---

cover = 0.5,                         // how much of total area to cover
count = Math.ceil(grid.length * cover); // coverage
cw = ch = w / cells;

ctx.setTransform(1,0,0,1,0,0);       // reset transforms
ctx.fillStyle = "rgb(32, 141, 83)";
ctx.globalCompositeOperation = "multiply";  // blend mode instead of alpha

if (ctx.globalCompositeOperation !== "multiply") ctx.globalAlpha = 0.5; // for IE

for (i = 0; i < count; i++) {
  overlap = true;
  while (overlap) {                  // if we have overlapping cells
    x = (Math.random() * cells) | 0;           // x index
    y = (Math.random() * cells * deltaYI) | 0; // calc y index + comp
    overlap = hasCircle(x, y);                 // already has circle?
    if (!overlap) {
      grid[y * cells + x] = 1;                 // set "true"
    }
  }
}

function hasCircle(x, y) {
  return grid[y * cells + x] === 1;
}

// render
ctx.beginPath();
cy = ch * 0.5;                               // start on Y axis
for (y = 0; y < (cells * deltaYI)|0; y++) {  // iterate rows + comp.
  toggle = !(y % 2);                         // toggle x offset
  for (x = 0; x < cells; x++) {              // columns
    if (grid[y * cells + x]) {               // has circle?
      cx = x * cw + (toggle ? cw * 0.5 : 0); // calc x
      ctx.moveTo(cx + cw * 0.5, cy);         // creat sub-path
      ctx.arc(cx, cy, cw * 0.5, 0, 2 * Math.PI); // add arc
      ctx.closePath();                       // close sub-path
    }
  }
  cy += ch * deltaY;                         // add deltaY
}
ctx.fill();                                  // fill all at once
body {background:#777}
canvas {padding:50px;background: rgb(226, 226, 226)}
<canvas width=600 height=600></canvas>

这里有重构的空间,随机化函数并不是最好的性能,但它应该足以让你继续下去。希望这对您有所帮助!

关于javascript - 随机生成 HTML Canva 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30314399/

相关文章:

javascript - Jquery append 两个具有不同类的html页面

javascript - 如何防止规范 URL

html - 使用单个 CSS 声明为多个元素着色

twitter-bootstrap - Bootstrap 4.1 固定 div,带 overflow-y 和全宽

html - 保留 div :hover open when changing nested select box

javascript - 为什么我的 https 来源没有使用 navigator Geolocation 服务的权限?

javascript - 更改 bootstrap 4.2 轮播持续时间

javascript - 在 AngularJS 和非 AngularJS 弹出窗口之间共享变量

javascript - JS - 如果窗口高度小于 ___px,请执行某些操作 - 这段代码有什么问题?

html - 什么是我如何摆脱它