I created class based functions in my project. Scroll class is to create smooth scroll behaviour using translateY property. The second one called SideNavigation generate bullet list navigation based on projects elements length. I want to achive smooth scroll effect also on click on those bullets, but can't find solution for this. Code snippet included. Hope anyone can help with this.
const config = {
ease: 0.1,
current: 0,
previous: 0,
rounded: 0
}
class Scroll {
constructor(velocity) {
this.velocity = velocity
}
setBodyHeight() {
document.body.style.height = document.getElementById('projects').getBoundingClientRect().height + 'px'
}
isMobile() {
return 'ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/)
}
onScroll() {
config.current = window.scrollY
config.previous += (config.current - config.previous) * config.ease
config.rounded = Math.round(config.previous * 100) / 100
const difference = config.current - config.rounded
const acceleration = difference / document.body.clientWidth
const velocity = +acceleration
const skew = velocity * this.velocity
const element = document.getElementById('projects')
this.isMobile() ? element.style.transform = `skewY(${skew}deg)` : element.style.transform = `translateY(-${config.rounded}px)`
requestAnimationFrame(() => this.onScroll())
}
}
class SideNavigation {
constructor() {
createBullets()
}
}
function createBullets() {
const bulletWrapper = document.createElement('div')
const bulletList = document.createElement('ul')
bulletWrapper.classList.add('side-nav')
for (let i = 0; i < document.getElementsByClassName('project').length; i++) {
const bullet = document.createElement('li')
bullet.setAttribute('id', '' + i)
bullet.addEventListener('click', event => {
console.log(document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop)
// scroll to current section
})
bulletList.append(bullet)
bulletWrapper.append(bulletList)
document.body.append(bulletWrapper)
}
}
window.addEventListener('load', () => {
const scrollInstance = new Scroll(8, true)
const sideNav = new SideNavigation()
scrollInstance.setBodyHeight()
requestAnimationFrame(() => scrollInstance.onScroll())
})
html,
body {
height: 100%;
}
main {
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
#projects {
width: 80%;
}
.project {
height: 500px;
width: 100%;
background: #333;
color: #fff;
}
.side-nav {
position: fixed;
right: 20px;
top: 20%;
z-index: 10;
}
.side-nav li {
width: 30px;
height: 30px;
display: block;
background: #333;
margin-bottom: 20px;
border-radius: 50%;
cursor: pointer;
}
<body>
<main>
<div id="projects">
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
</div>
</main>
</body>
I hope I understood your question correctly. Is this what you're looking for?
const config = {
ease: 0.1,
current: 0,
previous: 0,
rounded: 0
}
class Scroll {
constructor(velocity) {
this.velocity = velocity
}
setBodyHeight() {
document.body.style.height = document.getElementById('projects').getBoundingClientRect().height + 'px'
}
isMobile() {
return 'ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/)
}
onScroll() {
config.current = window.scrollY
config.previous += (config.current - config.previous) * config.ease
config.rounded = Math.round(config.previous * 100) / 100
const difference = config.current - config.rounded
const acceleration = difference / document.body.clientWidth
const velocity = +acceleration
const skew = velocity * this.velocity
const element = document.getElementById('projects')
this.isMobile() ? element.style.transform = `skewY(${skew}deg)` : element.style.transform = `translateY(-${config.rounded}px)`
requestAnimationFrame(() => this.onScroll())
}
}
class SideNavigation {
constructor() {
createBullets()
}
}
function createBullets() {
const bulletWrapper = document.createElement('div')
const bulletList = document.createElement('ul')
bulletWrapper.classList.add('side-nav')
for (let i = 0; i < document.getElementsByClassName('project').length; i++) {
const bullet = document.createElement('li')
bullet.setAttribute('id', '' + i)
bullet.addEventListener('click', event => {
console.log(document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop)
// scroll to current section
window.scrollBy(0, document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop - window.pageYOffset);
})
bulletList.append(bullet)
bulletWrapper.append(bulletList)
document.body.append(bulletWrapper)
}
}
window.addEventListener('load', () => {
const scrollInstance = new Scroll(8, true)
const sideNav = new SideNavigation()
scrollInstance.setBodyHeight()
requestAnimationFrame(() => scrollInstance.onScroll())
})
html,
body {
height: 100%;
}
main {
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
#projects {
width: 80%;
}
.project {
height: 500px;
width: 100%;
background: #333;
color: #fff;
}
.side-nav {
position: fixed;
right: 20px;
top: 20%;
z-index: 10;
}
.side-nav li {
width: 30px;
height: 30px;
display: block;
background: #333;
margin-bottom: 20px;
border-radius: 50%;
cursor: pointer;
}
<body>
<main>
<div id="projects">
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
</div>
</main>
</body>
The scrollBy function's second parameter allows to modify the window's Y axis. But as we want each bullet to jump to the start of it's project, we decrease the current Y axis of the page from the Y axis of the project window.scrollBy(0, document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop - window.pageYOffset).
Related
When I click I want to smoothly add segments to the progress bar. They are added but instantly. What could be the problem?
I tried to implement a smooth animation with setInterval, but nothing comes out. Percentages are also added instantly.
let progressBar = document.querySelector(".progressbar");
let progressBarValue = document.querySelector(".progressbar__value");
const body = document.querySelector("body");
let progressBarStartValue = 0;
let progressBarEndValue = 100;
let speed = 50;
body.addEventListener("click", function(e) {
if (progressBarStartValue === progressBarEndValue) {
alert("you have completed all the tasks");
} else {
let progress = setInterval(() => {
if (progressBarStartValue != 100) {
progressBarStartValue += 10;
clearInterval(progress);
}
progressBarValue.textContent = `${progressBarStartValue}%`;
progressBar.style.background = `conic-gradient(
#FFF ${progressBarStartValue * 3.6}deg,
#262623 ${progressBarStartValue * 3.6}deg
)`;
}, speed);
}
});
.progressbar {
position: relative;
height: 150px;
width: 150px;
background-color: #262623;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.progressbar::before {
content: "";
position: absolute;
height: 80%;
width: 80%;
background-color: #0f0f0f;
border-radius: 50%;
}
.progressbar__value {
color: #fff;
z-index: 9;
font-size: 25px;
font-weight: 600;
}
<main class="main">
<section class="statistic">
<div class="container">
<div class="statistic__inner">
<div class="statistic__text">
<h2 class="statistic__title">You're almost there!</h2>
<p class="statistic__subtitle">keep up the good work</p>
</div>
<div class="progressbar"><span class="progressbar__value">0%</span></div>
</div>
</div>
</section>
</main>
This may not be exactly what you're looking for, but with the conic-gradient() implementation you're using, I'd recommend checking out a library call anime.js.
Here's an example with your implementation (same html and css):
// your.js
let progressBar = document.querySelector(".progressbar");
let progressBarValue = document.querySelector(".progressbar__value");
const body = document.querySelector("body");
// Switched to object for target in anime()
let progressBarObject = {
progressBarStartValue: 0,
progressBarEndValue: 100,
progressBarAnimationValue: 0 * 3.6 // New value needed for smoothing the progress bar, since the progress value needs to be multiplied by 3.6
}
// Not necessary, but I recommend changing the event listener to pointerup for better support
// Also not necessary, I changed function to arrow function for my own preference
body.addEventListener("pointerup", e => {
e.preventDefault()
if (progressBarObject.progressBarStartValue === progressBarObject.progressBarEndValue) {
alert("you have completed all the tasks");
} else {
let newValue = 0 // Needed so we can set the value, before it's applied in anime()
if (progressBarObject.progressBarStartValue != 100) {
// Math.ceil() allows us to round to the nearest 10 to guarantee the correct output
newValue = Math.ceil((progressBarObject.progressBarStartValue + 10) / 10) * 10;
}
// Optional: Prevents accidentally going over 100 somehow
if (newValue > 100) {
newValue = 100
}
anime({
targets: progressBarObject,
progressBarStartValue: newValue,
progressBarAnimationValue: newValue * 3.6,
easing: 'easeInOutExpo',
round: 1, // Rounds to nearest 1 so you don't have 0.3339...% displayed in progressBarValue
update: () => {
progressBar.style.backgroundImage = `conic-gradient(
#FFF ${progressBarObject.progressBarAnimationValue}deg,
#262623 ${progressBarObject.progressBarAnimationValue}deg)`;
progressBarValue.textContent = `${progressBarObject.progressBarStartValue}%`;
},
duration: 500
});
}
});
Here's a CodePen using the anime.js CDN: Circular Progress Bar Smoothing
If you don't want to use a javascript library, then I'd recommend switching from the conic-gradient() to something else. I hear using an .svg circle with stroke and stroke-dasharray can work great with CSS transition.
You shouldn't setInterval your progress variable like this. instead, put it as a global variable outside the function then use it to gradually add 1 as long as the start value is less than progress, and you still can control the speed with your speed variable.
let progressBar = document.querySelector(".progressbar");
let progressBarValue = document.querySelector(".progressbar__value");
const body = document.querySelector("body");
let progressBarStartValue = 0;
let progressBarEndValue = 100;
let speed = 50;
let progress = 0;
body.addEventListener("click", function(e) {
if (progressBarStartValue === progressBarEndValue) {
alert("you have completed all the tasks");
} else {
progress += 10;
setInterval(() => {
if (progressBarStartValue < progress) {
progressBarStartValue += 1;
clearInterval();
}
progressBarValue.textContent = `${progressBarStartValue}%`;
progressBar.style.background = `conic-gradient(
#FFF ${progressBarStartValue * 3.6}deg,
#262623 ${progressBarStartValue * 3.6}deg
)`;
}, speed);
}
});
.progressbar {
position: relative;
height: 150px;
width: 150px;
background-color: #262623;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 3px solid red;
}
.progressbar::before {
content: "";
position: absolute;
height: 80%;
width: 80%;
background-color: #0f0f0f;
border-radius: 50%;
border: 3px solid blue;
}
.progressbar__value {
color: #fff;
z-index: 9;
font-size: 25px;
font-weight: 600;
}
<main class="main">
<section class="statistic">
<div class="container">
<div class="statistic__inner">
<div class="statistic__text">
<h2 class="statistic__title">You're almost there!</h2>
<p class="statistic__subtitle">keep up the good work</p>
</div>
<div class="progressbar"><span class="progressbar__value">0%</span></div>
</div>
</div>
</section>
</main>
Hi i'm trying to make a little game
Basically i'm trying to achieve the user strikes the match once it sparks, then strikes it again it lights the match
I've managed to get the "match to follow the cursor" and detect when the match "a div" intersects the match box "another div"
What i'm struggling with is that when the two divs intersect the boolean changes to true, but because its in the mouse move function it triggers true multiple time whilst moving across the strip
how do i trigger something when true counts to the value of 200 or above, i'm not sure how to trigger that?
i like the way this works as it mirrors how it would work in real life with pressure and velocity, but if there are any other suggestions there welcome.
heres the code i've been working with
<style>
.matchBox {
position: relative;
height: 86px;
width: 200px
}
.strip {
position: absolute;
background: red;
width: 100%;
height: 60%;
top: 50%;
transform: translateY(-50%);
}
.matchWrap {
height: 100px;
width: 100px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.matchTip {
height: 30px;
width: 30px;
background: yellow;
position: absolute;
top: 0;
left: 0;
}
</style>
<div>
<h1>Light the match</h1>
<div class="matchBox">
<div class="strip" id="pad">
</div>
</div>
</div>
<div class="matchWrap">
<div class="matchTip" id="tip">
</div>
<div>
const match = document.querySelector('.matchWrap')
function isTouchDevice() {
try {
document.createEvent(TouchEvent);
return true;
} catch (e) {
return false;
}
}
const move = (e) => {
try {
var x = !isTouchDevice() ? e.pageX : e.touches[0].pageX;
var y = !isTouchDevice() ? e.pageY : e.touches[0].pageY;
} catch (e) {}
match.style.top = y + "px";
match.style.left = x + "px";
}
var strike
document.addEventListener('mousemove', (e) => {
move(e);
function elementsOverlap(el1, el2) {
const domRect1 = el1.getBoundingClientRect();
const domRect2 = el2.getBoundingClientRect();
return !(
domRect1.top > domRect2.bottom ||
domRect1.right < domRect2.left ||
domRect1.bottom < domRect2.top ||
domRect1.left > domRect2.right
);
}
const el1 = document.getElementById('tip');
const el2 = document.getElementById('pad');
console.log(elementsOverlap(el1, el2)); // 👉️ true
var strike = elementsOverlap(el1, el2);
var spark = 200
var lit = 500
if (strike.length > spark) {
console.log('reached')
} else if (strike.length > lit) {
console.log('reached2')
}
})
Thanks
Mike
I'm trying to make an infinite marquee (scrolling horizontal text), but on scroll it speeds up the translation of the HTML elements. I am achieving this effect by using a linear interpolation function.
You can see the effect on this site that I'm trying to remake: https://altsdigital.com/ It says "Not your usual SEO agency"
Mine almost works - the problem is that when my HTML resets its position - my text overlaps and briefly translates to the left before correcting. Keep your eyes on the left side of the page. You will see that the text overlaps at one brief moment then translates left (during it's movement to the right), it eventually corrects itself as it plays retaining the original gap. You can see in this screenshot the "t" and "I" are overlapping. Shortly after this, the text on the left translates left and there is a gap between the letters. I want it to have a gap and not briefly translate left.
I have no idea how to fix this - I've tried calling the lerp function on scroll but nothing seems to change. Thanks in advance.
Here's the code:
const lerp = (current, target, factor) => {
let holder = current * (1 - factor) + target * factor;
holder = parseFloat(holder).toFixed(3);
return holder;
};
class LoopingText {
constructor(DOMElements) {
this.DOMElements = DOMElements;
this.lerpingData = {
counterOne: { current: 0, target: 0 },
counterTwo: { current: 100, target: 100 },
};
this.interpolationFactor = 0.1;
this.direction = true;
this.speed = 0.2;
this.render();
this.onScroll();
}
onScroll() {
window.addEventListener("scroll", () => {
this.lerpingData["counterOne"].target += this.speed * 5;
this.lerpingData["counterTwo"].target += this.speed * 5;
});
}
lerp() {
for (const counter in this.lerpingData) {
this.lerpingData[counter].current = lerp(
this.lerpingData[counter].current,
this.lerpingData[counter].target,
this.interpolationFactor
);
}
this.lerpingData["counterOne"].target += this.speed;
this.lerpingData["counterTwo"].target += this.speed;
if (this.lerpingData["counterOne"].target < 100) {
this.DOMElements[0].style.transform = `translate(${this.lerpingData["counterOne"].current}%, 0%)`;
} else {
this.lerpingData["counterOne"].current = -100;
this.lerpingData["counterOne"].target = -100;
}
if (this.lerpingData["counterTwo"].target < 100) {
this.DOMElements[1].style.transform = `translate(${this.lerpingData["counterTwo"].current}%, 0%)`;
} else {
this.lerpingData["counterTwo"].current = -100;
this.lerpingData["counterTwo"].target = -100;
}
}
render() {
this.lerp();
window.requestAnimationFrame(() => this.render());
}
}
let textArray = document.getElementsByClassName("item");
new LoopingText(textArray);
#import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght#0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Poppins";
}
.hero-section {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
position: relative;
width: 100%;
}
.loop-container {
position: relative;
width: 100%;
display: flex;
/* padding-right: 24px; */
}
.item {
position: absolute;
font-size: 15rem;
white-space: nowrap;
margin: 0;
}
span {
transition: all 0.2s;
cursor: default;
}
.hover:hover {
color: gray;
transition: all 0.2s;
}
<body>
<section class="hero-section">
<div class="loop-container">
<div class="item">Infinite Horizontal Looping Text</div>
<div class="item">Infinite Horizontal Looping Text</div>
</div>
</section>
<section class="hero-section">
</section>
</body>
I have a red container which initially is at bottom right of black container. I have a scale function that gradually scales the container. I want to make the bottom right position of red container to be fixed and scale it towards top left. How can I do that?
const box = document.getElementById("box")
const initHeight = 200
const initWidth = 200
const centerX = initWidth / 2
const centerY = initHeight / 2
function transform(scale, translate) {
if (translate) {
translate[0] = -centerX + translate[0]
translate[1] = -centerY + translate[1]
}
box.style.transform = `scale(${scale})${
translate ? ` translate(${translate.map((x) => x + "px").toString()})` : ""
}`
}
let initX = initWidth
let initY = initHeight
let scaleVal = 0.5
transform(scaleVal, [initX, initY])
function scale() {
scaleVal = scaleVal + 0.01
transform(scaleVal, [
initX - scaleVal * initWidth,
initY - scaleVal * initHeight
])
if (scaleVal <= 1) {
setTimeout(() => {
requestAnimationFrame(scale)
}, 50)
}
}
scale()
* {
box-sizing: border-box;
}
.box {
height: 200px;
width: 200px;
background-color: black;
position: absolute;
}
.box:nth-child(2) {
background-color: red;
}
<div id="app">
<div class="box"></div>
<div class="box" id="box"></div>
</div>
To lock the bottom right corner of the red box to the bottom right of the black box this snippet does two things: positions red box right bottom relative to the parent app container and sets the transform-origin to that spot too (normally transform origin is at the center of an element). It then uses a CSS animation to expand the red box and contract it again using scale.
This method does not need JS as it is a simple scaling transform, but of course some of the subtleties of the original transformations are lost because of tying the corner down.
* {
box-sizing: border-box;
}
body {
position: relative;
width: 100vw;
height: 100vh;
}
#app {
position: absolute;
height: 200px;
width: 200px;
}
.box:nth-child(1) {
height: 200px;
width: 200px;
background-color: black;
position: absolute;
top: 0;
left: 0;
}
#box {
background-color: red;
width: 100px;
height: 100px;
position: absolute;
bottom: 0;
right: 0;
transform-origin: right bottom;
animation: scale 5s 1 ease-in-out;
}
#keyframes scale {
0% {
transform: scale(1);
}
50% {
transform: scale(2);
}
100% {
transform: scale(1);
}
}
<div id="app">
<div class="box"></div>
<div class="box" id="box"></div>
</div>
Okay so I finally figured it out,
const box = document.getElementById("box")
let scale = 0
const initWidth = 50
const initHeight = 50
function fixed(num, fix = 1) {
return Number(parseFloat(num).toFixed(fix))
}
function scaleBox() {
const [x, y] = [
fixed((initWidth - scale * initWidth) / 2),
fixed((initHeight - scale * initHeight) / 2)
]
box.style.transform = `translate(${x}px, ${y}px) scale(${scale})`
scale = scale + 0.1
if (scale < 1) {
setTimeout(() => {
requestAnimationFrame(scaleBox)
}, 500)
}
}
scaleBox()
* {
box-sizing: border-box;
}
.box {
height: 50px;
width: 50px;
background-color: black;
position: absolute;
}
.box:nth-child(2) {
background-color: red;
transform: translate(0, 0) scale(0);
}
<div id="app">
<div class="box"></div>
<div class="box" id="box"></div>
</div>
Explanation
The trick is to translate the container in such a way that when its scaled after the translation, it always places itself in the bottom right of purple container.
To figure out the translation amount, let's first scale the container to 0.5 without any translation. It looks like this,
As you can see the container's width is 25 as 0.5(scale) * 50(init_width)=25 and position from container from all sides(top left, bottom left, top right, bottom right) will be (25/2, 25/2)=(12.5,12.5) since the container is scaled equally from all sides.
Since the position from bottom right is (12.5,12.5), we need to translate the container to (+12.5,+12.5) and then scale it to exactly place it at bottom right.
You can achieve many things using display:flex, it's great!
This is how I would approach your problem:
const handleClick = () => {
const blackDiv = document.getElementById("black-div");
const redDiv = document.getElementById("red-div");
let widthRatio = 0;
let heightRatio = 0;
const scaleUpTimer = setInterval(() => {
if (widthRatio === 1 || heightRatio === 1) clearInterval(scaleUpTimer);
widthRatio = redDiv.offsetWidth / blackDiv.offsetWidth;
heightRatio = redDiv.offsetHeight / blackDiv.offsetHeight;
redDiv.style.width = widthRatio * 100 + 2 + "%";
redDiv.style.height = heightRatio * 100 + 2 + "%";
}, 10);
};
#black-div {
width: 200px;
height: 200px;
background-color: rgb(0, 0, 0);
display: flex;
align-items: flex-end;
justify-content: flex-end;
}
#red-div {
background-color: red;
width: 50%;
height: 50%;
}
<div id='black-div'>
<div id='red-div' onclick={handleClick()}></div>
</div>
EDIT: I used onclick here but obviously you would have to handle the situations where someone clicks the red square and its already scaled up to avoid setting unnecessary timers. Or you could just call the function directly, without having to click anything.
<div class="game">
<div class="hole hole1">
<div class="mole"></div>
</div>
<div class="hole hole2">
<div class="mole"></div>
</div>
<div class="hole hole3">
<div class="mole"></div>
</div>
<div class="hole hole4">
<div class="mole"></div>
</div>
<div class="hole hole5">
<div class="mole"></div>
</div>
<div class="hole hole6">
<div class="mole"></div>
</div>
<div class="hole hole7">
<div class="mole"></div>
</div>
<div class="hole hole8">
<div class="mole"></div>
</div>
<div class="hole hole9">
<div class="mole"></div>
</div>
</div>
.game {
width: 300px;
height: 600px;
display: flex;
flex-wrap: wrap;
margin: 0 auto;
}
.hole {
flex: 1 0 33.33%;
overflow: hidden;
width: 100%;
position: relative;
}
.hole:after {
display: block;
background: url('gaura1.png') bottom center no-repeat;
background-size: 100%;
content: '';
width: 100%;
height:100%;
position: absolute;
z-index: 2;
}
.mole {
background: url('flowAlb.png') bottom center no-repeat;
background-size: 100%;
position: absolute;
width: 100%;
height:100%;
top:100%;
transition: all 0.4s;
}
.hole.up .mole {
top: -20px;
z-index:3;
}
I'm trying to learn web development with CSS, HTML and JAVASCRIPT(i'm new to all of them) and I'm working on some whack-a-mole game code that was free to work with. I understood what the code does, but I'm not sure how to work with. I have an event listener on click for each mole, but I wanna do something if the mole isn't clicked and I don't know how to check that. I tried different methods, using boolean variables or trying to check if the click was outside the element, but none of them worked. I'm pretty sure I didn't used them right, so I would really appreciate some help or information. I'll leave here the JS code. Thanks so much!
const holes = document.querySelectorAll('.hole');
const scoreBoard = document.querySelector('.score');
const moles = document.querySelectorAll('.mole');
const mySound=document.getElementById("sound");
const joc=document.getElementsByClassName("game");
let lastHole;
let timeUp = false;
let score = 0;
function randomTime(min, max) {
return Math.round(Math.random() * (max - min) + min);
}
function randomHole(holes) {
const index = Math.floor(Math.random() * holes.length);
const hole = holes[index];
if (hole === lastHole) {
return randomHole(holes);
}
lastHole = hole;
return hole;
}
function peep() {
const time = randomTime(500, 1000);
const hole = randomHole(holes);
hole.classList.add('up');
setTimeout(() => {
hole.classList.remove('up');
if (!timeUp) {
peep();
}
}, time);
}
function startGame() {
scoreBoard.textContent = 0;
timeUp = false;
score = 0;
peep();
setTimeout(() => timeUp = true, 90000)
}
function wack(e) {
if (!e.isTrusted) return;
score = score + 100;
this.parentNode.classList.remove('up');
scoreBoard.textContent = score;
}
moles.forEach(mole => mole.addEventListener('click', wack));
You can add a click event to the documentElement and check its target. Consequently you could also remove your other click handlers while doing this and check for the class mole.
;document.documentElement.onclick = function(event){
//REM: Target element of the click
var tTarget = event.srcElement || event.target;
//REM: Check which element was targted.
if(tTarget.id === 'sample'){
alert('You clicked on #sample')
}
else{
alert('You clicked on "' + tTarget.tagName + '"')
}
};
html, body{
height: 100%;
position: relative;
width: 100%
}
body{
background: yellow
}
div{
background: red
}
.sample{
background: lime;
height: 100%;
position: relative;
width: 100%
}
<div class = 'sample'>
<div id = 'sample'>click me or not</div>
</div>