如何为网格中的每个圆分配随机颜色,然后让每个圆从起始颜色开始在色谱中前进?

How can I assign a random color to each circle in a grid, then get each circle to progress through the color spectrum from the start color?

我正在尝试为每个圆圈分配一次随机颜色,然后让该颜色在色谱中不断变化。我是初学者,无法弄清楚如何阻止绘制函数中的随机颜色重置每个循环而不将其拉入设置函数,然后使所有圆圈从相同的随机颜色开始。下面是我目前所拥有的代码。此刻它似乎也在轻微地改变颜色,我认为这与 'for' 有关。我想要的只是一个圆圈网格,这些圆圈被分配了一次随机颜色,然后继续以相同的速度通过色轮推进它们的颜色。提前致谢!

let intervals = [10];
let count;
let frameWidth;
let distance;
let diam1;
let col1;
let sat1;
let bri1;
let speed;

function setup() {
  
  createCanvas(800, 800);  
  
  colorMode(HSB, 360, 100, 100, 1);
  
//initiate draw variables
  
  count = random(intervals);
  
  frameWidth = (width*0.8);
  
  distance = (frameWidth/count);
  
  col1 = random(360);
  
  diam1 = distance*0.5;  
  
  speed = 0.005;
  
}

function draw() {
  
  background(0, 0, 0, 1);

// draw grid of circles
  
  for (let x = width * 0.1; x <= width * 0.9; x += distance) {
    
    for (let y = height * 0.1; y <= height * 0.9; y += distance) {
      
      sat1 = 100;
      
      bri1 = 100;
      
      noStroke();
      
      fill(col1, sat1, bri1, 1);
      
      ellipse(x,y,diam1);
      
      col1 = col1 + speed
      
      if (col1 >= 360) {
        
      col1 = 0
      
      }
  
      }
    }
  }  

ui 将是一个二维圆网格。

数据结构将是一个二维颜色值数组。数据结构永远不需要更新;要获得一个圆圈的当前颜色,我们只需要知道它的初始颜色,以及已经过去的时间量!

我将使用 hsla() css 颜色指令来定义颜色,因为它使改变色调变得微不足道。

colourShiftingCircles 函数采用 canvas 上下文和一些显示参数,并将在提供的 canvas 上下文中保持动画(颜色转换)圆网格。

函数签名是:

colourShiftingCircles({ ctx, rad, numX, numY, saturation=100, lightness=50, huePerSec=30 })
  • ctx:canvas 上下文
  • rad: 以像素为单位的圆半径
  • numX: 跨圈数
  • numY:向下的圈数(numX x numY 圈的总数)
  • saturation:控制颜色的“色彩”或“非灰色”程度
  • lightness:控制如何向 black/white 颜色
  • 移动
  • huePerSec: 如何快速地循环色调

let canvas = document.querySelector('canvas');

// This just ensures the canvas is a reasonable size; it's optional
let resize = () => {
  let { width, height } = canvas.parentNode.getBoundingClientRect();
  if (width.toString() !== canvas.getAttribute('width')) canvas.setAttribute('width', width);
  if (height.toString() !== canvas.getAttribute('height')) canvas.setAttribute('height', height);
};
resize();
window.addEventListener('resize', resize);

let colourShiftingCircles = ({ ctx, rad, numX, numY, saturation=100, lightness=50, huePerSec=30 }) => {
  
  // This value allows the animation to be ended at some point in the future
  let control = { run: true, end: () => control.run = false };
  
  // Animation loop runs inside an `async` function:
  (async () => {
    
    // An array of size `numX` x `numY` items, defining initial hue values for circles
    let data = [ ...new Array(numX) ].map(() => [ ...new Array(numY) ].map(() => {
      return { hue: Math.random() * 360 };
    }));
    
    // Mark the start time; this will allow us to tell how much time has passed later
    let startTime = performance.now();
    
    while (control.run) {
      
      // Wait for animation frame; this is a basic principle of canvas animations
      await new Promise(r => requestAnimationFrame(r));
      
      // Figure out how much the hue has shifted by at this point in time
      let totalHueShift = ((performance.now() - startTime) / 1000) * huePerSec;
      
      // Draw every circle:
      for (let y = 0; y < numY; y++) { for (let x = 0; x < numX; x++) {
        
        // Calculate the hue based on the circle's initial colour, and the amount
        // of hue shifted due to passage of time
        let hue = data[x][y].hue + totalHueShift;
        
        // Simply draw a circle with an hsla fill colour
        ctx.beginPath();
        ctx.fillStyle = `hsla(${Math.floor(hue) % 360}deg ${saturation}% ${lightness}%)`;
        ctx.arc((rad * 2 * x) + rad, (rad * 2 * y) + rad, rad, 0, Math.PI * 2);
        ctx.fill();
        
      }}
      
    }
    
  })();
  
  return control;
  
};

let { end } = colourShiftingCircles({ ctx: canvas.getContext('2d'), rad: 20, numX: 5, numY: 5 });

// If you ever want to end the animation just call `end()`!
/* Just getting the canvas to display in a reasonable way; this is optional */
html, body, canvas { position: absolute; width: 100%; height: 100%; margin: 0; padding: 0; }
canvas { outline: 1px solid black; }
<canvas></canvas>

您必须在 setup 中创建随机颜色的网格:

let speed, colors, rows, columns;

function setup() {
    // [...]

    columns = Math.round(frameWidth / distance) + 1; 
    rows = Math.round(frameWidth / distance) + 1; 
    colors = [];
    for (let i = 0; i < columns; i ++) {
        colors.push([]);
        for (let j = 0; j < rows; j ++) {
            colors[i].push(random(360));
        }
    }
    speed = 1;
}

使用colors中的draw函数。完整示例:

let intervals = [10];
let count, frameWidth, distance;
let sat1, bri1;
let speed, colors, rows, columns, diameters;

function setup() {
    createCanvas(800, 800);  
    colorMode(HSB, 360, 100, 100, 1);
    //initiate draw variables
    count = random(intervals);
    frameWidth = (width*0.8);
    distance = (frameWidth/count);  
    
    columns = Math.round(frameWidth / distance) + 1; 
    rows = Math.round(frameWidth / distance) + 1; 
    colors = [];
    diameters = []
    for (let i = 0; i < columns; i ++) {
        colors.push([]);
        diameters.push([]);
        for (let j = 0; j < rows; j ++) {
            colors[i].push(random(360));
            diameters[i].push(random(TWO_PI));
        }
    }
    speed = 1;
}

function draw() {
    background(0, 0, 0, 1);

    // draw grid of circles
    for (let i = 0; i < columns; i ++) {
        for (let j = 0; j < rows; j ++) {
            sat1 = 100;
            bri1 = 100;
            noStroke();
            fill(colors[i][j], sat1, bri1, 1);
            let d = distance * (0.5 + 0.4 * sin(diameters[i][j]));
            ellipse(width * 0.1 + i * distance, height * 0.1 + j * distance, d);
            colors[i][j] = (colors[i][j] + speed) % 360;
            diameters[i][j] = diameters[i][j] + 0.05;
        }
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>