I have an application that I have written that adds a set of traffic lights on the screen upon the press of a button. The traffic light automatically cycles from red to yellow after 10 seconds, then on to green after two seconds, then back to yellow after 10 seconds and finally back to red. I would like to add several of these traffic lights to the screen and have them operating at the same time, but when I add a second traffic light, the first traffic light's sequence is frozen at whatever state it has reached. Any ideas as to how to get it to continue to operate - and thus have more than one light cycling through the sequence at the same time?
The transition is controlled by javascript via a state machine.
Anyone have any ideas as to how to get this working smoothly?
Thanks!
Rob
London, UK
var i = 1;
var TrafficLight = function(i) {
var count = 0;
var light_container = document.getElementById('light-container-' + i);
var currentState = new Red(this, light_container);
this.change = function(state) {
currentState = state;
currentState.go();
}
this.start = function() {
currentState.go();
}
}
var Red = function(light, light_container) {
this.light = light;
this.go = function() {
light_container.querySelector('#inner-circle-red').style.backgroundColor = '#d8412c';
console.log(light_container);
setTimeout(function() {
light.change(new Yellow(light, 'red', light_container))
}, 10000);
}
}
var Yellow = function(light, origin, light_container) {
this.light = light;
this.go = function() {
light_container.querySelector('#inner-circle-yellow').style.backgroundColor = '#fad201';
setTimeout(function() {
if (origin == 'red') {
light.change(new Green(light, light_container));
light_container.querySelector('#inner-circle-red').style.backgroundColor = '#111111';
light_container.querySelector('#inner-circle-yellow').style.backgroundColor = '#111111';
} else if (origin == 'green') {
light.change(new Red(light, light_container));
light_container.querySelector('#inner-circle-yellow').style.backgroundColor = '#111111';
}
}, 2000);
}
}
var Green = function(light, light_container) {
this.light = light;
this.go = function() {
light_container.querySelector('#inner-circle-green').style.backgroundColor = '#33A532';
setTimeout(function() {
light.change(new Yellow(light, 'green', light_container))
light_container.querySelector('#inner-circle-green').style.backgroundColor = '#111111';
}, 10000);
}
};
function run() {
document.getElementById("container").innerHTML += '<div id="light-container-' + i + '"><div class="outer-circle-red"><div id="inner-circle-red"></div></div><div class="outer-circle-yellow"><div id="inner-circle-yellow"></div></div><div class="outer-circle-green"><div id="inner-circle-green"></div></div></div>';
var light = new TrafficLight(i);
light.start();
i++;
}
.outer-circle-red,
.outer-circle-yellow,
.outer-circle-green {
background-color: #696969;
border: 2px solid black;
width: 50px;
height: 40px;
border-radius: 15px;
display: table;
}
#light-container-1,
#light-container-2,
#light-container-3 {
margin-top: 20px;
float: left;
margin-left: 70px;
}
#inner-circle-red,
#inner-circle-yellow,
#inner-circle-green {
width: 20px;
height: 20px;
border-radius: 25px;
border: 2px solid #111111;
margin: 0 auto;
margin-top: 7.5px;
background-color: #111111;
}
#button {
width: 200px;
height: 20px;
padding: 10px;
background-color: blue;
color: #ffffff;
cursor: pointer;
}
<div id="button" onclick="run()">+ Add a new traffic light</div>
<div id="container">
</div>
One issue is, as Lewis already stated that you have multiple elements with the same id
. JavaScript can only handle one of those.
The other issue is that you delete the content of #container
by using innerHTML
. The references you have stored in your TrafficLight
, Red
, Yellow
, and Green
classes is then destroyed. The store works correctly, but it can't be seen so. Use the DOM manipulation instead.
var light_container = document.createElement('div');
light_container.id = "light-container-" + i;
light_container.innerHTML = '<div class="outer-circle-red"><div class="inner-circle-red"></div></div><div class="outer-circle-yellow"><div class="inner-circle-yellow"></div></div><div class="outer-circle-green"><div class="inner-circle-green"></div></div>';
document.getElementById("container").appendChild(light_container);
var i = 1;
var TrafficLight = function(i) {
var count = 0;
var light_container = document.getElementById('light-container-' + i);
var currentState = new Red(this, light_container);
this.change = function(state) {
currentState = state;
currentState.go();
}
this.start = function() {
currentState.go();
}
}
var Red = function(light, light_container) {
this.light = light;
this.go = function() {
light_container.querySelector('.inner-circle-red').style.backgroundColor = '#d8412c';
setTimeout(function() {
light.change(new Yellow(light, 'red', light_container))
}, 10000);
}
}
var Yellow = function(light, origin, light_container) {
this.light = light;
this.go = function() {
light_container.querySelector('.inner-circle-yellow').style.backgroundColor = '#fad201';
setTimeout(function() {
if (origin == 'red') {
light.change(new Green(light, light_container));
light_container.querySelector('.inner-circle-red').style.backgroundColor = '#111111';
light_container.querySelector('.inner-circle-yellow').style.backgroundColor = '#111111';
} else if (origin == 'green') {
light.change(new Red(light, light_container));
light_container.querySelector('.inner-circle-yellow').style.backgroundColor = '#111111';
}
}, 2000);
}
}
var Green = function(light, light_container) {
this.light = light;
this.go = function() {
light_container.querySelector('.inner-circle-green').style.backgroundColor = '#33A532';
setTimeout(function() {
light.change(new Yellow(light, 'green', light_container))
light_container.querySelector('.inner-circle-green').style.backgroundColor = '#111111';
}, 10000);
}
};
function run() {
var light_container = document.createElement('div');
light_container.id = "light-container-" + i;
light_container.innerHTML = '<div class="outer-circle-red"><div class="inner-circle-red"></div></div><div class="outer-circle-yellow"><div class="inner-circle-yellow"></div></div><div class="outer-circle-green"><div class="inner-circle-green"></div></div>';
document.getElementById("container").appendChild(light_container);
var light = new TrafficLight(i);
light.start();
i++;
}
.outer-circle-red,
.outer-circle-yellow,
.outer-circle-green {
background-color: #696969;
border: 2px solid black;
width: 50px;
height: 40px;
border-radius: 15px;
display: table;
}
[id^=light-container] {
margin-top: 20px;
float: left;
margin-left: 70px;
}
.inner-circle-red,
.inner-circle-yellow,
.inner-circle-green {
width: 20px;
height: 20px;
border-radius: 25px;
border: 2px solid #111111;
margin: 0 auto;
margin-top: 7.5px;
background-color: #111111;
}
#button {
width: 200px;
height: 20px;
padding: 10px;
background-color: blue;
color: #ffffff;
cursor: pointer;
}
<div id="button" onclick="run()">+ Add a new traffic light</div>
<div id="container">
</div>