When mousemove() it only gets the position of first item. Now they are all overlapping. How can I improve this?
https://codepen.io/penny289/pen/JjJzYbv
$(window).mousemove(function(evt){
$('.img-box').each(function(){
var positionX= $(this).offset().left/100
var positionY= $(this).offset().top/100
$(this).css("left",positionX+evt.pageX/100+"%")
.css("top",positionY+evt.pageY/100+"%")
})
})
<div class="container">
<div class="img-box box-1">
<img src="https://images.unsplash.com/photo-1632012643163-c9c4fbbd9f05?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzEwNg&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-2">
<img src="https://images.unsplash.com/photo-1632778931175-128809d8facc?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzE2MQ&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-3">
<img src="https://images.unsplash.com/photo-1594734044877-2ebba0c14720?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzIwMg&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-4">
<img src="https://images.unsplash.com/photo-1630231211819-a131d7538a41?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzIxNQ&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-5">
<img src="https://images.unsplash.com/photo-1632073591482-0d69552e07df?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzI1NA&ixlib=rb-1.2.1&q=85">
</div>
</div>
It does not get the coordinates of the first image only. Rather, you seem to have several problems:
You are dividing by 100, presumably because you are working with percentages, but unless your screen is 100 pixels wide that is obviously wrong.
.offset() does return an offset relative to the document, but you are positioning your items relative to your container
You are trying to dynamically grab the offset every time, but if you go for this approach you would need to know what part of that offset is from the previous time you called this function. Otherwise you start accumulating the x and y position of your MouseEvent and quickly move the entire thing off the screen.
There is no reason for you to use percentages, so just work with absolute pixels and simplify your code.
Then store the initial offset with .data(..) so you don't have to subtract your previous mouse position and keep track of that every single time. Since you want to have the offset relative to the container (because your css renders it relative to the container), subtract the container offset from your image offset.
Now you can make the images move with your mouse by adding your mouse pageX/pageY.
Besides that, you should use a debounce (does not work in stacksnippets) and window.requestAnimationFrame so your cpu does not melt trying to draw something for every pixel your mouse moves, but rather only when it is ready to draw a single frame.
$(window).mousemove(function(evt){
//_.debounce(() => {
window.requestAnimationFrame(() => {
const containerOffsetX = $('.container').offset().left;
const containerOffsetY = $('.container').offset().top;
$('.img-box').each(function(elem, i){
let imageOffsetX = $(this).data('offsetX');
if (!imageOffsetX) {
imageOffsetX = $(this).offset().left - containerOffsetX;
$(this).data('offsetX', imageOffsetX);
}
let imageOffsetY = $(this).data('offsetY');
if (!imageOffsetY) {
imageOffsetY = $(this).offset().top - containerOffsetY;
$(this).data('offsetY', imageOffsetY);
}
const mouseOffsetX = evt.pageX;
const mouseOffsetY = evt.pageY;
const newPositionX = imageOffsetX + mouseOffsetX;
const newPositionY = imageOffsetY + mouseOffsetY;
$(this).css("left", `${newPositionX}px`)
.css("top", `${newPositionY}px`)
});
});
//}, 10);
});
body{
display:flex;
align-items:center;
justify-content:center;
}
.container{
width:70vw;
height:500px;
position:relative;
}
.img-box{
position:absolute;
}
.img-box img{
width:300px;
height:200px;
/* transform:translate(-50%); */
}
.img-box.box-1{
top:10%;
}
.img-box.box-2{
left:20%;
top:80%;
}
.img-box.box-3{
top:50%;
left:50%;
}
.img-box.box-4{
top:10%;
left:90%
}
.img-box.box-5{
left:90%;
top:70%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div class="container">
<div class="img-box box-1">
<img src="https://images.unsplash.com/photo-1632012643163-c9c4fbbd9f05?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzEwNg&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-2">
<img src="https://images.unsplash.com/photo-1632778931175-128809d8facc?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzE2MQ&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-3">
<img src="https://images.unsplash.com/photo-1594734044877-2ebba0c14720?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzIwMg&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-4">
<img src="https://images.unsplash.com/photo-1630231211819-a131d7538a41?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzIxNQ&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-5">
<img src="https://images.unsplash.com/photo-1632073591482-0d69552e07df?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzI1NA&ixlib=rb-1.2.1&q=85">
</div>
</div>
Related
I am attempting to scale an image on each button click, while maintaining it's orgin. However, I can't seem to get the orgin to stay in place (keep top / left) while scaling right side and bottom of image. Currently if you scale, top and left side of image get cut off.
Please see my JSfiddle attached as comment below.
let scale = 1;
$('#myBtn').click(function(){
scale+=0.1;
$('#my-image').css({'transform':'scale(' + scale + ')' });
$('#my-image').css({'transform-orgin':'top left'});
})
div {
float: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style = "overflow-x:scroll; overflow-y:scroll">
<div style="max-width: 800; height: 600">
<img id="my-image" src="https://images.techhive.com/images/article/2017/03/castle_moat-100714623-large.jpg" clss="img-fluid"/>
</div>
</div>
<button id=myBtn> Zoom In </button>
I'm trying to use a scroll function to run a function once it passes greater than or less than <a> tags. First the starting point which is fixed on the page:
<div style="height: 200px">
<input type="text" id="starting-point" />
<div>
This is setting the starting point at 200px from the top of the page. Then the container behind it could be anything from 1000px to 3000px when scrolling (using the window as scrolling).
<div style="height: 200px;">
<input type="text" id="starting-point" />
<div>
<div style="height: 3000px;">
<!-- ... content here -->
<div style="height: 200px;">
1
</div>
<div style="height: 300px;">
2
</div>
<div style="height: 240px;">
3
</div>
etc...
</div>
What I'm trying to achieve is for each <a> tag that passes the starting point, to do show something. So when scrolling it starts at 1, once 2 reaches the starting point, something on the page (like a textbox) would switch it from 1 to 2, and so on going down, and then work in reverse going back up. This is what I have so far:
$(document).ready(function () {
window.addEventListener('scroll', function (e) {
var setStart = $('#starting-point').offset().top - $(window).scrollTop(); // starting point
var getTag = $('a');
if (setStart >= getTag) {
run function here
}else{
run function here
}
});
});
I don't know how to set a variable to when an <a> tag passes that starting point to pass it into the function to run what I need. There could be 20 <a> tags on the page. Running a for loop I don't think solves the issue.
Here is a demo on how you could do it.
There could be some other way too.
On load, we get the position of the #starting-point and all the anchors which now have the scroll_target class.
Then, on scroll, you have to determine the scrolling direction... Because the logic is slightly different going up compared to going down.
Each time it passes a "target" position, the scroll_target is decremented/incremented.
So you know which anchor just passed because of the position array.
I made a text array to update the input based on the anchor's text that just passed. It could also be the anchor's value or a data-* attribute.
I left all console logs for you to see what is going on.
$(document).ready(function(){
var startPoint = $("#starting-point").offset().top;
console.log(startPoint);
var scrollTargets_pos = [];
var scrollTargets_text = [];
var scrollingDown = true;
var lastScroll = 0;
$(".scroll_target").each(function(){
scrollTargets_pos.push($(this).offset().top);
scrollTargets_text.push($(this).text());
});
console.log(scrollTargets_pos);
console.log(scrollTargets_text);
var passedIndex = -1;
$(window).on("scroll",function(){
var scrolled = $(this).scrollTop();
console.log(scrolled);
// Scroll direction
scrollingDown = (scrolled > lastScroll);
lastScroll = scrolled;
if(scrollingDown){
// Scrolling down...
//console.log("down");
if( scrolled+startPoint > scrollTargets_pos[passedIndex+1] ){
console.log("======================");
$("#starting-point").val(scrollTargets_text[passedIndex+1]);
passedIndex++;
}
}else{
// Scrolling up...
//console.log("up");
if( scrolled+startPoint < scrollTargets_pos[passedIndex] ){
console.log("======================");
$("#starting-point").val(scrollTargets_text[passedIndex])
passedIndex--;
}
}
});
}); // End ready
.startPointDiv{
position: fixed;
top: 100px;
left:0;
width:100%;
border-top: 1px solid red;
text-align: center;
}
.content{
height: 3000px;
margin-top: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="startPointDiv">
<input type="text" id="starting-point" />
</div>
<div class="content">
<!-- ... content here -->
<div style="height: 200px;">
1
</div>
<div style="height: 300px;">
2
</div>
<div style="height: 240px;">
3
</div>
etc...
</div>
I have a bar with inline-block divs. Some of them are out of viewport because I set: white-space:nowrap; overflow: hidden; for the container. I'm looking for ways to select last visible child. By visible I mean that the div is placed (preferably fully) in area of it's container.
As far as I know there is selector like that neither in CSS nor in jQuery. The closest one is jQuery's :visible but it says that all the divs are visible because they consume space in the page layout.
The only way out I see is to enumerate divs on load and every resize in order to calculate if the div is still in the container by summing it's width, padding and margins.
Do you have any better ideas?
#container {
white-space:nowrap;
overflow: hidden;
}
.element {
display: inline-block;
vertical-align:top;
}
<div id="container">
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
</div>
In current, non responsive version of stack overflow on the snippet we can see 4 full divs and small part of 5th. I'd like to select 5th one (or preferably 4th div because the next one isn't fully visible).
You could use media queries. Of course, this could become very cumbersome, depending on the number of child elements you have, but it does save the overhead of using an onresize event listener.
For the below Snippet, I've assumed that the parent element is running the full width of the screen.
*{box-sizing:border-box;margin:0;padding:0;}
#container{
font-size:0;
overflow:hidden;
white-space:nowrap;
}
.element{
display:inline-block;
opacity:.5;
padding:5px;
vertical-align:top;
width:150px;
}
img{
width:100%;
}
#media (max-width:299px){
.element:first-child{opacity:1;}
}
#media (min-width:300px) and (max-width:449px){
.element:nth-child(2){opacity:1;}
}
#media (min-width:450px) and (max-width:599px){
.element:nth-child(3){opacity:1;}
}
#media (min-width:600px) and (max-width:749px){
.element:nth-child(4){opacity:1;}
}
#media (min-width:750px) and (max-width:899px){
.element:nth-child(5){opacity:1;}
}
#media (min-width:900px) and (max-width:1049px){
.element:nth-child(6){opacity:1;}
}
#media (min-width:1050px) and (max-width:1199px){
.element:nth-child(7){opacity:1;}
}
#media (min-width:1200px){
.element:nth-child(8){opacity:1;}
}
<div id="container">
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
</div>
i've done some JQ code, hope it helps
this works if all elements have the same width. if they have different widths the code would need some small changes
see here > JSFIDDLE
JQ CODE :
var vwidth = $(window).width() // get window width
var ewidth = $(".element").width() // get element width
var total = vwidth / ewidth // calculate how many elements fit inside the window width
var integer = parseInt(total)// get the integer from the result above
$(".element").eq( integer - 1 ).addClass("lastvisible")// -1 because eq starts from 0
solution for elements with different widths :
JQ :
var vwidth = $(window).width(); // get screen width
$(".element").each(function(){
var eleft = $(this).offset().left // each element's distance from left of the screen
var ewidth = $(this).width()// each element's width
var total = eleft + ewidth
if (total < vwidth) { // if sum between distance from left of screen + element width is smaller than the window screen
that = $(this); // all elements that are visible inside the screen
}
});
that.addClass("lastvisible") //only the last element visible inside the screen
see fiddle here > JsFiddle
This is my way to make it work but I'll welcome any better way.
Everything is being calculated by jQuery:
var cwidth = parseInt($('#container').width()); // get container width
var lastElement = $('#container .element:first'); // assume that first element is visible
$("#container .element:not(:first)").each(function(){
//get right offset for every div
var rightOffset = $(this).offset().left
+ parseInt($(this).width())
+ parseInt($(this).css('padding-left'))
+ parseInt($(this).css('margin-left'));
//if the right offset is bigger than container width then stop enumerating - previous one was the last fully visible
if (rightOffset > cwidth){
return false;
}
//offset was lower than container with so this is our new fully visible element
lastElement = $(this);
});
lastElement.addClass("lastvisible")
advantages:
Working for different element sizes
Add same recalculating on window resize and you've got a working responsive way
drawbacks:
multiple jQuery recalculations that are quite havy for the browser
in my opinion ugly code
https://jsfiddle.net/6k5xujtc/1/
I have centered div for my side. Now I want to calculate left side blank space. How to do it by jquery.
My Markup
<main id="page_main" role="main">
<div class="content">
</div>
</main>
My Css
#page_main
{
width:100%;
}
.content
{
width:960px;
margin:0px auto;
}
Now I want to calculate the screen's left side blank space. Can you help me how to do it?
You can use offset() which returns coordinates of element relative to document. It return Object with top and left properties. DEMO
$(window).on("resize", function () {
var c = $(".content").offset().left;
$('.content').text(c)
}).resize();
I am currently making a grid layout for my site. What I want is a set of 9 images to load as fast as possible, and then, after the page loads, I want to retrieve more images, add them to the image containers and animate between them. I know how to do the transitions, but I do not know the best way to stack the images in order to animate between them. Create img nodes and appending them as children just adds them to the page. Additionally, trying to absolutely position each element wreaks havoc on my layout.
I know floating them would prevent the images from taking up vertical space but, as I am not using floats right now, I want to avoid using them just to stack images.
If you look at my HTML I am basically just trying to create a stack of several images in the divs, all of them on top of each other.
Any guidance would be great.
Here is my HTML:
<div id="mainContainer">
<div class="imageHolder"><img class="homeImages" src="test.png"></div>
<div class="imageHolder"><img class="homeImages" src="test1.png"></div>
<div class="imageHolder"><img class="homeImages" src="test2.png"></div>
<div class="imageHolder"><img class="homeImages" src="test3.png"></div>
<div class="imageHolder"><img class="homeImages" src="test4.png"></div>
<div class="imageHolder"><img class="homeImages" src="test5.png"></div>
<div class="imageHolder"><img class="homeImages" src="test6.png"></div>
<div class="imageHolder"><img class="homeImages" src="test7.png"></div>
<div class="imageHolder"><img class="homeImages" src="test8.png"></div>
</div>
I am using this javascript to preload the new images after page loads:
var imageHolders = document.querySelectorAll('.imageHolder');
var imageArray = [
'media/refined/newImage.png',
'media/refined/newImage1.png',
'media/refined/newImage2.png',
'media/refined/newImage3.png',
'media/refined/newImage4.png',
];
var imageNodeArray = [];
for(var i = imageArray.length - 1; i >= 0; i -= 1) {
var img = new Image();
img.onload = function() {
imageNodeArray.push(this);
};
img.src = imageArray[i];
}
document.onclick = function() {
imageNodeArray[0].setAttribute('class', 'changed opaque');
imageHolders[0].appendChild(imageNodeArray[0])
}
And the CSS is really what is getting me:
#mainContainer {
margin: 0 auto;
padding: 2.2em 0;
width: 85%;
text-align: center;
}
div.imageHolder {
display: inline;
}
img {
width: 30%;
}
.changed.opaque {
opacity: .5;
border: 2px solid red;
}
Thank you!
Set position of your main container as relative and of each image containers as absolute.
http://jsfiddle.net/ehu5j/