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.
Related
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 am trying to get Jquery UI Sortable working with the zoom. The issue is the mouse doesn't move with the same speed as the element you are dragging. There are quite a few examples posted about how to get this working with Draggable. Here is a example of the workaround for Draggable items:
http://jsfiddle.net/TqUeS/660/
var zoom = $('#canvas').css('zoom');
var canvasHeight = $('#canvas').height();
var canvasWidth = $('#canvas').width();
$('.dragme').draggable({
drag: function(evt,ui)
{
// zoom fix
ui.position.top = Math.round(ui.position.top / zoom);
ui.position.left = Math.round(ui.position.left / zoom);
// don't let draggable to get outside of the canvas
if (ui.position.left < 0)
ui.position.left = 0;
if (ui.position.left + $(this).width() > canvasWidth)
ui.position.left = canvasWidth - $(this).width();
if (ui.position.top < 0)
ui.position.top = 0;
if (ui.position.top + $(this).height() > canvasHeight)
ui.position.top = canvasHeight - $(this).height();
}
});
I would expect the Drag event to be replaced by the Sort event in the Sortable version of this, but as you can see from the below fiddle, it doesn't work. Setting ui.position in the sort event has no effect - it seems to set it and discard it after the event fires.
http://jsfiddle.net/TqUeS/658/
var zoom = $('#canvas').css('zoom');
var canvasHeight = $('#canvas').height();
var canvasWidth = $('#canvas').width();
$('#canvas').sortable({
items: "div",
sort: function(evt,ui)
{
// zoom fix
ui.position.top = Math.round(ui.position.top / zoom);
ui.position.left = Math.round(ui.position.left / zoom);
// don't let draggable to get outside of the canvas
if (ui.position.left < 0)
ui.position.left = 0;
if (ui.position.left + $(this).width() > canvasWidth)
ui.position.left = canvasWidth - $(this).width();
if (ui.position.top < 0)
ui.position.top = 0;
if (ui.position.top + $(this).height() > canvasHeight)
ui.position.top = canvasHeight - $(this).height();
}
});
If anyone has another workaround, I'd be happy to hear it.
Minor differences between draggable and sortable. In sort, the ui.helper is the item and position does not effect it in the same way, it's just a report of it's position.
For Draggable, in drag for ui.position, it states:
Current CSS position of the helper as { top, left } object. The values may be changed to modify where the element will be positioned. This is useful for custom containment, snapping, etc.
For Sortable, in sort for ui.position, it states:
The current position of the helper represented as { top, left }.
Try this:
Example: http://jsfiddle.net/Twisty/4nv60ob9/2/
HTML
<div id="canvas" data-zoom="0.5">
<div class="dragme"></div>
<div class="dragme"></div>
<div class="dragme"></div>
</div>
<div id="report"></div>
JavaScript
var zoom = $("#canvas").data("zoom");
console.log(typeof zoom, zoom.toString());
var canvasHeight = $('#canvas').height();
var canvasWidth = $('#canvas').width();
$('#canvas').sortable({
items: "div",
start: function(e, ui) {
console.log("Sort Start Triggered");
},
sort: function(evt, ui) {
console.log("Sort Triggered");
// zoom fix
ui.position.top = Math.round(ui.position.top / zoom);
ui.position.left = Math.round(ui.position.left / zoom);
$("#report").html("Top: " + ui.position.top + " Left: " + ui.position.left);
// don't let draggable to get outside of the canvas
if (ui.position.left < 0) {
ui.helper.css("left", 0);
}
if (ui.position.left + ui.helper.width() > canvasWidth) {
ui.helper.css("left", (canvasWidth - ui.helper.width()) + "px");
}
if (ui.position.top < 0) {
ui.helper.css("top", 0);
}
if (ui.position.top + ui.helper.height() > canvasHeight) {
ui.helper.css("top", (canvasHeight - ui.helper.height()) + "px");
}
$("#report").html("Top: " + (canvasHeight - ui.helper.height()) + " Left: " + (canvasWidth - ui.helper.width()));
}
});
I think that is working in the same way.
I've tried using jquery's built in draggable and I've tried using custom drag functions with no avail. Both have their respected issues and I will try to highlight both of them.
Basically, I am trying to allow the dragging of an element that is on a scaled div container. The following methods work okay on a scaled element that is less than around 2. But if you go any higher than that, we see some issues.
Any help would be appreciated. Thank you for your time.
HTML
<div id="container">
<div id="dragme">Hi</div>
</div>
Method 1 (Jquery draggable function)
I've tried the jquery draggable function as you can see in this jsfiddle example.
The problems I found in this example are the following:
Biggest concern: The droppable container does not change when it is scaled up. So if the element is being dragged over part of the scaled container that isn't a part of it's original size, it will fail.
When you click to drag a div, it teleports a little bit away from the mouse and is not a seamless drag.
JS
var percent = 2.5;
$("#dragme").draggable({
zIndex: 3000,
appendTo: 'body',
helper: function (e, ui) {
var draggable_element = $(this),
width = draggable_element.css('width'),
height = draggable_element.css('height'),
text = draggable_element.text(),
fontsize = draggable_element.css('font-size'),
textalign = draggable_element.css('font-size');
return $('<div id="' + draggable_element.id + '" name="' + draggable_element.attr('name') + '" class="text">' + text + '</div>').css({
'position': 'absolute',
'text-align': textalign,
'background-color': "red",
'font-size': fontsize,
'line-height': height,
'width': width,
'height': height,
'transform': 'scale(' + percent + ')',
'-moz-transform': 'scale(' + percent + ')',
'-webkit-transform': 'scale(' + percent + ')',
'-ms-transform': 'scale(' + percent + ')'
});
},
start: function (e, ui) {
$(this).hide();
},
stop: function (e, ui) {
$(this).show();
}
});
$("#container").droppable({
drop: function (event, ui) {
var formBg = $(this),
x = ui.offset.left,
y = ui.offset.top,
drag_type = ui.draggable.attr('id');
var element_top = (y - formBg.offset().top - $(ui.draggable).height() * (percent - 1) / 2) / percent,
element_left = (x - formBg.offset().left - $(ui.draggable).width() * (percent - 1) / 2) / percent;
$(ui.draggable).css({
'top': element_top,
'left': element_left
});
}
});
Method 2 - Custom drag function
I've tried using a custom drag function but it unusable after around a 2 scale.
jsfiddle on a scale(2) - Looks like the draggable div is having a seizure.
jsfiddle on a scale(2.5) - The draggable div flys away when you try to drag it.
JS
(function ($) {
$.fn.drags = function (opt) {
opt = $.extend({
handle: "",
cursor: "move"
}, opt);
if (opt.handle === "") {
var $el = this;
} else {
var $parent = this;
var $el = this.find(opt.handle);
}
return $el.css('cursor', opt.cursor).on("mousedown", function (e) {
if (opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
$(this).addClass('active-handle')
var $drag = $parent.addClass('draggable');
}
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
follow = function (e) {
$drag.offset({
top: e.pageY + pos_y - drg_h,
left: e.pageX + pos_x - drg_w
})
};
$(window).on("mousemove", follow).on("mouseup", function () {
$drag.removeClass('draggable');
$(window).off("mousemove", follow);
});
e.preventDefault(); // disable selection
}).on("mouseup", function () {
if (opt.handle === "") {
$(this).removeClass('draggable');
} else {
$(this).removeClass('active-handle');
$parent.removeClass('draggable');
}
});
}
})(jQuery);
$("#dragme").drags({}, function (e) {});
Here are a few of my findings to make sure dragging on a scaled container works for method one. The only caveat is to make sure you have var percent as the scaled percentage declared before any of these actions happen.
First, use this code at the top of your javascript. This wil help making sure that the droppable area works with a sacled container.
$.ui.ddmanager.prepareOffsets = function( t, event ) { var i, j, m = $.ui.ddmanager.droppables[ t.options.scope ] || [], type = event ? event.type : null, list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); droppablesLoop: for ( i = 0; i < m.length; i++ ) { if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { continue; } for ( j = 0; j < list.length; j++ ) { if ( list[ j ] === m[ i ].element[ 0 ] ) { m[ i ].proportions().height = 0; continue droppablesLoop; } } m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; if ( !m[ i ].visible ) { continue; } if ( type === "mousedown" ) { m[ i ]._activate.call( m[ i ], event ); } m[ i ].offset = m[ i ].element.offset(); m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth * percent, height: m[ i ].element[ 0 ].offsetHeight * percent }); } };
Here are a few functions that are necessary to fix the drag so it works on a scaled container.
function dragFix(event, ui) { var changeLeft = ui.position.left - ui.originalPosition.left, newLeft = ui.originalPosition.left + changeLeft / percent, changeTop = ui.position.top - ui.originalPosition.top, newTop = ui.originalPosition.top + changeTop / percent; ui.position.left = newLeft; ui.position.top = newTop; }
function startFix(event, ui) { ui.position.left = 0; ui.position.top = 0; var element = $(this); }
You will want this if you want to enable the element to be resizable on a scaled container.
function resizeFix(event, ui) { var changeWidth = ui.size.width - ui.originalSize.width, newWidth = ui.originalSize.width + changeWidth / percent, changeHeight = ui.size.height - ui.originalSize.height, newHeight = ui.originalSize.height + changeHeight / percent; ui.size.width = newWidth; ui.size.height = newHeight; }
To make an element draggable, I use the following function.
$("ELEMENT").resizable({ minWidth: - ($(this).width()) * 10, minHeight: - ($(this).height()) * 10, resize: resizeFix, start: startFix });
$("ELEMENT").draggable({ cursor: "move", start: startFix, drag: dragFix }); }
A similar problem is mentioned here: jquery - css "transform:scale" affects '.offset()' of jquery
It seems the problem arises from the fact that jQuery fails to return exact size for scaled elements and therefore failing setting right offset values to the element.
To solve this, he is suggesting first setting scale to 1 and setting offset and then again resetting scale value.
But this alone does not solve the problem here. Since mouse position is taken while it is scaled, position values should also be divided by scale value.
Here is an edited version of code:
var scl = 2.5;
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top/scl + drg_h - e.pageY/scl,
pos_x = $drag.offset().left/scl + drg_w - e.pageX/scl;
follow = function(e) {
var size = {
top:e.pageY/scl + pos_y - drg_h+scl*2,
left:e.pageX/scl + pos_x - drg_w+scl*2
};
$drag.parent().css("transform","scale(1)");
$drag.offset(size);
$drag.parent().css("transform","scale("+scl+")");
};
Note: I only replaced scale value for transform tag, since I am using chrome. You can also replace all instances or instead you can use a different class with 1 scale value.
JSFiddle is also here.
Here is an example of simple drag with scaling, however, in prue dom.
<style>
#dragme {
position:absolute;
border:1px solid red;
background:pink;
left:10px;
top:20px;
width:100px;
height:200px;
}
#container {
transform: scale(2,2) translate(100px,100px);
position:relative;
border:1px solid green;
background:grey;
width:200px;
height:300px;
}
</style>
<body>
<div id="container">
<div id="dragme">Hi</div>
</div>
<script>
var dragme=document.getElementById("dragme");
var container=document.getElementById("container");
dragme.onmousedown=function Drag(e){
this.ini_X = this.offsetLeft-e.clientX/2;
this.ini_Y = this.offsetTop-e.clientY/2;
container.onmousemove = move;
container.onmouseup = release;
return false;
}
function move(e){
e.target.style.left = e.clientX/2 + e.target.ini_X + 'px';
e.target.style.top = e.clientY/2 + e.target.ini_Y + 'px';
}
function release(){
container.onmousemove=container.onmouseup=null;
}
</script>
</body>
I've multiple, draggable divs inside of a scrollable div. When I drag them into the droppable zone (which is also a scrollable div), the doppable DIV doesn't scroll down. Just the page is moveing.
How to say, that just the droppable div should scroll while dragging?
Here is my current jquery code for making the divs draggable
$(".drag_item").draggable({
helper: 'clone',
scroll: true,
drag: function( event, ui ) {
$(this).css('z-index','100');
}
});
I came up with this solution:
var direction = {};
var bound = {};
var scrolling = false;
var container = document.getElementById("container");
$('#table-container')
.on('dragstart', draggable, function(event, ui) {
bound = {
right : $(container).offset().left + $(container).width() - 50,
left : $(container).offset().left + 50,
top : $(container).offset().top + 50,
bottom : $(container).offset().top + $(container).height() - 50
};
})
.on('dragstop', draggable, function(event, ui) {
direction = {};
})
.on('drag', draggable, function(event, ui) {
direction.right = event.clientX - bound.right;
direction.left = bound.left - event.clientX;
direction.up = bound.top - event.clientY;
direction.down = event.clientY - bound.bottom;
if ((direction.right > 0 || direction.left > 0|| direction.up > 0 || direction.down > 0) && !scrolling) {
scroll();
scrolling = true;
} else {
scrolling = false;
}
});
function scroll() {
if (direction.right > 0) {
container.scrollLeft = container.scrollLeft + (direction.right >> 1); //dividing by 2 to soften effect
}
if (direction.left > 0) {
container.scrollLeft = container.scrollLeft - (direction.left >> 1);
}
if (direction.down > 0) {
container.scrollTop = container.scrollTop + (direction.down >> 1);
}
if (direction.up > 0) {
container.scrollTop = container.scrollTop - (direction.up >> 1);
}
if (direction.right > 0 || direction.left > 0 || direction.up > 0 || direction.down > 0) {
setTimeout(scroll, 100);
}
}
Use "overflow=auto" it works for me.
<div style="overflow:auto;"></div>
OR
jQuery now supports scrollTop as an animation variable.
$("#id").animate({"scrollTop": $("#id").scrollTop() + 100});
You no longer need to setTimeout/setInterval to scroll smoothly.
I am using this following jQuery-UI code in my programming, can anybody know how to know, whether event.pageX and event.pageY is increasing or decreasing while resizing a particular div.
CODE:
fontSize = parseInt($(' span',this).css('fontSize'));
$(this).resizable({
disabled:false,
handles: 'nw, ne, se, sw',
resize: function(event, ui) {
xvalue = event.pageX;
yvalue = event.pageY;
fontSize = fontSize+.1;
$(" span",this).css("fontSize",fontSize);
}
});
can anybody how to get to know is that xvalue and yvalue is increasing or decreasing ??
var fontSize = parseInt($('span', this).css('fontSize'));
var xValue, yValue;
var f = function(event, ui) {
var isXIncreasing = xXalue < event.pageX;
var isYIncreasing = yValue < event.pageY;
// ^ you can do something with these now
xValue = event.pageX;
yValue = event.pageY;
fontSize = fontSize+.1;
$('span', this).css("fontSize",fontSize);
};
$(this).resizable({
disabled: false,
handles: 'nw, ne, se, sw',
resize: f
});
You can compare ui.originalSize and ui.size to see whether the current resizing operation is decreasing or increasing the size.
For instance:
resize: function(event, ui) {
if (ui.size.height > ui.originalSize.height) {
// element is taller than before
} else {
// element is the same size or smaller than before
}
}
By analogy, you can use ui.size.width and ui.originalSize.width to see if the element is wider than before.
See the API.