Creating a dynamic traffic light display: A step-by-step guide

//traffic lights:red,yellow,green
    fill(trafficFirstLightColor)
    ellipse(315, 40, 20, 20)
    fill(trafficSecondLightColor)
    ellipse(315, 40 + 25 * 1, 20, 20)
    fill(trafficThirdLightColor)
    ellipse(315, 40 + 25 * 2, 20, 20)


    //if three lights with black, first light on
    x+=10
    if (trafficFirstLightColor === "black" && trafficSecondLightColor === "black" && trafficThirdLightColor === "black" && x == 3000) {
        setTimeout(() => {
            trafficFirstLightColor = 'red';
        }, x)
    } else if (trafficFirstLightColor === "red" && x == 6000) {
        trafficFirstLightColor = "black"
        setTimeout(() => {
            trafficSecondLightColor = 'yellow';
        }, x-3000)
    } else if (trafficSecondLightColor === "yellow" && x == 9000) {
        trafficSecondLightColor = "black"
        setTimeout(() => {
            trafficThirdLightColor = 'green';
        }, x-6000)
    }

The attempt at creating a color changing traffic light every 3 seconds was unsuccessful...

Initially, all three traffic lights were set to black and assigned specific variables. Another variable x was created to be used in the if-else statement. When all lights are black, the first one turns red. Then after 3 seconds, the red light switches to yellow. Finally, after an additional 3 seconds, the yellow light changes to green. The plan seemed good but the code implementation had issues.

Answer ā„–1

When working with a p5.js configuration that includes the setup and draw functions, keep in mind that the draw function operates at up to 30/60 FPS. This eliminates the need for manually calling setTimeout to prompt changes. Instead, you can compare the current millis() value with the previous one to determine the time elapsed since the last invocation of draw().

For example, let's look at a scenario where we create a traffic light animation using p5.js without utilizing setTimeout:

let trafficFirstLightColor = 'black';
let trafficSecondLightColor = 'black';
let trafficThirdLightColor = 'black';
let start;

function setup() {
  createCanvas(400, 400);
  trafficFirstLightColor = 'black';
  trafficSecondLightColor = 'black';
  trafficThirdLightColor = 'black';
  start = millis();
}

function draw() {
  fill(trafficFirstLightColor);
  ellipse(315, 40, 20, 20);
  fill(trafficSecondLightColor);
  ellipse(315, 40 + 25 * 1, 20, 20);
  fill(trafficThirdLightColor);
  ellipse(315, 40 + 25 * 2, 20, 20);
  
  const now = millis();
  const cycle = now - start;
  
  if (cycle < 3000) {
    if (trafficFirstLightColor === 'black' &&
    trafficSecondLightColor === 'black' &&
    trafficThirdLightColor === 'black') {
      trafficFirstLightColor = 'red';
      return;
    }
  } else if (cycle < 6000) {
    if (trafficFirstLightColor === 'red') {
      trafficFirstLightColor = 'black';
      trafficSecondLightColor = 'yellow';
      return;
    }
  } else if (cycle < 9000) {
    if (trafficSecondLightColor === 'yellow') {
      trafficSecondLightColor = 'black';
      trafficThirdLightColor = 'green';
      return;
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

Answer ā„–2

When dealing with multiple values, it's best to utilize a data structure instead of using individual variables like thing1, thing2, thing3. In this scenario, we can opt for an array that contains 3 objects with color and duration properties. By cycling through the array or using an index to iterate through the lights while rendering them.

const lights = [
  {
    color: "green",
    duration: 10_000,
  },
  {
    color: "yellow",
    duration: 3_000,
  },
  {
    color: "red",
    duration: 10_000,
  },
];

function setup() {
  createCanvas(50, 50);
  noStroke();
  noLoop();
  renderLights();
}

const renderLights = () => {
  clear();
  const {duration, color} = lights[0];
  fill(color);
  ellipse(width / 2, height / 2, width, height);
  setTimeout(renderLights, duration);
  lights.push(lights.shift());
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

The code is designed for scalability (allowing addition and removal of lights), and by separating configuration from implementation logic, adjusting durations becomes simpler without the risk of breaking the code.

If your canvas is cleared every frame in draw, you can separate light cycling from drawing:

const lights = [
  {
    color: "green",
    duration: 10_000,
  },
  {
    color: "yellow",
    duration: 3_000,
  },
  {
    color: "red",
    duration: 10_000,
  },
];

function setup() {
  createCanvas(50, 50);
  noStroke();
  runLightCycle();
}

function draw() {
  background(0);
  renderCurrentLight();
}

const renderCurrentLight = () => {
  fill(lights[0].color);
  ellipse(width / 2, height / 2, width, height);
};

const runLightCycle = () => {
  setTimeout(() => {
    lights.push(lights.shift());
    runLightCycle();
  }, lights[0].duration);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

While setTimeout is not precise in timing, resulting in potential drift over time.

To prevent drift, tracking the time of the last light change and monitoring elapsed milliseconds since then can help maintain accuracy. Incrementing the last change time when exceeding the current light duration assists in consistency.

If displaying all lights simultaneously instead of changing one light's color, incorporating a loop can be beneficial:

const lights = [
  {
    color: "green",
    duration: 10_000,
  },
  {
    color: "yellow",
    duration: 3_000,
  },
  {
    color: "red",
    duration: 10_000,
  };
let currentLight = 0;
const lightSize = 50;

function setup() {
  createCanvas(lightSize, lightSize * lights.length);
  noStroke();
  noLoop();
  renderLights();
}

const renderLights = () => {
  clear();
  lights.forEach((e, i) => {
    fill(i === currentLight ? e.color : "black");
    ellipse(
      lightSize / 2,
      lightSize / 2 + i * lightSize,
      lightSize,
      lightSize
    );
  });
  setTimeout(renderLights, lights[currentLight].duration);
  currentLight = ++currentLight % lights.length;
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Dynamic hovering over isotopic elements

I'm looking to create a webpage where images are arranged dynamically like on this website: . I also want each image to have a hover effect displaying specific information about the image. After some research, I came across a JavaScript library calle ...

Adding distinct objects in React.js

Currently experimenting with building an e-commerce application using React just for fun. Iā€™m facing a challenge in setting state on a specific object as it gets added to an array. My scenario involves an array called cart where items selected from the ...

using single quotation marks for string keys in a JavaScript object

While working with nodejs, I encountered an issue when creating a list of objects with string keys and numbers as values. Upon logging the list using console.log(), I noticed that some keys had single quotes surrounding them while others did not. For exam ...

activate hover interactions across multiple layers of elements

On my webpage, I have a grid of hidden images that fade in when the mouse hovers over them. The code for this functionality is as follows: HTML <img class="Image" src="./img/foo.png"> CSS .Image { opacity: 0; } JS $(".CircleImage").hover( funct ...

How to Trigger a Callback Function in Angular Template?

Within my directive for tables, I have the ability to output values based on specific properties. For example: <tr ng-repeat="item in table.data"> <td ng-repeat="column in table.columns"> <i ng-if="column.type === 'icon&apo ...

Differences between the scope of if statements in JavaScript and Python

I have a function in React where I am trying to achieve the following: renderPost(data) { const dateStr = new Date(data.pub_date).toLocaleString(); let img='empty'; if (data.header_image_url.url !== null) { ...

Problem encountered with Blueimp gallery and Twitter Bootstrap

Blueimp gallery is being used to showcase a set of 8 images on a website, divided into two rows. The 5th thumbnail (first image on the second row) appears broken, even though it can be seen in the carousel presentation. Here's the link to view the th ...

Transforming a plain text field into an input field upon clicking a button or icon using Angular/Typescript

I am a beginner with Angular 6 and I'm trying to implement functionality where clicking a button or icon will change a text field into an input field. See the snippet of code and expected output below. Thank you in advance. <div> <mat-for ...

What is the best way to store the result from a JavaScript FileReader into a variable for future reference?

I am currently facing an issue uploading a local .json file to my web application. I have managed to display the file in the dev tools, but I am unable to make it accessible for further use. It seems like the problem lies in how I handle (or fail to handle ...

What is the process of integrating an EJS file into the app.js file?

Within my index.ejs file, I have included a script tag containing JavaScript for DOM manipulation. Now, I am looking to access a variable declared within this file from my app.js file. How can I make this happen? When referencing a variable in an ejs file ...

Creating PDFs with Puppeteer and math expressions using the page.$eval function

I have recently started using Puppeteer and have successfully converted an entire website to PDF. However, I am facing a challenge when trying to convert MathJax equations within a div to PDF. Currently, I am using the following code: // Requiring puppetee ...

Having trouble retrieving data from a contact form with php, js, and ajax?

I am facing an issue with my contact form on a website. I am unable to receive the filled fields from the contact form via email. Can someone please help me figure out what is wrong with the code or suggest an alternative solution? Any assistance in fixing ...

What is the best method for retrieving data from a loop in a vuetify carousel?

I am using vuetify to create a carousel that displays recipes stored in the database. However, I would like the carousel to expand below with all the details of the recipe when clicked. After some research, I found a Vuetify component that fits my requirem ...

Show a concealed vertical menu on mobile using CSS

I successfully implemented a drop-up footer on my website: $('#drop-up-open').click(function() { $('#drop-up #drop-upDashboard').slideToggle({ direction: "up" }, 300); $(this).toggleClass('drop-upClose'); }); // e ...

Encountering a "args" property undefined error when compiling a .ts file in Visual Studio Code IDE

I've created a tsconfig.json file with the following content: { "compilerOptions": { "target": "es5" } } In my HelloWorld.ts file, I have the following code: function SayHello() { let x = "Hello World!"; alert(x); } However ...

Trouble disabling specific days of the week in Meteor's Bootstrap3 datetimepicker

Currently, I'm utilizing bootstrap 3 within a meteor project and I have a requirement to deactivate most of the days of the week in a datetime picker. Although the other options I've configured appear to be functioning correctly, the daysOfWeekD ...

Encountering problems when trying to mock values with Jest

I'm currently integrating Jest into an existing project that is already utilizing enzyme and jasmine. Although I have installed the jest packages and configured them initially, I am facing an issue where the mock data is not being supplied correctly. ...

Encountered an error when attempting to run npm start due to the absence of the required module 'minizlib

I recently cloned a react-native project from GitHub to start working on it, but encountered an issue with npm start failing and displaying the following error: Error: Cannot find module 'minizlib' Require stack: - /usr/local/lib/node_modules/ex ...

Generate Address from Latitude and Longitude

For my project, I am trying to convert latitude and longitude coordinates into an address. While the Google Maps API is a potential solution, it requires an XML Response which complicates the process. I came across this helpful thread on Stack Overflow d ...

Encountering a reference error while attempting to troubleshoot streamline.js generated JavaScript code

After successfully setting up streamline.js and generating code using _node --standalone -c stest._js, I encountered an issue. The generated code was not readable and debugging it in tools like Chrome's developer console seemed impossible. However, I ...