I'm trying to drag and drop items on a page, but insteads of moving the item itself, I create a copy of it.
Here is my code. "copyDragDrop" is a div at the bottom of the page. It remains empty until the user strats dragging something.
function coordSouris()
{
return {
x:event.clientX + document.body.scrollLeft - document.body.clientLeft,
y:event.clientY + document.body.scrollTop - document.body.clientTop
};
}
function drag()
{
var pos = coordSouris(event);
copie = event.srcElement.cloneNode(true);
document.getElementById('copieDragDrop').appendChild(copie);
copie.style.position = 'absolute';
copie.style.display = 'block';
document.onmousemove = mouseMove;
document.onmouseup = drop;
}
function mouseMove()
{
if (copie != null)
{
var pos = coordSouris(event);
copie.style.left = pos.x;
copie.style.top = pos.y;
}
}
function drop()
{
var divCopie = document.getElementById('copieDragDrop');
if (divCopie.hasChildNodes() )
{
while ( divCopie.childNodes.length >= 1 )
{
divCopie.removeChild(divCopie.firstChild);
}
}
}
This code creates the copy, starts to move it, but after a few pixels, the copy stops following the mouse. If I release the mouse, "onmouseup" is not fired, but the copy starts to follow the mouse again ! I've tried the code on several items, the same bug occurs
I don't understand anything, any help is more than welcome.
UPDATE : I juste realised that all elements I tried the code on had something in common : they contained or were included in an ASP.net hyperlink control. The same code works well on regular HTML elements. There must be some auto-generated javascript for links that interferes with my code.
Couldn't find the auto-generated code responsible for the issue, so I simply solvec this by replacing Hyperlink controls by standard HTML anchors.
Related
I am trying to create a simple drag and drop activity in Adobe CC.
I have got the dragging function working fine, however I can't get it to detect when the dragged button hits the target.
Any help would be greatly appreciated!
Here is my code:
function Main()
{
createjs.Touch.enable(stage);//Emable Touch Gesture Recognition
createjs.Ticker.addEventListener("tick", this.update.bind(this));
this.addTargetsToButtons();//Add Button Actions
}
var phonemes = ["s","a","t","p","i","n","m","d","g","o","c","k","ck","e","u","r","h","b","f","ff","l","ll","ss"];
var draggablePhonemes = [this.b0, this.b1, this.b2];
var targets = [this.target1];
Main.prototype.addTargetsToButtons= function(){//Add Actions To All Our Buttons
for (i = 0; i<draggablePhonemes.length; i++){
console.log(draggablePhonemes[i]);
draggablePhonemes[i].addEventListener("pressmove", draggedStart.bind(this));
draggablePhonemes[i].addEventListener("pressup",draggedStop.bind(this));
draggablePhonemes[i].name = phonemes[i];
}
}
function draggedStart(event) {
console.log(event.currentTarget.name)
var p = stage.globalToLocal(event.stageX, event.stageY);
event.currentTarget.x = p.x;
event.currentTarget.y = p.y;
//The buttons can be dragged onto target1, target2, target3
}
function draggedStop(event) {
console.log(event.currentTarget.name + " Has Stopped Moving")
if (event.currentTarget.hitTest(targets[0].x,targets[0].y)){
console.log("Collision");
}
}
You need to add ondragover data attribute to the target and set it to this function:
function allowDrop(event) {
event.preventDefault();
console.log("Look, it hits the target");
}
By default, data/elements cannot be dropped in other elements. To allow that to happen, you must prevent the default handling of the element.
Note: You might also need to add ondrop data attribute to the target set to a function, so the actual drop can happen.
ex.
function drop(event) {
event.preventDefault();
var data = event.currentTarget.name;
event.target.appendChild(document.getElementById(data));
}
And this is what the html element should look like:
<div ondrop="drop(event)" ondragover="allowDrop(event)"></div>
I am in a fix. I am not able to identify a way to capture the keyboard show/hide status on a mobile device browser.
Problem :
I have a popup on a form in which a Text Field is present. When the user taps on the text field the keyboard shows up pushing the popup on the form and eventually making the text field invisible.
Is there a way to identify the key board show/hide status???
No, there is no way to reliably know when a keyboard is showing. The one level of control you do have is you can set your app to pan or resize when the keyboard shows up. If you set it to resize, it will recalculate your layout and shrink things so if fits the remaining screen. If you choose pan, it will keep the same size and just slide up the entire app.
you can find out keyboard show/hide inside your application,Try following code inside oncreate method,and pass your parent layout to view.
final View activityRootView = rellayLoginParent;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
Rect r = new Rect();
// r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
//MyLog.w("height difference is", "" + heightDiff);
if (heightDiff > 100)
{ // if more than 100 pixels, its probably a keyboard...
if(lytAppHeader.getVisibility() == View.VISIBLE)
{
lytAppHeader.setVisibility(View.GONE);
}
}
else
{
if(lytAppHeader.getVisibility() == View.GONE)
{
lytAppHeader.setVisibility(View.VISIBLE);
}
}
}
});
It seems there is no reliable way to do this in the browser. The closest I have come is to listen for focus events and then temporarily listen for resize events. If a resize occurs in the next < 1 second, it's very likely that the keyboard is up.
Apologies for the jQuery...
onDocumentReady = function() {
var $document = $(document);
var $window = $(window);
var initialHeight = window.outerHeight;
var currentHeight = initialHeight;
// Listen to all future text inputs
// If it's a focus, listen for a resize.
$document.on("focus.keyboard", "input[type='text'],textarea", function(event) {
// If there is a resize immediately after, we assume the keyboard is in.
$window.on("resize.keyboard", function() {
$window.off("resize.keyboard");
currentHeight = window.outerHeight;
if (currentHeight < initialHeight) {
window.isKeyboardIn = true;
}
});
// Only listen for half a second.
setTimeout($window.off.bind($window, "resize.keyboard"), 500);
});
// On blur, check whether the screen has returned to normal
$document.on("blur.keyboard", "input[type="text"],textarea", function() {
if (window.isKeyboardIn) {
setTimeout(function() {
currentHeight = window.outerHeight;
if (currentHeight === initialHeight) {
window.isKeyboardIn = false;
}, 500);
}
});
};
Alright, I have a chess board with all the spots and pieces. It's generated onload with two four cycles from a 2D array. The idea is, that you should be able to drag a chess piece (something I've already implemented correctly), and let it go in a valid position. The letting go part should trigger an event in the actual board spots. So each of the 64 spots have an even listener that looks like this.
element.on("mouseup",function(e){
if(Game.current==undefined||!$(this).hasClass("valid")){return;}
var col,row;
col = $(this).attr("column");
row = $(this).attr("row");
Game.current.attr({
"column":col,
"row":row
});
Game.move(Game.current);
Game.changeTurn();
Game.current = undefined;
});
The function triggers normally when I click on a square in the board, however when I drag and drop a chess piece there, it doesn't register that the mouse is up. It let's go of the piece, however since the cursor is directly over the chess piece and said piece "blocks" the cursor from being directly above the spot. It is also worth noting that my HTML structure is like this.
<board>
<spot></spot>
<piece></piece>
</board>
By which I mean, that the pawns, bishop etc. aren't inside the spots, so the event doesn't have anything to "bubble" through.
A better approach would be attach the listener of mouseup to the window object doing something like this
$(window).on('mouseup', on_mouse_up );
and then, from the mouse position calculating the right spot.
function on_mouse_up( e ) {
// Get the mouse position
x = e.pageX;
y = e.pageY;
// Calculate the spot from the mouse position
}
(function ($) {
"use strict";
//console.log($);
$('document').ready(function () {
var target;
$('#wrapper').mousedown(function (e) {
var el = $(e.target);
if (el.hasClass('elem')) {
target = el;
}
});
$('#wrapper').mouseup(function (e) {
var el = $(e.target);
//console.log(e);
if (target) {
if (el.hasClass('kletca')) {
el.append(target);
}
}
target = undefined;
});
});
}(jQuery));
http://jsfiddle.net/32DTv/ a simple example
I found this script by theZillion (http://thezillion.wordpress.com/2012/08/29/javascript-draggable-no-jquery/) that makes a div draggable. I'm trying to use this script to move a div by class name. And not by ID.
I have an event handler that works, but not when I'm adding the script... The console shows no errors either. Any ideas about how to make this work?
This is the code I have:
function wrappmover(){
var moveEvent = "dice-window-wrapper";
var addClassArr= document.getElementsByClassName(moveEvent);
for(var i=0; i<addClassArr.length; i++){
var addClass = addClassArr[i];
addClass.addEventListener("click", movewrapp, true);
}
function movewrapp() {
var classToMove = "dice-window-wrapper";
var elems = document.getElementsByClassName(classToMove);
var tzdragg = function(){
return {
startMoving : function(evt){
evt = evt || window.event;
var posX = evt.clientX,
posY = evt.clientY,
a = document.getElementsByClassName(classToMove),
divTop = a.style.top,
divLeft = a.style.left;
divTop = divTop.replace('px','');
divLeft = divLeft.replace('px','');
var diffX = posX - divLeft,
diffY = posY - divTop;
document.onmousemove = function(evt){
evt = evt || window.event;
var posX = evt.clientX,
posY = evt.clientY,
aX = posX - diffX,
aY = posY - diffY;
tzdragg.move('elem',aX,aY);
}
},
stopMoving : function(){
document.onmousemove = function(){}
},
move : function(divid,xpos,ypos){
var a = document.getElementById(divid);
document.getElementById(divid).style.left = xpos + 'px';
document.getElementById(divid).style.top = ypos + 'px';
}
}
}();
Okay, so you want to have draggable elements on your page?
Take a look at the following code (and here's a working example). I hope you will find it self-explanatory, but just in case there are also comments:
// Wrap the module in a self-executing anonymous function
// to avoid leaking variables into global scope:
(function (document) {
// Enable ECMAScript 5 strict mode within this function:
'use strict';
// Obtain a node list of all elements that have class="draggable":
var draggable = document.getElementsByClassName('draggable'),
draggableCount = draggable.length, // cache the length
i; // iterator placeholder
// This function initializes the drag of an element where an
// event ("mousedown") has occurred:
function startDrag(evt) {
// The element's position is based on its top left corner,
// but the mouse coordinates are inside of it, so we need
// to calculate the positioning difference:
var diffX = evt.clientX - this.offsetLeft,
diffY = evt.clientY - this.offsetTop,
that = this; // "this" refers to the current element,
// let's keep it in cache for later use.
// moveAlong places the current element (referenced by "that")
// according to the current cursor position:
function moveAlong(evt) {
that.style.left = (evt.clientX - diffX) + 'px';
that.style.top = (evt.clientY - diffY) + 'px';
}
// stopDrag removes event listeners from the element,
// thus stopping the drag:
function stopDrag() {
document.removeEventListener('mousemove', moveAlong);
document.removeEventListener('mouseup', stopDrag);
}
document.addEventListener('mouseup', stopDrag);
document.addEventListener('mousemove', moveAlong);
}
// Now that all the variables and functions are created,
// we can go on and make the elements draggable by assigning
// a "startDrag" function to a "mousedown" event that occurs
// on those elements:
for (i = 0; i < draggableCount; i += 1) {
draggable[i].addEventListener('mousedown', startDrag);
}
}(document));
Load or wrap it in <script></script> tags as close as possible to </body> so that it doesn't block the browser from fetching other resources.
Actually, if you remove the comments, it's a very small function. Much smaller and more efficient than the one from the website you've provided.
A possible improvement
Consider replacing the anonymous wrapper with something like makeDraggable(selector); where selector is a CSS selector, so you could do crazy stuff like:
makeDraggable('#dragMe, #dragMeToo, .draggable, li:nth-child(2n+1)');
It can be achieved by using document.querySelectorAll that is able to perform complex CSS queries instead of a simple class name lookup by document.getElementsByClassName.
Things to watch out for
If the page has any scrolling - the drag will look broken; consider adjusting the positioning of the dragged element by scrollX and scrollY
This will obviously not work in Internet Explorer (figure it out yourself).
There might be memory leaks (needs profiling and testing).
EDIT: A solution for adding new draggable elements
So you want to be able to add more draggable elements? There are several approaches to tackle this. For example you could write a makeDraggable(element); function and call it on the element you're adding to the DOM. It will work of course, but let's have a look at something different, shall we?
Instead of querying the DOM in search of draggable elements and assigning them event listeners, why don't we assign just one for the "mousedown" event on document body.
When triggered, the event object will contain a reference to the target element which is the object the event has been dispatched on (the element you mousedown-ed). The relevant part of the code will now resemble this:
// Performs a check if the current element is draggable and if yes,
// then the dragging is initiated:
function startDragIfDraggable(evt) {
// Check if the target element (referenced by evt.target) contains a
// class named "draggable" (http://stackoverflow.com/questions/5898656/):
if (evt.target.classList.contains('draggable')) {
// Invoke startDrag by passing it the target element as "this":
startDrag.call(evt.target, evt);
}
}
// Listen for any "mousedown" event on the document.body and attempt dragging
// the target element (the one where "mousedown" occurred) if it's draggable:
document.body.addEventListener('mousedown', startDragIfDraggable);
And here's a working example of the above code. As a bonus it features a simulation of adding new draggable elements to the DOM.
In addition to being able to drag dynamically-added draggable elements, this approach will also save us some memory because we can now avoid assigning a bunch event listeners to a bunch of elements. However, if the application you're developing is very click-intensive (e.g. a game) then you might waste a little bit of CPU because of checks on every click.
I am writing a plugin that creates a select marquee box when the mouse is clicked on a canvas div. So far i've written the plugin with the click() and mousemove() events adjacent to each other in the code (i dont know of any way to embed events inside other events). But this becomes a problem when the mouse moves over the canvas before a click. Does anyone know how to initialize a mousemove handler with a click?
Here is the code i have written so far:
$.fn.createBox = function(id) {
$(id).css({
cursor:'crosshair'
});
$(id).click(function(e) {
var clickLocX = e.pageX;
var clickLocY = e.pageY;
$('<div>').attr({
'class':'newBox',
'ctr':'on'
})
.css({
top:clickLocY,
left:clickLocX
})
.appendTo(id);
});
//Mousemove must be initialized only AFTER the click. HOW TO DO THIS?
$(id).mousemove(function(e){
var XpageCoord = e.pageX;
var YpageCoord = e.pageY;
window.Xloc = XpageCoord;
window.Yloc = YpageCoord;
var boxOffset = $('.newBox').offset();
var boxHeight = YpageCoord - boxOffset.top;
var boxWidth = XpageCoord - boxOffset.left;
$('.newBox').css({
height:boxHeight + 'px',
width:boxWidth + 'px'
});
});
}
Just set the mousemove handler from within the click handler and use a flag to determine whether or not it has already been set to avoid adding it multiple times.
EDIT: An example
assignedMoveHandler = false;
$(id).click(function(e) {
// other stuff...
if(!assignedMoveHandler) {
$(id).mousemove(function(e) {
// mouse move handling code...
});
assignedMoveHandler = true;
}
}
I use a global here which you may or may not care about, I lookup the jquery object twice, etc., so it could be cleaned up a bit, but this is the general idea. When the click handler fires you check to see if you've assigned a mousemove handler yet. If not, assign it.