停止有限状态机

时间:2019-06-14 13:53:04

标签: javascript html state-machine

我有一个编写的应用程序,可以在按下按钮时在屏幕上添加一组交通信号灯。交通灯会在10秒钟后自动从红色变为黄色,然后在两秒钟后变为绿色,然后在10秒钟后恢复为黄色,最后变为红色。我添加了一个控件,该控件允许用户单独启动每个交通信号灯。我试图弄清楚如何使用户能够永久停止每个交通信号灯,而不停止其他所有信号灯。

到目前为止,这是我更新的代码-请注意在var Red内部添加了'this.stop()'函数。我希望代码在此停止旋转,而不是继续变为黄色和绿色。

谢谢

Rob

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();
  }

  this.stop = function() {
    currentState.stop();
  }

}

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))
    }, 12000);
  }

  this.stop = function() {
    light_container.querySelector('.inner-circle-red').style.backgroundColor = '#111111';
    light_container.querySelector('.inner-circle-yellow').style.backgroundColor = '#111111';
    light_container.querySelector('.inner-circle-green').style.backgroundColor = '#111111';
    // Switch all the lights off.
    return;
  }
}

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;
  console.log('here');
  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';
    }, 14000);
  }
};


function initiate() {
  var light_container = document.createElement('div');
  light_container.id = "light-container-" + i;
  light_container.className = "light-container";
  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><label class="switch"><input type="checkbox" class="off" onclick="toggleRun(this, ' + i + ');"><span class="slider round"></span></label>';
  document.getElementById("container").appendChild(light_container);
  i++;
}

function toggleRun(item, i) {
  if (item.className == "off") {
    item.className = "on";
    run(i);
  } else {
    item.className = "off";
    stop(i);
  }
}

function run(i) {

  var light = new TrafficLight(i);

  light.start();

}

function stop(i) {
  var light = new TrafficLight(i);
  light.stop();
}

function exit(status) {

  var i;

  if (typeof status === 'string') {
    alert(status);
  }

  window.addEventListener('error', function(e) {
    e.preventDefault();
    e.stopPropagation();
  }, false);

  var handlers = [
    'copy', 'cut', 'paste',
    'beforeunload', 'blur', 'change', 'click', 'contextmenu', 'dblclick', 'focus', 'keydown', 'keypress', 'keyup', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'resize', 'scroll',
    'DOMNodeInserted', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument', 'DOMNodeInsertedIntoDocument', 'DOMAttrModified', 'DOMCharacterDataModified', 'DOMElementNameChanged', 'DOMAttributeNameChanged', 'DOMActivate', 'DOMFocusIn', 'DOMFocusOut', 'online', 'offline', 'textInput',
    'abort', 'close', 'dragdrop', 'load', 'paint', 'reset', 'select', 'submit', 'unload'
  ];



  function stopPropagation(e) {
    e.stopPropagation();
    // e.preventDefault(); // Stop for the form controls, etc., too?
  }
  for (i = 0; i < handlers.length; i++) {
    window.addEventListener(handlers[i], function(e) {
      stopPropagation(e);
    }, true);
  }

  if (window.stop) {
    window.stop();
  }

  throw '';
}
#button {
  width: 200px;
  height: 20px;
  padding: 10px;
  background-color: blue;
  color: #ffffff;
  cursor: pointer;
}

.button {
  width: 15px;
  height: 20px;
  padding: 10px;
  background-color: red;
  color: #ffffff;
  cursor: pointer;
  margin: 20px auto;
  text-align: center;
  text-transform: uppercase;
  font-weight: bold;
}

.outer-circle-red,
.outer-circle-yellow,
.outer-circle-green {
  background-color: #696969;
  margin: 0 auto;
  border: 2px solid black;
  width: 50px;
  height: 40px;
  border-radius: 15px;
  display: table;
}

.light-container {
  margin: 20px 30px 0 30px;
  margin-top: 20px;
  float: left;
}

.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;
}


/* The switch - the box around the slider */

.switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
  margin-top: 20px;
}


/* Hide default HTML checkbox */

.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}


/* The slider */

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked+.slider {
  background-color: #2196F3;
}

input:focus+.slider {
  box-shadow: 0 0 1px #2196F3;
}

input:checked+.slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(26px);
}


/* Rounded sliders */

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}
<div id="button" onclick="initiate()">+ Add a new traffic light</div>

<div id="container">

</div>

1 个答案:

答案 0 :(得分:0)

解决方案是保存var id = setTimeout()返回的ID,以便以后可以使用clearTimeout( id );完全停止超时功能再次触发。

例如:this.timeout = setInterval(function(){ /* insert the color changing code */ }, 10000 );

如果选择这种解决方案,将超时代码放入单个超时中而不是为每种颜色使用单独的类将很方便。但是,如果您希望每种颜色都有不同的超时时间,则可以始终使用数组来存储所有超时,并循环使用该数组来取消。