Make div expandable when I drop an image on it - javascript

Check out this fiddle, here I can drag and drop images on .drop-zone but I want to improve it such that if I drag image on it, the .drop-zone div expands to the position where I am putting the image. Scrollable would be fine.
<div class="drag"><img src="http://www.causingeffect.com/images/made/images/example/cow_50_50_c1.jpg" /></div>
<div class="drag"><img src="http://www.coffeecup.com/images/software/feature-icons/image_editing.png" /></div>
<div class="drag"><img src="http://www.neatimage.com/im/Neat-Image-Logo-64.png" /></div>
<div class="clear"></div>
<div class="drop-zone"></div>
JS
jQuery(function($) {
$('.drop-zone').droppable({
accept: '.drag',
drop: function(event, ui) {
var $clone = ui.helper.clone();
if (!$clone.is('.inside-drop-zone')) {
$(this).append($clone.addClass('inside-drop-zone').draggable({
containment: '.drop-zone'
}));
}
}
});
$('.drag').draggable({
helper: 'clone'
});
});
CSS
.drop-zone{border: 1px solid #9C9898;height:350px;width:400px;margin:0 auto;margin-top: 10px; overflow:auto;}
.clear{clear:both;}

You need some way to detect those edges. I'm using some child divs inside .drop-zone. Next problem is that you need .drop-zone to have position: relative and that messes up the drag/drop library. I applied the fix described here.
Next you find out that mouseover no longer propagates through the .drag element while dragging it, so you need to make sure .drop-zone-edge divs are above it, thus the custom z-index values. Try it out here.
Apply the same technique for top, left and right and make .drop-zone-edges transparent.
HTML:
<div class="drop-zone">
<div class="drop-zone-edge drop-zone-top"></div>
<div class="drop-zone-edge drop-zone-bottom"></div>
</div>
CSS:
.drag {
z-index: 100;
}
.drop-zone-edge {
width: 100%;
height: 10px;
background-color: red;
position: absolute;
z-index: 200;
}
.drop-zone-top {
top: 0;
}
.drop-zone-bottom {
bottom: 0;
}
JS:
var isDown = false;
$(document).mousedown(function() {
isDown = true;
})
.mouseup(function() {
isDown = false;
});
$('.drop-zone').droppable({
accept: '.drag',
drop: function(event, ui) {
var $clone = ui.helper.clone();
if (!$clone.is('.inside-drop-zone')) {
$(this).append($clone.addClass('inside-drop-zone').draggable({
containment: '.drop-zone'
}));
}
var parent = $('.drop-zone');
var leftAdjust = $clone.position().left - parent.offset().left;
var topAdjust = $clone.position().top - parent.offset().top;
$clone.css({left: leftAdjust, top: topAdjust});
}
});
$('.drag').draggable({
helper: 'clone'
});
var shouldEnlargeBottom = false;
$('.drop-zone-bottom').on('mouseover', function(e) {
if(isDown) {
shouldEnlargeBottom = true;
}
});
$('.drop-zone-bottom').on('mouseout', function(e) {
shouldEnlargeBottom = false;
});
function enlarge() {
if(shouldEnlargeBottom) {
var newHeight = $('.drop-zone').height() + 3;
$('.drop-zone').height(newHeight);
}
}
setInterval(enlarge, 100);

Related

Get continues co-ordinates from drop element while hovering a draggable element over it

Hey guys I need to get the continuous co-ordinates of the element on which I hold a draggable element! Like mousemove which gives continuous co-ordinates but on draggable the mousemove is not triggering on the droppable element. So I tried out over of droppable which gives the co-ordinates only once. So is there any other way to get the x,y continuously on the element where I hold a draggable element over it !!!
over: function (event, ui) {
var x = event.clientX, y = event.clientY, DOM_ELEM_COORD = event.target.getBoundingClientRect(),
placeHolder = wf_template.TEMPLATE_UTILITIES.DRAGDROP_API.placeholder.clone(); firstMove = false;
$(placeHolder).mousemove(function (event) {
if ((event.clientY > (event.target.getBoundingClientRect().y + (event.target.getBoundingClientRect().height * (.20)))) ||
(event.clientY < ((event.target.getBoundingClientRect().y + (event.target.getBoundingClientRect().height * (.80))))))
event.target.remove();
});
console.log(event.clientX, event.clientY);
var upper_Limit = DOM_ELEM_COORD.height * (.20), droppable_Limit = DOM_ELEM_COORD.height * (.60), lower_Limit = DOM_ELEM_COORD.height * (.80);
if (y < (DOM_ELEM_COORD.y + upper_Limit)) {
$(".draggable-placeholder").remove();
$(event.target).hasClass("workflow-info-row info-row-child") == true ? event.target.before(placeHolder[0]) : false;
firstMove = true;
console.log("top");
} else if (y > (DOM_ELEM_COORD.y + upper_Limit) && y < (DOM_ELEM_COORD.y + droppable_Limit)) {
$(".draggable-placeholder").remove();
firstMove = false;
console.log("middle");
} else if (y > (DOM_ELEM_COORD.y + lower_Limit)) {
$(".draggable-placeholder").remove();
$(event.target).hasClass("workflow-info-row info-row-child") == true ? event.target.after(placeHolder[0]) : false;
firstMove = false;
console.log("end");
}
},
It is sort of hard to give an example with the limited code you provided. Since draggable knows the drag position, it's easy to use this to gather the details you are looking for. Sounds like you only need them when the item is over the droppable, so we can keep a flag using .data() on the helper and report the detail to whatever function is needed.
$(function() {
$("#draggable").draggable({
start: function(event, ui) {
ui.helper.data("start-pos", ui.position);
ui.helper.data("record", false);
},
drag: function(event, ui) {
if (ui.helper.data("record")) {
var pos = ui.position;
var off = ui.offset;
var ev = [
event.clientX,
event.clientY
];
$("#log").html("<label>P:</label>[" + pos.left + "," + pos.top + "]<br /><label>O:</label>[" + off.left + "," + off.top + "]<br /><label>E:</label>[" + ev[0] + "," + ev[1] + "]");
}
}
});
$("#droppable").droppable({
drop: function(event, ui) {
$(this)
.addClass("ui-state-highlight")
.find("p")
.html("Dropped!");
},
over: function(event, ui) {
ui.helper.data("record", true);
},
out: function(event, ui) {
ui.helper.data("record", false);
}
});
});
#draggable {
width: 100px;
height: 100px;
padding: 0.5em;
float: left;
margin: 10px 10px 10px 0;
}
#droppable {
width: 150px;
height: 150px;
padding: 0.5em;
float: left;
margin: 10px;
}
#log {
width: 120px;
height: 3em;
padding: 0.5em;
float: left;
margin: 10px;
font-family: Courier, monospaced;
font-size: .65em;
}
#log label {
display: inline-block;
width: 2em;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="draggable" class="ui-widget-content">
<p>Drag me to my target</p>
</div>
<div id="droppable" class="ui-widget-header">
<p>Drop here</p>
</div>
<div id="log" class="ui-widget-content"> </div>
This is a very basic example, yet it should be enough to help clarify. You can also use event to collect details about mouse movement in the same way if you choose. I would also configure the tolerance to fit your needs too.
Hope that helps.

Event-bubbling with z-indices

JSFiddle: https://jsfiddle.net/uLap7yeq/19/
Problem
Consider two elements, canvas and div, which are on the same tree depth and have the same parent. They are both placed on the same position using CSS however div has the higher z-index. How can you capture events from the div and pass them along to the lower z-index? Do I have to do .dispatchEvent() on the canvas?
EDIT: To clarify, I'd like the div to receive the event, do whatever it wants and then pass it along to the next z-indexed element.
The JSFiddle pasted inline:
/*
How can I pass the event along to #canvas?
*/
$('#container').on('click', function(e) {
console.log('#container click');
});
$('#canvas').on('click', function(e) {
console.log('#canvas click');
});
$('#other-div').on('click', function(e) {
console.log('#other-div click');
});
#other-div {
z-index: 1;
position: absolute;
top: 0;
left: 0;
}
#canvas {
z-index: 0;
position: absolute;
top: 0;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="other-div">
<p>
Something
</p>
</div>
<canvas id="canvas" width="200" height="200"></canvas>
</div>
Adding css property pointer-events: none; to the #other-div will let clicks or other pointer-related events to pass through the div and reach both the canvas and the container
#other-div {
z-index: 1;
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
See Fiddle 1
If this is not suitable because you need that the other-div too captures the event (as per your comment) then you may trigger programmatically an event on the canvas when the container is clicked
$('#container').on('click', function(e) {
console.log('#container click');
$('#canvas').click(); // <------
});
$('#canvas').on('click', function(e) {
e.stopImmediatePropagation(); // <------
console.log('#canvas click');
});
$('#other-div').on('click', function(e) {
console.log('#other-div click');
});
When the cointainer receives a click then it triggers a click on the undelying canvas too: $('#canvas').click();
Note that when the click finally hits the canvas the event must stop propagate, otherwise it will bubble and hit both the #other-div and the #container leading to an infinite loop. This is why you have e.stopImmediatePropagation();
See Fiddle 2
You can trigger a custom event when you click on the outer-div and make the canvas listening to this event:
$('#container').on('click', function(e) {
console.log('#container click');
});
$('#canvas').on('click custom', function(e) {
console.log('#canvas click');
});
$('#other-div').on('click', function(e) {
console.log('#other-div click');
$('#canvas').trigger( "custom");
});
#other-div {
z-index: 1;
position: absolute;
top: 0;
left: 0;
background:rgba(255,0,0,0.2);
}
#canvas {
z-index: 0;
position: absolute;
top: 0;
left: 0;
background:rgba(255,255,0,0.2);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="other-div">
<p>
Something
</p>
</div>
<canvas id="canvas" width="200" height="200"></canvas>
</div>
You can use a dynamic approach by patching the Element prototype:
if (!document.elementsFromPoint) {
document.elementsFromPoint = elementsFromPoint;
}
function elementsFromPoint(x, y) {
var parents = [];
var parent = void 0;
do {
if (parent !== document.elementFromPoint(x, y)) {
parent = document.elementFromPoint(x, y);
parents.push(parent);
parent.style.pointerEvents = 'none';
} else {
parent = false;
}
} while (parent);
parents.forEach(function (parent) {
parent.style.pointerEvents = 'initial';
});
return parents;
}
Element.prototype.makeEventGoThrough = function(eventName) {
$(this).on(eventName, (e) => {
var elements = document.elementsFromPoint(e.clientX, e.clientY);
var children = [].slice.call(this.children);
elements = elements.filter(element => element !== this && !children.find(el => el === element));
elements.forEach(element => $(element).trigger(eventName));
});
}
/*
How can I pass the event along to #canvas?
*/
document.getElementById('other-div').makeEventGoThrough('click');
$('#other-div').on('click', () => console.log('other-div clicked'));
$('#canvas').on('click', () => console.log('canvas clicked'));
#other-div {
z-index: 1;
position: absolute;
top: 0;
left: 0;
}
#canvas {
z-index: 0;
position: absolute;
top: 0;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="other-div">
<p>
Something
</p>
</div>
<canvas id="canvas" width="200" height="200"></canvas>
</div>

How to get the start value and end value of a div after dragging

Hi i have a div which is draggable .My requirement is
1. I want the start value and end value of the div after dragging in a text box
2.Now its is only drag in right side only i want it drag also from left side of the div
i tried some steps but it is not perfect because the value is not displaying and the dragging from left is not working middle table is my parent div
$(function () {
var container = $('.middletablediv'),
base = null,
handle = $('.handle'),
isResizing = false,
screenarea = screen.width;
handle.on('mousedown', function (e) {
base = $(this).closest(".scalebar");
isResizing = true;
lastDownX = e.clientX;
offset = $(this).offset();
xPos = offset.left;
});
$(document).on('mousemove', function (e) {
// we don't want to do anything if we aren't resizing.
if (!isResizing)
return;
p = parseInt(e.clientX - base.offset().left),
// l = parseInt(p * (3 / 11));
base.css('width', p);
k = parseInt(xPos - base.offset().left);
$("#startvalue").value(k)
$("#stopvalue").value(p)
}).on('mouseup', function (e) {
// stop resizing
isResizing = false;
});
});
.handle{
position: absolute;
top:1px;
right: 0;
width: 10px;
height: 5px;
cursor: w-resize;
}
.middletablediv{
float:left;
width:35%;
}
.scalebar{
margin-top: 13px;
height: 7px;
position: relative;
width:20px;
background-color: green; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="middletablediv">
<div id="newvalue1" class="scalebar">
<div class="handle" style="left:0"></div> <div class="handle"></div>
</div>
</div>
<input id="startvalue" type="text">startvalue</input>
<input id="stopvalue" type="text" />stopvalue</input>
how i solve this issue
You should use val() instead of value(). Also, the way dragging works the end value can be smaller than the start value, so I added a couple of things to handle that problem in a simple way (just switch values). Finally, to drag from the left, you should handle the left dragging differently, so I gave the left handle a unique id and also padded the whole parent div a bit to make it more apparent.
$(function () {
var container = $('.middletablediv'),
base = null,
handle = $('.handle'),
isResizing = false,
isLeftDrag = false;
screenarea = screen.width;
handle.on('mousedown', function (e) {
base = $(this).closest(".scalebar");
isResizing = true;
if($(this).attr('id')=='lefthandle')isLeftDrag=true;
else isLeftDrag=false;
lastDownX = e.clientX;
offset = $(this).offset();
xPos = offset.left;
});
$(document).on('mousemove', function (e) {
// we don't want to do anything if we aren't resizing.
if (!isResizing)
return;
if(isLeftDrag){
p = parseInt(base.offset().left - e.clientX);
k = parseInt(base.offset().left - xPos);
base.css('margin-left',-p);
base.css('width',p);
}
else{
p = parseInt(e.clientX - base.offset().left),
// l = parseInt(p * (3 / 11));
base.css('width', p);
k = parseInt(xPos - base.offset().left);
}
//if(k>p){var temp = k; k = p; p = temp;}
$("#startvalue").val(k)
$("#stopvalue").val(p)
}).on('mouseup', function (e) {
// stop resizing
isResizing = false;
});
});
.handle{
position: absolute;
top:1px;
right: 0;
width: 10px;
height: 5px;
cursor: w-resize;
}
.middletablediv{
float:left;
width:35%;
}
.scalebar{
margin-top: 13px;
height: 7px;
position: relative;
width:20px;
background-color: green; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="middletablediv" style="padding-left:100px; overflow:visible;">
<div id="newvalue1" class="scalebar">
<div class="handle"id="lefthandle" style="left:0"></div> <div class="handle"></div>
</div>
</div><br><br>
<input id="startvalue" type="text">startvalue</input>
<input id="stopvalue" type="text" />stopvalue</input>

How to make this slider control to work in both directions?

I'm trying to make a range slider but it's working in single direction(to right) only and dragging out of parent container(#volume). How can I fix this?
I've attached a demo fiddle link.
Markup
<div id="volume">
<div class="progress">
<div class="volumeslider"></div>
</div>
</div>
CSS
#volume{
width:300px;
background: #ddd;
cursor:pointer;
}
.progress{
height:10px;
background:#999;
position:relative;
width:0;
}
.volumeslider {
background: #808080;
position: absolute;
width: 20px;
height: 20px;
border-radius: 15px;
right: -10px;
top: -5px;
}
JS
$('.volumeslider').bind('mousedown', function(e){
$('.volumeslider').bind('mousemove', function(e){
$('.progress').width(e.pageX - $('.progress').offset().left + 'px');
$(this).css('left', e.pageX - ($(this).width()/2) );
});
$('.volumeslider').bind('mouseup',function(){
$('.volumeslider').unbind('mousemove');
});
});
JS Fiddle:
http://jsfiddle.net/2mYm7/
You have not taken into consideration the padding you have given to the body element.
I have made some changes to the code.
$('.volumeslider').bind('mousedown', function (e) {
console.log('binded');
$('.volumeslider').bind('mouseup', function (e) {
console.log('unbinded');
$('.volumeslider').unbind('mousemove');
});
$('.volumeslider').bind('mousemove', function (e) {
console.log('mousemove');
$('.progress').width(e.pageX - $('.progress').offset().left + 'px');
$(this).css('left', e.pageX - 25- $(this).width());
});
});
Check this jsFiddle http://jsfiddle.net/2mYm7/1/
Here's an example of how to make it work always and everywhere. Right now it will stay dragging forever if you leave the element.
It includes border checks and makes sure the body is large enough so it stops dragging wherever on the page.
http://jsfiddle.net/2mYm7/5/
var dragging = null;
function startDrag(){
console.log('started dragging', this);
var $this = $(this);
dragging = $this;
$(document.body).bind('mouseup', stopDrag);
$(document.body).bind('mousemove', drag);
}
function stopDrag(){
console.log('stopped dragging', dragging[0]);
$(document.body).unbind('mouseup', stopDrag);
$(document.body).unbind('mousemove', drag);
dragging = null;
}
function drag(e){
var slider = dragging;
var progress = slider.parent();
var container = progress.parent();
var maxOffset = container.width();
progress.width(Math.min(e.pageX - progress.offset().left, maxOffset) + 'px');
}
$('.volumeslider').bind('mousedown', startDrag);

jQueryUI draggable element inside iframe - bad behavior with scrolled iframes

I am experiencing troubles while having a draggable div inside an (scrolled) iframe. Please have look at this fiddle: http://jsfiddle.net/CqE43/
This is the used code:
$('#test').contents().find('body').append('<div id="wrapper" style="width: 300px; height: 900px; background: #ff0000; display: block; margin-top:50px;"><div id="drag" style="width: 100px; height: 100px; background-color: blue;" ></div></div>');
$('#test').contents().find('#drag').draggable({
iframeFix: true,
start: function( event, ui ) {
console.log('start');
},
drag: function( event, ui ) {
console.log('drag');
},
stop: function( event, ui ) {
console.log('stop');
}
});
The strange behavior is: if the iframe is not scrolled everything works like expected but if one scrolls the iframe a bit, an offset appears while dragging.
Ok, I've got a (not the but a) solution.
Here is the fiddle: http://jsfiddle.net/CqE43/17/
and this is the source code:
$(function () {
$('#test').contents().find('body').append('<div id="wrapper" style="width: 300px; height: 900px; background: #ff0000; display: block; margin-top:50px;"><div id="drag" style="width: 100px; height: 100px; background-color: blue;" ></div></div>');
var myDraggable = $('#test').contents().find('#drag').draggable({iframeFix: true}).data('ui-draggable');
myDraggable._mouseDrag = function(event, noPropagation) {
if ( this.offsetParentCssPosition === "fixed" ) {
this.offset.parent = this._getParentOffset();
}
//Compute the helpers position
this.position = this._generatePosition(event);
this.positionAbs = this._convertPositionTo("absolute");
//Call plugins and callbacks and use the resulting position if something is returned
if (!noPropagation) {
var ui = this._uiHash();
if(this._trigger("drag", event, ui) === false) {
this._mouseUp({});
return false;
}
this.position = ui.position;
}
if(!this.options.axis || this.options.axis !== "y") {
this.helper[0].style.left = this.position.left+"px";
}
if(!this.options.axis || this.options.axis !== "x") {
this.helper[0].style.top = $('#test').contents().find('body').scrollTop()+this.position.top+"px";
}
if($.ui.ddmanager) {
$.ui.ddmanager.drag(this, event);
}
return false;
}
});
Yes, it is not beautiful ubt it does work quite well!

Categories

Resources