I am new to JavaScript and i am tying to automate this traffic light sequence. I have used if and if else statements to preform the task but I am unable to automate it so it
I don't usually write ready-to-go code, but there are so many things wrong with yours that I was... compelled to.
Functions: use 'em! Don't copy-paste the same code over and over, that's a sign you're doing it wrong!
setInterval
takes a reference to a function. I don't know what your "previous attempts" were since you never bothered telling us, but I'll hazard a guess that you wrote setInterval(changelight(), 1000)
and wondered why it only ever did the first one.
You can re-use a canvas context! Just get it once and draw on it forever!
Avoid "magic numbers" like these colours[0]
in your original code. Give things meaningful names, such as colours.red
, colours.off
so you can easily find and change them if you want!
Use a counter to step through your cycles, don't rely on equality to some arbitrary value. Use %
operator to effectively create a repeating cycle of the given length.
Find patterns and exploit them. A UK traffic light goes in four steps: (red), (red+yellow), (green), (red). US is similar but without the (red+yellow) step... I guess they like testing people's reflexes or something.
Put it all together, this is what you get:
var c = document.createElement('canvas'),
ctx = c.getContext('2d');
c.width = 150;
c.height = 300;
document.body.appendChild(c);
var cycle = 0,
colours = {
red: "#cc0000",
yellow: "#cccc00",
green: "#00cc00",
off: "#333333"
};
function drawLight(id,colour) {
// avoid repetition, use a function!
ctx.fillStyle = colours[colour];
ctx.beginPath();
ctx.arc(95, 50 + 100*id, 40, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
}
function changelight(){
ctx.stokeStyle = "black";
ctx.lineWidth = 3;
// top light: red if cycle = 0 or 1, off otherwise
drawLight(0, cycle <= 1 ? 'red' : 'off');
// middle light: yellow if cycle = 3 (and 1 for UK lights, we have red+yellow before green), off otherwise
drawLight(1, cycle == 1 || cycle == 3 ? 'yellow' : 'off');
// bottom light: green if cycle = 2
drawLight(2, cycle == 2 ? 'green' : 'off');
// increment cycle
cycle = (cycle + 1) % 4;
}
// start the magic
setInterval(changelight,1000);
I would clean things up a bit... you can move all the drawing to one place. Then use a start and stop function. Actually, you can easily combine the start and stop but I will leave that to you. Here you go:
function light(c) {
this.current = 0;
this.colors = ["green", "yellow", "red"];
this.ctx = c.getContext("2d");
}
light.prototype.draw = function() {
this.ctx.beginPath();
this.ctx.arc(95, 50, 40, 0, 12 * Math.PI);
this.ctx.fillStyle = this.colors[this.current];
this.ctx.fill();
}
light.prototype.start = function() {
if(this.interval)
return;
this.draw();
this.interval = setInterval(function() {
this.current = (this.current + 1) % this.colors.length;
console.log("drawing: ", this.colors[this.current]);
this.draw();
}.bind(this), 3000);
}
light.prototype.stop = function() {
if (!this.interval)
return;
clearInterval(this.interval);
delete this.interval;
}
var myLight = new light(document.getElementById("myCanvas"));
<canvas id="myCanvas"></canvas>
<button onclick="myLight.start()">start</button>
<button onclick="myLight.stop()">stop</button>