I'm building a website and I have a problem in one of the steps. I display the photo gallery, after click the button the photo resize to the whole page, then I use the buttons to move the previous and next photos, everything works. I want to add functionality on a mobile device in swapping photo, but I have a problem with that.
If I select photo [2] I can only scroll pictures forward [3] and back [1]. I can't even display the selected photo[2].
Can someone help and point out what I'm doing wrong?
I’ve just started learning JavaScript.
[1]: https://codepen.io/AdamXodeo/pen/rNrgmom
https://codepen.io/AdamXodeo/pen/rNrgmom
const photos = Array.from(document.querySelectorAll(".gallery_item img"));
const popup = document.querySelector(".popup");
const popup_close = document.querySelector(".popup_close");
const popup_img = document.querySelector(".popup_img");
const arrow_left = document.querySelector(".popup_arrow--left");
const arrow_right = document.querySelector(".popup_arrow--right");
let currentImgIndex=0;
let isDragging=false;
let startPos=0;
let currentTranslate=0;
let prevTranslate=0;
let animationID=0;
photos.forEach((photo, index) => {
const showPopup = (e) => {
popup.classList.remove("hidden");
popup_img.src = e.target.src;
currentImgIndex = index;
};
photo.addEventListener("click", showPopup);
// touch events
popup_img.addEventListener("touchstart", touchStart(index));
popup_img.addEventListener("touchend", touchEnd);
popup_img.addEventListener("touchmove", touchMove);
});
const showNextImg = () => {
if (currentImgIndex === photos.length - 1) {
currentImgIndex = 0;
} else {
currentImgIndex++;
}
popup_img.src = photos[currentImgIndex].src;
};
const showPreviousImg = () => {
if (currentImgIndex === 0) {
currentImgIndex = photos.length - 1;
} else {
currentImgIndex--;
}
popup_img.src = photos[currentImgIndex].src;
};
const closePopup = () => {
popup.classList.add("fade-out");
setTimeout(() => {
popup.classList.add("hidden");
popup.classList.remove("fade-out");
}, 300);
};
document.addEventListener("keydown", (e) => {
if (!popup.classList.contains("hidden")) {
if (e.code === "ArrowRight" || e.keyCode === 39) {
showNextImg();
}
if (e.code === "ArrowLeft" || e.keyCode === 37) {
showPreviousImg();
}
if (e.code === "Escape" || e.keyCode === 27) {
closePopup();
}
}
});
popup_close.addEventListener("click", closePopup);
arrow_right.addEventListener("click", showNextImg);
arrow_left.addEventListener("click", showPreviousImg);
function touchStart(index){
return function (event) {
currentImgIndex = index;
startPos = getPositionX(event);
isDragging = true;
popup.classList.add("grabbing");
}
}
function touchMove(event){
if(isDragging){
const currentPosition = getPositionX(event);
currentTranslate = prevTranslate + currentPosition - startPos;
}
}
function touchEnd(){
isDragging = false;
const movedBy = currentTranslate - prevTranslate;
if(movedBy < -30 && currentImgIndex < photos.length - 1) currentImgIndex += 1 ;
if(movedBy > 30 && currentImgIndex > 0) currentImgIndex -= 1;
changePhotoByIndex();
popup.classList.remove("grabbing");
}
function getPositionX(event){
return event.type.includes("mouse") ? event.pageX : event.touches[0].clientX;
}
function animation() {
if (isDragging) requestAnimationFrame(animation);
}
function changePhotoByIndex() {
popup_img.src = photos[currentImgIndex].src;
prevTranslate = currentTranslate;
}
const prevButton = document.querySelector('#prev');
const nextButton = document.querySelector('#next');
const images = document.querySelectorAll('.gallery img');
let currentImage = 0;
images[currentImage].classList.add('active');
prevButton.addEventListener('click', function() {
images[currentImage].classList.remove('active');
currentImage--;
if (currentImage < 0) {
currentImage = images.length - 1;
}
images[currentImage].classList.add('active');
});
nextButton.addEventListener('click', function() {
images[currentImage].classList.remove('active');
currentImage++;
if (currentImage >= images.length) {
currentImage = 0;
}
images[currentImage].classList.add('active');
});
.gallery {
display: flex;
}
.gallery img {
width: 100%;
height: auto;
display: none;
}
.gallery .active {
display: block;
}
<div class="gallery">
<img src="https://www.pakainfo.com/wp-content/uploads/2021/09/dummy-user-image-url-300x200.jpg" class="active">
<img src="https://www.pakainfo.com/wp-content/uploads/2021/09/live-image-link-300x157.jpg">
<img src="https://www.pakainfo.com/wp-content/uploads/2021/09/online-dummy-image-url-300x201.jpg">
<img src="https://www.pakainfo.com/wp-content/uploads/2021/09/test-image-online-300x148.jpg">
<img src="https://www.pakainfo.com/wp-content/uploads/2021/09/sample-image-url-link-300x300.png">
</div>
<button id="prev">Previous</button>
<button id="next">Next</button>
Related
I created flappy bird by following a youtube tutorial. Inside Bird.js there is a function called handleJump, inside that function when i put "Space", the bird jumps whenever i press space key on keyboard, but when i change it to "touchstart" the bird doesn't jump when i touch the screen! what am i doing wrong? what should i do?
The main page ( f.js ):
import { updateBird, setupBird, getBirdRect } from "./Bird.js";
import {
updatePipes,
setupPipes,
getPassedPipesCount,
getPipesRects,
} from "./Pipe.js";
//document.addEventListener("keypress", handleStart, { once: true });
document.addEventListener("touchstart", handleStart, { once: true });
const title = document.querySelector("[data-title]");
const subtitle = document.querySelector("[data-subtitle]");
let lastTime;
function updateLoop(time) {
if (lastTime == null) {
lastTime = time;
window.requestAnimationFrame(updateLoop);
return;
}
const delta = time - lastTime;
updateBird(delta);
updatePipes(delta);
if (checkLose()) return handleLose();
lastTime = time;
window.requestAnimationFrame(updateLoop);
}
function checkLose() {
const birdRect = getBirdRect();
const insidePipe = getPipesRects().some((rect) =>
isCollision(birdRect, rect)
);
const outsideWorld = birdRect.top < 0 || birdRect.bottom > window.innerHeight;
return outsideWorld || insidePipe;
}
function isCollision(rect1, rect2) {
return (
rect1.left < rect2.right &&
rect1.top < rect2.bottom &&
rect1.right > rect2.left &&
rect1.bottom > rect2.top
);
}
function handleStart() {
title.classList.add("hide");
setupBird();
setupPipes();
lastTime = null;
window.requestAnimationFrame(updateLoop);
}
function handleLose() {
setTimeout(() => {
title.classList.remove("hide");
subtitle.classList.remove("hide");
subtitle.textContent = `${getPassedPipesCount()} Pipes`;
document.addEventListener("touchstart", handleStart, { once: true });
}, 100);
}
Bird.js :
const birdElem = document.querySelector("[data-bird");
const BIRD_SPEED = 0.5;
const JUMP_DURATION = 120;
let timeSinceLastJump = Number.POSITIVE_INFINITY;
export function setupBird() {
setTop(window.innerHeight / 2);
document.removeEventListener("touchstart", handleJump); //keydown
document.addEventListener("touchstart", handleJump); //keydown
}
export function updateBird(delta) {
if (timeSinceLastJump < JUMP_DURATION) {
setTop(getTop() - BIRD_SPEED * delta);
} else {
setTop(getTop() + BIRD_SPEED * delta);
}
timeSinceLastJump += delta;
}
export function getBirdRect() {
return birdElem.getBoundingClientRect();
}
function setTop(top) {
birdElem.style.setProperty("--bird-top", top);
}
function getTop() {
return parseFloat(getComputedStyle(birdElem).getPropertyValue("--bird-top"));
}
function handleJump(e) {
if (e.code !== "touchstart") return;
timeSinceLastJump = 0;
}
I fixed it by removing the return
Before:
function handleJump(e) {
if (e.code !== "touchstart") return;
timeSinceLastJump = 0;
}
After:
function handleJump(e) {
if (e.code !== "touchstart");
timeSinceLastJump = 0;
}
The code came from a course, I didn't write it myself, but I understand what it means and is supposed to do.
My dimensions for ship are 75px by 75px. At full size it moves.
My dimensions for the moon are 50px by 35px. At full size, it moves, but WITH the rocket ship.
The goal of the app is for the user to use the arrow keys to move the ship to the moon, upon collision, the moon moves to a random location. There is no score to keep, that's all.
But like I said nothing is moving.
Any help is appreciated. I think the problem lies either in my Javascript or image sizes.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie-edge">
<title>Lunar Landing</title>
<link rel="stylesheet" href="app.css">
</head>
<body>
<img src="img/ship.png" id="ship">
<img src="img/moon.png" id="moon">
<script src="app.js"></script>
</body>
</html>
function isTouching(a, b) {
const aRect = a.getBoundingClientRect();
const bRect = b.getBoundingClientRect();
return !(
aRect.top + aRect.height < bRect.top ||
aRect.top > bRect.top + bRect.height ||
aRect.left + aRect.width < bRect.left ||
aRect.left > bRect.left + bRect.width
);
}
const init = () => {
const avatar = document.querySelector('#ship');
const coin = document.querySelector('#moon');
moveCoin();
window.addEventListener('keyup', function(e) {
if (e.key === 'ArrowDown' || e.key === 'Down') {
moveVertical(avatar, 50);
}
else if (e.key === 'ArrowUp' || e.key === 'Up') {
moveVertical(avatar, -50);
}
else if (e.key === 'ArrowRight' || e.key === 'Right') {
moveHorizontal(avatar, 50);
avatar.style.transform = 'scale(1,1)';
}
else if (e.key === 'ArrowLeft' || e.key === 'Left') {
moveHorizontal(avatar, -50);
avatar.style.transform = 'scale(-1,1)';
}
if (isTouching(avatar, coin)) moveCoin();
});
};
const moveVertical = (element, amount) => {
const currTop = extractPos(element.style.top);
element.style.top = `${currTop + amount}px`;
};
const moveHorizontal = (element, amount) => {
const currLeft = extractPos(element.style.left);
element.style.left = `${currLeft + amount}px`;
};
const extractPos = (pos) => {
if (!pos) return 100;
return parseInt(pos.slice(0, -2));
};
const moveCoin = () => {
const x = Math.floor(Math.random() * window.innerWidth);
const y = Math.floor(Math.random() * window.innerHeight);
coin.style.top = `${y}px`;
coin.style.left = `${x}px`;
};
init();
So I think there were some unnecessary lines of code in my JS file. Also my CSS something. I rewatched the tutorial and followed along, now it works great!
Here's my CSS code...
img {
width: 100px;
position: absolute;
top: 100px;
left: 100px;
}
Here's my JavaScript:
function isTouching(a, b) {
const aRect = a.getBoundingClientRect();
const bRect = b.getBoundingClientRect();
return !(
aRect.top + aRect.height < bRect.top ||
aRect.top > bRect.top + bRect.height ||
aRect.left + aRect.width < bRect.left ||
aRect.left > bRect.left + bRect.width
);
}
const ship = document.querySelector('#rship');
const moon = document.querySelector('#bmoon');
window.addEventListener('keyup', function(e){
if(e.key === 'ArrowDown' || e.key === 'Down'){
const currTop = extractPos(ship.style.top);
ship.style.top = `${currTop + 50}px`;
}
else if(e.key === 'ArrowUp' || e.key === 'Up'){
const currTop = extractPos(ship.style.top);
ship.style.top = `${currTop - 50}px`;
}
else if(e.key === 'ArrowRight' || e.key === 'Right'){
const currLeft = extractPos(ship.style.left);
ship.style.left = `${currLeft + 50}px`;
ship.style.transform = 'scale(1, 1)';
}
else if(e.key === 'ArrowLeft' || e.key === 'Left'){
const currLeft = extractPos(ship.style.left);
ship.style.left = `${currLeft - 50}px`;
ship.style.transform = 'scale(-1, 1)';
}
if (isTouching(ship, moon)) moveMoon();
});
const extractPos = (pos) => {
if(!pos) return 100;
return parseInt(pos.slice(0, -2));
};
const moveMoon = () => {
const x = Math.floor(Math.random() * window.innerHeight);
const y = Math.floor(Math.random() * window.innerWidth);
moon.style.top = `${x}px`;
moon.style.left = `${y}px`;
}
moveMoon();
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 months ago.
Ok, so I've been struggling with something I think it's pretty simple. Not sure if it's the Babel compiler or what. So I've got this class:
export default class animateFormClass {
constructor(formSelector, buttonElement = null, currentCard = null, prevCard = null, nextCard = null) {
this.form = document.querySelector(formSelector);
this.direction = 'forward';
this.progressBar = document.getElementById('progressbar');
this.opacity = this.opacityLeft = 0;
this.buttonElement = buttonElement;
this.currentCard = currentCard;
this.prevCard = prevCard;
this.nextCard = nextCard;
}
animateForm() {
if (this.direction === 'forward') {
if (this.nextCard !== null) {
this.fadeOut = setInterval(this.fadeOutAnimation, 10);
this.updateProgressBar;
}
} else if (this.direction === 'back') {
if (this.prevCard !== null) {
this.fadeOut = setInterval(this.fadeOutAnimation, 10);
this.updateProgressBar;
}
}
}
fadeOutAnimation() {
this.opacity = this.opacity - 0.05;
console.log(this.opacity, this.currentCard);
if (this.opacity >= 0) {
this.currentCard.style.opacity = this.opacity;
} else {
this.currentCard.classList.add('d-none');
this.fadeIn = setInterval(this.fadeInAnimation, 10);
clearInterval(this.fadeOut);
}
}
fadeInAnimation() {
this.opacityLeft = this.opacityLeft + 0.1;
let cardElement;
if (this.direction === 'forward') {
cardElement = this.nextCard;
} else if (this.direction === 'back') {
cardElement = this.prevCard;
}
cardElement.classList.remove('d-none');
if (this.opacityLeft <= 1) {
cardElement.style.opacity = this.opacityLeft;
} else {
clearInterval(this.fadeIn);
}
}
updateProgressBar() {
let activeElement = this.progressBar.querySelector('.active');
let nextListElement = activeElement.nextElementSibling;
let prevListElement = activeElement.previousElementSibling;
if (this.direction === 'forward') {
if (nextListElement !== null) {
activeElement.classList.remove('active');
activeElement.classList.add('step-completed');
nextListElement.classList.add('active');
}
} else if (this.direction === 'back') {
if (prevListElement !== null) {
activeElement.classList.remove('active');
prevListElement.classList.remove('step-completed');
prevListElement.classList.add('active');
}
}
}
}
and from another file I'm importing the class like this:
import animateFormClass from './animateForm';
Ok so in this file I've got some code in which I update some of the object properties but in the animateForm() method the properties seem to be OK BUT when those same object properties are used by the other method called fadeOutAnimation() I've got this message of undefined in the this.currentCard property.
Here's the code in which I make the class instance:
if (document.getElementById('register')) {
let animate = new animateFormClass('#register');
let currentCard, prevCard, nextCard;
document.getElementById('register').addEventListener('click', function(e) {
if (e.target.classList.contains('next')) {
animate.direction = 'forward';
animate.currentCard = e.target.closest('fieldset');
animate.nextCard = animate.currentCard.nextElementSibling;
animate.animateForm();
} else if (e.target.classList.contains('prev')) {
animate.direction = 'back';
animate.animateForm(e.target);
}
});
}
I get the error when the animate.animateForm() method is called. My environment is working on a PHP web app using Laravel and using the watch task that Laravel has out of the box.
EDIT:
Thank you for your help, I was able to fix it. If anyone was wondering, I changed all the methods of the class as properties and used the arrow function syntax. So thanks again!!!
When you're doing setInterval(this.fadeOutAnimation, 10), 'this' inside 'fadeOutAnimation' is binded by window. Use setInterval(() => { this.fadeOutAnimation() }, 10); It preserves 'this' context.
Thank you for your help, I was able to fix it. If anyone was wondering, I changed all the methods of the class as properties and used the arrow function syntax. So thanks again!!!
Here's the new code:
export default class animateFormClass {
constructor(formSelector) {
this.form = document.querySelector(formSelector);
this.direction = null;
this.progressBar = document.getElementById('progressbar');
this.opacity = this.opacityLeft = 0;
this.buttonElement = null;
this.currentCard = null;
this.prevCard = null;
this.nextCard = null;
this.animateForm = (buttonElement) => {
this.buttonElement = buttonElement;
this.currentCard = this.buttonElement.closest('fieldset');
this.nextCard = this.currentCard.nextElementSibling;
this.prevCard = this.currentCard.previousElementSibling;
if(this.direction === 'forward') {
if(this.nextCard !== null) {
this.fadeOut = setInterval(() => { this.fadeOutAnimation() }, 10);
this.updateProgressBar();
}
}
else if(this.direction === 'back') {
if(this.prevCard !== null) {
this.fadeOut = setInterval(() => { this.fadeOutAnimation() }, 10);
this.updateProgressBar();
}
}
}
this.fadeOutAnimation = () => {
this.opacity = this.opacity - 0.05;
if(this.opacity >= 0) {
this.currentCard.style.opacity = this.opacity;
}
else {
this.currentCard.classList.add('d-none');
this.fadeIn = setInterval(this.fadeInAnimation, 10);
clearInterval(this.fadeOut);
}
}
this.fadeInAnimation = () => {
this.opacityLeft = this.opacityLeft + 0.1;
let cardElement;
if(this.direction === 'forward') {
cardElement = this.nextCard;
}
else if(this.direction === 'back') {
cardElement = this.prevCard;
}
cardElement.classList.remove('d-none');
if(this.opacityLeft <= 1) {
cardElement.style.opacity = this.opacityLeft;
}
else {
clearInterval(this.fadeIn);
}
}
this.updateProgressBar = () => {
let activeElement = this.progressBar.querySelector('.active');
let nextListElement = activeElement.nextElementSibling;
let prevListElement = activeElement.previousElementSibling;
if(this.direction === 'forward') {
if(nextListElement !== null) {
activeElement.classList.remove('active');
activeElement.classList.add('step-completed');
nextListElement.classList.add('active');
}
}
else if(this.direction === 'back') {
if(prevListElement !== null) {
activeElement.classList.remove('active');
prevListElement.classList.remove('step-completed');
prevListElement.classList.add('active');
}
}
}
}
}
I am new to JS and need your help with this issue please. I need to apply key-up and key-down using HTML, CSS and JS. I have the original code and I am trying to modify it so I can move through the panel using key-up and key-down, but it does not seem to work at all. Here is a snippet of the original code for the part I am working on:
const P_CONTAINERS_LIST = "containersList";
const P_CONTAINER_EDIT = "containerEdit";
const P_CONTAINER_DELETE = "containerDelete";
Logic.registerPanel(P_CONTAINERS_EDIT, {
panelSelector: "#edit-containers-panel",
// This method is called when the object is registered.
initialize() {
Logic.addEnterHandler(document.querySelector("#exit-edit-mode-link"), () => {
Logic.showPanel(P_CONTAINERS_LIST);
});
},
// This method is called when the panel is shown.
prepare() {
const fragment = document.createDocumentFragment();
Logic.identities().forEach(identity => {
const tr = document.createElement("tr");
fragment.appendChild(tr);
tr.classList.add("container-panel-row");
tr.innerHTML = escaped`
<td class="userContext-wrapper">
<div class="userContext-icon-wrapper">
<div class="usercontext-icon"
data-identity-icon="${identity.icon}"
data-identity-color="${identity.color}">
</div>
</div>
<div class="container-name truncate-text"></div>
</td>
<td class="edit-container pop-button edit-container-icon">
<img
src="/img/container-edit.svg"
class="pop-button-image" />
</td>
<td class="remove-container pop-button delete-container-icon">
<img
class="pop-button-image"
src="/img/container-delete.svg"
/>
</td>`;
tr.querySelector(".container-name").textContent = identity.name;
tr.querySelector(".edit-container").setAttribute("title", `Edit ${identity.name} container`);
tr.querySelector(".remove-container").setAttribute("title", `Remove ${identity.name} container`);
Logic.addEnterHandler(tr, e => {
if (e.target.matches(".edit-container-icon") || e.target.parentNode.matches(".edit-container-icon")) {
Logic.showPanel(P_CONTAINER_EDIT, identity);
} else if (e.target.matches(".delete-container-icon") || e.target.parentNode.matches(".delete-container-icon")) {
Logic.showPanel(P_CONTAINER_DELETE, identity);
}
});
});
const list = document.querySelector("#edit-identities-list");
list.innerHTML = "";
list.appendChild(fragment);
return Promise.resolve(null);
},
});
<div class="scrollable panel-content" tabindex="-1">
<table class="unstriped">
<tbody id="edit-identities-list"></tbody>
</table>
</div>
I tried to insert the following part in my JS code, but the problem still exists:
document.addEventListener("keydown", (e) => {
const selectables = [...document.querySelectorAll("[tabindex='0'], [tabindex='-1']")];
const element = document.activeElement;
const index = selectables.indexOf(element) || 0;
function next() {
const nextElement = selectables[index + 1];
if (nextElement) {
nextElement.focus();
}
}
function previous() {
const previousElement = selectables[index - 1];
if (previousElement) {
previousElement.focus();
}
}
switch (e.keyCode) {
case 40:
next();
break;
case 38:
previous();
break;
default:
if ((e.keyCode >= 49 && e.keyCode <= 57) &&
Logic._currentPanel === "containerEdit") {
const element = selectables[e.keyCode - 48];
if (element) {
element.click();
}
}
break;
}
});
Thank you very much.
Your sample seems functional, so I suspect your issue relates to whatever Logic._currentPanel is and the concept of document.activeElement in that respect.
For selectables.indexOf(element) results -1 when element it is out of index or not known, not null or undefined, so const index = selectables.indexOf(element) || 0; won't be 0;
document.addEventListener("keydown", (e) => {
const selectables = [...document.querySelectorAll("[tabindex='0'], [tabindex='-1']")];
const element = document.activeElement;
const index = selectables.indexOf(element) || 0;
function next() {
const nextElement = selectables[index + 1];
if (nextElement) {
nextElement.focus();
}
}
function previous() {
const previousElement = selectables[index - 1];
if (previousElement) {
previousElement.focus();
}
}
switch (e.keyCode) {
case 40:
next();
break;
case 38:
previous();
break;
default:
if ((e.keyCode >= 49 && e.keyCode <= 57)) {
const element = selectables[e.keyCode - 48];
if (element) {
element.click();
}
}
break;
}
});
div {
display:block;
padding: 1in;
border:0.1em solid black;
}
div:focus {
box-shadow: 0px 0px 10px green;
}
<div tabindex="-1">
1
</div>
<div tabindex="-1">
2
</div>
So I have write a script for my portfolio website to scroll to section by index. It works on every tested browser and smartphone but on a mac device it does not work probably instead to scroll to the next sections it is going automatically to the second next section.
Hopefully someone can help me.
var anchorPoints = [];
var anchorLocation = [];
var anchorIndex = 0;
var waiting = false;
var canScroll = true;
var offset = 0
window.onload = function () {
anchorPoints = document.getElementsByClassName("js-anchor");
for (i = 0; i < anchorPoints.length; i++) {
getLocation = anchorPoints[i].getBoundingClientRect();
getLocation = getLocation.top - offset;
anchorLocation.push(parseInt(getLocation));
}
}
$(document).on('mousewheel DOMMouseScroll', function (e) {
if (detectMobile() == true) {
return;
}
if ((waiting || canScroll == false)) {
return;
}
e.preventDefault();//prevent the default mousewheel scrolling
var active = $('section.active');
var delta = e.originalEvent.detail < 0 || e.originalEvent.wheelDelta > 0 ? 1 : -1;
waiting = true;
if (delta < 0) {
anchorIndex += 1;
if (anchorIndex > (anchorPoints.length - 1)) {
anchorIndex = 0;
}
scrollTo({
top: anchorLocation[anchorIndex],
left: 0,
behavior: 'smooth'
});
console.log(anchorIndex);
console.log('scrolling down');
} else {
anchorIndex -= 1;
if (anchorIndex < 0) {
anchorIndex = anchorPoints.length - 1;
}
scrollTo({
top: anchorLocation[anchorIndex],
left: 0,
behavior: 'smooth'
});
console.log(anchorIndex);
console.log('scrolling up');
}
setTimeout(function () {
waiting = false;
}, 1000);
});