Garacesh Posted February 8, 2017 Posted February 8, 2017 (edited) So apparently as part of the Computing course, our kids have to program a traffic light in Javascript. Stage 1 is programming it to operate each stage on button-click (red, red-amber, green, amber) Red.jpg Start Sequence <br /> var lightStage = [<br /> "Red Amber.jpg",<br /> "Green.jpg",<br /> "Amber.jpg",<br /> "Red.jpg",<br /> ];<br /> var seqPos = 0;<br /> function changeTraffic() {<br /> var lightImage = document.getElementById('lightImg')<br /> lightImage.src=lightStage[seqPos];<br /> ++seqPos<br /> if (seqPos >= lightStage.length) seqPos = 0;<br /> }<br /> Every time someone clicks 'Start Sequence', it progresses through, as it should. Once seqPos gets too high, it is reset to 0. Second stage is that they have to click a button to start the sequence, which will then run automatically until they click a button that stops the sequence. This is where the Computing staff are having difficulty, so they've passed it to me and I can't figure it out, either. <br /> var lightStage = [<br /> "Red Amber.jpg",<br /> "Green.jpg",<br /> "Amber.jpg",<br /> "Red.jpg",<br /> ];<br /> var seqPos = 0;<br /> function changeTraffic() {<br /> for (seqPos = 0; seqPos < 4; seqPos++) {<br /> var lightImage = document.getElementById('lightImg')<br /> lightImage.src=lightStage[seqPos];<br /> setTimeout(changeTraffic, 2000);<br /> }<br /> }<br /> Now, this works, in a fashion. It runs through the loop successfully, but since there's no pause/wait/sleep/etc, it appears to instantly run through the sequence back to red (so it doesn't look like it's doing anything, but it is, confirmed by changing red.jpg in the list to something else.) Closest I've managed to get is a 'good enough' multiple functions <br /> function changeTraffic() {<br /> setTimeout(RedAmberLight, 2000);<br /> setTimeout(GreenLight, 4000);<br /> setTimeout(AmberLight, 6000);<br /> setTimeout(RedLight, 8000);<br /> }<br /> function RedAmberLight() {<br /> var image = document.getElementById('Light');<br /> image.src="Red Amber.jpg";<br /> }<br /> function GreenLight() {<br /> var image = document.getElementById('Light');<br /> image.src="Green.jpg";<br /> }<br /> function AmberLight() {<br /> var image = document.getElementById('Light');<br /> image.src="Amber.jpg";<br /> }<br /> function RedLight() {<br /> var image = document.getElementById('Light');<br /> image.src="Red.jpg";<br /> }<br /> But surely there's got to be a better way? Edited February 8, 2017 by Garacesh
webman Posted February 8, 2017 Posted February 8, 2017 Here's my attempt at this challenge Tried to keep it simple and with comments where necessary. Start Sequence Stop Sequence <br /> var TrafficLights = (function() {<br /> <br /> // The image<br /> var imageTag = document.getElementById("lightImg");<br /> // Keep track of whether the sequence is running<br /> var running = false;<br /> // The number of seconds between light changes<br /> var interval = 1;<br /> // Different stages of the traffic light<br /> var stages = [<br /> "Red.jpg",<br /> "Red Amber.jpg",<br /> "Green.jpg",<br /> "Amber.jpg"<br /> ];<br /> // Current stage of the traffic light<br /> var stage = 0;<br /> // Timer for automatically changing light<br /> var timer = null;<br /> <br /> /**<br /> * Start the traffic light sequence<br /> *<br /> */<br /> function start() {<br /> // Mark that the light sequence is running<br /> running = true;<br /> // Tell the light to change<br /> changeLight();<br /> }<br /> <br /> /**<br /> * Stop the sequence from running<br /> *<br /> */<br /> function stop() {<br /> // Mark that the sequence is not running<br /> running = false;<br /> // Stop the automatic timer from running<br /> clearInterval(timer);<br /> }<br /> <br /> /**<br /> * Change the light to the next one in the sequence<br /> *<br /> */<br /> function changeLight() {<br /> <br /> // If the timer is not running, this function does not need to do anything<br /> if (running === false) {<br /> clearInterval(timer);<br /> return;<br /> }<br /> <br /> // If the current stage gets higher than the nubmer of stages there are, reset to 0<br /> if (stage >= stages.length) {<br /> stage = 0;<br /> }<br /> <br /> // Get the image from the list of stages<br /> var image = stages[stage];<br /> // Update the image tag<br /> imageTag.src = image;<br /> imageTag.alt = image;<br /> // Increase the current stage by 1<br /> stage++;<br /> // Set a timeout to change the light at the next interval<br /> timer = setTimeout(changeLight, interval * 1000);<br /> }<br /> <br /> // These functions will be available on the `TrafficLights` object to allow interaction<br /> return {<br /> start: start,<br /> stop: stop<br /> }<br /> <br /> })();<br /> 2
Garacesh Posted February 8, 2017 Author Posted February 8, 2017 Wow, you're serious? All that just because it doesn't have a sleep()? I've passed it on to the teacher in question. Thanks a bunch. I'd have thought that if the exam board want kids to be coding something, they would have provided their own examples of it being done 'properly' to mark against? Apparently not.
Zamy_Arkre_Nendmed Posted March 19, 2018 Posted March 19, 2018 (edited) Traffic Lights can't always be the same duration in every light.... So, i started to expand this html code.. The improved code with different seconds in every light (Credits from Webman): Start Sequence Stop Sequence <br /> // Traffic Lights v1.1 (From Webman)<br /> // Thank you very much (Webman) for creating such impressive ideas!<br /> // Improved with different durations in every light!<br /> // But in this script, i will use input tag instead<br /> var TrafficLights = (function() { <br /> // The image <br /> var imageTag = document.getElementById("lightImg"); <br /> // Keep track of whether the sequence is running <br /> var running = false; <br /> // Different stages of the traffic light (Also defines the light) <br /> var stages = [ <br /> { <br /> "name": "green", <br /> "path": "green.jpg" <br /> }, <br /> { <br /> "name": "yellow", <br /> "path": "yellow.jpg" <br /> }, <br /> { <br /> "name": "red", <br /> "path": "red.jpg" <br /> } <br /> ]; <br /> // Different amount of seconds in every light change (Must be an positive integer!)<br /> var seconds_every_step = [<br /> 6, <br /> 1, <br /> 4 <br /> ]; <br /> // Current stage of the traffic light <br /> var stage = 0; <br /> // Current steps of the traffic light <br /> var steps = 0; <br /> // Timer for automatically changing light <br /> var timer = null; <br /> /** * Start the traffic light sequence * */ <br /> function start() { <br /> // Mark that the light sequence is running <br /> running = true; <br /> // Tell the light to change <br /> changeLight(); <br /> } <br /> <br /> /** * Stop the sequence from running * */ <br /> function stop() {<br /> // Mark that the sequence is not running <br /> running = false; <br /> // Stop the automatic timer from running <br /> clearInterval(timer); <br /> } <br /> <br /> /** * Change the light to the next one in the sequence * */<br /> function changeLight() { <br /> // If the timer is not running, this function does not need to do anything <br /> if (running === false) { <br /> clearInterval(timer); <br /> return; <br /> } <br /> else { <br /> };<br /> <br /> // If the current stage gets higher than the number of stages there are, reset to 0 <br /> if (stage >= stages.length) { <br /> stage = 0; <br /> } <br /> else { <br /> }; <br /> // If the current steps gets higher than the number of seconds in a step there are, reset to 0 <br /> if (steps >= seconds_every_step.length) {<br /> steps = 0;<br /> } <br /> else {<br /> }; <br /> <br /> // Get the image from the list of stages <br /> var image = stages[stage]; <br /> var wait_seconds = seconds_every_step[steps];<br /> // Update the image tag and defines the light name<br /> imageTag.src = image.path;<br /> imageTag.alt = String("Traffic light color is " + image.name + "."); <br /> <br /> // Increase the current stage by 1 <br /> stage++; <br /> // Increase the current steps by 1 <br /> steps++; <br /> // Set a timeout to change the light at the next interval <br /> timer = setTimeout(changeLight, wait_seconds * 1000); <br /> } <br /> // These functions will be available on the `TrafficLights` object to allow interaction <br /> return { <br /> start: start, <br /> stop: stop <br /> }<br /> })();<br /> Notes! If the variable "seconds_every_step" is more than 3 lengths like this: var seconds_every_step = [ 20, 40, 32, 5 ] It means that the every light based on the variable "stage" will return like this: Green light: 20 seconds, Yellow light: 40 seconds, Red light: 32 seconds, Green light: 5 seconds, Yellow light: 20 seconds (repeated step), Red light: 40 seconds, ... Edited March 19, 2018 by Zamy_Arkre_Nendmed Want to add more statements...
spadam Posted March 20, 2018 Posted March 20, 2018 Sorry, just stumbled across this before turning in and thought I'd chip in. Webman's solution is a good one with a few nice features but your first attempt was actually pretty close to a minimalist solution. Just do away with the for loop in the function that changes the image and it should behave more as you expect (i.e. only advance the image one stage each time the function is called). Here's an example of something similar that you can play with: Cycle /div> <br /> var stages = [<br /> 'red','orange','green'<br /> ];<br /> var current_stage = 0;<br /> var panel = document.getElementById('panel');<br /> function cycle(){<br /> if(current_stage >= stages.length) current_stage = 0;<br /> panel.style.background = stages[current_stage];<br /> current_stage++;<br /> setTimeout(cycle, 1000);<br /> }<br /> 1
ReadTheNetwork Posted March 20, 2018 Posted March 20, 2018 (edited) Here's my attempt (expanding @spadam): Cycle <br /> var stage = 0;<br /> var red = document.getElementById('red');<br /> var amber = document.getElementById('amber');<br /> var green = document.getElementById('green');<br /> function cycle() {<br /> switch(stage) {<br /> case 0:<br /> red.style.background = 'red';<br /> amber.style.background = 'black';<br /> break;<br /> case 1:<br /> amber.style.background = 'orange'; <br /> break;<br /> case 2:<br /> green.style.background = 'green';<br /> red.style.background = 'black';<br /> amber.style.background = 'black';<br /> break;<br /> case 3:<br /> green.style.background = 'green';<br /> break;<br /> case 4:<br /> green.style.background = 'black';<br /> amber.style.background = 'orange';<br /> }<br /> (stage==4) ? stage=0 : stage++; // a fancy way to do - if(stage==4){stage=0} else{stage++;}<br /> setTimeout(cycle, 1000);<br /> }<br /> Edited March 20, 2018 by ReadTheNetwork
spadam Posted March 23, 2018 Posted March 23, 2018 Nice addition.. Stick border-radius: 25px; on those divs and it's almost the real thing! 1
ReadTheNetwork Posted March 23, 2018 Posted March 23, 2018 Nice addition.. Stick border-radius: 25px; on those divs and it's almost the real thing! Better? - even added some flair <br /> #back {<br /> width: 75px;<br /> height: 180px;<br /> background: black;<br /> text-align: center;<br /> }<br /> div.light {<br /> transition: background-color 0.5s ease;<br /> margin: auto;<br /> width:50px; <br /> height:50px; <br /> background: grey;<br /> border-radius: 25px;<br /> padding: 5px;<br /> }<br /> Cycle <br /> var stage = 0;<br /> var red = document.getElementById('red');<br /> var amber = document.getElementById('amber');<br /> var green = document.getElementById('green');<br /> function cycle() {<br /> switch(stage) {<br /> case 0:<br /> red.style.background = 'red';<br /> amber.style.background = 'grey';<br /> break;<br /> case 1:<br /> amber.style.background = 'orange'; <br /> break;<br /> case 2:<br /> green.style.background = 'green';<br /> red.style.background = 'grey';<br /> amber.style.background = 'grey';<br /> break;<br /> case 3:<br /> green.style.background = 'green';<br /> break;<br /> case 4:<br /> green.style.background = 'grey';<br /> amber.style.background = 'orange';<br /> }<br /> (stage==4) ? stage=0 : stage++; // a fancy way to do - if(stage==4){stage=0} else{stage++;}<br /> setTimeout(cycle, 1500);<br /> }<br /> 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now