在 p5js 中逐渐给矩形上色

Gradually color rectangles in p5js

我正在尝试使用 p5.js 在浏览器中构建冒泡排序算法的可视化。我已经设法实现了该算法,并且条形图成功地切换了位置。现在我想在考虑交换它们时给条着色(当它们在 'bubble' 中时,就像在冒泡排序中一样)。给它们上色很容易,但颜色会急剧变化,看起来不太好。我想要的是逐渐改变颜色。例如从蓝色渐变为绿色。这是我的设置和绘制函数:

let bars = []; // array of Bar objects
let values = [];
let greenColor;
let blueColor;
let redColor;
let orangeColor;

function setup() {
  //Init colors
  greenColor = color(16, 112, 1);
  blueColor = color(158, 207, 224);
  redColor = color(208, 0, 46);
  orangeColor = color(253, 148, 8);  

  createCanvas(900, 900);
  textSize(15);
  // Create objects
  for (let i = 0; i < 10; i++) {
    values[i] = round(random(150));
    bars.push(new Bar(i*50 + i*10, values[i], -1));
  }
}

function draw() {
  background(255, 255, 255);
  for (let i = 0; i < bars.length; i++) {
    bars[i].display();
  }
}

设置和绘制函数使用自定义 class 命名栏。 Draw 使用 Bar.display() 函数将矩形绘制到屏幕上。如下所示:

display() {


if (this.colorState == 1) {
  let firstColor = blueColor;
  let secondColor = blueColor;

  if (this.currentColor == "green") {
    firstColor = greenColor;
  } else if (this.currentColor == "red") {
    firstColor = redColor;
  } else if (this.currentColor == "orange") {
    firstColor = orangeColor;
  } else {
    firstColor = blueColor;
  }

  if (this.nextColor == "green") {
    secondColor = greenColor;
  } else if (this.nextColor == "red") {
    secondColor = redColor;
  } else if (this.nextColor == "orange"){
    secondColor = orangeColor;
  } else {
    firstColor = blueColor;
  }


  if (this.amt <= 1.0) {
    var gradient = lerpColor(firstColor, secondColor, this.amt);
    this.amt += 0.05;
    fill(gradient);
  } else {
    this.colorState = 0;
    this.currentColor = this.nextColor;
    this.amt = 0;
  }


} else {
  if (this.currentColor == "green") {
    fill(greenColor);
  } else if (this.currentColor == 'blue') {
    fill(blueColor);
  } else if (this.currentColor == "red") {
    fill(redColor);
  } else {
    fill(orangeColor);
  }
}

noStroke();
rect(this.x, this.y, 50, this.height);
fill(color(0, 0, 0));
text(-this.height, this.x + 15, (height / 2) + (this.height) - 20, 60, 60);

function mouseClicked() {
    bars[0].colorState = 1;
    bars[0].nextColor = "green";
}

我发现将 lerpColor 与 amt 参数一起使用可以让我逐渐改变颜色。当我想淡入下一种颜色时,我将它增加 0.05。截至目前,它可以使颜色褪色,但随后会出现闪烁效果,它会在几毫秒内变黑,我不知道为什么。请帮我解决这个问题。这是 js fiddle:

https://jsfiddle.net/jomzkct4/(稍微向下滚动以查看栏)。

有一个帧,当颜色过渡完成时 amt > 1,填充颜色没有重新分配,所以它使用前一帧的颜色 fill(color(0, 0, 0))。您可以通过在此代码块中添加不同的颜色来进行测试:

else {
    this.colorState = 0;
    this.currentColor = this.nextColor;
    this.amt = 0;
    // Now it "blinks" red
    fill([255, 0, 0])
}

最终,您可能希望在 colorState 值为 0 时重用颜色分配逻辑,或者调整 if (this.colorState == 1) {...} else{...} 块的逻辑。

let bars = []; // array of Bar objects
let values = [];
let greenColor;
let blueColor;
let redColor;
let orangeColor;

function setup() {
  //Init colors
  greenColor = color(16, 112, 1);
  blueColor = color(158, 207, 224);
  redColor = color(208, 0, 46);
  orangeColor = color(253, 148, 8);  

  createCanvas(900, 900);
  textSize(15);
  frameRate(10)
  // Create objects
  for (let i = 0; i < 10; i++) {
    values[i] = round(random(150));
    bars.push(new Bar(i*50 + i*10, values[i], -1));
    
  }
}

function draw() {
  background(255, 255, 255);
  for (let i = 0; i < bars.length; i++) {
    bars[i].display();
  }
}

// Bar class
class Bar {
  constructor(xCord, heightIn) {
    this.x = xCord;
    this.y = height / 2;
    this.speed = 1;
    this.height = -heightIn;
    this.currentColor = "blue";
    this.nextColor = "blue";
    this.amt = 0;
    this.colorState = 0; //0 for static, 1 for changing
  }
  display() {
    if (this.colorState == 1) {
      let firstColor = blueColor;
      let secondColor = blueColor;

      if (this.currentColor == "green") {
        firstColor = greenColor;
      } else if (this.currentColor == "red") {
        firstColor = redColor;
      } else if (this.currentColor == "orange") {
        firstColor = orangeColor;
      } else {
        firstColor = blueColor;
      }

      if (this.nextColor == "green") {
        secondColor = greenColor;
      } else if (this.nextColor == "red") {
        secondColor = redColor;
      } else if (this.nextColor == "orange"){
        secondColor = orangeColor;
      } else {
        firstColor = blueColor;
      }


      if (this.amt <= 1.0) {
        var gradient = lerpColor(firstColor, secondColor, this.amt);
        this.amt += 0.05;
        fill(gradient);
      } 
      
      else {
        this.colorState = 0;
        this.currentColor = this.nextColor;
        this.amt = 0;
       
//      Either reuse the logic:

       /*  if (this.currentColor == "green") {
          fill(greenColor);
        } else if (this.currentColor == 'blue') {
          fill(blueColor);
        } else if (this.currentColor == "red") {
          fill(redColor);
        } else {
          fill(orangeColor);
        } */
      }
    } 
    
//       or tweak the logic of the if-else block
    
    //else{
    
    if (this.colorState == 0) {
      if (this.currentColor == "green") {
        fill(greenColor);
      } else if (this.currentColor == 'blue') {
        fill(blueColor);
      } else if (this.currentColor == "red") {
        fill(redColor);
      } else {
        fill(orangeColor);
      }
    }

    noStroke();
    rect(this.x, this.y, 50, this.height);
    fill(color(0, 0, 0));
    text(-this.height, this.x + 15, (height / 2) + (this.height) - 20, 60, 60);
  }
}


function mouseClicked() {
    bars[0].colorState = 1;
    bars[0].nextColor = "green";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>