Basically, I'm trying to drop a draggle element in a droppable element with jquery draggable widget, but the droppable element's drop function gets called when the draggable element is on the same line as the droppable element, it's meant to get called only when the draggable element is over the droppable element.
This is a link to the full code https://jsfiddle.net/AdokiyePaul/5z41se6h/4/
This image below describes the error, the black line illustrates the draggable element and shows that the droppable element still gets highlighted even when the draggable element is not over it.
This is the jquery function used
$(function () {
// var zoom = $("#articles").css("zoom");
$(".article").draggable({
revert: 'invalid',
zindex: 1000,
appendTo: "body",
containment: "window",
cursorAt: {
// top: 200,
// left: 50
},
scroll: false,
helper: "clone",
start: function (event, ui) {
offset_start = {
x: ui.position.left - event.pageX,
y: ui.position.top - event.pageY,
};
// var factor = 1 / zoom - 1;
ui.position.top += Math.round(
ui.position.top - ui.originalPosition.top
//* factor
);
ui.position.left += Math.round(
ui.position.left - ui.originalPosition.left
//* factor
);
$(ui.helper).addClass("article-dragging");
},
stop: function (event, ui) {
$(ui.helper).removeClass("article-dragging");
},
drag: function (event, ui) {
// ui.position.top = event.pageY + offset_start.y;
// ui.position.left = event.pageX + offset_start.x;
ui.position.top =
event.pageY - $(".article-dragging").outerHeight() / 2;
ui.position.left =
event.pageX - $(".article-dragging").outerWidth() / 2;
},
});
$("#folders li").droppable({
accept: "div.article",
hoverClass: "over",
drop: function (event, ui) {
ui.draggable.detach().appendTo($(this));
},
});
});
Consider the following.
$(function() {
console.log('dkdk')
$(".article").draggable({
appendTo: "body",
revert: 'invalid',
zindex: 1000,
containment: "window",
scroll: false,
helper: function(event) {
var $el = $(event.target).closest(".article");
return $("<div>", {
class: "article article-dragging"
}).html($el.children().clone()).position({
my: "center",
at: "center",
of: event
});
}
});
$("#folders li").droppable({
accept: "div.article",
hoverClass: "over",
drop: function(event, ui) {
ui.draggable.detach().appendTo($(this));
},
});
});
Example: https://jsfiddle.net/Twisty/pf1xnet6/32/
I found that the positioning was causing a lot of odd issues. I also saw these with clone, so I just created a new element with the right items and used this as the Helper.
Related
I have few components on my page which are draggable. They have the class
draggable. When this is dragged and stops I need to get the left and top positions
function init() {
var p = $('#groups-parent');
$('.draggable').draggable({
obstacle: ".obstacle",
preventCollision: true,
containment: [
p.offset().left, p.offset().top, p.offset().left + p.width() - 225, p.offset().top + p.height() - 50
],
start: function(event, ui) {
$(this).removeClass('obstacle');
},
stop: function (event, ui) {
console.log(ui);
$('#groups-parent').css({ 'min-height': Math.max(500, ui.position.top + 50) });
$(this).addClass('obstacle');
getTopLeftPosition();
}
});
}
Here is my function that should get the left and top positions.
function getTopLeftPosition(e) {
var coordX = e.pageX - $(this).offset().left,
coordY = e.pageY - $(this).offset().top;
alert(coordX + ' , ' + coordY);
}
This does not work. All I get in my browser is this error message
Cannot read properties of undefined (reading 'left')
How can I get this left and top positions? The alert should indicate it.
You probably just need to bind this to the function, by changing
getTopLeftPosition();
to either
getTopLeftPosition.call(this, event);
or
getTopLeftPosition.bind(this)(event)
I'm using jQuery UI slider and drag and drop to create a way of specifying a rating out of 100 for each div.
The problem is when I drag my divs onto the slider, I do not know how to get the value for the position of each div on the slider. Here is a plnk + some code;
http://plnkr.co/edit/wSS2gZnSeJrvoBNDK6L3?p=preview
$(init);
function init() {
var range = 100;
var sliderDiv = $('#ratingBar');
sliderDiv.slider({
min: 0,
max: range,
slide: function(event, ui) {
$(".slider-value").html(ui.value);
}
});
var divs = '.itemContainer'
$(divs).draggable({
containment: '#content',
cursor: 'move',
snap: '#ratingBar',
revert: function(event, ui) {
$(this).data("uiDraggable").originalPosition = {
top: 0,
left: 0
};
return !event;
}
});
var position = sliderDiv.position(),
sliderWidth = sliderDiv.width(),
minX = position.left,
maxX = minX + sliderWidth,
tickSize = sliderWidth / range;
$('#ratingBar').droppable({
tolerance: 'touch',
drop: function(e, ui) {
var finalMidPosition = $(ui.draggable).position().left + Math.round($(divs).width() / 2);
if (finalMidPosition >= minX && finalMidPosition <= maxX) {
var val = Math.round((finalMidPosition - minX) / tickSize);
sliderDiv.slider("value", val);
$(".slider-value").html(ui.value);
}
}
});
$(".slider-value").html(sliderDiv.slider('value'));
}
Hope someone can offer some advice,
Cheers
(Also, if someone knows why I can drop the divs outside of the rating bar on either side, please let me know!)
Jquery UI has a function called stop and there is where you want to handle all the calculations as such:
stop: function(event, ui) {
// Object dragged
var e = ui.helper;
// Offset of that object
var eOffset = e.offset().left;
// Sliders offset
var sliderOffset = sliderDiv.offset().left;
// Subtract their offsets
var totalOffset = eOffset - sliderOffset;
// Width of box dragged
var boxWidth = ui.helper.width();
// Subtract their widths to account for overflow on end
var sliderW = sliderDiv.width() - boxWidth;
// Get percent moved
var percent = totalOffset / sliderW * 100;
// Find .slider-value and replace HTML
e.find(".slider-value").html(Math.round(percent));
}
This will be located here:
$(divs).draggable({
containment: '#content',
cursor: 'move',
snap: '#ratingBar',
revert: function(event, ui) {
$(this).data("uiDraggable").originalPosition = {
top: 0,
left: 0
};
return !event;
},
.... <-- HERE
});
I have provided commenting for every line so you understand what I did.
Above your draggable function you need to define a tighter containment area as such:
var left = sliderDiv.offset().left;
var right = left + sliderDiv.width();
var top = sliderDiv.offset().top;
var bottom = top + sliderDiv.height();
var height = $(".itemContainer").height();
var width = $(".itemContainer").width();
$(divs).draggable({
containment: [left, 0, right - width, bottom - height],
.....
});
This will prevent the draggable from being moved left, right, or below the slider.
Basically you grab the position of the object grabbed, adjust for some offset, adjust for some width, calculate the percentage, and replace the html (Could use text() as well).
Here is your plunker redone: http://plnkr.co/edit/3WSCo77c1cC5uFiYO8bV?p=preview
Documentation:
Jquery UI
Jquery .find
I would like to reset the score of my div scrolling across the jQuery slider to 0 if it is returned to it's original position.
here is a plnk + some code;
https://plnkr.co/edit/oqhrDeP52vdzcKqpQvbl?p=preview
$(init);
function init() {
function findPosition(e, ui) {
var position = sliderDiv.position(),
sliderWidth = sliderDiv.width(),
minX = position.left,
maxX = minX + sliderWidth,
tickSize = sliderWidth / range;
var finalMidPosition = ui.offset.left - 53 + Math.round($(divs).width() / 2 - 5)
if (finalMidPosition >= minX && finalMidPosition <= maxX) {
var val = Math.round((finalMidPosition - minX) / tickSize);
sliderDiv.slider("value", val);
$(".slider-value", this).html(val);
$("#text1").val($(".item1 .slider-value").html())
}
}
var range = 100;
var sliderDiv = $('#ratingBar');
sliderDiv.slider({
min: 0,
max: range,
});
var divs = '.itemContainer'
$(divs).draggable({
containment: "#containment",
cursor: 'move',
snap: '#ratingBar',
snapMode: 'outer',
drag: findPosition,
revert: function(event, ui) {
$(this).data("uiDraggable").originalPosition = {
top: 0,
left: 0
};
return !event;
}
});
var position = sliderDiv.position(),
sliderWidth = sliderDiv.width(),
minX = position.left,
maxX = minX + sliderWidth,
tickSize = sliderWidth / range;
$('#ratingBar').droppable({
tolerance: 'touch',
drop: findPosition,
out: function(event, ui) {
$(".slider-value", ui.draggable).html(0);
$("#text1").val($(".item1 .slider-value").html())
}
});
$(".slider-value").html(sliderDiv.slider('value'));
}
I have had this working as expected in a different plnk, which leads me to believe that the issue is with either using the Drag: findPosition inside the Draggable or using $(".slider-value", this).html(val); instead of a variation of $(".slider-value", ui.draggable).html(val);.
Below, is a plnk which has the desired effect, but does not automatically update the value;
https://plnkr.co/edit/GIfq7Ws0EsjyS7yRhIzl?p=preview
Thanks for any help/advice!
I offer this as a solution. I made some minor HTML changes and then updated the jQuery.
My Fork: https://plnkr.co/edit/IPRoqprQt34Q08pugO9T?p=preview
HTML
<div id="content">
<div id="containment">
<div id="itemArea">
<div id="row">
<div class="itemContainer">
<div class="item1">
<span class="slider-value"></span>
</div>
<div class="candle"></div>
</div>
</div>
<div id="barContainer">
<div id="ratingBar"></div>
</div>
</div>
</div>
</div>
jQuery
$(init);
var over = false;
function init() {
function findPosition(e, off) {
if (e == "out") {
over = false;
sliderDiv.slider("value", 0);
$(".slider-value").html(0);
$("#text1").val(0);
return;
}
if(e == "in"){
over = true;
}
if (over && e == "drag") {
var position = sliderDiv.position(),
sliderWidth = sliderDiv.width(),
minX = position.left,
maxX = minX + sliderWidth,
tickSize = sliderWidth / range;
var finalMidPosition = off.left - 53 + Math.round($(divs).width() / 2 - 5)
if (finalMidPosition >= minX && finalMidPosition <= maxX) {
var val = Math.round((finalMidPosition - minX) / tickSize); // had to add -12…
sliderDiv.slider("value", val);
$(".slider-value").html(val);
$("#text1").val(val)
}
}
}
var range = 100;
var sliderDiv = $('#ratingBar');
sliderDiv.slider({
min: 0,
max: range,
});
var divs = '.itemContainer'
$(divs).draggable({
containment: "#containment",
cursor: 'move',
snap: '#ratingBar',
snapMode: 'outer',
drag: function(e, ui) {
findPosition("drag", ui.offset);
},
revert: function(event, ui) {
$(this).data("uiDraggable").originalPosition = {
top: 0,
left: 0
};
return !event;
}
});
var position = sliderDiv.position(),
sliderWidth = sliderDiv.width(),
minX = position.left,
maxX = minX + sliderWidth,
tickSize = sliderWidth / range;
$('#ratingBar').droppable({
tolerance: 'touch',
drop: findPosition,
over: function(e, ui) {
$("#text1").addClass("hover");
findPosition("in", ui.offset);
},
out: function(event, ui) {
$("#text1").removeClass("hover");
findPosition("out", ui.offset);
$("#text1").val($(".item1 .slider-value").html());
}
});
$(".slider-value").html(sliderDiv.slider('value'));
}
This allows an intercept upon touch. Also, over only triggers once and does not continue to update throughout the drag. So I set a flag to indicate when over is true and when it is and drag is happening, we want to update the values. Once dropped, we can determine what to do. If the drag is out, we revert the value to 0.
I am using Fabric.js and jQuery UI for a drag and drop scene creator. When I drag and drop an image into the canvas the image becomes blurry/pixelated and appears to be zoomed in. I've been searching Stackoverflow and Google forever and can't find any solutions. I'd appreciate any suggestions on how to fix it!
Here is my code:
// HTML
<canvas id="scene"></canvas>
// Draggable setup
$('.scene-item').draggable({
helper: 'clone',
appendTo: 'body',
containment: 'window',
scroll: false,
zIndex: 9999
});
// Drop Setup
var canvas = new fabric.Canvas('scene');
canvas.setDimensions({
width: '800px',
height: '500px'
}, {
cssOnly: true
});
document.getElementById("scene").fabric = canvas;
canvas.on({
'object:moving': function(e) {
e.target.opacity = 0.5;
},
"object:modified": function(e) {
e.target.opacity = 1;
}
});
$('#scene').droppable({
drop: function(e, ui) {
if ($(e.target).attr('id') === 'scene') {
var pointer = canvas.getPointer();
fabric.Image.fromURL(ui.draggable[0].currentSrc, function (img) {
console.log(img);
img.set({
left: pointer.x - 20,
top: pointer.y - 20,
width: 52,
height: 52,
scale: 0.1
});
//canvas.clear();
canvas.add(img);
canvas.renderAll();
});
}
}
});
This is what the images look like on and off the canvas:
Here is a demo jsfiddle.net/dmLr6cgx/1
I figured out the problem. I had to replace:
canvas.setDimensions({
width: '800px',
height: '500px'
}, {
cssOnly: true
});
with
canvas.setHeight(500);
canvas.setWidth(800);
canvas.renderAll();
And now it works fine.
This is the code I have so far for my draggable-droppable-resizable functionality:
var cont1 = $(this.el).find('.image');
var cont2 = $(this.el).find('#container2');
console.log(cont1);
$(cont1).draggable({
helper: 'clone',
cursor: 'move',
revert: 'true'
});
$(cont2).droppable({
accept: 'img',
drop: function(event, ui) {
var $canvas = $(this);
var $container = $('<div>');
if (!ui.draggable.hasClass('canvas-element')) {
var $canvasElement = ui.draggable.clone();
$canvasElement.addClass('canvas-element');
$container.draggable({
cursor: "move",
// delay: 1000,
scroll: false
// containment: "parent"
}).resizable({
//containment: "parent",
handles: 'n, e, s, ne, nw, se, sw',
aspectRatio: true
});
$container.append($canvasElement).prependTo(cont2);
$canvasElement.css({
left: $container.left,
top: $container.top,
position: 'relative',
height: '100%',
width: '100%'
});
//$canvasElement.css('left', ui.position.left-80+'px').css('top', ui.position.top-80+'px').appendTo(this);
}
}
});
Here's the jsFiddle.
What I would like to achieve is for the dropped images to remain in the place where they were dropped.
There are also some other issues - the images that have already been dropped before change their positions after a new one gets dropped and I would like to get rid of this issue.
What can I change to implement that functionality?
You will need to set the .image elements to position: absolute when inside of the container. You then need to calculate their left and top based on the position of the drop event and the offset of the container.
CSS:
#container2 .image{
position: absolute;
}
JS:
var containerOffset = $container.offset();
$canvasElement.css({
left: ui.position.left - containerOffset.left,
top: ui.position.top - containerOffset.top
});
http://jsfiddle.net/E9y8Q/7/