user7558372
user7558372

Reputation:

Iterate array with animation and conditions

I want to iterate (using setIterval) an an array of string like that:

const colors = ['all', 'red', 'blue', 'green', 'yellow']

The result is:

console.log('all') 
console.log('red')    // after 20 sec
console.log('blue')   // after 10 sec
console.log('green')  // after 10 sec
console.log('yellow') // after 10 sec

But I have to consider also a random number: during the iteration, I may or may not want to show that color (this is related to single color (red, blue, green, yellow) not all). This depends on a certain condition that we can consider a random number in this simplified example:

if(Math.random() >= 0.5)
    showTheColor
else
    doesntShowTheColor

I simulate an example:

start animation
  show color all for 20 seconds

coin throw for color red = 0.7
  show color red for 10 seconds

coin throw for color blue = 0.4
  /

coin throw for color green = 0.1
  /

coin throw for color yellow = 0.8
  show color yellow for 10 seconds

show color all for 20 seconds

coin throw for color red = 0.2
  /

coin throw for color blue = 0.3
  /

coin throw for color green = 0.78
  show color green for 10 seconds

coin throw for color yellow = 0.5
  show color yellow for 10 seconds

show color all for 20 seconds

coin throw for color red = 0.6
  show color red for 10 seconds

coin throw for color blue = 0.7
  show color blue for 10 seconds

coin throw for color green = 0.4
  /

coin throw for color yellow = 0.1
  /

show color all for 20 seconds

coin throw for color red = 0.2
  /

coin throw for color blue = 0.1
  /

coin throw for color green = 0.3
  /

coin throw for color yellow = 0.15
  /

// NB: doesn't show color all for 20 seconds because all the previous colors are null. If I showed all for 20 sec, I would have a total of 40 sec of all and that's not what I want
coin throw for color red = 0.5 
  show color red for 10 seconds

Here is a piece of my code:

const INTERVAL_ALL = 20 // sec
const INTERVAL_SINGLE = 10 // sec

export class Animation extends React.Component {
  interval = null
  i = -1
  colors: string[]

  async componentDidMount() {
    this.colors = ['all', 'red', 'blue', 'green', 'yellow']
    this.startPlaying()
  }

  startPlaying = () => {
    this.interval = window.setInterval(() => this.updateColor(), INTERVAL * 1000) // which interval?
  }

  // where do I put conditions and how?
  updateColor() {
    this.i = this.i === this.colors.length - 1 ? 0 : this.i + 1
    const color = this.colors[this.i]
    this.doSomethingWithColor(color)
  }

  componentWillUnmount() {
    clearInterval(this.interval)
  }

  doSomethingWithColor(color) {
    console.log(color)
  }

  render() {
    return (...)
  }
}

The code is a simplified version, it doesn't take into account the different types of timing and conditions. I need help

Thanks a lot

Upvotes: 1

Views: 415

Answers (2)

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

possibly you're looking for something like this:

Keeping it relatively simply, here's a sandbox as well: https://codesandbox.io/s/gallant-bardeen-7rxmh

class App extends React.Component {
  state = {
    colors: ["red", "orange", "yellow", "green", "blue"],
    currentColor: "red",
    currentIndex: 0,
    colorWasSkipped: false
  };

  componentDidMount() {
    this.changeColor();
  }

  componentDidUpdate() {
    const { currentIndex, colorWasSkipped } = this.state;

    setTimeout(
      () => {
        this.changeColor();
      },
      currentIndex === 0 && !colorWasSkipped
        ? "20000"
        : colorWasSkipped
        ? 0
        : "10000"
    );
  }

  changeColor = () => {
    const { colors, currentIndex } = this.state;
    const randomNumber = Math.random();

    const newColor =
      currentIndex < colors.length - 1 ? colors[currentIndex + 1] : colors[0];

    const newIndex = currentIndex < colors.length - 1 ? currentIndex + 1 : 0;

    if (randomNumber >= 0.5) {
      console.log(randomNumber + " changed " + newColor);
      this.setState({
        currentColor: newColor,
        currentIndex: newIndex,
        colorWasSkipped: false
      });
    } else {
      console.log(randomNumber + " skip " + newColor);
      this.setState({
        currentIndex: newIndex,
        colorWasSkipped: true
      });
    }
  };

  render() {
    const color = this.state.currentColor;
    return <div style={{ height: "200px", background: `${color}` }} />;
  }
}

Let me know if you have any questions. If a color is skipped, we immediately try a new color and if its random number is less than 0.5, we skip it as well. The cycle continues until we get a number greater than or equal to 0.5, then we display that color for 10 seconds, unless we are back at index 0, where we display that color for 20 seconds instead.

Upvotes: 1

Smytt
Smytt

Reputation: 364

I am not a React guy per se, but let me know if this is what you are looking for. Also, you did not mention what the behaviour should be if after a coin toss nothing should happen - should we toss the coin once more right away or should we still wait for the interval?

const INTERVAL_ALL = 20 // sec
const INTERVAL_SINGLE = 10 // sec

export class Animation extends React.Component {
  // interval = null - not needed, timeout will do
  activeInterval: number;
  i = 1 // should start at index 1, right after 'all'
  colors: string[]
  currentColor: string;

  async componentDidMount() {
    this.colors = ['all', 'red', 'blue', 'green', 'yellow']
    this.currentColor = this.colors[0] // set current color to 'all' at beginning
    this.activeInterval = INTERVAL_ALL; // animation starts with all, so 20 secs.
    this.startPlaying();
  }

  startPlaying = () => {
    setTimeout(() => {
      this.attemptColorChange();
    }, this.activeInterval * 1000) //
  }

  // where do I put conditions and how?
  pickNewColor(): string {
    this.i = this.i % this.colors.length
    const newColor = this.colors[this.i++]
    return newColor;
  }

  componentWillUnmount() {
    // clearInterval(this.interval)
  }

  attemptColorChange() {
    const newColor = this.pickNewColor();
    const shouldChangeColor = Math.random() >= 0.5
    if (shouldChangeColor) {
      if (newColor === 'all') {
        this.activeInterval = INTERVAL_ALL;
      } else {
        this.activeInterval = INTERVAL_SINGLE;
      }
      this.currentColor = newColor;
      this.startPlaying();
    }
    else {
      this.attemptColorChange();
    }
  }

  render() {

  }
}

Upvotes: 0

Related Questions