Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Completed #10

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Lift-Simulation
Create a web app where you can simulate lift mechanics for a client

## [Resources referred](https://github.com/vikhyat187/Lift-Simulation/blob/dev/links.md)
# UI Example
![Lift Simulation Example](Lift-Simulation-Example.png "Lift Simulation Example")

Expand Down
25 changes: 25 additions & 0 deletions links.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[screen.width vs window.width](https://stackoverflow.com/questions/37443482/what-is-the-difference-between-window-innerwidth-and-screen-width)

[screen.width vs screen.availWidth](https://stackoverflow.com/questions/5456582/screen-width-and-screen-availwidth-difference-in-javascript)

[dom manipulation js](https://www.section.io/engineering-education/dom-manipulation-with-javascript/)

[real vs virtual dom](https://www.mindbowser.com/react-virtual-dom-vs-real-dom/)

[set attribute](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute)

[spread operator ...](https://codeburst.io/what-are-three-dots-in-javascript-6f09476b03e1)

[translateY](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateY)

[getBoundingClient](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect)

[get width and height of element](https://stackoverflow.com/questions/294250/how-do-i-retrieve-an-html-elements-actual-width-and-height)

[css transform and transition](https://www.lambdatest.com/blog/css-transforms-and-transitions-property/#:~:text=So%2C%20what's%20the%20difference%20between,from%20one%20state%20to%20another.)

[for creating doors](https://developer.mozilla.org/en-US/docs/Web/CSS/inset-inline-start)

[== vs ===](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#:~:text=%3D%3D%3D%20%E2%80%94%20strict%20equality%20(triple%20equals,%E2%80%94%20loose%20equality%20(double%20equals))

[transitionend event js](https://developer.mozilla.org/en-US/docs/Web/API/Element/transitionend_event)
128 changes: 128 additions & 0 deletions src/css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
.form{
display: flex;
align-items: center;
gap: 1rem;
flex-direction: column;
flex-basis: content;
}

.input-group{
display: flex;
justify-content: space-between;
gap: 8px;
}

.floors-generated{
margin: 8px;
display: flex;
flex-direction: column;
}

.floor{
height: 8rem;
display: flex;
flex-direction: column;
justify-content: end;
border-bottom: 1px solid black;
}

.floor-container{
display: flex;
align-items: flex-end;
gap: 4rem;
height: 100%;
}

.lift-buttons{
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
gap: 4px;
}

.lift-buttons > button{
padding: 4px 8px;
border-radius: 2px;
font-weight: bold;
border: 2px transparent;
background-color: rgb(85, 156, 149);
color: black;
}

.lifts{
display: flex;
gap: 2rem;
}

.lift{
width: 4rem;
height: 5rem;
background-color: black;
border: 1px solid black;
position: relative;
overflow: hidden;

}

.lift::before{
content: '';
display: block;
position: absolute;
block-size: 100%;
inset-inline-start: 0.5px;
inline-size: 49%;
background-color: cyan;
}

.lift::after{
content: '';
display: block;
position: absolute;
inset-inline-end: 0.5px;
inline-size: 48%;
block-size: 100%;
background-color: cyan;
}

.door-operation::before{
animation: left-door 5000ms ease;
}

.door-operation::after{
animation: right-door 5000ms ease;
}

@keyframes left-door{
0%{
transform: translateX(0%);
}
50%{
transform: translateX(-100%);
}
100%{
transform: translateX(0%);
}
}

@keyframes right-door{
0%{
transform: translateX(0%);
}
50%{
transform: translateX(100%);
}
100%{
transform:translateX(0%);
}
}

@media screen and (max-width:600px){
.lift{
width: 3rem;
height: 4rem;
}
.lifts{
gap: 1rem;
}
}
45 changes: 45 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./css/main.css" />
<title>Lift Simulation</title>
</head>
<body>
<div>
<form class="form">
<div class="input-group">
<label for="floors-input">Floors</label>
<input
min="2"
value="4"
defaultValue="2"
type="number"
name="floors"
id="floors-input"
required
/>
</div>
<div class="input-group">
<label for="lifts-input">Lifts</label>
<input
min="1"
defaultValue="1"
value="4"
type="number"
name="lifts"
id="lifts-input"
required
/>
</div>
<button type="submit" id="generate-btn">Generate</button>
</form>

<div class="floors-group" id="floors-group"></div>
</div>

<script type="module" src="./js/main.js"></script>
</body>
</html>
152 changes: 152 additions & 0 deletions src/js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
const form = document.querySelector(".form");
const floorsGroup = document.getElementById("floors-group");

form.addEventListener("submit", (e) => {
e.preventDefault();

const floorsCount = Number(e.target.elements[0].value);
const liftsCount = Number(e.target.elements[1].value);

const screenWidth = screen.availWidth;

if (screenWidth < 600 && liftsCount > 2) {
alert("This screen size cant have more than 2 lifts");
}else if(liftsCount > floorsCount) {
alert("Please enter lifts count <= floors count");
}
else {
floorsGroup.innerHTML = "";
generateFloorsAndLifts(floorsCount, liftsCount);
}
});

function generateFloorsAndLifts(floors, lifts) {
const floorsArray = [];

const liftsGroup = document.createElement("div");
liftsGroup.setAttribute("class", "lifts");

// generate Lifts
for (let i = 0; i < lifts; i++) {
const lift = document.createElement("div");
lift.setAttribute("class", "lift");
lift.setAttribute("data-floor", `1`);
lift.setAttribute("data-lift", `${i + 1}`);
liftsGroup.append(lift);
}

// generate floors
for (let i = 0; i < floors; i++) {
const floor = document.createElement("div");
floor.setAttribute("class", "floor");
floor.setAttribute("data-floor", `${i + 1}`);
const liftButtons = document.createElement("div");
liftButtons.setAttribute("class", "lift-buttons");
const callBtn = document.createElement("button");
callBtn.setAttribute("class", `floor-call-btn`);
callBtn.setAttribute("data-floor", `${i + 1}`);
callBtn.textContent = "Call";
const floorTitle = document.createElement("h4");
floorTitle.textContent = `F - ${i + 1}`;
liftButtons.append(callBtn, floorTitle);
const floorContainer = document.createElement("div");
floorContainer.setAttribute("class", "floor-container");
floorContainer.append(liftButtons);
if (i === 0) floorContainer.append(liftsGroup);

floor.append(floorContainer);
floorsArray.unshift(floor);
}

floorsGroup.append(...floorsArray);
}

let previouslyCalledOne;

document.addEventListener("click", (e) => {
const floorCall = Number(e.target.dataset.floor);

if (floorCall && previouslyCalledOne !== floorCall) {
previouslyCalledOne = floorCall;
//Move the lift
processMovementRequest(floorCall);
}
});

function processMovementRequest(floorNo) {
const lifts = Array.from(document.querySelectorAll(".lift"));

// getting all the non-busy lifts
const nonBusyLifts = lifts.filter((lift) => !lift.classList.contains("busy"));

if (nonBusyLifts.length) {
// get the closes lift to the current Floor
const {
lift,
distance
} = getClosestLift(floorNo, nonBusyLifts);
moveLiftToFloor(floorNo, lift, distance);
} else {
setTimeout(() => {
processRequest(floorCall);
}, 1000);
}
}

function getClosestLift(floorCall, lifts) {
let distance = null;
let lift = "";

for (const _lift of lifts) {
// getting distance between the currentFloorCall and the lift
const floorDistance = Math.abs(floorCall - Number(_lift.dataset.floor));

// finding closest lift to the floorCall based on floor Distance
if (distance > floorDistance || distance === null) {
distance = floorDistance;
lift = _lift;
}
}
return {
lift,
distance
};
}

function moveLiftToFloor(floorCall, lift, distance) {
const currentFloor = Number(lift.dataset.floor);

const {
height
} = document
.querySelector(`[data-floor='${floorCall}']`)
.getBoundingClientRect();

if (currentFloor !== floorCall) {
lift.style.transform = `translateY(-${height * (floorCall - 1)}px)`;
lift.style.transition = `all ${distance * 2}s ease-in`;
lift.dataset.floor = floorCall;
lift.classList.add("busy");

// open doors when lift has reached the floor
setTimeout(() => {
lift.classList.add("door-operation");
}, distance * 2000 + 500);

// free the lift
lift.addEventListener("transitionend", (e) => {
setTimeout(() => {
lift.classList.remove("door-operation");
lift.classList.remove("busy");
}, 5500);
});
} else {
// If lift at same floor open doors
lift.classList.add("door-operation");
lift.classList.add("busy");
setTimeout(() => {
lift.classList.remove("door-operation");
lift.classList.remove("busy");
}, 5500);
}
}