elevator-state-machine's People
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';
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';
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.