jQuery make image popup in random position not working - javascript

I want to make an image randomly show up every 2 sec using jQuery. But the image always shows in a static position (top-left). I console.logged the attribute of the image and its left and top shows random px.
let score = 0;
let id = 0;
$(document).ready(function () {
setInterval(setImage, 2000);
});
function setImage() {
$("#container").append(
`<img src='images/virus.gif' id='${id}' width='75px' position='absolute' class='virus' left=${randomLeft()} top=${randomTop()}/>`
);
$("#" + id)
.slideUp(0)
.fadeIn(1000);
id++;
$("#" + id).on("click", function (event) {
$(event.target).remove();
score++;
console.log($(event.target).attr("id"), score);
});
}
function randomTop() {
let height = $(window).height();
let randomHeight = Math.floor(Math.random() * (height - 75)) + "px";
return randomHeight;
}
function randomLeft() {
let width = $(window).width();
let randomLeft = Math.floor(Math.random() * (width - 75)) + "px";
return randomLeft;
}

You need to use style rather than left/top attributes
style="left:10px;right:10px"
Couple of other tweaks to your snippet:
include jquery (option on the left of snippet editor adds <script> to the html)
needs a #container to put them in, I made this position:relative so the position:absolute will work
removed the need for the $("#"+id) re-finding by chaining the append
put the i++ at the beginning so that you don't try to attach click to something that doesn't exist yet (but doesn't matter as not used for re-finding new element)
$(this).remove() must come after $(this).attr("id") - you were removing it before getting its ID
used this inside the click handler rather than event.target
would be better as data-id=${++id} rather than using a numerical id, but that's a small change (not made)
Updated snippet:
let score = 0;
let id = 0;
$(document).ready(function() {
setInterval(setImage, 2000);
});
function setImage() {
var img = $(`<img src='images/img4.jpg' id='${++id}' class='virus' style='left:${randomLeft()};top:${randomTop()}' />`);
img.appendTo("#container")
.slideUp(0)
.fadeIn(1000)
.on("click", function() {
score++;
console.log($(this).attr("id"), score);
$(this).remove();
});
}
function randomTop() {
let height = $(window).height();
let randomHeight = Math.floor(Math.random() * (height - 75)) + "px";
return randomHeight;
}
function randomLeft() {
let width = $(window).width();
let randomLeft = Math.floor(Math.random() * (width - 75)) + "px";
return randomLeft;
}
#container {
position: relative;
height: 100%;
width: 100%;
}
.virus {
border: 1px solid red;
position: absolute;
width: 75px;
height: 20px;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='container'></div>

Related

Non-Linear DOM Animations

Question: WHAT THE "myMove()" METHOD DOES? Can you explain it?
#myContainer {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#myAnimation {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
Click Me
function myMove() {
var elem = document.getElementById("myAnimation");
var pos = 0;
var id = setInterval(frame, 10);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
Quick note: In this answer, I'll be assuming the final question reads:
What does the `myMove()` method do?
Let's first take a look at the variables:
var elem = document.getElementById("myAnimation");
var pos = 0;
var id = setInterval(frame, 10);
The variable elem refers to the red box which is being moved across the canvas (a div element). We set the pos tick variable to 0, which will control how many times we will move the box across the screen. Finally, id refers to a setInterval function which calls the defined frame function every 10 milliseconds.
Now let's look at the function frame:
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
First, it runs a quick check to see if the ticks are done, or in other words, checks to see if the position is 350. Then, if it is, it stops the loop. If it is not, it makes the box move down 1 pixel by setting the position from the top to the pos variable.
All of this code is contained within the myMove() function.

alert when scrollbar is at 75%

document.onscroll = function()
{
if (document.documentElement.scrollTop + window.innerHeight > document.documentElement.scrollHeight * 0.75)
{
var height = document.documentElement.height;
document.documentElement.height = height + 500;
alert('75%');
}
};
html {
height: 1000px;
}
I want this code to run every time the scrollbar reaches 75% of its height to add 500px then repeat the function when it reaches the 75% again.
The code works on my environment but if I scrolled fast I get multiple alerts and the 500px gets added more than once.
I tried the following:
document.documentElement.scrollTop + window.innerHeight == document.documentElement.scrollHeight * 0.75
but it never alerted.
There is no such height property on documentElement object. To update the height you have to access style property documentElement.
Try this.
document.onscroll = function()
{
if (document.documentElement.scrollTop + window.innerHeight > document.documentElement.scrollHeight * 0.75)
{
var height = document.documentElement.style.height;
document.documentElement.style.height = (+height.slice(0,-2) + 500) + "px";
alert('75%');
}
};
<!DOCTYPE html>
<html style="height: 1600px">
</html>
Hope this helps :).
EDIT: Attached screenshots.
Use console for better results
var sw_75 = false;
window.onscroll = function () {
if (sw_75) return;
if (document.documentElement.scrollTop + window.innerHeight > document.documentElement.scrollHeight * 0.75) {
console.log('75%');
sw_75 = true;
var body = document.getElementsByTagName('body')[0];
var height = parseInt(body.style.height.replace("px", ""));
body.style.height = (height + 500) + "px";
sw_75 = false;
}
};
html, body {
margin: 0px;
padding: 0px;
}
<body style="height:1000px;"></body>

Recalculate scrolling div position when used in a clipping path

I am using clipping paths to change my logo colour base on the background colour.
In addition to this the logo scrolls from top to bottom based on the users vertical position on the page. Top of page = logo at top, bottom of page = logo at bottom etc.
Unfortunately when I added the clipping paths the logos lost their scroll position and after the first one, do not work at all.
Is there a way around this? Also, the logo position was a little off to start with so if there is any way of addressing this at the same time.
You can see the original question here:
div position based on scroll position
I have tried this, but I can't seem to get it to work.
Scroll position lost when hiding div
I am using Advanced Custom Fields and each sections PHP file has this in the header as part of the clipping path using either the white or dark version of the logo accordingly. Its parent is positioned relatively and its child absolutely.
div class="logo-scroll">
<div class="scroll-text">
<img width="53px" height="260px" src="/wp-content/uploads/2019/07/sheree-walker-web-design-edinburgh-vertical-01.svg"/>
</div>
</div>
The Javascript
const docHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
const logo = document.querySelector('.scroll-text');
const logoHeight = logo.offsetHeight;
// to get the pseudoelement's '#page::before' top we use getComputedStyle method
const barTopMargin = parseInt(getComputedStyle(document.querySelector('#page'), '::before').top);
let viewportHeight, barHeight, maxScrollDist, currentScrollPos, scrollFraction;
logo.style.top = barTopMargin + 'px';
window.addEventListener('load', update);
window.addEventListener('resize', setSizes);
document.addEventListener('scroll', update);
setSizes();
function update() {
currentScrollPos = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
scrollFraction = currentScrollPos / (docHeight - viewportHeight);
logo.style.top = barTopMargin + (scrollFraction * maxScrollDist) + 'px';
}
function setSizes() {
viewportHeight = window.innerHeight;
// to get the pseudoelement's '#page::before' height we use getComputedStyle method
barHeight = parseInt(getComputedStyle(document.querySelector('#page'), '::before').height);
maxScrollDist = barHeight - logoHeight;
update();
}
The CSS
.logo-scroll .scroll-text img {
padding: 0 6px 0 17px;
}
#page::before {
content: "";
position: fixed;
top: 30px;
bottom: 30px;
left: 30px;
right: 30px;
border: 2px solid white;
pointer-events: none;
-webkit-transition: all 2s; /* Safari prior 6.1 */
transition: all 2s;
}
.logo-scroll {
position: fixed;
left: 30px;
top: 30px;
bottom: 30px;
border-right: 2px solid white;
width: 75px;
z-index: 10;
}
.scroll-text {
position: fixed;
}
let logos, logoHeight, barTopMargin;
let viewportHeight;
window.addEventListener('load', init);
window.addEventListener('resize', setSizes);
document.addEventListener('scroll', update);
function init(lockUpdate) {
logos = document.querySelectorAll('.scroll-text');
setSizes(lockUpdate);
}
function update() {
// ensure initialization and prevent recursive call
if (!logos) init(true);
//*************************************************
/**************************************************
THIS LINE MUST BE HERE.
**************************************************/
let maxScrollDist = document.documentElement.scrollHeight - viewportHeight;
//*************************************************
let currentScrollPos = document.documentElement.scrollTop;
let newTop;
let middle = currentScrollPos + viewportHeight/2;
let middleY = maxScrollDist/2;
if (middle >= (maxScrollDist+viewportHeight)/2) {
let p = (middleY - Math.floor(middle - (maxScrollDist+viewportHeight)/2))*100/middleY;
newTop = viewportHeight/2 - logoHeight/2;
newTop += (100-p)*(viewportHeight/2)/100;
newTop -= (100-p)*(barTopMargin +logoHeight/2)/100;
newTop = Math.max(newTop, viewportHeight/2 - logoHeight/2); /*fix*/
} else {
let p = (middleY - Math.floor(-middle + (maxScrollDist+viewportHeight)/2))*100/middleY;
newTop = barTopMargin*(100-p)/100+(viewportHeight/2 - (logoHeight/2)*p/100 )*p/100;
newTop = Math.min(newTop, viewportHeight/2 - logoHeight/2); /*fix*/
}
logos.forEach(function(el) {
el.style.top = newTop + "px";
});
}
function setSizes(lockUpdate) {
logoHeight = logos[0].offsetHeight;
barTopMargin = parseInt(getComputedStyle(document.querySelector('#page'), '::before').top);
viewportHeight = window.innerHeight;
if (lockUpdate === true) return;
update();
}
updated and tested.
to check it put this code in your console:
document.removeEventListener('scroll', update);
document.onscroll = function() {
let _logoHeight = logos[0].offsetHeight;
let _barTopMargin = parseInt(getComputedStyle(document.querySelector('#page'), '::before').top);
let _viewportHeight = window.innerHeight;
let _maxScrollDist = document.documentElement.scrollHeight - _viewportHeight;
let currentScrollPos = document.documentElement.scrollTop;
let percent100 = currentScrollPos + _viewportHeight;
let scrolledPercent = currentScrollPos * 100/_maxScrollDist;
let newTop = ((_viewportHeight - _logoHeight/2)*scrolledPercent/100);
let middle = currentScrollPos + _viewportHeight/2;
let middleY = _maxScrollDist/2; // 100
if (middle >= (_maxScrollDist+_viewportHeight)/2) {
let y1 = middleY - Math.floor(middle - (_maxScrollDist+_viewportHeight)/2);
let p = y1*100/middleY;
newTop = _viewportHeight/2 - _logoHeight/2;
newTop += (100-p)*(_viewportHeight/2)/100;
newTop -= (100-p)*(30 +_logoHeight/2)/100;
newTop = Math.max(newTop, _viewportHeight/2 - _logoHeight/2); /*fix*/
} else {
let y2 = middleY - Math.floor(-middle + (_maxScrollDist+_viewportHeight)/2);
let p = y2*100/middleY;
newTop = 30*(100-p)/100+(_viewportHeight/2 - (_logoHeight/2)*p/100 )*p/100;
newTop = Math.min(newTop, _viewportHeight/2 - _logoHeight/2); /*fix*/
}
logos.forEach(function(el) {
el.style.top = newTop + "px";
});
}
CSS fix:
custom.css :: line 767
#media (max-width: 1000px)...
.scroll-text {
padding-left: 13px;
/*width: 27px;*/
}
.scroll-text img {
/* remove it. but if necessary move it to .scroll-text rule above
width: 27px; */
}
custom.css :: line 839
#media (max-width: 599px)...
.logo-scroll {
/*display: none; why! remove it*/
}
custom.css :: line 268
.scroll-text {
position: fixed;
/* height: 280px; remove it*/
padding-left: 20px;
}
see this capture
finally, have a nice day and goodby.
You are selecting only the first 'logo-text'. Instead of:
const logo = document.querySelector('.scroll-text');
You should use querySelectorAll:
const logos = document.querySelectorAll('.scroll-text');
Then, in your scroll handler, you should move them all.
So, you would then substitute each instance of usage of logo with a loop through the all the logo elements:
logos.forEach(logo => logo.style.top = ...);
Please be aware that you are doing quite expensive stuff in a scroll handler, which is not great for rendering performance. You might also want to use requestAnimationFrame to improve the rendering performance. Check out the reference page on MDN. Actually, I quickly whipped a version using requestAnimationFrame but there was no sensible performance improvement. This is probably due to the fact that apparently rAF fires roughly at the same rate than the scroll event. Anyway, I removed it to avoid confusion. If you detect performance issues, let me know.
I suggest, though, that you move the logo using transform: translate() rather than top. Here you have a complete solution. I tried it in Chrome.
const docHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
const logos = document.querySelectorAll('.scroll-text');
const logoHeight = logos[0].offsetHeight;
// to get the pseudoelement's '#page::before' top we use getComputedStyle method
const barTopMargin = parseInt(getComputedStyle(document.querySelector('#page'), '::before').top);
let viewportHeight, barHeight, maxScrollDist, currentScrollPos, scrollFraction;
window.addEventListener('load', update);
window.addEventListener('resize', setSizes);
document.addEventListener('scroll', update);
setSizes();
function update() {
currentScrollPos = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
scrollFraction = currentScrollPos / (docHeight - viewportHeight);
const translateDelta = barTopMargin + (scrollFraction * maxScrollDist);
logos.forEach(logo => logo.style.transform = `translateY(${translateDelta}px)`);
}
function setSizes() {
viewportHeight = window.innerHeight;
// to get the pseudoelement's '#page::before' height we use getComputedStyle method
barHeight = parseInt(getComputedStyle(document.querySelector('#page'), '::before').height);
maxScrollDist = barHeight - logoHeight;
update();
}

generate animation as if it were a marquee

I do not know much about css, but I think this code could help me generate a marquee. basically I want the animation that is done with the boxes, be done with the texts.
My main problem occurs with the animation, it is not very fluid, I want it to be more fluid and it starts from the end of the container to the left. How can I do it? I would be very grateful.
http://jsfiddle.net/joof5dhx/
<div id="horizontalScroller">
<div>it is a message a little more of 100 characteres</div>
<div>it is a message a little more of 110 characteres</div>
<div>it is a message a little more of 120 characteres</div>
<div>it is a message a little more of 130 characteres</div>
</div>
window.horizontalScroller = function($elem) {
var left = parseInt($elem.css("left"));
var temp = -1 * $('#horizontalScroller > div').height();
if(left < temp) {
left = $('#horizontalScroller').height()
$elem.css("left", left);
}
$elem.animate({ left: (parseInt(left)-60) }, 900, function () {
window.horizontalScroller($(this))
});
}
$(document).ready(function() {
var i = 0;
$("#horizontalScroller > div").each(function () {
$(this).css("left", i);
i += 60;
window.horizontalScroller($(this));
});
});
http://jsfiddle.net/hhcbtyyg/
You could just:
window.horizontalScroller = function($elem)
{
var left = parseInt($elem.css("left"));
$elem.animate({ left: (parseInt(left)-60) }, 900, function ()
{
// get the current left of the element
var currentLeft = parseInt($(this).css("left"));
// get the width of the element
var width = $(this).width();
// get the container
var container = $(this).parent("#horizontalScroller");
// get the width of the container
var containerWidth = $(container).width();
// check if the element goes out of the view item X + item w < 0
if ((currentLeft + width) <= 0)
{
// put it on the opposite side: simply container w + item w
$(this).css("left", (containerWidth + width) + "px");
}
window.horizontalScroller($(this))
});
}
I just don't understand why you use height in your code above. If there is something I don't know let me know.
UPDATED:
To make the items appear on the leftmost by default:
$(document).ready(function() {
var container = $("#horizontalScroller");
var children = $(container).children();
var containerW = $(container).width();
// Loop through each item of container
for (var i = 0; i < children.length; i++)
{
var item = children[i];
var itemW = $(item).width();
// this is simply the space between them, remove if you don't need it
var padding = 10 * (i + 1);
// simply: padding + Container Width + (Item Width * (i + 1))
// (Item Width * (i + 1)) because you need to position each element beside each other.
$(item).css("left", (padding + containerW + itemW * (i + 1)) + "px");
window.horizontalScroller($(item));
}
});
your updated fiddle
hope that helps
Hi checked this version of your jsfiddle, i did some modificaitons, since your animation starts from whatever the value of height is your div had. check this I tried to match the height of your css and width in your css, i just noticed that the "left" var in your js gets the height of your element.
CSS:
#horizontalScroller {
position: absolute;
width:300px;
height: 300px;
border: 1px solid red;
overflow: hidden;
}
Maybe you can get some tips how to accomplish it in responsive way.
JSFIDDLE

windows.scrollBy adding a fixed scrolling value to top

I have this function I'm using it in my AngularJS directive. This function scrolls to the top of the page, but this is not what I am aiming to do: I want to make it scroll up just 400px or 30%.
function scrollToTop() {
var scrollDuration = 500;
var scrollStep = -window.scrollY / (scrollDuration / 15);
console.log(scrollStep);
var scrollInterval = setInterval(function () {
if (window.scrollY != 0) {
window.scrollBy(0, scrollStep);
} else {
clearInterval(scrollInterval);
}
}, 15);
}
I tried changing the scrollStep variable to be 300 or any other number but I can't understand it actually.
The total distanceToScroll is either an arbitrary number of pixels (i.e 400) or the whole window-scroll distance if it is less than 400. For that you can use Math.min. scrollStep is calculated dependently from distanceToScroll. You need to keep a count of "how much I've scrolled so far" in the setInterval, lets call it distanceScrolled. Keep scrolling until you have covered the distanceToScroll.
function scrollToTop() {
var scrollDuration = 500;
var stepDuration = 15;
var distanceToScroll = Math.min(400, window.scrollY);
var scrollStep = distanceToScroll / (scrollDuration / stepDuration);
console.log(scrollStep);
var distanceScrolled = 0;
var scrollInterval = setInterval(function () {
if (distanceScrolled < distanceToScroll) {
window.scrollBy(0, -1 * scrollStep);
distanceScrolled += scrollStep
} else {
clearInterval(scrollInterval);
}
}, stepDuration);
}
document.getElementById('btn').addEventListener('click', scrollToTop);
#very-high {
height: 3000px;
}
#btn {
position: fixed;
right: 10px;
top: 10px;
}
<div id="very-high"></div>
<button id="btn">Scroll</button>

Categories