How to make an image click() after Keydown Function - javascript

I have an image that moves over divs. I have methods that are called after each div is clicked. How do i make my image simulate a mouseclick after it has been moved.
My code :
if (e.keyCode == 39) {
$("#img").animate({marginLeft: "+=107px"}, {queue:false}, "slow");
return false;
}
(39) Being the right move .
So after I click the right keyboard button , i want my image to move to the right (DONE) and then a mouseclick to click at the center of this image to click on the divs behind it.
I cant use the trigger() and click() functions because I don't know which corresponding divisor the image is over and hence cant $(#...)
The image moves perfectly over the divisors though.
<div id="Blocks">
<div id="41" class="square" ></div>
<div id ="42" class="square" ></div>
<div id ="43" class="square" ></div>
<div id ="44" class="square" ></div>
</div>
<div id ="Blocks2">
<div id ="31" class="square"></div>
<div id ="32" class="square"></div>
<div id ="33" class="square"></div>
<div id ="34" class="square"></div>
</div>
<div id ="Blocks3">
<div id ="21" class="square"></div>
<div id ="22" class="square"></div>
<div id ="23" class="square"></div>
<div id ="24" class="square"></div>
</div>
<div id ="Blocks4">
<div id ="11" class="square" ></div>
<div id ="12" class="square"></div>
<div id ="13" class="square"></div>
<div id ="14" class="square"></div>
</div>
Image moves over one of these divs , need to fire an event to know over which div id it is

1- Click is always registered on the upper-most div ( higher z-index ) that's under the cursor.
* You can't click "behind"
2- " because i dont know which corresponding divisor the image is over and hence cant $(#...) "
is false: you CAN find the div under your current position, because:
* you know your cursor coordinates
* you can know your divs offset ( = coordinates )
Proof: there's a plugin for that

Assuming you are using the jQuery animate() function (http://api.jquery.com/animate/), you can define a function to be called on complete (when the animation is finished).
Here is a working example (really rough method; definitely not the method I would use, and can be improved in numerous ways; would be better to use knowledge of matrix of divs instead of relying on CSS position (ie, extend the data object usage further), and replace hardcoded dimensions with width/height programmatically, etc.).
I also recommend using queue: true instead of false because it will be easier to manage (your example has a problem right now if user hits the key quickly multiple times in a row)
Scroll down to end of code and click "Run Snippet" and click "Full page" for best results.
$(document.body).on("keydown", function(e) {
if (e.keyCode > 36 && e.keyCode < 41) {
var $img = $("#img");
var dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1
var axis = e.keyCode === 38 || e.keyCode === 40 ? "top" : "left";
var data = $img.data("goal"); // used to restrict movement at bounds
if (!data) {
data = {
left: 0,
top: 0
};
$img.data("goal", data);
}
var pos = (axis === "left" ? data.left : data.top);
if ((dir > 0 && pos < 180) || (dir < 0 && pos > 0)) {
var moveAmt = 60 * dir;
if (axis === "left") {
data = {
left: data.left + moveAmt,
top: data.top
};
} else {
data = {
top: data.top + moveAmt,
left: data.left
};
}
$img.data("goal", data);
var moveCmd = {};
moveCmd[axis] = "+=" + moveAmt + "px";
$img.animate(moveCmd, {
queue: true, // easier to manage than 'false'
speed: "slow",
easing: "swing",
complete: function() {
// this function is called when animation completes
$(this).addClass("moved");
// get number; from http://stackoverflow.com/questions/1100503/how-to-get-just-numeric-part-of-css-property-with-jquery
var imgLeft = +($(this).css('left').replace(/[^-\d\.]/g, '')); // coerce to number
var imgTop = +($(this).css('top').replace(/[^-\d\.]/g, '')); // coerce to number
$(".square").each(function() {
var offset = $(this).offset();
if (offset.left === imgLeft && offset.top === imgTop) {
var fromKeyboard = true;
$(this).trigger("click", [fromKeyboard]);
return false;
}
});
}
});
}
return false;
}
});
$(".square").on("click", function(e, fromKeyboard) {
var str = "Clicked " + this.id;
if (fromKeyboard) {
str += " (FROM KEYBOARD)";
}
$("#feedback").html(str);
});
BODY {
margin: 0;
}
DIV {
margin: 0;
padding: 0;
}
#img {
position: absolute;
border: 5px solid Red;
background-color: Blue;
width: 50px;
height: 50px;
z-index: 101;
top: 0px;
left: 0px;
}
#img.moved {
background-color: Orange;
}
.square {
margin: 0;
display: inline-block;
width: 50px;
height: 50px;
background-color: #eee;
border: 5px solid #666;
}
.row {
font-size: 0;
}
#feedback {
padding: 10px;
color: #666;
font-family: 'Segoe UI', Arial, Sans-serif;
font-size: 14px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="img"></div>
<div id="Blocks" class="row">
<div id="41" class="square"></div>
<div id="42" class="square"></div>
<div id="43" class="square"></div>
<div id="44" class="square"></div>
</div>
<div id="Blocks2" class="row">
<div id="31" class="square"></div>
<div id="32" class="square"></div>
<div id="33" class="square"></div>
<div id="34" class="square"></div>
</div>
<div id="Blocks3" class="row">
<div id="21" class="square"></div>
<div id="22" class="square"></div>
<div id="23" class="square"></div>
<div id="24" class="square"></div>
</div>
<div id="Blocks4" class="row">
<div id="11" class="square"></div>
<div id="12" class="square"></div>
<div id="13" class="square"></div>
<div id="14" class="square"></div>
</div>
<div id="feedback">Click into the document area and then hit the ARROW keys</div>
In the complete function you can put the code for simulating the mouse click. If you know the dimensions of #img and the divs and their positions, you can probably use some collision detection logic to figure out which one to click, then it is a simple matter of firing the click event on the target element.
You need to post your markup that shows these DIVS and #img before we can help you further tho..

Related

Add different images when mouse moving in jquery

I'm trying to make a jquery code where you can show different images (1-3 different images) when you move the mouse around.
The images will be right beside the cursor, and they will only appear 1-3, not more than that. And each time the mouse moves, these images will change.
I currently have this as my html code,
<div class="mainbody">
<section class="container">
<div class="img_div">
</div>
</section>
</div>
And my jquery code looks like this:
let img_array = ['./img/awards_icon.png', './img/norinuri_icon.png'];
$("div.mainbody").mousemove(function(e) {
for(i=0; i<img_array.length; i++){
$('.img_div').append("<img src='" + img_array[i] +"'/>");
$('.img_div').fadeIn("5000");
$('.img_div').finish().fadeOut("5000");
$('.img_div').offset({
left: e.pageX,
top: e.pageY + 20
});
}
});
The 2 images that I have in my jquery array appears when the mouse moves, but instead of only having 2 images these images add continuously, without stopping.
So each time I would move my mouse, the images would continue to add infinitely.
I will add more images in the jquery array for sure,
but how should I have only two images added, and change these images as I move the mouse?
Use background-image
var imageArr=["https://www.w3schools.com/css/paper.gif","https://www.w3schools.com/css/gradient_bg.png","https://www.w3schools.com/css/img_tree.png"];
var count=0;
$( ".mainbody" ).mouseover(function() {
$( ".img_div" ).css('background-image', 'url("' + imageArr[count] + '")');
if(count == imageArr.length-1)
count=0;
else
count++;
});
.mainbody{
width: 500px;
height: 500px;
border:1px solid red;
}
.img_div{
width: 200px;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="mainbody">
<section class="container">
<div class="img_div">
</div>
</section>
</div>
Here is working fiddle;
USING mousemove (to avoid the images to change so many times while mouse move I use timeout)
var imageArr=["https://www.w3schools.com/css/paper.gif","https://www.w3schools.com/css/gradient_bg.png","https://www.w3schools.com/css/img_tree.png"];
var count=0;
var timeoutid = 0;
function setImage() {
$( ".img_div" ).css('background-image', 'url("' + imageArr[count] + '")');
if(count == imageArr.length-1)
count=0;
else
count++;
}
$(".mainbody").mousemove(function() {
clearTimeout(timeoutid);
timeoutid = setTimeout(setImage, 100);
});
.mainbody{
width: 500px;
height: 500px;
border:1px solid red;
}
.img_div{
width: 200px;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="mainbody">
<section class="container">
<div class="img_div">
</div>
</section>
</div>
화이팅!
I have created a working example for you. You can try it now:
<div class="mainbody">
<section class="container">
<div class="img_div">
hello
</div>
</section>
css
.mainbody {
border:1px solid red;
display:block;
height:1000px
}
jquery
let img_array = ['https://anotherjavaduke.files.wordpress.com/2018/08/avataaars-2.png',
'https://images2.minutemediacdn.com/image/upload/c_crop,h_1192,w_2121,x_0,y_111/f_auto,q_auto,w_1100/v1554921884/shape/mentalfloss/22461-istock-176984635.jpg'];
$("div.mainbody").on('mousemove', function(e) {
var i;
$('.img_div').html('')
for (i = 0; i < img_array.length; i++) {
console.log($('.img_div').has('img').length)
if ($('.img_div').has('img').length < img_array.length) {
$('.img_div').append("<img style='width:100px; height:100px' src='" + img_array[i] + "'/>");
$('.img_div').fadeIn("5000");
$('.img_div').finish().fadeOut("5000");
$('.img_div').offset({
left: e.pageX,
top: e.pageY + 20
});
}
}
});
Working example
[Codepen] https://codepen.io/prashen/pen/ZEEqJEo

Press a button and change the color of box elsewhere on page [duplicate]

This question already has answers here:
How to change div background color on button click?
(2 answers)
Closed 3 years ago.
I'm very new to coding and have learned my very limited knowledge from forums and tutorials online. I seem to be up against a problem that I cannot for the life of me figure out.
My goal is to press one of three buttons (Leadership, Program, Team) at the top of a grid (the grid lists our services) and have the appropriate grid box change colors. For example, pressing the Leadership button would turn a grid box blue, Program would turn a grid box yellow, and Team would turn a grid box green. This means that a grid box might be linked to more than one of the buttons, as our services overlap. So depending on what button is pressed, a single grid box might change to blue, yellow, or green.
I figured out how to do toggle buttons which show the body onclick. BUT that means A LOT of redundancy. (I would have to do a grid with the appropriately colored boxes for Leadership, another one for Program, and another one for Team). So, I think I'm on the wrong path there.
I've searched toggles, buttons, anchors, event listeners, targets, you name it. It seems like it all relates to the button itself, not how the button relates to an element on the page.
I am very grateful to anyone who can point me in the right direction! Thank you!
function goToAnchor(anchor) {
var loc = document.location.toString().split('#')[0];
document.location = loc + '#' + anchor;
return false;
}
var divs = ["Div1", "Div2", "Div3", "Div4"];
var visibleDivId = null;
function divVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
.square-grey {
display: table-cell;
height: 100px;
width: 600px;
text-align: center;
vertical-align: middle;
border-radius: 5%;
/*make it pretty*/
background: #F5F5F5;
color: #999999;
padding: 10px 15px 10px 15px;
font: 20px "helvetica";
font-weight: 350;
box-shadow: 2px 3px 3px #999999;
}
div.highlit {
padding: 25px;
}
<div class="row">
<div class="buttons">
<div style="text-align:center">
<div class="col-sm-4">
Enterprise
</div>
<div class="col-sm-4">
Program
</div>
<div class="col-sm-4">
Team
</div>
</div>
</div>
</div>
<div class="inner_div">
<div id="Div1">
<div class="row">
<div style="text-align:center">
<div class="col-sm-3">
<div class="top-buffer">
<div class="square-grey">
Strategic Alignment
</div>
</div>
</div>
<div class="col-sm-3">
<div class="top-buffer">
<div class="square-grey">
Adaptive Leadership
</div>
</div>
</div>
<div class="col-sm-3">
<div class="top-buffer">
<div class="square-grey">
Portfolio Management
</div>
</div>
</div>
<div class="col-sm-3">
<div class="top-buffer">
<div class="square-grey">
Cultural Shift
</div>
</div>
</div>
</div>
</div>
</div>
<div id="Div2" style="display: none;">I'm Div Two</div>
<div id="Div3" style="display: none;">I'm Div Three</div>
</div>
</div>
Edited answer, you can add IDs to the boxes and pass them to function.
const changeColor = (elements, color) => {
elements.forEach(el => {
const element = document.querySelector(el);
element.style.backgroundColor = color;
})
}
.colorbox {
width: 100px;
height: 100px;
background-color: aquamarine;
margin-bottom: 10px;
}
<div class="colorbox" id="colorbox1"></div>
<div class="colorbox" id="colorbox2"></div>
<div class="colorbox" id="colorbox3"></div>
<button onclick="changeColor(['#colorbox1', '#colorbox3'], 'tomato')">Change 1 & 3 to tomato</button>
<button onclick="changeColor(['#colorbox1', '#colorbox2'], 'aliceblue')">Change 1 & 2 to aliceblue</button>
<button onclick="changeColor(['#colorbox2', '#colorbox3'], '#ff0000')">Change 2 & 3 to reddest</button>

Dynamically change nth-child number

ngx-datatable > div > datatable-body > datatable-selection:hover > datatable-scroller > datatable-row-wrapper:nth-child(n) > datatable-body-row > div.datatable-row-center.datatable-row-group > datatable-body-cell:nth-child(1) {
background-color: #E9F1FA !important;
}
This is my long selector. I am trying to highlight the entire column based on the user hovering over an item on a column. This works great, except that it only highlights whatever nth-child I am using on the last datatable-body-cell:nth-child(1) I can change it to any number and it works, but it isn't dynamic. I want it to only select the column that is being hovered over. I've tried datatable-body-cell:nth-child(n):hover and datatable-body-cell:hover and a lot of different varieties but it either highlights the whole table, or nothing at all, unless I specify the nth-child.
Is there a way I can dynamically change the nth-child based on the what child the user is hovering over (with CSS or Javascript)?
Any help would be appreciated!
You can use document.querySelector to get the column and set its style it is being hovered over on mouseenter and reset it back to normal on mouseleave.
var n = 1;//the number
document.querySelector('ngx-datatable > div > datatable-body > datatable-selection:hover > datatable-scroller > datatable-row-wrapper:nth-child('+n+') > datatable-body-row > div.datatable-row-center.datatable-row-group > datatable-body-cell:nth-child(1)').style.setProperty('background-color', '#E9F1FA', 'important');
Demo:
var children = document.querySelectorAll('div.child');
Array.prototype.slice.call(children).forEach(function(child){
var n = child.parentNode.getAttribute('data-num');
var parent = document.querySelector('div.table>div:nth-child('+n+')');
child.addEventListener('mouseenter', function(e){
parent.style.backgroundColor = "yellow";
this.style.backgroundColor = "red";
});
child.addEventListener('mouseleave', function(e){
var n = +this.parentNode.getAttribute('data-num');
parent.style.backgroundColor = "";
this.style.backgroundColor = "";
});
});
.table{
height: 250px;
width: 400px;
margin: 5px;
padding: 5px;
background-color: goldenrod;
}
.column{
background-color: dodgerblue;
margin: 5px;
}
.child{
border: 1px solid black;
}
<div class="table">
<div class="column" data-num="1">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
</div>
<div class="column" data-num="2">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
</div>
<div class="column" data-num="3">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
</div>
</div>

Drag and drop not working for on the fly elements firefox

I have a page that generates some draggable elements.
However I noticed that on firefox I cannot get them to drag while on chrome I can.To create a new element i press the create item button.Here is my code
/*
* #param event A jquery event that occurs when an object is being dragged
*/
function dragStartHandler(event){
//e refers to a jQuery object
//that does not have dataTransfer property
//so we have to refer to the original javascript event
var originalEvent = event.originalEvent;
var currentElement = originalEvent.target;
console.log("Hack it");
console.log($(currentElement).data());
//We want to store the data-task-id of the object that is being dragged
originalEvent.dataTransfer.setData("text",$(currentElement).data("task-id"));
originalEvent.dataTransfer.effectAllowed = "move";
}
$(document).ready(function(){
//When a new task/item is creatted it is assigned a unique data attribute which is the task index
var taskIndex = 0;
$(".text-info").addClass("text-center");
$(".createTask").addClass("btn-block").on("click",function(){
//Find the category whict this button belongs to
var currentCategory = $(this).parent(".box");
var categoryId = currentCategory.data("category");
//Create a new task
var task = $("<div class='list-group-item droppable' draggable='true' data-task-id="+taskIndex+"></div>");
//Assign a data-task-id attribute and set its text
task.text("Data id = "+taskIndex);
taskIndex++;
task.appendTo($(this).prev(".dropTarget"));
});
$(".droppable").on("dragstart",dragStartHandler);
$(".dropTarget").on("dragenter",function(event){
event.preventDefault();
event.stopPropagation();
$(this).addClass("highlighted-box");
}).on("dragover",false)
.on("drop",function(event){
event.preventDefault();
event.stopPropagation();
var originalEvent = event.originalEvent;
//Retrieve the data-task-id we stored in the event
var taskId = originalEvent.dataTransfer.getData("text");
console.log(taskId);
//The object that will be moved is determined by the id we stored on the event parameter
var objectToMove =$("body").find(`[data-task-id='${taskId}']`);
console.log(objectToMove);
var category = $(this).parent(".box").data("category");
objectToMove.data("category-group",category);
//Remove the square object from its previous position
//and append it to the current dropTarget
$(objectToMove).appendTo(this);
return false;
});
});
.highlighted-box {
box-shadow: 0 0 4px 4px #EBE311;
}
.dropTarget {
height: 10em;
width: 10em;
/* border:2px solid; */
margin: auto;
}
.dropTarget .droppable{
margin: auto;
position: relative;
top: 20%;
}
.droppable {
background-color: dodgerblue;
/* height: 6em;
border-radius: 5px; */
/* box-shadow: 0 0 5px 5px #3D0404; */
/* width: 6em; */
}
#square2{
background-color: red;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<body>
<div class="jumbotron intro text-center">
<h1>Drag and drop demo</h1>
</div>
<div class="row">
<div class="col-md-3 box" data-category="0">
<h1 class="text-info">Ideas</h1>
<div class="dropTarget list-group">
</div>
<div class="btn btn-info createTask">
Create item
</div>
</div>
<div class="col-md-3 box" data-category="1">
<h1 class="text-info">Wornking on</h1>
<div class="dropTarget list-group">
</div>
<div class="btn btn-info createTask">
Create item
</div>
</div>
<div class="col-md-3 box" data-category="2">
<h1 class="text-info">Completed</h1>
<div class="dropTarget list-group">
</div>
<div class="btn btn-info createTask">
Create item
</div>
</div>
<div class="col-md-3 box" data-category="3">
<h1 class="text-info">Accepted</h1>
<div class="dropTarget list-group">
</div>
<div class="btn btn-info createTask">
Create item
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-6">
<div id="square" draggable="true" data-index = "0" class="droppable list-group-item"></div>
</div>
<div class="col-md-6">
<div id="square2" class="droppable list-group-item" draggable="true" data-index="1"></div>
</div>
</div>
</div>
</body>
The problem with my code was the event delegation.
To fix it I did the following:
$("body").on("dragstart",".droppable",dragStartHandler);
Here you can find more more here

Complex continuous scroll loop

I have a code similar to:
<div id='right-column'>
<div id='results'>
<div id='result1>
<div class='main'></div>
<div class='details'></div>
</div>
<!-- ... -->
<div id='result50>
<div class='main'></div>
<div class='details'></div>
</div>
</div>
</div>
the total number of results depends of the ajax query, I insert all the results dynamically in one go.
div.main is always visible (fixed height) and div.details "unfolds/folds" below div.main when the user clicks on a result div.
the details div height can vary.
If #results scrollHeight is bigger than #right-column height, I would like to create a continuous scroll loop.
In this case, scrolling past #result50 would show #result1, scrolling before #result1 would show #result50.
I can't .append() the first child to the bottom as in some cases a portion of a result can be seen on top and at the bottom of the column.
I can't duplicate a result unless I detect if .details is unfolded/folded.
The fact that the height of a result can change when a user unfolds the .details div, makes it even more complicated...
Here is an example of continuous scroll loop (2 columns):
$(document).ready(function() {
var num_children = $('#up-left').children().length;
var child_height = $('#up-left').height() / num_children;
var half_way = num_children * child_height / 2;
$(window).scrollTop(half_way);
function crisscross() {
$('#up-left').css('bottom', '-' + window.scrollY + 'px');
$('#down-right').css('bottom', '-' + window.scrollY + 'px');
var firstLeft = $('#up-left').children().first();
var lastLeft = $('#up-left').children().last();
var lastRight = $('#down-right').children().last();
var firstRight = $('#down-right').children().first();
if (window.scrollY > half_way ) {
$(window).scrollTop(half_way - child_height);
lastRight.appendTo('#up-left');
firstLeft.prependTo('#down-right');
} else if (window.scrollY < half_way - child_height) {
$(window).scrollTop(half_way);
lastLeft.appendTo('#down-right');
firstRight.prependTo('#up-left');
}
}
$(window).scroll(crisscross);
});
div#content {
width: 100%;
height: 100%;
position: absolute;
top:0;
right:0;
bottom:0;
left:0;
}
#box {
position: relative;
vertical-align:top;
width: 100%;
height: 200px;
margin: 0;
padding: 0;
}
#up-left {
position:absolute;
z-index:4px;
left: 0;
top: 0px;
width: 50%;
margin: 0;
padding: 0;
}
#down-right {
position:fixed;
bottom: 0px;
z-index: 5px;
left: 50%;
width: 50%;
margin: 0;
padding: 0;
}
h1 {margin: 0;padding: 0;color:#fff}
.black {background: black;}
.white {background: grey;}
.green {background: green;}
.brown {background: brown;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div id="content">
<div id="up-left">
<div id="box" class="brown">
<h1>ONE</h1>
</div>
<div id="box" class="black">
<h1>TWO</h1>
</div>
<div id="box" class="white">
<h1>THREE</h1>
</div>
<div id="box" class="black">
<h1>FOUR</h1>
</div>
<div id="box" class="white">
<h1>FIVE</h1>
</div>
<div id="box" class="black">
<h1>SIX</h1>
</div>
</div><!-- #up-left -->
<div id="down-right">
<div id="box" class="white">
<h1>SIX</h1>
</div>
<div id="box" class="black">
<h1>FIVE</h1>
</div>
<div id="box" class="white">
<h1>FOUR</h1>
</div>
<div id="box" class="black">
<h1>THREE</h1>
</div>
<div id="box" class="white">
<h1>TWO</h1>
</div>
<div id="box" class="green">
<h1>ONE</h1>
</div>
</div><!-- #down-right -->
</div><!-- .content -->
(fiddle: http://jsfiddle.net/franckl/wszg1d6c/)
Any hint/ideas on how I could do it ?
Move items to top or bottom based on scroll direction
You can use jQuery's .append() and .prepend() to move items without cloning them.
You'll use similar techniques to infinite scrolling with lazy loading (AJAX), but in this scenario you want to handle scrolling up as well as down, and instead of loading new content from the server, you're just recycling existing DOM elements in the list.
Below I demonstrate one technique. I store the scroll position in the element's .data cache for easy retrieval when detecting scrolling direction. I chose to detect scrolling direction to avoid making unnecessary variable assignments upfront to improve performance. Otherwise, you'd be getting elements and doing math for a scroll event that isn't going to happen in that direction.
The scroll handler:
$('#right-column').on('scroll', function (e) {
var $this = $(this),
$results = $("#results"),
scrollPosition = $this.scrollTop();
if (scrollPosition > ($this.data('scroll-position') || 0)) {
// Scrolling down
var threshold = $results.height() - $this.height() - $('.result:last-child').height();
if (scrollPosition > threshold) {
var $firstResult = $('.result:first-child');
$results.append($firstResult);
scrollPosition -= $firstResult.height();
$this.scrollTop(scrollPosition);
}
} else {
// Scrolling up
var threshold = $('.result:first-child').height();
if (scrollPosition < threshold) {
var $lastResult = $('.result:last-child');
$results.prepend($lastResult);
scrollPosition += $lastResult.height();
$this.scrollTop(scrollPosition);
}
}
$this.data('scroll-position', scrollPosition)
});
A complete working example:
$('#right-column').on('scroll', function (e) {
var $this = $(this),
$results = $("#results"),
scrollPosition = $this.scrollTop();
if (scrollPosition > ($this.data('scroll-position') || 0)) {
// Scrolling down
var threshold = $results.height() - $this.height() - $('.result:last-child').height();
if (scrollPosition > threshold) {
var $firstResult = $('.result:first-child');
$results.append($firstResult);
scrollPosition -= $firstResult.height();
$this.scrollTop(scrollPosition);
}
} else {
// Scrolling up
var threshold = $('.result:first-child').height();
if (scrollPosition < threshold) {
var $lastResult = $('.result:last-child');
$results.prepend($lastResult);
scrollPosition += $lastResult.height();
$this.scrollTop(scrollPosition);
}
}
$this.data('scroll-position', scrollPosition)
});
$('#results').on('click', '.result', function (e) {
$(this).find('.details').toggle();
});
$('#newNumber').on('input', function (e) {
var results = '';
for (var n = 1; n <= $(this).val(); n++) {
results +=
'<div class="result" id="result' + n + '">' +
' <div class="main">Result ' + n + '</div>' +
' <div class="details">Details for result ' + n + '</div>' +
'</div>';
}
$('#results').html(results);
});
body {
font-family: sans-serif;
}
h1 {
font: bold 2rem/1 Georgia, serif;
}
p {
line-height: 1.5;
margin-bottom: 1em;
}
label {
font-weight: bold;
margin-bottom: 1em;
}
.column {
box-sizing: border-box;
float: left;
width: 50%;
height: 100vh;
padding: 1em;
overflow: auto;
}
#right-column {
background-color: LemonChiffon;
}
.result {
padding: 1em;
cursor: pointer;
}
.result .main {
height: 2em;
font-weight: bold;
line-height: 2;
}
.result .details {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class=
"column" id="left-column">
<p>Existing DOM elements are moved to the top or bottom of the list depending on your scroll direction.</p>
<label>Change the number of results to display
<input id="newNumber" type="number" value="10" />
</div>
<div class=
"column" id="right-column">
<div id="results">
<div id="result1" class="result">
<div class="main">Result 1</div>
<div class="details">Details for result 1</div>
</div>
<div id="result2" class="result">
<div class="main">Result 2</div>
<div class="details">Details for result 2</div>
</div>
<div id="result3" class="result">
<div class="main">Result 3</div>
<div class="details">Details for result 3</div>
</div>
<div id="result4" class="result">
<div class="main">Result 4</div>
<div class="details">Details for result 4</div>
</div>
<div id="result5" class="result">
<div class="main">Result 5</div>
<div class="details">Details for result 5</div>
</div>
<div id="result6" class="result">
<div class="main">Result 6</div>
<div class="details">Details for result 6</div>
</div>
<div id="result7" class="result">
<div class="main">Result 7</div>
<div class="details">Details for result 7</div>
</div>
<div id="result8" class="result">
<div class="main">Result 8</div>
<div class="details">Details for result 8</div>
</div>
<div id="result9" class="result">
<div class="main">Result 9</div>
<div class="details">Details for result 9</div>
</div>
<div id="result10" class="result">
<div class="main">Result 10</div>
<div class="details">Details for result 10</div>
</div>
</div>
</div>
A complete working example on CodePen, if you prefer.

Categories