jquery draggable offsetting on first drop - jquery-ui

Using JQuery UI draggable/droppable I am running into an issue where the draggable drop area is offset (normally to the left but inconsistent distance). The image can be directly over the drop area and fail and on next attempt, in exact same location, pass.
So, dragged item looks in correct spot over mouse but is incorrect when dropped... but only first attempt.
function dragAndDrop(draggedItem,dropZone,size)
{
var bool = 0;
var draggedItem = $(draggedItem);
var dragFromLeft = draggedItem.offset().left;
var dragFromTop = draggedItem.offset().top;
var dropZone = $(dropZone);
//var size = size;
draggedItem.draggable //Make item draggable
({
opacity:1,
revert:function()//'invalid'
{
$(".strobeRed").fadeTo(100, .50).fadeTo(100, 0);
$(this).offset({top: dragFromTop, left: dragFromLeft})
},
drag:function(event, ui)
{
$(this).height(size);
$(this).width(size);
},
cursorAt:
{
left:(size/2),
top:(size/2)
}
});
dropZone.droppable //Make item droppable
({
accept:draggedItem,
drop: function(event, ui)
{
$( ui.draggable ).fadeOut(),
$( this ).droppable( "option", "disabled", true ).css("background-color", "green"), //$(this) = $(event.target)
$( this ).draggable( "option", "disabled", true )
}
});
}
sample image
* EDIT 1
Adding function call from edge animate *
draggable and droppable objects are just divs with class names.
yepnope({nope:['jquery-ui.js','cookbook.js'],complete:init});
function init(){
dragAndDrop(".item1",'.dz1',50);
dragAndDrop(".item2",'.dz2',50);
dragAndDrop(".item3",'.dz3',50);
dragAndDrop(".item4",'.dz4',50);
dragAndDrop(".item5",'.dz5',50);
dragAndDrop(".item6",'.dz6',50);
dragAndDrop(".item7",'.dz7',50);
dragAndDrop(".item8",'.dz8',50);
dragAndDrop(".item9",'.dz9',50);
}
* EDIT 2
fixed issue, introduced another *
by having the scale prior to adding the draggable, it now drops correctly. The new issue is the first item I touch of each type scales and relocates to pointer but the drops. It doesn't fail it just stops being dragged.
function dragAndDrop(draggedItem,dropZone,scaleHeight,scaleWidth)
{
var bool = 0;
var draggedItem = $(draggedItem);
var dragFromLeft = draggedItem.offset().left;
var dragFromTop = draggedItem.offset().top;
var dropZone = $(dropZone);
var currentMousePos = { x: -1, y: -1 };
draggedItem.mousedown(function(event){
currentMousePos.x = event.pageX - (scaleWidth/2);
currentMousePos.y = event.pageY - (scaleHeight/2);
$(this).height(scaleHeight);
$(this).width(scaleWidth);
$(this).offset({top: currentMousePos.y, left: currentMousePos.x});
draggedItem.draggable //Make item draggable
({
opacity:1,
revert:function()//'invalid'
{
$(".strobeRed").fadeTo(100, .50).fadeTo(100, 0);
$(this).offset({top: dragFromTop, left: dragFromLeft})
}
})
});
dropZone.droppable //Make item droppable
({
accept:draggedItem,
drop: function(event, ui)
{
//$( ui.draggable ).fadeOut(),
$( this ).droppable( "option", "disabled", true ).css("background-color", "green"), //$(this) = $(event.target)
$( this ).draggable( "option", "disabled", true )
},
tolerance: "touch"
});
}

** I FOUND IT **
Ok, so my first attempt was calculating the draggable as its original size. The second attempt was not dragging the first item of each type during first attempt. I believe it was stuck in mousedown event and not running the draggable. every time after that draggable was already applied so it worked.
The fix was to assign draggable to everything in the beginning but pull the scaling into a second function. It now scales the item, centers it on mouse, drags and drops.
function dragAndDrop(draggedItem,dropZone,scaleHeight,scaleWidth)
{
var bool = 0;
var draggedItem = $(draggedItem);
var dragFromLeft = draggedItem.offset().left;
var dragFromTop = draggedItem.offset().top;
var dropZone = $(dropZone);
var currentMousePos = { x: 0, y: 0};
draggedItem.draggable //Make item draggable
({
opacity:1,
revert:function()//'invalid'
{
$(".strobeRed").fadeTo(100, .50).fadeTo(100, 0);
$(this).offset({top: dragFromTop, left: dragFromLeft})
}
})
draggedItem.mousedown(function(event){
currentMousePos.x = event.pageX - (scaleWidth/2);
currentMousePos.y = event.pageY - (scaleHeight/2);
$(this).height(scaleHeight);
$(this).width(scaleWidth);
$(this).offset({top: currentMousePos.y, left: currentMousePos.x});
});
dropZone.droppable //Make item droppable
({
accept:draggedItem,
drop: function(event, ui)
{
//$( ui.draggable ).fadeOut(),
$( this ).droppable( "option", "disabled", true ).css("background-color", "green"), //$(this) = $(event.target)
$( this ).draggable( "option", "disabled", true )
},
tolerance: "touch"
});
}

Related

Jquery-ui append template on drop and make appended templates child as droppable(nested)

How to Append template while dropping and dropped template's child as droppable(nested).
$template=$("<div class="static">box1</div><div class="droppable-box-nested">box2</div>");
Need to append above code to my below fiddle while dropping and box2 is droppable.
Jsfiddle
You have some syntax issues in your $template, it should be something like:
var $template = $("<div class='static'>Box 1</div><div class='droppable-box-nested'>Box 2</div>");
The use of " breaks out of your string and you should use '.
Working example: https://jsfiddle.net/Twisty/vwyd9cz1/1/
JavaScript
$(function() {
var $template = $("<div class='static'>Box 1</div><div class='droppable-box-nested'>Box 2</div>");
$('.dragItem').draggable({
helper: 'clone',
connectToSortable: "#column2,#column2 div"
});
$('.dragItem').sortable({
containment: "parent"
});
$('#column2').sortable({
placeholder: "highlight"
});
$('#column2').droppable({
accept: '.dragItem',
drop: function(event, ui) {
var draggable = ui.draggable;
var droppable = $(this);
var drag = $('#column2').has(ui.draggable).length ? draggable : draggable.clone().draggable({});
drag.appendTo(column2);
$template.insertAfter(drag);
drag.sortable({
placeholder: "highlight"
});
drag.droppable({
accept: ".dragItem",
drop: function(event, ui) {
var draggable = ui.draggable;
var droppable = $(this);
var drag = $('#column2').has(ui.draggable).length ? draggable : draggable.clone().draggable({});
}
})
drag.css({
width: '',
height: ''
})
}
});
});

Howler.js duration onload

I have the following script, using howler.js and jquery-ui-1.8.21.custom.min.js:
$(function(){
var sounduser1 = new Howl({
urls: ['studio/keysintheair.mp3', 'studio/keysintheair.ogg'],
buffer:true,
volume: 1.0,
onend: function() {
$('.buttons').fadeIn();
},
});
var sounduser2 = new Howl({
urls: ['studio/keysintheair-original.mp3'],
buffer:true,
volume: 0.1,
});
var thisArray = {
user1: sounduser1,
user2: sounduser2
};
$.each( thisArray, function(key,value) {
$('.buildplayer .player').clone().attr('id',key).appendTo('#song');
$('#song .player:last .waveform').css("width", value._duration + "px");
$('#song .player:last .slider').slider({
value: value.volume() * 100,
range: "min",
animate: true,
orientation: "horizontal",
//Slider Event
slide: function(event, ui) { //When the slider is sliding
var now_id = $(this).parent().parent('.player').attr('id');
thisArray[now_id].volume(ui.value/100);
},
});
});
$('.mainplayer .trackslider').slider({
value: 0,
range: "min",
animate: true,
orientation: "horizontal",
//Slider Event
slide: function trackslider(event, ui) { //When the slider is sliding
var audiogetlength = Object.keys( thisArray ).map(function ( key ) { return thisArray[key]._duration; });
var longest = Math.max.apply( null, audiogetlength );
var dividedlength = 100/ui.value;
$.each( thisArray, function( key, value ) {
value.pos(longest/dividedlength);
if (ui.value > value._duration) {
value.stop();
}
});
},
});
setInterval(function starttrackslider() {
var dividedslider = sounduser1._duration/sounduser1.pos();
$('.trackslider').slider('value', 100/dividedslider);
},1000);
//Single Audio Track Player
$('.ex1-play').on('click', function(){
var now_id = $(this).parent().parent('.player').attr('id');
thisArray[now_id].stop().play();
});
$('.ex1-stop').on('click', function(){
var now_id = $(this).parent().parent('.player').attr('id');
thisArray[now_id].stop();
});
$('.ex1-loop').on('click', function(){
var now_id = $(this).parent().parent('.player').attr('id');
thisArray[now_id].loop(true);
});
//Main All Track Player
$('.main-play').on('click', function(){
$.each( thisArray, function( key, value ) {
value.stop().play();
$('.buttons').fadeOut();
});
});
$('.main-pause').on('click', function(){
$.each( thisArray, function( key, value ) {
value.pause();
});
});
$('.main-stop').on('click', function(){
$.each( thisArray, function( key, value ) {
value.stop();
$('.buttons').fadeIn();
});
});
$('.main-loop').on('click', function(){
$.each( thisArray, function( key, value ) {
value.loop(true);
});
});
});
At the last part of $('.mainplayer .trackslider').slider({ }); you will find if (ui.value > value._duration) {value.stop();}
value equals the Howl called sounduser2
Both audiotracks start at the same time. Using a slider will make me skip through the audio. The slider will have the length of the longest audiotrack - which is Howl called sounduser1. Using the slider will return a number which will activate the position of the audio.
If the slider returns a number bigger then the actual length of the audiotrack it should stop the shorter audiotrack.
For some reason it won't stop playing, eventhough the situation is right. Is there anybody who knows what to do?
$('.mainplayer .trackslider').slider({
value: 0,
range: "min",
animate: true,
orientation: "horizontal",
//Slider Event
slide: function (event, ui) { //When the slider is sliding
var audiogetlength = Object.keys( thisArray ).map(function ( key ) { return thisArray[key]._duration; });
var longest = Math.max.apply( null, audiogetlength );
var dividedlength = 100/ui.value;
$.each( thisArray, function( key, value ) {
var percentvalue = (value._duration/longest)*100;
if (percentvalue > ui.value) {
if (value.pos()==0) {
value.play().pos(longest/dividedlength);
} else {
value.pos(longest/dividedlength);
}
} else {
value.stop();
}
});
}
});
Did the trick

iPad image glitch while img revert with jquery-ui draggable

When I drag an image on iPad with jQuery-ui Draggable, I get a small portion of the dragged image printed on the screen during the revert.
Anyone have an idea why and how to solve this?
Here is an example: http://jsfiddle.net/cRDMX/1/
Javascript
var next = false;
$(document).ready(function() {
$( ".slider .btn" ).draggable({
revert: function() {
if(next) {
$("#container").addClass("active");
alert("open")
return false;
} else {
return true;
}
},
axis: "x",
containment: "parent",
drag: function() {
var lft = $( ".slider .btn" ).position().left;
if(lft > 190) {
next = true;
}
}
});
});
Environnement:
iPad 4
iOS 6.1.3

jQueryUI droppable, stop propagation to overlapped sibling

As you can see here: http://jsfiddle.net/rA4CB/6/
When I make the drop in the overlapped area it is received in both droppables, greedy doesn't work when the items are siblings. Is there any way to block the reception on droppables lower in the zIndex?
BTW, mouseOver won't fire for the droppable element as the mouse is actually over the draggable element.
relevant JS:
$(function() {
$( "#draggable" ).draggable();
$( "#droppable" ).droppable({
tolerance:'pointer',
drop: function( event, ui ) {
$( this )
.addClass( "ui-state-highlight" )
.find( "p" )
.html( "Dropped!" );
}
});
$( "#droppable2" ).droppable({
tolerance:'pointer',
greedy:true,
drop: function( event, ui ) {
$( this )
.addClass( "ui-state-highlight" )
.find( "p" )
.html( "Dropped!" );
}
});
});
Okay, so I spend an hour trying to figure it out, then as soon as I ask I then find my answer
http://jsfiddle.net/rA4CB/7/
Modified the JS to the following:
$(function() {
$( "#draggable" ).draggable();
$( "#droppable" ).droppable({
tolerance:'pointer',
drop: function( event, ui ) {
$( this )
.addClass( "ui-state-highlight" )
.find( "p" )
.html( "Dropped!" );
}
});
$( "#droppable2" ).droppable({
tolerance:'pointer',
greedy:true,
drop: function( event, ui ) {
$( this )
.addClass( "ui-state-highlight" )
.find( "p" )
.html( "Dropped!" );
},
over: function(event, ui){
$( "#droppable" ).droppable( "disable" )
},
out: function(event, ui){
$( "#droppable" ).droppable( "enable" )
}
});
});
$( "#droppable" ).droppable({
greedy: true,
drop: function( event, ui ) {
if(ui.helper.is(".dropped")) {
return false;
}
ui.helper.addClass(".dropped");
}
});
Just set a css class on ui.helper of draggable. If the draggable has been accepted once, it will be refused by all other droppables (Could be done with the droppable "accept" parameter,too , like accept : ":not(.dropped)" and the class added to ui.draggable).
If you have a number of droppable in a container area then what????
You must re think for that problem. Greedy works for only parent to child relationship not in siblings. So you must edit droppable js or put your own logic for it.
So if you have a numbers of droppable then you must write some extra code to handle dropping on perfect droppable as it is in this example A number of siblings droppables
For making perfect siblings droppable modify your droppbale as below
var topElement = undefined;
var topElementArray = Array();
$( "#draggable" ).draggable();
$( ".droppableBox" ).droppable({
activeClass: "active-droppable",
tolerance:'pointer',
over: function( event, ui ) {
// This is for only show a message that z-index must be required for proppable
// you can remove it after testing or after development
if ($(this).css("z-index") == 'auto') {
alert("Please provide z-index for every droppable.");
return;
}
//
topElement = undefined;
topElementArray = Array();
// Change it as you want to write in your code
// For Container id or for your specific class for droppable or for both
$('#demo > .droppableBox').each(function(){
_left = $(this).offset().left, _right = $(this).offset().left + $(this).width();
_top = $(this).offset().top, _bottom = $(this).offset().top + $(this).height();
if (event.pageX >= _left && event.pageX <= _right && event.pageY >= _top && event.pageY <= _bottom) {
topElementArray.push($(this).attr('id'));
}
});
},
drop: function( event, ui ) {
if (!topElement) {
topElement = determineTopElement(topElementArray);
}
if ($(this).attr('id') == $(topElement).attr('id')) {
$( this ).addClass( "ui-state-highlight" ).find( "p" ).html( "Dropped!" );
// Your code after successful dropped element on specific siblings
// Start writing code for dropped element & perfect droppable
}
}
});
determineTopElement = function(_array) {
var topElement;
var zIndexHighest = 0;
for (i = 0; i < _array.length; i++){
var element = $("#"+ _array[i]);
var z_index = $(element).css("z-index");
if( z_index > zIndexHighest){
zIndexHighest = z_index;
topElement = element;
}
}
return topElement;
}
In certain circonstances :
myjQuery.droppable({
over:function(evt,ui){
ui.draggable.attr('drg_time', this.drg_time = evt.timeStamp)
},
accept:function(draggeds){
if(draggeds.attr('drg_time'))
{
return draggeds.attr('drg_time') == this.drg_time
}
return draggeds.hasClass('acceptable_classes_here')
},
out:function(evt,ui){
// useless but cleaner
ui.draggable.removeAttr('drg_time')
}
drop:...,
})
I had the same problem and made a small plugin :)
check it out:
https://stackoverflow.com/a/16720944/1308461
I find that using #invertedSpear's method will cause UI state change which is not desirable in some cases. Here is the code.
var lastOpertion = new Date().getTime();
drop: function (event, ui) {
if (new Date().getTime() - lastOpertion < 100) return;
lastOpertion = new Date().getTime();
....
}
So, when trying to find simple solution I came up with this (and it works for me):
window.overNowOnThis = "";
window.olderOnes = [];
$obj.droppable({
accept: ".draggable_imgs",
drop: function(e, ui) {
if(window.overNowOnThis == this){
// Do whatever
}
},
over: function(event, ui){
window.olderOnes.push(window.overNowOnThis);
window.overNowOnThis = this;
},
out: function(){
var lastElem = window.olderOnes.pop();
window.overNowOnThis = lastElem;
}
});
Top element would be selected because on it "over" fires the last one. Also - if there is more than two siblings - then when moving out of element we set the last one as current. Using global "window" was for example. Better option would be using classes as it can safely keep data.
It's very similar to invertedSpear answer. I had to change it a little bit because enabling/disabling inside "over"/"out" didn't work for me .I had to do below instead
$("#droppable2").droppable({
greedy: true,
drop: function (event, ui) {
$("droppable").droppable("disable");
}
}
I had to explicitly enable"droppable" div when I needed it. For instance, enable it when starting the drag event. Eg
$("#drageMe").draggable({
start:function(event,ui){
$("droppable").droppable("enable");
}
})
try greedy option in ui dropable. see the fiddle link below for demo:
http://jsfiddle.net/creators_guru/3vT5C/embedded/result/
$( ".circles" ).droppable({
greedy: true,
drop: function( event, ui ) {
$_data = ('drgged class = ' + ui.draggable.attr('class'));
$_data1 = ('droped id = #' + $(this).attr('id'));
$('#data').html($_data + '<br/>'+$_data1);
return false;
}
});

jquery ui slider, stop sliding if certain conditions are met

Using the jQuery UI Slider, I'm trying to figure out how to make it so that the slider stops working once certain conditions are met. Any ideas? I thought stopping event propogation in the "start" part would work, but ...it doesn't. So I'm still clueless and lost.
<script type="text/javascript">
$(document).ready(function () {
var spendable = 1000;
var spent = 0;
function spend(quantity) {
var remaining = spendable - quantity;
$('#spendable').text(remaining);
}
$("#eq .slider").each(function () {
var current = 0;
$(this).slider({
range: "min",
step: 100,
value: 0,
min: 0,
max: 500,
animate: true,
orientation: "horizontal",
start: function (event, ui) {
if (spent < spendable)
return true;
event.stopPropagation();
},
slide: function (event, ui) {
// set the current value to whatever is selected.
current = ui.value;
$(this).parent('div:eq(0)').find('.spent').text(current);
var totalled = 0;
$("#eq .slider").each(function () {
totalled += parseInt($(this).parent('div:eq(0)').find('.spent').text());
spend(totalled);
});
}
});
});
Try:
.....
slide: function (event, ui) {
// set the current value to whatever is selected.
current = ui.value;
if(current > 300){
current = 300; //otherwise, it's stuck at 301
return false;
}
....rest of your code

Resources