Moving car indicator with jump
The following code adds a small car that drives along the forest line I added in my previous blog post. It follows the mouse on the horizontal axis. If clicked it drives autonomously off the grid and returns from the other side - forever trapped in the forest. If clicked while driving away, the car will perform a front flip. You can see how it works on my art page.
HTML:
JAVASCRIPT:
<script>
document.addEventListener('DOMContentLoaded', function () {
const subString = '/art';
const getURL = window.location.href;
if (getURL.includes(subString)) {
//mobile check
const headerActions = document.querySelector('.header-actions');
let isTouch = false;
function checkHeader() {
const styles = window.getComputedStyle(headerActions);
isTouch = styles.getPropertyValue('display') !== 'flex';
}
checkHeader();
if (isTouch === false) {
const footer = document.getElementById('footer-sections');
const bottomSeparator = footer.querySelector('.horizontalrule-block');
const carMainContainer = document.createElement('div');
carMainContainer.id = "carMainContainer";
carMainContainer.classList.add('carMainContainer');
const carContainer = document.createElement('div');
carContainer.id = "carContainer";
carContainer.classList.add('carContainer');
const forestCar = document.createElement('div');
forestCar.id = "forestCar";
forestCar.classList.add('forestCar');
const forestCarInnerContainer = document.createElement('div');
forestCarInnerContainer.id = "forestCarInnerContainer";
forestCarInnerContainer.classList.add('forestCarInnerContainer');
forestCarInnerContainer.appendChild(forestCar);
carContainer.appendChild(forestCarInnerContainer);
carMainContainer.appendChild(carContainer);
bottomSeparator.appendChild(carMainContainer);
//setup
let debounceTimeout;
let lastCarX = 0;
let autodrive = false;
let autodriveJump = false;
const maxSpeed = 100; // pixels per second
const debounceTime = 1 * 1000;
const carMinDuration = 5;
const carMaxDuration = 10;
let zoomFactor = parseFloat(document.body.style.zoom) || 1;
const containerRect = carMainContainer.getBoundingClientRect();
const carWidth = forestCarInnerContainer.offsetWidth;
forestCarInnerContainer.style.transform = `translateX(${-carWidth}px)`;
// Move car based on the calculated mouse position
function moveCar(mouseX) {
const containerRect = carMainContainer.getBoundingClientRect();
const containerLeft = containerRect.left;
let carX = mouseX - containerLeft - carWidth / 2;
if (carX < 0) {
carX = 0;
} else if (carX > containerRect.width - carWidth) {
carX = containerRect.width - carWidth;
}
const distance = Math.abs(carX - lastCarX);
lastCarX = carX;
const duration = distance / maxSpeed;
const cappedDuration = Math.min(Math.max(duration, carMinDuration), carMaxDuration);
forestCarInnerContainer.style.transition = `transform ${cappedDuration}s ease-out`;
forestCarInnerContainer.style.transform = `translateX(${carX}px)`;
}
//initiate movement on mouse move
document.addEventListener('mousemove', function (event) {
if (autodrive === false) {
const mouseX = event.clientX;
moveCar(mouseX);
}
});
//drive off and return
forestCar.addEventListener('click', function () {
if (autodrive === false) {
autodrive = true;
zoomFactor = parseFloat(document.body.style.zoom) || 1;
const farRightX = (containerRect.width / zoomFactor) + carWidth;
forestCarInnerContainer.style.transition = `transform ${carMaxDuration}s ease-out`;
forestCarInnerContainer.style.transform = `translateX(${farRightX}px)`;
setTimeout(() => {
forestCarInnerContainer.style.transition = 'none';
forestCarInnerContainer.style.transform = `translateX(${-carWidth}px)`;
lastCarX = -carWidth;
autodrive = false;
}, (carMaxDuration + 1) * 1000);
} else { //jump and flip if click while autodrive
if (autodriveJump === false) {
autodriveJump = true;
forestCar.style.transition = 'all 1s linear';
forestCar.classList.add('forestCarJump');
setTimeout(() => {
forestCar.classList.remove('forestCarJump');
forestCar.style.transition = 'all 0s linear';
forestCar.style.transform = `translateY(${0}px) rotate(0deg)`;
autodriveJump = false;
}, 1 * 700); //match the css animation speed
}
}
});
//exit
}
}
});
</script>CSS:
@keyframes carJump {
50% {transform: translateY(-30px) rotate(180deg);}
100% {transform: translateY(0px) rotate(360deg);}
}
//CAR IN FOREST//
#carMainContainer {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
width: 75%;
height: 200px;
transform: translateX(-50%);
align-items: center;
bottom: 50%;
left: 50%;
padding: 0;
}
#carContainer {
position: absolute;
pointer-events: none;
width: 100%;
height: 100%;
top: 0;
-webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 10%, rgba(0,0,0,1) 90%, rgba(0,0,0,0) 100%);
mask-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 10%, rgba(0,0,0,1) 90%, rgba(0,0,0,0) 100%);
}
#forestCarInnerContainer {
position: absolute;
pointer-events: none;
width: 56px !important;
height: 28px !important;
transition: all 1s linear;
bottom: 0;
left: 0;
transform-origin: center;
}
#forestCar {
position: absolute;
pointer-events: auto;
cursor: pointer;
width: 56px !important;
height: 28px !important;
background: url('https://images.squarespace-cdn.com/content/v1/6654b2fee26f292de13f1a9d/836bffeb-d10a-491a-815b-b1b0b215eaa0/beetleCarIcon1.png') no-repeat center center;
background-size: contain;
transition: all 5s ease;
margin-bottom: 1px;
z-index: 99999;
bottom: 0;
opacity: 1;
left: 0;
padding-bottom: 0px;
}
#forestCar.forestCarJump {
animation: carJump 0.7s linear forwards;
}
COMMENTS:
Leave a comment: