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
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>
My title isn't probably really clear so I'll add some explanations. I've created a map using RaphaelJS. I got different regions and I've managed to add different animations/attributes when hovering them.
The main issue I'm facing right now is that when hovering one I'd like that all the other shapes that are not hovered disappear. I could do it easily for many HTML elements by adding a class "hovered" when the event is triggered but this doesnt work with Raphael, or at least I don't know how to apply a class to a shape.
Here is a bit of my code :
var regions = {}; // I'm putting all my shapes in there. for example region.myRegion = paper.path();
for (var state in region) {
region[state].color = "#c6d2ec";
(function (st, state) {
st[0].style.cursor = "pointer";
st[0].onmouseover = function () {
st.animate({fill: st.color}, 100);
st.animate({transform: "s1.3"}, 100);
paper.safari();
};
st[0].onmouseout = function () {
st.animate({fill: "#e5e5e5"}, 300);
st.animate({transform: "s1"}, 100);
paper.safari();
};
})(region[state], state);
}
Can anybody give me a hint of how I could achieve this? Thanks.
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.
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.