Git Product home page Git Product logo

elevator-state-machine's People

Contributors

mymai91 avatar

Watchers

 avatar  avatar

elevator-state-machine's Issues

test 1

import React, { useState } from 'react';
import 'antd/dist/antd.css';
import './App.css';

import { useMachine } from '@xstate/react';
import { Machine, assign } from 'xstate';
import { Button, Card, Radio, Steps } from 'antd';

// https://xstate.js.org/viz/

const { Step } = Steps;

function App() {
const elevatorMachine = Machine(
{
id: 'elevator',
initial: 'stop',
context: {
level: 1,
chosenLevel: 1,
isError: false,
},
states: {
stop: {
// current is stop the transition only can up or down
// entry: 'checkValue',
on: {
UP: 'up',
DOWN: 'down',
},
},
down: {
// current is down the transition only can up or stop
on: {
PRESS_LEVEL: [
{
target: 'moving.go_down',
cond: 'pressLevelDownValidate',
actions: assign({
chosenLevel: (context, event) => +event.value,
}),
},
{ target: 'error.go_down' }
]
// PRESS_LEVEL: {
// target: 'moving.go_down',
// actions: assign({
// chosenLevel: (context, event) => +event.value,
// }),
// cond: 'pressLevelDownValidate',
// },
// ERROR: {
// actions: assign({
// isError: (context, event) => true,
// }),
// },
},
},
up: {
// current is up the transition only can down or up
on: {
PRESS_LEVEL: [
{
target: 'moving.go_up',
cond: 'pressLevelUpValidate',
actions: assign({
chosenLevel: (context, event) => +event.value,
}),
},
{ target: 'error.go_up' }
]
// PRESS_LEVEL: {
// target: 'moving.go_up',
// actions: assign({
// chosenLevel: (context, event) => +event.value,
// }),
// cond: 'pressLevelUpValidate',
// },
// ERROR: {
// actions: assign({
// isError: (context, event) => true,
// }),
// },
},
},
error: {
// initial: 'finished',
states: {
go_up: {
// activities: ['moving'],
// // actions: ['moving_up_action'],
// // exit: 'logScreenChange',
// entry: 'reachedLevel',
// on: {
// REACHED: 'reached',
// MOVING: {
// target: 'go_up',
// actions: assign({
// level: (context, event) => event.value + 1,
// }),
// cond: {
// type: 'isMoveUp',
// },
// },
// },
},
go_down: {
// activities: ['moving'],
// entry: 'reachedLevel',
// on: {
// REACHED: 'reached',
// MOVING: {
// target: 'go_down',
// actions: assign({
// level: (_context, event) => event.value - 1,
// }),
// cond: {
// type: 'isMoveDown',
// },
// },
// },
},
reached: {
after: [
{
delay: 1000,
target: 'finished',
},
],
},
finished: {
type: 'final',
},
},
onDone: 'stop',
},
moving: {
initial: 'finished',
states: {
go_up: {
activities: ['moving'],
// actions: ['moving_up_action'],
// exit: 'logScreenChange',
entry: 'reachedLevel',
on: {
REACHED: 'reached',
MOVING: {
target: 'go_up',
actions: assign({
level: (context, event) => event.value + 1,
}),
cond: {
type: 'isMoveUp',
},
},
},
},
go_down: {
activities: ['moving'],
entry: 'reachedLevel',
on: {
REACHED: 'reached',
MOVING: {
target: 'go_down',
actions: assign({
level: (_context, event) => event.value - 1,
}),
cond: {
type: 'isMoveDown',
},
},
},
},
reached: {
after: [
{
delay: 1000,
target: 'finished',
},
],
},
finished: {
type: 'final',
},
},
onDone: 'stop',
},
},
},
{
actions: {
reachedLevel: context => {
const { level, chosenLevel } = context;
if (level === chosenLevel) {
send('REACHED');
}
},
},
activities: {
moving: (context, _event) => {
let { level } = context;
setTimeout(() => {
return send({
type: 'MOVING',
value: level,
});
}, 1000);
},
},
guards: {
pressLevelDownValidate: (context, event, { cond }) => {
console.log('event', event.value);
const chosenLevel = event.value;
const { level } = context;
// if (chosenLevel > level) {
// send('ERROR');
// }
return chosenLevel < level;
},
pressLevelUpValidate: (context, event, { cond }) => {
console.log('event', event.value);
const chosenLevel = event.value;
const { level } = context;
// if (chosenLevel < level) {
// send('ERROR');
// }
return chosenLevel > level;
},
isMoveUp: (context, event, { cond }) => {
const { level, chosenLevel } = context;

      return level < chosenLevel;
    },
    isMoveDown: (context, event, { cond }) => {
      const { level, chosenLevel } = context;

      return chosenLevel < level;
    },
  },
},

);

const [tmpChosenLevel, setTmpChosenLevel] = useState(null);
const [current, send] = useMachine(elevatorMachine);
const { level, chosenLevel, isError } = current.context;

// console.log('current.value', current.value)
console.log('current.context outside chosenLevel', chosenLevel);

const handleGoUp = () => {
send('UP');
};

const handleGoDown = () => {
send('DOWN');
};

const handleChooseLevel = e => {
setTmpChosenLevel(e.target.value);
send({
type: 'PRESS_LEVEL',
value: e.target.value,
});
};

return (


<div style={{ margin: 50 }}>
<Button type="primary" onClick={() => handleGoUp()}>
Up

<Button type="danger" onClick={() => handleGoDown()}>
Down

  <Card title="Door" style={{ width: 300, margin: '0 auto', marginBottom: 50 }}>
    {current.matches('stop') && (
      <div>
        You are at level {level}
        <p>Door Close</p>
      </div>
    )}

    {current.matches({ moving: 'go_up' }) && (
      <div>
        <p>Current level {level}</p>
        <p>Moving up to level {chosenLevel}</p>
      </div>
    )}

    {current.matches({ moving: 'go_down' }) && (
      <div>
        <p>Current level {level}</p>
        <p>Moving down to level {chosenLevel}</p>
      </div>
    )}

    {current.matches({ moving: 'reached' }) && (
      <div>
        <p>Reached level {level}</p>
      </div>
    )}
    {current.matches('up') && (
      <div>
        <p>Press Go Up</p>
        <p>Door opened</p>
        <p>Please Press Level</p>
      </div>
    )}

    {current.matches('down') && (
      <div>
        <p>Press Go Down</p>
        <p>Door opened</p>
        <p>Please Press Level</p>
      </div>
    )}

    {current.matches('error.go_up') && (
      <div>
        You are at level {level}
        <p>Can not go up to level {tmpChosenLevel}</p>
      </div>
    )}

    {current.matches('error.go_down') && (
      <div>
        You are at level {level}
        <p>Can not go down to level {tmpChosenLevel}</p>
      </div>
    )}

    {/* {current.matches('up') && (
      <div>
        {isError ? (
          <div>
            You are at level {level}
            <p>Can not go up to level {tmpChosenLevel}</p>
          </div>
        ) : (
            <div>
              <p>Press Go Up</p>
              <p>Door opened</p>
              <p>Please Press Level</p>
            </div>
          )}
      </div>
    )} */}

    {/* {current.matches('down') && (
      <div>
        {isError ? (
          <div>
            You are at level {level}
            <p>Can not go down to level {tmpChosenLevel}</p>
          </div>
        ) : (
            <div>
              <p>Press Go Down</p>
              <p>Door opened</p>
              <p>Please Press Level</p>
            </div>
          )}
      </div>
    )} */}
  </Card>

  <Card title="Elevator" style={{ width: 300, margin: '0 auto' }}>
    <Radio.Group defaultValue="1" buttonStyle="solid" onChange={e => handleChooseLevel(e)}>
      <Radio.Button value="1">1</Radio.Button>
      <Radio.Button value="2">2</Radio.Button>
      <Radio.Button value="3">3</Radio.Button>
      <Radio.Button value="4">4</Radio.Button>
      <Radio.Button value="5">5</Radio.Button>
    </Radio.Group>
    <div style={{ marginTop: 50 }}>
      <Steps direction="vertical" size="small" current={level - 1}>
        <Step title="Level 1" />
        <Step title="Level 2" />
        <Step title="Level 3" />
        <Step title="Level 4" />
        <Step title="Level 5" />
      </Steps>
    </div>
  </Card>
</div>

);
}

export default App;

test

import React, { useState } from 'react';
import 'antd/dist/antd.css';
import './App.css';

import { useMachine } from '@xstate/react';
import { Machine, assign } from 'xstate';
import { Button, Card, Radio, Steps } from 'antd';

// https://xstate.js.org/viz/

const { Step } = Steps;

function App() {
  let elevatorTransition = null;
  let currentFloor = null;
  const elevatorMachine = Machine(
    {
      id: 'elevator',
      initial: 'stop',
      context: {
        level: 1,
        chosenLevel: 1,
      },
      states: {
        stop: {
          // current is stop the transition only can up or down
          on: {
            UP: 'up',
            DOWN: 'down',
          },
        },
        down: {
          // current is down the transition only can up or stop
          on: {
            // UP: 'up',
            // STOP: 'stop',
            PRESS_LEVEL: {
              target: 'moving.go_down',
              actions: assign({
                level: (context, event) => event.value
              }),
            },
          },
        },
        up: {
          // current is up the transition only can down or up
          on: {
            // DOWN: 'down',
            // STOP: 'stop',
            PRESS_LEVEL: {
              target: 'moving.go_up',
              actions: assign({
                chosenLevel: (context, event) => +event.value,
              }),
            },
          },
        },
        moving: {
          initial: 'reached',
          states: {
            go_up: {
              activities: ['moving_up'],
              // exit: 'logScreenChange',
              // entry: 'moving_up_action',
              on: {
                REACHED: 'reached',
                MOVING: {
                  actions: assign({
                    level: (context, event) => event.value,
                  }),
                  // cond: {
                  //   type: 'movingUpValidate',
                  // }
                },
              },
            },
            go_down: {
              on: {
                REACHED: 'reached',
              },
            },
            wait: {
              on: {
                REACHED: 'reached',
              },
            },
            reached: {
              activities: ['clearElevatorTransition'],
              type: 'final',
            },
          },
          onDone: 'stop'
        },
      },
    },
    {
      actions: {
        moving_up_action: () => {
          currentFloor = level;
          console.log('current.context inside', current.context)
          elevatorTransition = setInterval(() => {
            currentFloor = currentFloor + 1;
            return send({
              type: 'MOVING',
              value: currentFloor,
            });
          }, 1000);
        }
      },
      activities: {
        moving_up: () => {
          currentFloor = level;
          console.log('current.context inside', current.context)
          elevatorTransition = setInterval(() => {
            currentFloor = currentFloor + 1;
            return send({
              type: 'MOVING',
              value: currentFloor,
            });
          }, 1000);
        },
        clearElevatorTransition: () => {
          send('STOP');
          return () => clearInterval(elevatorTransition);
        },
      },
      guards: {
        movingUpValidate: (context, event, { cond }) => {
          console.log('context', context)
        }
      }
    },
  );

  const [current, send] = useMachine(elevatorMachine);
  const { level, chosenLevel } = current.context;

  // console.log('current.value', current.value)
  console.log('current.context outside', current.context)


  if (current.matches('moving') && level === chosenLevel) {
    send('REACHED');
  }

  const handleGoUp = () => {
    send('UP');
  };

  const handleGoDown = () => {
    send('DOWN');
  };

  const handleChooseLevel = e => {
    send({
      type: 'PRESS_LEVEL',
      value: e.target.value,
    });
  };

  return (
    <div className="App">
      <div style={{ margin: 50 }}>
        <Button type="primary" onClick={() => handleGoUp()}>
          Up
        </Button>
        <Button type="danger" onClick={() => handleGoDown()}>
          Down
        </Button>
      </div>

      <Card title="Door" style={{ width: 300, margin: '0 auto', marginBottom: 50 }}>
        {current.matches('stop') && (
          <div>
            You are at level {level}
            <p>Door Close</p>
          </div>
        )}

        {current.matches({ moving: 'go_up' }) && (
          <div>
            <p>Current level {level}</p>
            <p>Moving up to level {chosenLevel}</p>
          </div>
        )}

        {current.matches({ moving: 'reached' }) && (
          <div>
            <p>Reached level {level}</p>
          </div>
        )}

        {current.matches('up') && <p>Go Up</p>}
        {current.matches('down') && <p>Go Down</p>}
      </Card>

      <Card title="Elevator" style={{ width: 300, margin: '0 auto' }}>
        <Radio.Group defaultValue="1" buttonStyle="solid" onChange={e => handleChooseLevel(e)}>
          <Radio.Button value="1">1</Radio.Button>
          <Radio.Button value="2">2</Radio.Button>
          <Radio.Button value="3">3</Radio.Button>
          <Radio.Button value="4">4</Radio.Button>
          <Radio.Button value="5">5</Radio.Button>
        </Radio.Group>
        <div style={{ marginTop: 50 }}>
          <Steps direction="vertical" size="small" current={level - 1}>
            <Step title="Level 1" description="This is a description." />
            <Step title="Level 2" description="This is a description." />
            <Step title="Level 3" description="This is a description." />
            <Step title="Level 4" description="This is a description." />
            <Step title="Level 5" description="This is a description." />
          </Steps>
        </div>
      </Card>

      {/* <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header> */}
    </div>
  );
}

export default App;

test3

import React, { useState } from 'react';
import 'antd/dist/antd.css';
import './App.css';

import { useMachine } from '@xstate/react';
import { Machine, assign } from 'xstate';
import { Icon, Card, Radio, Row, Col, Layout } from 'antd';

// https://xstate.js.org/viz/

function App() {
const elevatorMachine = Machine(
{
id: 'elevator',
initial: 'stop',
context: {
level: 1,
chosenLevel: 1,
direction: '',
isDisablePressLevelBtn: true,
doorStatus: 'close',
},
states: {
stop: {
// current is stop the transition only can up or down
on: {
UP: {
target: 'up',
actions: assign({
direction: (context, event) => 'up',
isDisablePressLevelBtn: false,
doorStatus: 'open',
}),
},
DOWN: {
target: 'down',
actions: assign({
direction: (context, event) => 'down',
isDisablePressLevelBtn: false,
doorStatus: 'open',
}),
},
},
},
down: {
// current is down the transition only can up or stop
id: 'elevator_down',
on: {
PRESS_LEVEL: [
{
target: 'moving.go_down',
cond: 'pressLevelDownValidate',
actions: assign({
chosenLevel: (context, event) => +event.value,
doorStatus: 'close',
}),
},
{
target: 'error.go_down',
actions: assign({
chosenLevel: (context, event) => +event.value,
doorStatus: 'close',
}),
},
],
},
},
up: {
// current is up the transition only can down or up
id: 'elevator_up',
on: {
PRESS_LEVEL: [
{
target: 'moving.go_up',
cond: 'pressLevelUpValidate',
actions: assign({
chosenLevel: (context, event) => +event.value,
doorStatus: 'close',
}),
},
{
target: 'error.go_up',
actions: assign({
chosenLevel: (context, event) => +event.value,
doorStatus: 'close',
}),
},
],
},
},
error: {
states: {
go_up: {
entry: 'errorPressDirection',

          on: {
            REACHED: {
              target: '#elevator_moving.go_down',
              actions: assign({
                direction: (context, event) => 'down',
              }),
            },
          },
        },
        go_down: {
          entry: 'errorPressDirection',

          on: {
            REACHED: {
              target: '#elevator_moving.go_up',
              actions: assign({
                direction: (context, event) => 'up',
              }),
            },
          },
        },
      },
    },
    moving: {
      id: 'elevator_moving',
      initial: 'finished',
      states: {
        go_up: {
          activities: ['moving'],
          entry: 'reachedLevel',
          on: {
            REACHED: 'reached',
            MOVING: {
              target: 'go_up',
              actions: assign({
                level: (context, event) => event.value + 1,
              }),
              cond: {
                type: 'isMoveUp',
              },
            },
          },
        },
        go_down: {
          activities: ['moving'],
          entry: 'reachedLevel',
          on: {
            REACHED: 'reached',
            MOVING: {
              target: 'go_down',
              actions: assign({
                level: (_context, event) => event.value - 1,
              }),
              cond: {
                type: 'isMoveDown',
              },
            },
          },
        },
        reached: {
          entry: assign({
            doorStatus: 'open',
          }),
          after: {
            1000: 'finished'
          }
          // after: [
          //   {
          //     actions: assign({
          //       doorStatus: 'open',
          //     }),
          //   },
          //   {
          //     delay: 1000,
          //     target: 'finished',
          //   },
          // ],
        },
        finished: {
          type: 'final',
        },
      },
      onDone: {
        target: 'stop',
        actions: assign({
          direction: (_context, _event) => '',
          isDisablePressLevelBtn: true,
          doorStatus: 'close',
        }),
      },
    },
  },
},
{
  actions: {
    reachedLevel: context => {
      const { level, chosenLevel } = context;
      if (level === chosenLevel) {
        send('REACHED');
      }
    },
    errorPressDirection: context => {
      setTimeout(() => {
        return send('REACHED');
      }, 1000);
    },
  },
  activities: {
    moving: (context, _event) => {
      console.log('MOVING');
      let { level } = context;
      setTimeout(() => {
        return send({
          type: 'MOVING',
          value: level,
        });
      }, 1000);
    },
  },
  guards: {
    pressLevelDownValidate: (context, event, { cond }) => {
      const chosenLevel = event.value;
      const { level } = context;

      return chosenLevel < level;
    },
    pressLevelUpValidate: (context, event, { cond }) => {
      const chosenLevel = event.value;
      const { level } = context;

      return chosenLevel > level;
    },
    isMoveUp: (context, event, { cond }) => {
      const { level, chosenLevel } = context;

      return level < chosenLevel;
    },
    isMoveDown: (context, event, { cond }) => {
      const { level, chosenLevel } = context;

      return chosenLevel < level;
    },
  },
},

);

const [tmpChosenLevel, setTmpChosenLevel] = useState(null);
const [current, send] = useMachine(elevatorMachine);
const { level, chosenLevel, direction, isDisablePressLevelBtn, doorStatus } = current.context;

// console.log('current.value', current.value)
console.log('current.context outside direction', current.context);

const handlePressUpDown = e => {
if (e.target.value === 'up') {
send('UP');
} else {
send('DOWN');
}
};

const handleChooseLevel = e => {
setTmpChosenLevel(e.target.value);
send({
type: 'PRESS_LEVEL',
value: e.target.value,
});
};

const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};

return (





<h2 style={{ color: '#333', fontSize: 32 }}>Elevator

{current.matches('stop') && (

You are at level {level}


Door Close



)}

          {current.matches({ moving: 'go_up' }) && (
            <div>
              <h3>Going Up</h3>
              <p>Current level {level}</p>
              <p>Moving up to level {chosenLevel}</p>
            </div>
          )}

          {current.matches({ moving: 'go_down' }) && (
            <div>
              <h3>Going Down</h3>
              <p>Current level {level}</p>
              <p>Moving down to level {chosenLevel}</p>
            </div>
          )}

          {current.matches({ moving: 'reached' }) && (
            <div>
              <p>Reached level {level}</p>
            </div>
          )}
          {current.matches('up') && (
            <div>
              <p>Press Go Up</p>
              <p>Door opened</p>
              <p>Please Press Level</p>
            </div>
          )}

          {current.matches('down') && (
            <div>
              <p>Press Go Down</p>
              <p>Door opened</p>
              <p>Please Press Level</p>
            </div>
          )}

          {current.matches('error.go_up') && (
            <div>
              <h2>ERROR</h2>
              You are at level {level}
              <p>Can not go up to level {tmpChosenLevel}</p>
            </div>
          )}

          {current.matches('error.go_down') && (
            <div>
              <h2>ERROR</h2>
              You are at level {level}
              <p>Can not go down to level {tmpChosenLevel}</p>
            </div>
          )}
        </div>
      </div>
    </Col>
  </Row>
  <Row type="flex" justify="center" align="middle">
    <Col span={2}>
      <div style={{ margin: 50 }}>
        <Radio.Group
          value={direction}
          onChange={e => handlePressUpDown(e)}
          className="pressUpDownBtn"
        >
          <Radio.Button className="radioOpenDoorStyle" value="up">
            <Icon type="up-circle" style={{ fontSize: '30px', color: '#08c' }} />
          </Radio.Button>
          <Radio.Button className="radioOpenDoorStyle" value="down">
            <Icon type="down-circle" style={{ fontSize: '30px', color: '#08c' }} />
          </Radio.Button>
        </Radio.Group>
      </div>
    </Col>
    <Col span={8}>
      <div className="elevator">
        <div className="">
          <Row type="flex" justify="space-around" align="middle">
            <Col span={12}>
              <div>
                <div className="direction-wrapper">
                  {current.matches({ moving: 'go_down' }) && (
                    <div className="direction-container">
                      <div className="chevron chevron-down"></div>
                      <div className="chevron chevron-down"></div>
                      <div className="chevron chevron-down"></div>
                    </div>
                  )}

                  {current.matches({ moving: 'go_up' }) && (
                    <div className="direction-container">
                      <div className="chevron chevron-up"></div>
                      <div className="chevron chevron-up"></div>
                      <div className="chevron chevron-up"></div>
                    </div>
                  )}
                </div>
                <p style={{ fontSize: 60, margin: 0 }}>{level}</p>
              </div>
            </Col>
          </Row>
        </div>
        <div className="stage">
          <div className="stage-content" style={{ height: 500 }}>
            <Radio.Group
              className="state-group-button"
              defaultValue="1"
              buttonStyle="solid"
              onChange={e => handleChooseLevel(e)}
              disabled={isDisablePressLevelBtn}
            >
              <Radio.Button style={radioStyle} value="5">
                5
              </Radio.Button>
              <Radio.Button style={radioStyle} value="4">
                4
              </Radio.Button>
              <Radio.Button style={radioStyle} value="3">
                3
              </Radio.Button>
              <Radio.Button style={radioStyle} value="2">
                2
              </Radio.Button>
              <Radio.Button style={radioStyle} value="1">
                1
              </Radio.Button>
            </Radio.Group>
          </div>
          <label className={`${doorStatus} curtain-container`}>
            <div className="curtain-panel">
              <div className={`${doorStatus} left-curtain curtain`}></div>
              <div className={`${doorStatus} right-curtain curtain`}></div>
            </div>
          </label>
        </div>
      </div>
    </Col>
  </Row>
</div>

);
}

export default App;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.