drag drop div multiple select fail on combined demo - javascript

I am creating a div and place a new div inside that i can drag around using;
http://threedubmedia.com/code/event/drag#demos
I combined the following demo's:
contain
active
multi
live (dynamically add new divs)
resize2
I can dynamically add new divs to the contained space, this div is also re-sizable and movable.
The problem is that it behaves weird.
- after clicking add, you cannot instantly drag that new box.
- multiple select does not work for all items
- I've had a situation where multiple select 3 items, but i can't un-select them.
here the code:
http://jsfiddle.net/GVNv5/2/
scenario 1: dragging
the 3 boxes are stacked on top of each-other ( no problem here)
- try dragging the top box immediately (without clicking it first) you see it doesn't move. Let go of your mouse and try again, now it will move. (the second and third boxes will move also)
- click add a box button and try to move it immediately, it also doesn't move.(the second time it will)
- click a box to select it.(color red) You will see non of the boxes will get selected.
scenario 2: multiselect
Run the demo again
- click on a box to select it.(color red) It will not select on first click. (hold mouse still)
- click on box and drag mouse, now release mouse.. box is selected.
- select box 1 and 2
- create new box and select it
- now you cannot un-select box 1 and 2.
<html>
<head>
<script src="http://threedubmedia.com/inc/js/jquery-1.7.2.js"></script>
<script src="http://threedubmedia.com/inc/js/jquery.event.drag-2.2.js"></script>
<script src="http://threedubmedia.com/inc/js/jquery.event.drag.live-2.2.js"></script>
</head>
<body>
<style type="text/css">
.drag {
font-size:8px;
position: absolute;
border: 1px solid #89B;
/*background: #BCE;*/
background: rgba(212, 217, 240, .8);
height: 58px;
width: 58px;
cursor: move;
}
#map_container {
height: 299px;
width:50%;
border: 1px dashed #888;
}
.handle {
position: absolute;
height: 6px;
width: 6px;
border: 1px solid #89B;
background: #9AC;
}
.NW, .NN, .NE {
top: -4px;
}
.NE, .EE, .SE {
right: -4px;
}
.SW, .SS, .SE {
bottom: -4px;
}
.NW, .WW, .SW {
left: -4px;
}
.SE, .NW {
cursor: nw-resize;
}
.SW, .NE {
cursor: ne-resize;
}
.NN, .SS {
cursor: n-resize;
left: 50%;
margin-left: -4px;
}
.EE, .WW {
cursor: e-resize;
top: 50%;
margin-top: -4px;
}
.selected {
background-color: #ECB;
border-color: #B98;
}
.selected .handle {
background-color: #CA9;
border-color: #B98;
}
.active {
background-color: #BEE;
border-color: #8BB;
}
</style>
<script type="text/javascript">
jQuery(function($){
var $div = $('#map_container');
//----------------------------------------------------------
// adding new div to drag
//----------------------------------------------------------
var num = 1;
$('#add').click(function(){
num++;
$('<div class="drag">'+num+
'<div class="handle NE"></div>'+
'<div class="handle NN"></div>'+
'<div class="handle NW"></div>'+
'<div class="handle WW"></div>'+
'<div class="handle EE"></div>'+
'<div class="handle SW"></div>'+
'<div class="handle SS"></div>'+
'<div class="handle SE"></div>'+
'</div>')
.appendTo( $div )
});
//----------------------------------------------------------
//dragging and resizing //----------------------------------------------------------
$( document ).on("drag",function(){
$('.drag')
.click(function(){
$( this ).toggleClass("selected");
})
.drag("init",function(){
if ( $( this ).is('.selected') )
return $('.selected');
})
.drag("start",function( ev, dd ){
dd.attr = $( ev.target ).prop("className");
$( this ).addClass("active");
//console.log(dd.attr);//to log some stuff to the console (you could use firefox firebug to see)
dd.limit = $div.offset();
dd.limit.bottom = dd.limit.top + $div.outerHeight() - $( this ).outerHeight();
dd.limit.right = dd.limit.left + $div.outerWidth() - $( this ).outerWidth();
dd.width = $(this).width();
dd.height = $(this).height();
})
.drag(function( ev, dd ){
var props = {};
if ( dd.attr.indexOf("E") > -1 ){
props.width = Math.max( 32, dd.width + dd.deltaX );
}
if ( dd.attr.indexOf("S") > -1 ){
props.height = Math.max( 32, dd.height + dd.deltaY );
}
if ( dd.attr.indexOf("W") > -1 ){
props.width = Math.max( 32, dd.width - dd.deltaX );
props.left = dd.originalX + dd.width - props.width;
}
if ( dd.attr.indexOf("N") > -1 ){
props.height = Math.max( 32, dd.height - dd.deltaY );
props.top = dd.originalY + dd.height - props.height;
}
var props2 = {};
if ( dd.attr.indexOf("drag") > -1 )
{
props2.top =Math.min( dd.limit.bottom, Math.max( dd.limit.top, dd.offsetY ) );
props2.left =Math.min( dd.limit.right, Math.max( dd.limit.left, dd.offsetX ) );
}
$( this ).css( props2 );
if(dd.attr == 'drag')
{
//you can do stuff here if needed
}
else if(dd.attr == 'handle NE' || dd.attr == 'handle NN' || dd.attr == 'handle NW' || dd.attr == 'handle WW' || dd.attr == 'handle EE' || dd.attr == 'handle SW' || dd.attr == 'handle SS' || dd.attr == 'handle SE')
{
$( this ).css( props );
}
})
.drag("end",function(){
$( this ).removeClass("active");
});
});
});
</script>
<input type="button" id="add" value="Add a Box" />
<div id="map_container">
<div class="drag">
<div class="handle NE"></div>
<div class="handle NN"></div>
<div class="handle NW"></div>
<div class="handle WW"></div>
<div class="handle EE"></div>
<div class="handle SW"></div>
<div class="handle SS"></div>
<div class="handle SE"></div>
</div>
<div class="drag">
<div class="handle NE"></div>
<div class="handle NN"></div>
<div class="handle NW"></div>
<div class="handle WW"></div>
<div class="handle EE"></div>
<div class="handle SW"></div>
<div class="handle SS"></div>
<div class="handle SE"></div>
</div>
<div class="drag">
<div class="handle NE"></div>
<div class="handle NN"></div>
<div class="handle NW"></div>
<div class="handle WW"></div>
<div class="handle EE"></div>
<div class="handle SW"></div>
<div class="handle SS"></div>
<div class="handle SE"></div>
</div>
</div>
</body>
</html>

i think you must use
$(document).on('click')
instead of using
$(document).on('drag')
because drag will not fire on 1st action..
check out here i have done it: http://jsfiddle.net/CD3fb/

Related

How to make dynamically created elements draggable with gridstack?

In my project I'm using this drag and drop library called gridstack. You can see their documentation on github here. When you hardcode elements inside the dom and initialize the gridstack, those elements are draggable. But when the elements are created dynamically with a forloop, they are not draggable even if they have the proper draggable classes. How can I make this work?
//initialize grid stack
var grid = GridStack.init({
minRow: 5, // don't collapse when empty
cellHeight: 70,
acceptWidgets: true,// acceptWidgets - accept widgets dragged from other grids or from outside (default: false).
dragIn: '.newWidget', // class that can be dragged from outside
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper:'clone' }, // clone or can be your function
removable: '#trash', // drag-out delete class
});
//gridstack on change
grid.on('added removed change', function(e, items) {
let str = '';
items.forEach(function(item) { str += ' (x,y)=' + item.x + ',' + item.y; });
console.log(e.type + ' ' + items.length + ' items:' + str );
});
//dynamic elemenets
const arr = ["Bruh cant drag me!", "Nope me neither", "Me too mouhahaha"];
//loop
for (let i = 0; i < arr.length; i++) {
var div = document.createElement('div');
var el = "<div class='newWidget grid-stack-item ui-draggable ui-resizable ui-resizable-autohide'> <div class='grid-stack-item-content' style='padding: 5px;'> "+arr[i]+"</div></div>";
div.innerHTML = el;
$('.dynamic').append(div);
}
.grid-stack-item-removing {
opacity: 0.8;
filter: blur(5px);
}
#trash {
background: rgba(255, 0, 0, 0.4);
padding: 5px;
text-align: center;
}
.grid-stack-item{
background: whitesmoke;
width: 50%;
border: 1px dashed grey;
}
.grid-stack {
background : #F0FFC0;
}
<!-- jquery -->
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<!-- gridstack-->
<link rel="stylesheet" href="https://gridstackjs.com/node_modules/gridstack/dist/gridstack-extra.min.css"/>
<script src="https://gridstackjs.com/node_modules/gridstack/dist/gridstack-h5.js"></script>
<!-- body-->
<body>
<div id="trash"><span>drop here to remove</span> </div>
<br>
<div class="dynamic"></div>
<div class="newWidget grid-stack-item ui-draggable ui-resizable ui-resizable-autohide">
<div class="grid-stack-item-content" style="padding: 5px;">
<div>
</div>
<div>
<span>I'm original domster! Drag and drop me!</span>
</div>
</div>
</div>
<br>
<div class="grid-stack"></div>
</body>
This issue was raised here. The grid does not automatically track external changes so the grid needs to be re-initialize for the dragIn option to notice the new dynamic widgets
GridStack.setupDragIn()
Full code
//initialize grid stack
var grid = GridStack.init({
minRow: 5, // don't collapse when empty
cellHeight: 70,
acceptWidgets: true,// acceptWidgets - accept widgets dragged from other grids or from outside (default: false).
dragIn: '.newWidget', // class that can be dragged from outside
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper:'clone' }, // clone or can be your function
removable: '#trash', // drag-out delete class
});
//gridstack on change
grid.on('added removed change', function(e, items) {
let str = '';
items.forEach(function(item) { str += ' (x,y)=' + item.x + ',' + item.y; });
console.log(e.type + ' ' + items.length + ' items:' + str );
});
//dynamic elemenets
const arr = ["Bruh cant drag me!", "Nope me neither", "Me too mouhahaha"];
//loop
for (let i = 0; i < arr.length; i++) {
var div = document.createElement('div');
var el = "<div class='newWidget grid-stack-item ui-draggable ui-resizable ui-resizable-autohide'> <div class='grid-stack-item-content' style='padding: 5px;'> "+arr[i]+"</div></div>";
div.innerHTML = el;
$('.dynamic').append(div);
}
GridStack.setupDragIn(
'.newWidget',
);
.grid-stack-item-removing {
opacity: 0.8;
filter: blur(5px);
}
#trash {
background: rgba(255, 0, 0, 0.4);
padding: 5px;
text-align: center;
}
.grid-stack-item{
background: whitesmoke;
width: 50%;
border: 1px dashed grey;
}
.grid-stack {
background : #F0FFC0;
}
<!-- jquery -->
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<!-- gridstack-->
<link rel="stylesheet" href="https://gridstackjs.com/node_modules/gridstack/dist/gridstack-extra.min.css"/>
<script src="https://gridstackjs.com/node_modules/gridstack/dist/gridstack-h5.js"></script>
<!-- body-->
<body>
<div id="trash"><span>drop here to remove</span> </div>
<br>
<div class="dynamic"></div>
<div class="newWidget grid-stack-item ui-draggable ui-resizable ui-resizable-autohide">
<div class="grid-stack-item-content" style="padding: 5px;">
<div>
</div>
<div>
<span>I'm original domster! Drag and drop me!</span>
</div>
</div>
</div>
<br>
<div class="grid-stack"></div>
</body>

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

How to add new panels before and after clicked panel

Report designer detail band contains Add band button which shoud add new panels immediately before and after detail panel.
$parentpanel = $this.parents(".designer-panel:first");
is used to find parent panel and .prepend() / append() to add new panels.
Panels are added as Detail panel child elements.
How to add panels before and after Detail panel in same DOM level like group header and footer panels in sample html.
Elements should probably added to $parentpanel.parent() element list before and after $parentpanel element.
Is there some selector or append command in jQuery for this ?
$(function() {
var startpos,
selected = $([]),
offset = {
top: 0,
left: 0
};
$('#designer-detail-addband').on('click', function() {
var $this = $(this),
$parentpanel = $this.parents(".designer-panel:first");
$parentpanel.prepend('<div class="panel designer-panel">' +
'<div class="panel-body designer-panel-body" style="height:1px">' +
'</div>' +
'<div class="bg-warning">' +
'<div class="panel-footer"><i class="glyphicon glyphicon-chevron-up">' +
'</i> Group heade {0}: <span id="band{0}_expr" contenteditable="true">"groupexpression"</span>' +
'</div></div></div>');
$parentpanel.append('<div class="panel designer-panel">' +
'<div class="panel-body designer-panel-body" style="height:1px"></div>' +
'<div class="bg-warning">' +
'<div class="panel-footer"><i class="glyphicon glyphicon-chevron-up">' +
'</i> Group footer {0}' +
'</div></div></div>');
});
$(".designer-panel-body").droppable({
accept: ".designer-field"
});
$(".designer-field").draggable({
start: function(event, ui) {
var $this = $(this);
if ($this.hasClass("ui-selected")) {
selected = $(".ui-selected").each(function() {
var el = $(this);
el.data("offset", el.offset());
});
} else {
selected = $([]);
$(".designer-field").removeClass("ui-selected");
}
offset = $this.offset();
},
drag: function(event, ui) {
// drag all selected elements simultaneously
var dt = ui.position.top - offset.top,
dl = ui.position.left - offset.left;
selected.not(this).each(function() {
var $this = $(this);
var elOffset = $this.data("offset");
$this.css({
top: elOffset.top + dt,
left: elOffset.left + dl
});
});
}
});
$(".panel-resizable").resizable({
minWidth: "100%",
maxWidth: "100%",
minHeight: 1
});
})
.panel-resizable {
min-height: 1px;
overflow: hidden;
margin: 0;
padding: 0;
}
.designer-field {
border: 1px solid lightgray;
white-space: pre;
overflow: hidden;
position: absolute;
}
.designer-panel-body {
min-height: 1px;
overflow: hidden;
margin: 0;
padding: 0;
}
.panel-footer {
padding: 0;
}
.designer-panel,
.panel-body {
margin: 0;
padding: 0;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
</head>
<body>
<div class='panel designer-panel'>
<div class='panel-body designer-panel-body panel-resizable' style='height:2cm'>
<div class='designer-field' style='left:5px;top:6px;width:180px'>field 1 in group 1 header</div>
<div class='designer-field' style='left:54px;top :36px;width:160px'>field 2 in group 1 header</div>
</div>
<div class='panel-footer'>Group 1 Header</div>
</div>
<div class='panel designer-panel'>
<div class='panel-body panel-resizable' style='height:1cm'>
<div class='designer-field' style='left:24px;top:2px;width:140px'>field in detail group</div>
</div>
<div class='panel-footer panel-primary'>Detail <a role="button" id="designer-detail-addband"> Add group</a>
</div>
</div>
<div class='panel'>
<div class='panel-body panel-resizable' style='height:1cm'>
<div class='designer-field' style='left:44px;top:2px;width:140px'>field in group 1 footer</div>
</div>
<div class='panel-footer panel-warning'>Group 1 Footer</div>
</div>
Try jQuery's before, after functions. Or insertBefore, insertAfter
Also you can use
$this.closest(".designer-panel");
instead of
$this.parents(".designer-panel:first");
See closest

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.

How to make an image click() after Keydown Function

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..

Categories