I want create an effect "taking stone from bowl". New div element ".stone" should creating under mouse cursor by clicking on specified div ".bowl". The stone should be straight draggable while the user click and press the mouse.
All I could write is adding new element that user can move by second click, but not by first:
$(".bowl").on('mousedown', function ( event ) {
var $stone = $('<div class="stone"></div>').css({
left: event.pageX - 25,
top: event.pageY - 25,
position: "absolute"
});
$(this).parent().append($stone);
$stone.draggable();
});
https://jsfiddle.net/rzab2h5u/
How I can do it right way?
This can be done by basically passing the event to the draggable after it's been created. Reference: https://forum.jquery.com/topic/trigger-draggable-on-mousedown
Working example: https://jsfiddle.net/Twisty/s3tfa3dr/
JavaScript
$(function() {
var bowl = $(".bowl");
bowl.droppable({
accept: ".stone",
greedy: true,
drop: function(event, ui) {
ui.draggable.detach();
}
});
bowl.on('mousedown', function(event) {
var $this = $(this);
var $stone = $('<div>', {
class: "stone",
id: "stone-" + ($(".stone").length + 1)
}).css({
left: event.pageX - 25,
top: event.pageY - 25,
position: "absolute"
}).appendTo($this.parent()).draggable({
start: function(ui, event) {
console.log("Drag Started");
}
});
$stone.trigger(event);
});
});
We basically re-trigger the same event on the new object.
Related
I saw a CodePen that allowed dragging an event from FullCalendar to trash or back to an external list. I forked the CodePen: https://codepen.io/hlim18/pen/EMJWQP?editors=1111. The JavaScript part of the working code with jQuery is the following:
$(document).ready(function() {
/* initialize the external events
-----------------------------------------------------------------*/
$('#external-events .fc-event').each(function() {
// store data so the calendar knows to render an event upon drop
$(this).data('event', {
title: $.trim($(this).text()), // use the element's text as the event title
stick: true // maintain when user navigates (see docs on the renderEvent method)
});
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
/* initialize the calendar
-----------------------------------------------------------------*/
$('#calendarSchedule').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
editable: true,
droppable: true, // this allows things to be dropped onto the calendar
dragRevertDuration: 0,
drop: function() {
// is the "remove after drop" checkbox checked?
if ($('#drop-remove').is(':checked')) {
// if so, remove the element from the "Draggable Events" list
console.log(this);
$(this).remove();
}
},
eventDragStop: function( event, jsEvent, ui, view ) {
if(isEventOverDiv(jsEvent.clientX, jsEvent.clientY)) {
$('#calendar').fullCalendar('removeEvents', event._id);
var el = $( "<div class='fc-event'>" ).appendTo( '#external-events-listing' ).text( event.title );
el.draggable({
zIndex: 999,
revert: true,
revertDuration: 0
});
el.data('event', { title: event.title, id :event.id, stick: true });
}
}
});
var isEventOverDiv = function(x, y) {
var external_events = $( '#external-events' );
var offset = external_events.offset();
offset.right = external_events.width() + offset.left;
offset.bottom = external_events.height() + offset.top;
// Compare
if (x >= offset.left
&& y >= offset.top
&& x <= offset.right
&& y <= offset .bottom) { return true; }
return false;
}
});
I would like to write the code without using jQuery. So, I tried to change jQuery to vanilla JavaScript. But, the calendar is not even displayed in the screen.
This is how I tried: https://codepen.io/hlim18/pen/bZyaQj?editors=1111.
The JavaScript part with vanilla JavaScript I tried is the following:
/* initialize the external events
-----------------------------------------------------------------*/
var draggable_events = document.querySelectorAll('#external-events .fc-event');
for(var i=0; i<draggable_events.length; i++){
// store data so the calendar knows to render an event upon drop
draggable_events[i].fullCalendar('renderEvent', {
title: draggable_events[i].innerText, // use the element's text as the event title
stick: true // maintain when user navigates (see docs on the renderEvent method)
});
// make the event draggable
draggable_events[i].draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
}
/* initialize the calendar
-----------------------------------------------------------------*/
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendarSchedule');
var calendar = new FullCalendar.Calendar(calendarEl, {
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
editable: true,
droppable: true, // this allows things to be dropped onto the calendar
dragRevertDuration: 0,
drop: function() {
// is the "remove after drop" checkbox checked?
if (document.getElementById('drop-remove').checked = true) {
// if so, remove the element from the "Draggable Events" list
this.remove();
}
},
eventDragStop: function( event, jsEvent, ui, view ) {
if(isEventOverDiv(jsEvent.clientX, jsEvent.clientY)) {
calendarEl.fullCalendar('removeEvents', event._id);
var el = document.querySelector('fc-event').setAttribute("id", "external-events-listing").text( event.title );
el.draggable({
zIndex: 999,
revert: true,
revertDuration: 0
});
el.data('event', { title: event.title, id :event.id, stick: true });
}
}
}
});
var isEventOverDiv = function(x, y) {
var external_events = document.getElementById('external-events');
var offset = external_events.offset();
offset.right = external_events.width() + offset.left;
offset.bottom = external_events.height() + offset.top;
// Compare
if (x >= offset.left && y >= offset.top && x <= offset.right && y <= offset .bottom){
return true;
}
return false;
}
In the CodePen, I don't see any errors. But, when I test with my app I'm working on, I see the following error:
Uncaught TypeError: draggable_events[i].fullCalendar is not a function
at viewMonthly.js:15
I'm not even sure how many problems are there in total to solve to make the code work with vanilla JavaScript... :(
So, I'd appreciate any advice. Thank you in advance! :)
fullCalendar in versions prior to V4 is a jquery plugin and needs jquery to work
Is there a way how to add listener "droppable" to element, which is actually hovered while dragging "draggable" element?
I've tried this, but it does not work.
$("#draggable span.item").draggable({
helper: "clone",
drag: function(event, ui) {
var pos = ui.position;
var element = document.elementFromPoint(pos.left, pos.top);
$(element).droppable({
classes: {
"ui-droppable-hover": "hover"
},
drop: function(event, ui) {
console.log('dropped');
}
});
}
});
I am trying this because I need apply "droppable" to many elements and classic way via jQuery $("#droppable span.item").droppable(); is very slow in this case. So I would like to init "droppable" listener only for elements, which are hovered while dropping.
did you try this
$(document).ready(function() {
var $dragging = null;
$(document.body).on("mousemove", function(e) {
if ($dragging) {
$dragging.offset({
top: e.pageY,
left: e.pageX
});
}
});
$(document.body).on("mousedown", "div", function (e) {
$dragging = $(e.target);
});
$(document.body).on("mouseup", function (e) {
$dragging = null;
});
});
Hello wizards of the internet,
I want to show a hidden element from a cloned object when it is is dropped into a certain container, called "plug1". But what it does right now is it shows the hidden element on the main object and not on the cloned object. It's also not supposed to jump back to its original position. See this gif for an example.
I believe it has something to do with the sym.getSymbol("cup1").$("hold1").show(); line, but I can't put my finger on it.
Does anyone have an idea as to how I can fix this?
Script:
sym.$(function () {
sym.$("cup1").draggable({
helper: "clone",
cursor: 'move'
});
sym.$("Stage").droppable({
drop: function (event, ui) {
var $canvas = $(this);
if (!ui.draggable.hasClass('canvas-element')) {
var $canvasElement = ui.draggable.clone();
$canvasElement.addClass('canvas-element');
$canvasElement.draggable({
containment: 'Stage'
});
$canvas.append($canvasElement);
$canvasElement.css({
left: (ui.position.left),
top: (ui.position.top),
position: 'absolute'
});
sym.$("cup1").hide().clone().appendTo('Stage');
}
}
});
//hold
sym.$("plug1").droppable({
greedy: 'true',
accept: function() { return true; },
drop: function (event, ui) { tolerance: 'fit', sym.getSymbol("cup1").$("hold1").show(); }
});
});
I am trying to change the color of one specific to Red or Green when I right click it. At the moment, when I right click and change the color, it changes the color of all events, which is not what I want. I need that particular targetted event only.
.fc-event refers to all events but how do I denote a specific event.
All the events are being parsed via JSON object and presented on the calendar.
Here is what I have done so far, any help would be greatly appreciated :-
$(document).bind("contextmenu", function (event) {
event.preventDefault();
$(".custom-menu").data('event', $(this)).finish().toggle(100).
css({
top: event.pageY + "px",
left: event.pageX + "px"
});
});
$(document).bind("mousedown", function(e) {
// If the clicked element is not the menu
if (!$(e.target).parents(".custom-menu").length > 0) {
// Hide it
$(".custom-menu").hide(100);
}
});
// If the menu element is clicked
$("ul.custom-menu li").click(function() {
switch($(this).attr("data-action")) {
case "red":
var $event = $(".fc-event");
$event.css("background-color","red");
break;
case "green":
var $event = $(".fc-event");
$event.css("background-color","green");
break;
}
// Hide it AFTER the action was triggered
$(".custom-menu").hide(100);
});
Here is the calender being displayed.
$(document).ready(function() {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
var calendar = $('#calendar').fullCalendar({
editable: true,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
events: "events.php");
})
Any assistance on how this will be done would be appreciated.
Regards,
Overview:
I have a page which uses jquery.event.drag and jquery.event.drop.
I need to be able to drag and drop onto elements which are constantly being added to the dom, even after the drag has started.
Problem:
When the dragstart event fires it checks for available drop targets and adds them to the drag object.
The problem I have is I am adding drop targets dynamically, after the dragstart event has fired, and therefore the user cannot drop onto these dynamically added drop targets.
Example:
http://jsfiddle.net/blowsie/36AJq/
Question:
How can I update the drag to allow dropping on elements which have been added to the dom after drag has started?
You can use this snippet.
The important function is: $.event.special.drop.locate();
Tested on chrome/safari/firefox/ie9 and seems to work.
SEE DEMO
UPDATE
For overlapping events, see if following code works. I set it inside an anonymous function just to avoid any global variable.
Idea is to use currentTarget property of event to check if not the same element is triggering same event. I set an id on newdrop element just in purpose of test here.
SEE UPDATED DEMO
(function () {
var $body = $("body"),
newdrops = [],
currentTarget = {},
ondragstart = function () {
$(this).css('opacity', .75);
}, ondrag = function (ev, dd) {
$(this).css({
top: dd.offsetY,
left: dd.offsetX
});
}, ondragend = function () {
$(this).css('opacity', '');
for (var i = 0, z = newdrops.length; i < z; i++)
$(newdrops[i]).off('dropstart drop dropend').removeClass('tempdrop');
newdrops = [];
}, ondropstart = function (e) {
if (currentTarget.dropstart === e.currentTarget) return;
currentTarget.dropstart = e.currentTarget;
currentTarget.dropend = null;
console.log('start::' + e.currentTarget.id)
$(this).addClass("active");
}, ondrop = function () {
$(this).toggleClass("dropped");
}, ondropend = function (e) {
if (currentTarget.dropend === e.currentTarget) return;
currentTarget.dropend = e.currentTarget;
currentTarget.dropstart = null;
console.log('end::' + e.currentTarget.id)
$(this).removeClass("active");
};
$body.on("dragstart", ".drag", ondragstart)
.on("drag", ".drag", ondrag)
.on("dragend", ".drag", ondragend)
.on("dropstart", ".drop", ondropstart)
.on("drop", ".drop", ondrop)
.on("dropend", ".drop", ondropend);
var cnt = 0;
setInterval(function () {
var dataDroppables = $body.data('dragdata')['interactions'] ? $body.data('dragdata')['interactions'][0]['droppable'] : [];
var $newDrop = $('<div class="drop tempdrop" id="' + cnt + '">Drop</div>');
cnt++;
$("#dropWrap").append($newDrop);
var offset = $newDrop.offset();
var dropdata = {
active: [],
anyactive: 0,
elem: $newDrop[0],
index: $('.drop').length,
location: {
bottom: offset.top + $newDrop.height(),
elem: $newDrop[0],
height: $newDrop.height(),
left: offset.left,
right: offset.left + $newDrop.width,
top: offset.top,
width: $newDrop.width
},
related: 0,
winner: 0
};
$newDrop.data('dropdata', dropdata);
dataDroppables.push($newDrop[0]);
$newDrop.on("dropstart", ondropstart)
.on("drop", ondrop)
.on("dropend", ondropend);
$.event.special.drop.locate($newDrop[0], dropdata.index);
newdrops.push($newDrop[0]);
}, 1000);
})();
I wasn't able to get this working using jquery.event.drag and jquery.event.drop, but I did make it work with the native HTML5 events:
http://jsfiddle.net/R2B8V/1/
The solution was to bind the events on the drop targets within a function and call that to update the bindings. I suspect you could get this working with jquery.event.drag and jquery.event.drop using a similar principal. If I can get those working I will update my answer.
Here is the JS:
$(function() {
var bind_targets = function() {
$(".drop").on({
dragenter: function() {
$(this).addClass("active");
return true;
},
dragleave: function() {
$(this).removeClass("active");
},
drop: function() {
$(this).toggleClass("dropped");
}
});
};
$("div[draggable]").on({
dragstart: function(evt) {
evt.originalEvent.dataTransfer.setData('Text', 'data');
},
dragend: function(evt) {
$('.active.drop').removeClass('active');
}
});
setInterval(function () {
$("#dropWrap").append('<div class="drop">Drop</div>');
// Do something here to update the dd.available
bind_targets();
}, 1000)
});
You can't. On dragstart, possible drop zones are calculated from the DOM, and can't be edited until dragend. Even constantly rebinding the .on() (Demo: http://jsfiddle.net/36AJq/84/) will not provide the desired effect.
I solved the issue a little differently. (Demo: http://jsfiddle.net/36AJq/87/)
Start with every <div> in the HTML.
Apply opacity: 0 to make it invisible, and width: 0 to keep it from getting a dropend when hidden.
Use setInterval to show the next hidden div ($('.drop:not(.visible)').first()) each 1000ms.
JS:
$("body")
.on("dragstart", ".drag", function () {
$(this).css('opacity', .75);
})
.on("drag", ".drag", function (ev, dd) {
$(this).css({
top: dd.offsetY,
left: dd.offsetX
});
})
.on("dragend", ".drag", function () {
$(this).css('opacity', '');
})
.on("dropstart", ".drop", function () {
$(this).addClass("active");
})
.on("drop", ".drop", function () {
$(this).toggleClass("dropped");
})
.on("dropend", ".drop", function () {
$(this).removeClass("active");
});
setInterval(function () {
$('.drop:not(.visible)').first()
.addClass('visible').removeClass('hidden');
}, 1000)
Enable the refreshPositions option.
Why not place all the divs into the page and set their visibility to hidden? Then use setInterval() to change each one's visibility every second.