Hello
I'm currently working on a project that is very similar to the following codepen that I found a long while ago. It's essential a Tinder-like application;
https://codepen.io/suez/pen/MaeVBy
Within the codepen is the following JavaScript/jQuery:
function pullChange() {
animating = true;
deg = pullDeltaX / 10;
$card.css("transform", "translateX("+ pullDeltaX +"px) rotate("+ deg +"deg)");
var opacity = pullDeltaX / 100;
var rejectOpacity = (opacity >= 0) ? 0 : Math.abs(opacity);
var likeOpacity = (opacity <= 0) ? 0 : opacity;
$cardReject.css("opacity", rejectOpacity);
$cardLike.css("opacity", likeOpacity);
};
$(document).on("mousedown touchstart", ".demo__card:not(.inactive)", function(e) {
if (animating) return;
$card = $(this);
$cardReject = $(".demo__card__choice.m--reject", $card);
$cardLike = $(".demo__card__choice.m--like", $card);
var startX = e.pageX || e.originalEvent.touches[0].pageX;
$(document).on("mousemove touchmove", function(e) {
var x = e.pageX || e.originalEvent.touches[0].pageX;
pullDeltaX = (x - startX);
if (!pullDeltaX) return;
pullChange();
});
$(document).on("mouseup touchend", function() {
$(document).off("mousemove touchmove mouseup touchend");
if (!pullDeltaX) return; // prevents from rapid click events
release();
});
});
What I'm looking to achieve is the implementation of two buttons to "simulate" the mouse dragging. So - if you play with the codepen - you'll see that it's possible to drag the cards left and right. A "like" or "dislike" decision is then made based upon how far left or right it was dragged. Also, if you drag a card too far or too little in one direction, the card will snap to a set point upon release.
I want to give the users an option to click a "Like" or 'Dislike" button instead of dragging. Hitting one of these buttons will then perform the same actions as if the card had been dragged.
Is this simple to do? Can anybody give me any guidance? I've spent a bit of time with this, and can't seem to get it to work, so any help would be greatly appreciated!
Let me know if you need more data or information.
Thanks!
Your question left out the important parts of the code; the pullChange() and release() functions. Since those are the functions that actually control the card moving, you should be able to bind them to a button click with a slight caveat. pullChange() utilizes the DeltaX variable and expects it to be there to tell it how far to move, so you'll need to set this by hand since there won't be a drag event telling it how far.
Related
I am using raphael.js to manipulate images inside a "paper". I have realized that all mouse events (click, mousedown, mouseup, dragstart...) are triggered by any mouse button.
In this JSFiddle there is an example to drag two objects, it is possible to drag them around with left, right or middle mouse buttons
JSFiddle
How can I filter the events depending on which button was clicked? For instance, I would like to drag only with the left mouse button
I have read in another StackOverflow post that it is possible to identify the mouse button with e.which, it will return 1, 2, or 3 depending on the pressed button but I cannot find a way to use this variable to filter the event triggers.
I have found a Bug report about this issue but it is open since 2012. I have tried to use part of the code to filter the mouse button with if(e.which == 1) and then I made a console entry. In this way the console entry only appears when I attempt to make a drag with the left button, it won't appear with the other buttons. I have not found a way to implement the rest of the code
Does anybody know what is g.doc.documentElement or g.doc.body (From the bug report code)?
Thank you in advance for your support
Have a good day
I have found a way to do it, instead of installing raphael using npm install raphael I have downloaded the js file from github and then edited the drag function in the following way:
elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
function start(e) {
if (e.which == 1) {
(e.originalEvent || e).preventDefault();
var x = e.clientX,
y = e.clientY,
scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
this._drag.id = e.identifier;
if (supportsTouch && e.touches) {
var i = e.touches.length, touch;
while (i--) {
touch = e.touches[i];
this._drag.id = touch.identifier;
if (touch.identifier == this._drag.id) {
x = touch.clientX;
y = touch.clientY;
break;
}
}
}
this._drag.x = x + scrollX;
this._drag.y = y + scrollY;
!drag.length && R.mousemove(dragMove).mouseup(dragUp);
drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
onstart && eve.on("raphael.drag.start." + this.id, onstart);
onmove && eve.on("raphael.drag.move." + this.id, onmove);
onend && eve.on("raphael.drag.end." + this.id, onend);
eve("raphael.drag.start." + this.id, start_scope || move_scope || this, this._drag.x, this._drag.y, e);
}
}
this._drag = {};
draggable.push({el: this, start: start});
this.mousedown(start);
return this;
};
This works fine, I have to do the same for each mouse event but I think the information would be helpful for someone else.
i am trying to convert two "click" functions, into hammer.js "tap" functions instead. the idea is that tapping the bottom-half of the div does one thing--it should navigate to the next div; and tapping the top-half does another--it should navigate to the previous div.
here is the function working perfectly without hammer.js:
$(document).ready(function() {
$('.panel').click(function(e) {
// top
if ($(this).outerHeight() / 2 > e.pageY - $(this).offset().top) {
/* do something (go to PREV div) */
}
// bottom
if ($(this).outerHeight() / 2 < e.pageY - $(this).offset().top) {
/* do something (go to NEXT div) */
}
});
});
and here is a first attempt at the hammer.js tap conversion:
window.addEventListener('load', function() {
var element = document.getElementById('container');
var hammertime = Hammer(element).on('tap', function(event) {
alert('Tap!');
})
}, false);
you can see, i have yet to split the hammer.js tap into the two separate functions. i have tried many different variations of using the same calculation as is in the top code to split the two activities, but it is either totally unresponsive, or hammer.js activates both activities concurrently.
i am a brand newbie at hammer.js (and javascript in general) and cannot figure out if i am erroneously mixing jquery with javascript, or am just having difficulty with hammer.js.
i should mention, however, that i have successfully created panleft, and panright, activities for the same site. and the reason i need to convert the "click" function to a "tap" function instead, is so that all gestures are handled by hammer.js, and not mixed--as the mixed gestures are making the site navigation too sensitive.
any assistance would be greatly appreciated.
UPDATE: per some of the help below, here is an attempt to incorporate the calculation into the tap function:
window.addEventListener('load', function() {
var element = document.getElementById('container');
var hammertime = Hammer(element).on('tap', function(e) {
if ($('.panel').outerHeight() / 2 > e.gesture.center.Y - $('.panel').offset().top) {
alert('Top tap!');
}
if ($('.panel').outerHeight() / 2 < e.gesture.center.Y - $('.panel').offset().top) {
alert('Bottom tap!');
}
})
}, false);
even using e.gesture.center.Y as a replacement for e.pageY--but to no avail. i still cannot get this work...
i've gotten this to work now:
var element = document.getElementById('panel');
$(element).hammer().on('tap', function(e) {
if ($('#panel').outerHeight() / 2 > e.gesture.center.pageY - $('#panel').offset().top) {
alert('Top tap!');
}
if ($('#panel').outerHeight() / 2 < e.gesture.center.pageY - $('#panel').offset().top) {
alert('Bottom tap!');
}
});
but only in hammer.js v1.0.5. i have opened a new question on what needs to change to make it work in v2.x.
without jquery
basically what I am looking for is the ability to see if the mouse is over a div when a countdown finishes
if the user is over the div then perform action for that div
onmouseover only triggers when the mouse crosses the threshold of the div, if the mouse hasn't moved it wouldn't trigger, so that wouldn't work
I need to determine if the mouse is currently over a div at a specific point in time, if it has moved or not from the starting point
all of my hunting has only found onmousover, and nothing to see if the mouse just happens to be there to begin with
I don't have the javascript skills to determine overall coords of div, then map mouse coords and see if it fits there... which is what I believe I need to do
After reading the second answer (the one with millions of a elements) on this SO question, I've came up with this method works without moving the mouse on page load, without involving millions of elements.
HTML
<div id=t></div>
CSS
#t {
/* for illustrative purposes */
width: 10em;
height: 5em;
background-color: #0af;
}
#t:hover {
border-top-style: hidden;
}
JavaScript
document.addEventListener('click', function () {
var c = window.getComputedStyle(document.getElementById('t')).getPropertyValue('border-top-style');
if (c === 'hidden') {
alert('Mouse in box');
} else {
alert('Mouse not in box');
}
}, false);
As stated earlier, bind to the finish event of your countdown instead of the click event on the document.
You may also use any CSS style that's changed on :hover, I chose border-top-style as it is conspicuous. If you're using a border, choose something else.
Here's a jsFiddle.
set a flag to true onmouseover and to false onmouseleave. when countdown finishes if flag is true then it is over element.
HTML
<div id="div-name">the section of the code i am working with has a countdown timer, when it reaches 0 i need to know if the mouse is over a specific box</div>
<button id="notification" onclick="javascript: letsCountIt(5);">click to start countdown</button>
JS
window.ev = false;
document.getElementById('div-name').onmouseover = function () {
window.ev = true;
console.log(window.ev);
}
document.getElementById('div-name').onmouseout = function () {
window.ev = false;
console.log(window.ev);
}
window.letsCountIt = function (cdtimer) {
cdtimer--;
document.getElementById('notification').innerHTML = cdtimer;
if (cdtimer == 0) {
if (window.ev === true) {
alert('over');
} else {
alert('not over');
}
} else {
setTimeout(function(){letsCountIt(cdtimer);}, 1000);
}
}
Look into document.elementFromPoint . When you pass an x,y to elementFromPoint, it will return whatever element (or <body>, if no other specific element) is at that point. You can easily check if this element is the element you want.
The problem then is finding out what point your mouse is at. How to get the mouse position without events (without moving the mouse)? seems to say - don't. At least use mouseMove to track the cursor. The linked question gives examples of how to do so. (Look to the lower scoring answers, as the higher ones only got points for being snarky.)
Just want to say that, I think jQuery's mouseenter and mouseleave events would make this a lot easier, but if you can't use them, maybe this will help you.
Depending on how your page is laid out, this may not be too difficult. You can get the position of your element using the following. Quoting from another answer
element.offsetLeft and element.offsetTop are the pure javascript
properties for finding an element's position with respect to its
offsetParent; being the nearest parent element with a position of
relative or absolute
So, if your element is positioned relatively to the body, so far so good (We don't need to adjust anything).
Now, if we attach an event to the document mousemove event, we can get the current coordinates of the mouse:
document.addEventListener('mousemove', function (e) {
var x = e.clientX;
var y = e.clientY;
}, false);
Now we just need to determine if the mouse falls within the element. To do that we need the height and width of the element. Quoting from another answer
You should use the .offsetWidth and .offsetHeight properties. Note
they belong to the element, not .style.
For example:
var element = document.getElementById('element');
var height = element.offsetHeight;
var width = element.offsetWidth;
Now we have all the information we need, and just need to determine if the mouse falls within the element. We might use something like this:
var onmove = function(e) {
var minX = element.offsetLeft;
var maxX = minX + element.offsetWidth;
var minY = element.offsetTop;
var maxY = minY + element.offsetHeight;
if(e.clientX >= minX && e.clientX <= maxX)
//good horizontally
if(e.clientY >= minY && e.clientY <= maxY)
//good vertically
}
This code works, but the mouse has to be moved once after page load.
var coords;
var getMouseCoordinates = function (e) {
'use strict';
return {
x: e.clientX,
y: e.clientY
};
};
document.addEventListener('mousemove', function (e) {
coords = getMouseCoordinates(e);
}, false);
document.addEventListener('click', function () {
var divCoords = document.getElementById('t').getBoundingClientRect();
if (coords.x >= divCoords.left && coords.x <= divCoords.right && coords.y >= divCoords.top && coords.y <= divCoords.bottom) {
alert('Mouse in box');
} else {
alert('Mouse not in box');
}
}, false);
You wouldn't bind to the click event of document, but rather the finish event of your countdown.
Here's an example. Try clicking in the output window.
You don't need any coordinates or mouse events, if you know a selector for that element:
if (document.querySelector('#elementSelector:hover')) {
alert('I like it when you touch me!');
}
I know I can use mousedown selection for it, but I am wanting the clicked on sprite to follow my mouse, there is a mousetracker function of sorts mentioned in the api; but unfortunately there are no examples of this other than stating that it allows mouse detection.
//add mousedown events for yarnballs.
$(".gQ_sprite").mousedown(function() {
clickedDivId = $(this).attr('id');
if(clickedDivId.charAt(8) == "-")
{
currentClickedDivId = clickedDivId
$(document).mousemove(function(e){
spriteXPosition = e.pageX
spriteYPosition = e.pageY
});
}
});
I have the location of the mouse selected, just not sure how to get the selected sprite to follow it.
any help would be greatly appreciated.
What Mati said is correct: $.gQ.mouseTracker allows you to access the mouse's state outside of an event handler. The example he gives is correct but it can't be used to move a gQ object (sprite, tile-map or group) around because you'r not allowed to use the .css() function for those. Doing so will break collision detection.
If what you want is to move a gQ object you should do this instead :
$('#' + currentClickedDivId).xy($.gQ.mouseTracker.x, $.gQ.mouseTracker.y);
But since this should be done in a periodical callback, the smoothness of the dragging will depend on the refresh rate.
If you want to use event handlers instead you could modify you code to look like this (without using the mouseTracker):
var clickedDiv;
var clickedDivOffset = {x:0, y:0};
$(".gQ_sprite").mousedown(function(e) {
clickedDiv = $(this);
clickedDivOffset = {
x: e.pageX - clickedDiv.x() - $().playground().offset().left,
y: e.pageY - clickedDiv.y() - $().playground().offset().top
};
});
$(".gQ_sprite").mouseup(function() {
clickedDiv = false;
});
$().playground().mousemove(function(e) {
if(clickedDiv){
clickedDiv.xy(
e.pageX - clickedDivOffset.x,
e.pageY - clickedDivOffset.y,
);
}
});
This will implement a drag-n-drop effect. If you want the clicked element to stick to the mouse you will have to slightly adapt the code but the basics will remain the same.
According to the documentation:
If the mouse tracker is enabled you can check the state of the mouse at anytime by looking into the object $.gQ.mouseTracker where x and y contain the position of the mouse and 1, 2 and 3 a boolean value where true means that the first, second or thrid button is pressed.
Observe the output of:
$("#playground").playground({ refreshRate: 60, mouseTracker: true });
$.playground().startGame();
$.playground().registerCallback(function(){
console.log( $.gQ.mouseTracker );
}, 1000);
To make those divs actually follow the cursor, you have to use .css()
$('#' + currentClickedDivId).css({
top: $.gQ.mouseTracker.y + 'px',
left: $.gQ.mouseTracker.x + 'px'
});
If I have a div that is a 5x5 square or something. I want to be able to click on it, then while holding down the mouse, move it in a direction, and upon release of the mouse, have the div fly towards the direction i "flicked". How can I accomplish this with jquery or javascript? Not sure if an algorithm or logic is behind this.
From a conceptual perspective (I'll be beaten with actual code no doubt shortly) I would register the mouse coordinates on MouseDown, and compare them against the mouse coordinates on MouseUp to determine the angle at which to move the div (this would allow the DIV to continue moving in the correct direction, even when the MouseUp was close to the DIV).
The easier way would be to just move the square towards the MouseUp coordinates (i.e. mouse down coordinates don't really matter in a small DIV), but this doesn't work as well if the MouseUp is very close to the MouseDown.
Either way, use something like this answer (How to make a div or object gradually move to point of mouseclick with javascript?), except on MouseUp/MouseRelease instead of click, ideally towards a projected point (along the line between MouseDown and MouseUp at a specified distance).
Edit
I've included a Prototype example below (it's very rushed and could use plenty of optimisations + clearer concept on the differences between Page/Graph y-axis, as well as some better handling of steep slopes, as well as calculating distance to fling based on distance between mousedown/mouseup as fauxtrot mentions in comments, as well as perhaps disabling fling after the first fling as you can keep "flinging it around" at the moment, as well as "out of bounds" checks and perhaps reverse bouncing off the edges).
Running Example: http://jsfiddle.net/9B9sA/
HTML
<div id="bluebox"
style="width:100px;
height:100px;
background-color:blue;
position:absolute;
left:300px;
top:300px;"> </div>
jQuery (including jQuery UI for animate)
var startDownX, startDownY;
$(document).ready(function() {
/* Stop default Firefox etc. drag */
$(document).bind("dragstart", function() {
return false;
});
/* Capture start of flings */
$('#bluebox').mousedown(function (event) {
startDownX = event.pageX;
startDownY = event.pageY;
});
/* Work out fling direction on end of fling */
$(document).mouseup(function(event){
/* Page y-axis is different from graph */
var rise = -(event.pageY - startDownY);
var run = event.pageX - startDownX;
var newX = $('#bluebox').position().left;
var newY = $('#bluebox').position().top;
var distanceToFling = 100;
if (run == 0 || Math.abs(rise/run) > 3) {
if (rise > 0) {
newY -= distanceToFling;
} else if (rise < 0) {
newY += distanceToFling;
}
}
else {
if (run > 0) {
newX += distanceToFling;
newY -= (rise/run) * distanceToFling;
}
else {
newX -= distanceToFling;
newY += (rise/run) * distanceToFling;
}
}
$('#bluebox').animate({
left: newX,
top: newY
}, 1000);
}); });
Jquery is your friend, here is a good plugin, check it out