I would like to drag a svg element onto HTML element.
Not sure what a smart way to do so.
However, I think my method is dirty, but I think I can start drag from svg element with d3.behavior.drag() and on drag function of d3, I am going to clone a copy(please think it is simply a circle object) and let jquery ui handle the drag events.
The problem is I don't know how to trigger drag event on newly created jquery element.
var drag= d3.behavior.drag()
.on("drag", function(d) {
// make a Clone html object .dragging-node
$('.dragging-node').attr('draggable', true);
$('.dragging-node').trigger('dragstart');
});
var node = vis.selectAll("g.node")
.data(nodes)
.enter().append("svg:g")
.attr("class", "node")
.call(drag);
Any idea how to start drag for this newly created clone object?
Or is there any smarter way to get what I want?
Any help would be appreciated!
I did something like this once, and it worked ok for simple stuff, but after some time it became clear that using jQueryUI's Draggable is saner, since it's much more robust. I also needed to use Droppable functionality in conjunction; maybe your needs are less demanding. If so:
You don't need to artificially trigger events from the cloned element (aka "drag helper" in jQueryUI's draggable terminology). Instead, let the events continue to be triggered on the element that initiated the drag and has the drag behavior applied to it, but update the helper's position.
Something like this:
// Helper is the cloned element, which doesn't exist until dragging begins
// (alternatively it could pre-exist but be hidden)
var $helper = null
// the parent container of $helper,
// which presumably is outside of the SVG
var $helperParent = $('body')
var drag = d3.behavior.drag()
.on("dragstart", function(d) {
$helper = ... // somehow make the cloned helper, on dragstart (not on drag)
.appendTo($helperParent)
})
.on("drag", function(d) {
// determine the mouse position relative to the helper's parent
// (not relative to the SVG element that initiated the drag)
mousepos = d3.mouse($helperParent[0])
// update the helper's position
$helper.css({
left: mousepos[0],
top: mousepos[1]
});
})
.on("dragend", function(d) {
// remove (or hide) the helper
$helper.remove();
});
Related
I create a new jQuery element after the mouse is in a down position and before it is released. (After mousedown).
I would like to programmatically trigger dragging on the new element using jQuery UI, so that it will automatically begin dragging with my mouse movement. I don't want to have to release and then click the mouse again.
I have tried the following...
var element = $("<div />");
element.appendTo("body").draggable().trigger("mousedown");
...however this does not work.
Does anyone have any suggestions on how to accomplish this?
UPDATE: After some searching the poster of this question has the identical problem. However the suggested solution, which boils down to...
$("body").on("mousedown", function(e) {
$("<div />").draggable().appendTo("body").trigger(e);
});
...no longer works in the latest versions jQuery and jQuery-UI, and instead generates a Maximum Call Stack Exceeded error.
The draggable plugin expects its mousedown events to use its namespace and to point to the draggable object as the target. Modifying these fields in the event works with jQuery 1.8.3 and jQuery UI 1.9.2.
$("body").on("mousedown", function(e) {
var div = $("<div />").draggable().appendTo("body");
e.type = "mousedown.draggable";
e.target = div[0];
div.trigger(e);
});
Demo here: http://jsfiddle.net/maCmB/1/
UPDATE:
See fuzzyBSc's answer below. It's the proper way to do this.
This is totally a hack, but it seems to do the trick:
var myDraggable = $('#mydraggable').draggable();
// Yeah... we're going to hack the widget
var widget = myDraggable.data('ui-draggable');
var clickEvent = null;
myDraggable.click(function(event){
if(!clickEvent){
widget._mouseStart(event);
clickEvent = event;
}
else {
widget._mouseUp(event);
clickEvent = null;
}
});
$(document).mousemove(function(event){
console.log(event);
if(clickEvent){
// We need to set this to our own clickEvent, otherwise
// it won't position correctly.
widget._mouseDownEvent = clickEvent;
widget._mouseMove(event);
}
});
Here's the plunker
My example uses an element that already exists instead of creating one, but it should work similarly.
Create your draggable function on mouseover
$('#futureDragableElement').mouseover(function() {
$(this).draggable();
});
As the draggable initialization has already be done, your first mouse click will be taken into account
You have to bind the mousedown event to the element in question, then you can trigger the event.
From http://api.jquery.com/trigger/
Any event handlers attached with .bind() or one of its shortcut
methods are triggered when the corresponding event occurs. They can be
fired manually, however, with the .trigger() method. A call to
.trigger() executes the handlers in the same order they would be if
the event were triggered naturally by the user:
$('#foo').bind('click', function() {
alert($(this).text());
});
$('#foo').trigger('click');
Hacks are not needed if you are creating the element during the event and that element is not too complicated. You can simply set draggable to the element that mousedown occurs and use draggable helper property to create a helper that is going to be your new element. On dragStop clone the helper to the location in dom you want.
$('body').draggable({
helper: function() {
return '<div>your newly created element being dragged</div>';
},
stop: function (e,ui) {
ui.helper.clone().appendTo('body');
}
});
Of course you would need to set position for the helper, so mouse is on it. This is just a very basic example.
i am trying to add a new image when i click the z pass button
my this part of the code is not working
http://jsfiddle.net/UjJEJ/24/
$(".ctaSpecialOne").click(function(){
alert("clicked");
$(this).parent().unbind("mouseenter").children("img").attr("src", "http://www.onlinegrocerystore.co.uk/images/goodfood.jpg");
});
You need to traverse to the sibling a since that's where your image is
$(this).parent().unbind("mouseenter").siblings('a').children("img").attr("src", "http://www.onlinegrocerystore.co.uk/images/goodfood.jpg");
http://jsfiddle.net/WAvVw/
EDIT
You need to traverse to get the element which you bound hover to
$(this)
.closest('.specialHoverOne') // get element you bound hover to
.unbind("mouseenter") // unbind event
.end() // start over at this
.parent() // get parent
.siblings('a') //find a sibling
.children("img") // get children img
.attr("src", "http://www.onlinegrocerystore.co.uk/images/goodfood.jpg"); // change src
http://jsfiddle.net/mwPeb/
I'm sure there's a better way to traverse but I'm short on time right now
I am using https://github.com/furf/jquery-ui-touch-punch to map the touch events. jQuery UI droppable has the below code in which the event and ui objects are passed automatically. I want to write a custom handler to which I can pass the same objects. Could any one suggest how I can get the reference of ui object on touchend event on IPAD ? So that I can use same drop function for both desktop and IPAD.
drop: function(event, ui) {
dropFunction(event, ui);
}
so on touchend event I can call dropFunction(event,ui)
Additional info:
I am trying to achieve drag and drop from table row to a jstree. If I just use Touch Punch without modification I am able to do the drag and drop is also being called. As I am reading the values using the below code, it works on desktop browser but not on IPAD.
var newOrgId = $('#ohTreeDiv .jstree-hovered').find('span:last').text()
the jstree-hovered class is added automatically to the hovered node when using desktop browser however this does not get added on Ipad, so I am adding this class manually in touchend method. After this step I even get the hovered class added. When touchend happens it looks like the drop is not being called.
After dragging the element on the target node of the jstree I have to tap it so that the drop is triggered. #FrédéricHamidi
Below is the touchend code which I had to modify little bit to make it working with jstree so that I can read the values with jstree-hovered class. One tip I want to add is when testing remove all the alerts as it will intefere with the values we read using jQuery.
c._touchEnd = function(f) {
var i = f.originalEvent.changedTouches[0];
var elementFromPoint1 = document.elementFromPoint(i.clientX, i.clientY);
var id=elementFromPoint1.id;
var str=new String(id);
var pos=str.indexOf("dropTarget");
if(pos>=0){
elementFromPoint1.className="jstree-hovered";
}
if (!a) {
return;
}
d(f, "mouseup");
d(f, "mouseout");
if (!this._touchMoved) {
d(f, "click");
}
a = false;
};
I am working on a tool based on jQuery UI draggable functionality.
I have a number of boxes in the left column of the table. When they are dragged in yellow area, I would expect the remaining divs to move upwards to fill the space left by the box that was moved.
But it's not happening. Why?
It is pretty difficult to test but from my knowledge on the question here is a possible cause/solution to this.
The droppable plugin does not remove the dragged element from its original markup position, it is visually moved to the droppable element (with some option allowing to accept to drop certain elements or not, events, etc).
The elements have a position: relative css rule, which represents the "normal flow" for elements (in the order they appear in the markup). So even if the element is visually placed elsewhere on the page with css, its place in the markup is still the same and it is still taking the space it normally should.
This fiddle illustrate what i'm trying to explain :-)
By looking at the source code form the "working website", they actually remove the dragged element from the original draggable list and re-create it in the droppable list !
When they define the .droppable() they do this:
h.droppable({
tolerance: "intersect",
accept: ".card",
greedy: true,
drop: function (a, b) {
card = b.draggable;
putCardIntoStack(card, c)
}
});
On the drop event, they call putCardIntoStack(card, c) passing the currently dragged element as the card parameter. Within this method, they remove the original "card" (a.remove()) and re-create it in the dropzone (newcard = createCard();):
function putCardIntoStack(a, b) {
progressVal = $('#progBarRd').width();
card_idDOM = a.attr('id');
card_idDB = card_idDOM.substr(IDPREFIX_CARD.length, card_idDOM.length - IDPREFIX_CARD.length);
stack_idDB = b.substr(IDPREFIX_STACK.length, b.length - IDPREFIX_STACK.length);
$.ajax({
url: URL_DRAGDROPAJAX,
type: 'POST',
data: 'action=movecard&cardid=' + card_idDB + '&tostack=' + stack_idDB + '&prog=' + progressVal
});
// 'a' is the card
// they extract the id/content from the dragged card
cardId = a.attr('id');
cardLabel = a.text();
// they remove the card from the DOM
a.remove();
// they create a new card with the extracted info
newcard = createCard(cardId, cardLabel);
newcard.addClass('stackcard');
// and append it to the dropzone
$('#' + b).removeClass("empty").find('.stackDrop').append(newcard);
globalcheck()
}
jQuery UI does a similar thing on the droppable demo page. On the drop event, they call a function deleteImage() which removes the dragged image from the original markup and appends it to the drop zone.
I hope I'm clear enough :-)
I also hope I'm right, it is pretty difficult to test quickly but it makes sense :-)
I'm using jQuery and I have the following problem:
In my site I have a chessboard with pieces. Every square is a simple div with the background property to show white or black. Over these squares (inside the divs) I've put an img tag referencing the piece that must be over that square. Something like:
<div id="a8" class="square" style="background-image: url('/images/background_white.png')">
<img id="piece_a8" class="piece" src="/images/rook_black.png" />
</div>
I can control the movement of the pieces using jQuery. Every piece-class img is a draggable and every square-class div is a droppable. I already have a server-side function that, given a set of coordinates, returns "VALID" if the movement is valid, and "INVALID" if otherwise. My idea is, if the server returns "INVALID", the piece must return to its origin square, and if the server returns "VALID", the piece must stay in its new square, deleting every other piece inside the target square.
My problem is, I don't know how can I enforce this return value in my jQuery code. I've tried putting functions in the revert property of the draggable, and in the accept and drop functions of the droppable, but I haven't found how to make $.get return false or true.
Any help would be really appreciated.
Thanks in advance,
Léster
Nevermind, answered.
In case someone needs to know, the trick is in 2 parts:
First: In the draggable definition, under the start event, add a function that saves the original position. Like this:
$('item_to_drag').draggable({
start: function(){
$(this).data("origPosition",$(this).position());
}
});
Second: In the droppable definition, under the drop event, do your .get and use a function to process the answer; in case your conditions are not met, animate the draggable back to its original position. Like this:
drop: function (event, ui) {
$.get(url,function(data) {
if (data == '"INVALIDO"')
{
ui.draggable.animate(ui.draggable.data("origPosition"),"slow");
}
else
{
//store new positions, whatever;
}
}
);
}
That'll do the trick.
Part of the answer came from here: In jQuery, how to revert a draggable on ajax call failure? .