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
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 trying to scroll an image by dragging my cursor. I'm using the Draggable jQuery library but I'm having a problem.
I need to determine the limit of the image so that I can block the drag to avoid showing white space.
Anyone can help me with that?
jsfiddle
<div style="width:100%;height:100%;" id="parent">
<img src="http://cdn.wallpapersafari.com/10/37/Aim58J.jpg" id="draggable"/>
$( "#draggable" ).draggable({
axis: 'x,y',
cursor: "crosshair",
});
If you need scrolling by dragging, do not use dragging. Use simple mouse move instead. Look at the example below. In this case you can scroll any content inside your container.
Hope it would help.
UPDATED:
If you need dragging of some background element, you should to drag it by mousemove and calculate visible area according to container size.
So, in few words - Drag image left till its width minus left offset is bigger than container(window) width, and so on for right, top and down offsets.
// Main script
function run() {
var $image = $('#draggable');
var $window = $(window);
var isStarted = false;
var cursorInitialPosition = {left: 0, top: 0};
var imageInitialPosition = {left: 0, top: 0};
var imageSize = {width: $image.width(), height: $image.height()};
// stop dragging
var stop = function() {
isStarted = false;
$window.unbind('mousemove', update);
};
// update image position
var update = function(event) {
// size of container (window in our case)
var containerSize = {width: $window.width(), height: $window.height()};
var left = imageInitialPosition.left + (event.pageX - cursorInitialPosition.left);
var top = imageInitialPosition.top + (event.pageY - cursorInitialPosition.top);
// don't allow dragging too left or right
if (left <= 0 && imageSize.width + left >= containerSize.width) {
$image.css('left', left);
}
// don't allow dragging too top or down
if (top <= 0 && imageSize.height + top >= containerSize.height) {
$image.css('top', top);
}
};
$window.mousedown(function(event){
var position = $image.position();
cursorInitialPosition.left = event.pageX;
cursorInitialPosition.top = event.pageY;
imageInitialPosition.left = position.left;
imageInitialPosition.top = position.top;
$(window).mousemove(update);
});
$window.mouseout(stop);
$window.mouseup(stop);
}
$(function(){
// wait for image loading because we need it size
var image = new Image;
image.onload = run;
image.src = "http://cdn.wallpapersafari.com/10/37/Aim58J.jpg";
});
https://jsfiddle.net/2hxz49bj/5/
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.
Update:
Here is the final fiddle. Thanks Twisty.
https://jsfiddle.net/natjkern/55n1Lg61/14/
Here is a mock up of my site
http://jsfiddle.net/natjkern/pjq9wqLy/
On the right I have a fixed list of elements called #userList. This element must be set to overflow: auto, as the number of user elements is variable. I then need to drag a copy into dropzone, which again can vary in size, so it's container must be also set to overflow auto. I need the container to auto scroll when dragged element is dragged to edge to allow user to place element anywhere in dropzone. So far my best idea is to append to body first to escape the original auto overflow container then append to #dropzone on droppable({over:}). But this isn't really working out. Any UI experts out there that can give me a hand?
Here is my code so far:
$(document).ready(function () {
$('.moveMe').draggable({
helper: "clone",
appendTo: 'body',
revert: 'invalid',
scroll: true,
});
$('#dropZone').droppable({
accept: '.moveMe',
//here is where my problem arrises
// I need #dropZoneCon to scroll to place
over: function (event, ui) {
ui.helper.draggable.detach().appendTo($(this));
$('#DropZone div').css('position','absolute');
ui.helper.draggable.draggable('option', 'containment', 'parent');
},
/* */
drop: function (event, ui) {
ui.helper.draggable.detach().appendTo($(this));
$('#DropZone div').css('position','absolute');
ui.helper.draggable.draggable('option', 'containment', 'parent');
},
});
});
Note: commenting out over: allow me to place element where I would like, but I really need the scrolling to work.
This is a little clunky, but it does what you're looking to do.
http://jsfiddle.net/Twisty/55n1Lg61/5/
JQuery
$(document).ready(function() {
var tEntered = false;
$('.moveMe').draggable({
helper: "clone",
appendTo: 'body',
revert: 'invalid',
drag: function(e, u) {
var curPos = u.offset;
var $target = $("#dropZoneCon");
var tVP = $target.offset();
var tW = Math.floor($target.width());
var tH = Math.floor($target.height());
var pad = 20;
var scrInc = 10;
var x0 = tVP.top;
var x1 = tVP.top + tH;
var y0 = tVP.left;
var y1 = tVP.left + tW;
$("#dragInfo").html("Over #dropZone: " + tEntered + ", top: " +
tVP.top + "/" + curPos.top + "/" + x1 + " left: " + tVP.left + "/" + curPos.left + "/" + y1);
if (tEntered) {
// Increase Scroll
if (curPos.left >= (y1 - pad) && curPos.left <= y1) {
$target.scrollLeft($target.scrollLeft() + scrInc);
}
if (curPos.top >= (x1 - pad) && curPos.top <= x1) {
$target.scrollTop($target.scrollTop() + scrInc);
}
// Decrease Scroll
if (curPos.left >= y0 && curPos.left <= (y0 + pad)) {
$target.scrollLeft($target.scrollLeft() - scrInc);
}
if (curPos.top >= x0 && curPos.top <= (x0 + pad)) {
$target.scrollTop($target.scrollTop() - scrInc);
}
}
}
});
$('#dropZone').droppable({
accept: '.moveMe',
over: function(e, u) {
tEntered = true;
},
out: function(e, u) {
tEntered = false;
},
drop: function(event, ui) {
ui.draggable.detach().appendTo($(this));
$('#DropZone div').css('position', 'absolute');
ui.draggable.draggable('option', 'containment', 'parent');
},
});
});
So we do a lot of the heavy lifting in the drag event since we can determine the position of the drag object from this event. In the drag event we define a number of variables:
curPos the current position of our draggable object in { top, left }
$target the dropZone container
tVP the Target View Port offset in { top, left }
tW & tH the Target's Width and Height
scrInc a value we will use to increase or decrease the scroll position
pad the amount of pixels to use as the edge detection of tVP
x0 & x1 are the tVP top edge and bottom edge
y0 & y1 are the tVP left edge and right edge
I defined tEntered outside of these functions, so I can access it from either draggable or droppable. Since droppable has over and out, we can use those to change this value.
Now, when tEntered is true, meaning we are dragging an object over the target, we look to see if the x and y might be within our padding. If they are we increase or decrease the scroll position.
I found this helpful: http://www.jqwidgets.com/community/topic/how-detect-area-dropped-inside-a-div-into-another-div/
This should allow you to do what you want unless I misunderstood. Comment if you have questions.
I am placing an image on the canvas using drap & drop but the problem is, after dropping the image on canvas, image is loosing it's original position where it is dropped.
Sometimes it comes down from the original position and sometimes moves to right. Here is the code:
$("#draggable1").draggable({
stop: function(event, ui)
{
var canv = document.getElementById("tools_sketch");
var rect = canv.getBoundingClientRect();
x = event.clientX - rect.left;
y = event.clientY - rect.top;
ans = confirm("Is it correct position?");
if (ans)
{
dropimg_over_ground("img1", x, y);
$('#draggable1').remove();
}
}
});
dropimg_over_ground = function(imgid, lefti, topi)
{
var c = document.getElementById("tools_sketch");
var ctx = c.getContext("2d");
var img = document.getElementById(imgid);
ctx.drawImage(img, lefti, topi);
}
I have searched forum alot and tried many solutions but it's not worked.
Just subtract the offset of the container:
$('#drag').draggable({
stop: function(e, ui){
console.log('drag');
console.log($(this).offset().top - $('#canvas').offset().top)
console.log($(this).offset().left - $('#canvas').offset().left)
}
});
$("#canvas").droppable({
accept: "#drag",
drop: function (event, ui) {
},
out: function (event, ui) {
console.log('dragged out');
}
});
Working example,
http://jsfiddle.net/kBM6u/6/
check the console for the results
Regards