I have a canvas where i click and drag the images but they keep "snapping" back to their starting point which is really annoying. I don't know why i can't work out the mistake i've made in my logic.
My mousemove event has:
function updt(evt) {
var difx = evt.pageX - clickx;
var dify = evt.pageY - clicky;
offsets.cur_offsetx = init_offsetx - difx;
offsets.cur_offsety = init_offsety - dify;
if (offsets.cur_offsetx < 0) {
offsets.cur_offsetx = 0;
clickx = evt.pageX;
}
if(offsets.cur_offsety < 0){
offsets.cur_offsety = 0;
clicky = evt.pageY;
}
}
I made a jsfiddle to re-create the problem: http://jsfiddle.net/jQkNv/1/
Click and drag your mouse to the right and it will keep snapping the images back to their original start point.
How do i fix this?
Live Demo
Changing it to the following worked for me.
if (offsets.cur_offsetx <= 0) {
offsets.cur_offsetx = 0;
}
if(offsets.cur_offsety <= 0){
offsets.cur_offsety = 0;
}
edit I stopped updating x and y and it seems to work.
Related
I have made a fiddle here and I am using Chrome.
I want to drag the red dashed/dotted line on the left to the right. A new flex column is added on mouseup OR when you exceed a part of the container, depending on the number of columns already added. For now I just try to add max 5 columns.
The first "drag" works as expected
mouse down
while holding mousedown drag to right
column is added on mouseup or when exceeding some width
Now I want to repeat these steps and add another one. But now the behaviour is different:
mouse down
drag it to the right but it gets stuck
I have to release the mouse button and move to the right and get out of the function
Here is some code, I've tried some stuff with bubble true or false on the eventlisteners but no luck. Should I use other events?
var container = document.querySelector('.js-flex-container'),
containerRow = container.querySelector('.js-flex-row'),
oldX = 0,
oldY = 0,
rect = container.getBoundingClientRect(),
mouseupEvent = new MouseEvent('mouseup'),
newDiv,
colCount,
captureMouseMove = function captureMouseMove(event){
var directionX = 0,
directionY = 0;
if ((event.clientX - rect.left) > oldX) {
// "right"
newDiv.style.width = oldX + 'px';
if (oldX >= Math.round(rect.right / colCount)) {
container.dispatchEvent(mouseupEvent);
}
}
oldX = (event.clientX - rect.left);
};
container.querySelector('.js-flex-column').addEventListener('mousedown', function(event){
var colWidth = event.clientX - rect.left,
columns = container.querySelectorAll('.col');
colCount = columns.length + 1;
newDiv = document.createElement('div');
newDiv.className = 'col-x';
columns[0].parentNode.insertBefore(newDiv, columns[0]);
container.addEventListener('mousemove', captureMouseMove);
});
container.addEventListener('mouseup', function(){
console.log('mouseup');
if (typeof newDiv !== 'undefined') {
newDiv.style.width = '';
newDiv.className = 'col col-' + colCount;
container.removeEventListener('mousemove', captureMouseMove);
}
});
Chrome is doing something (funky) with the event after move.
Adding event.preventDefault() should do the trick
captureMouseMove = function captureMouseMove(event){
var directionX = 0,
directionY = 0;
if ((event.clientX - rect.left) > oldX) {
// "right"
newDiv.style.width = oldX + 'px';
if (oldX >= Math.round(rect.right / colCount)) {
container.dispatchEvent(mouseupEvent);
}
}
oldX = (event.clientX - rect.left);
event.preventDefault(); // <---
};
I would also recommend that you don't use container for mouseup events. Instead use window so releasing outside of the container doesn't cause issues. You could do the same for mousemove.
What I want to achieve is a javascript animation with variable speed based on cursor position.
For that porpouse I'm using jquery's animate function and mousever event and javascript's setInterval function, but those aren't required, so if there is a better way to achieve it I would be more than happy to hear it (the only requeriment would be javascript).
The problem I'm facing is that I can't change speed dinamicly, for some reason the speed keeps adding to the one it already had instead of set what I wanted and even if it would change as spected it just doesn't happen in a smoothly way because of an unknown reason for me.
Here is the javascript that I have so far:
//settings for container_slider. Are used in startSlider() which handles the animation
var steps_animation_speed = 1000;
var steps_interval = 1500;
var steps_speed_factor = 1; // 100%
var amount_sliders = 3;
//cache DOM elements
var $container_slider = $('#container_slider');
var $shown_slides = $('.shown_slides', $container_slider);
var $slide = $(".slide");
// Just making sure sizing (widths) fits as they should.
var slides_width = $container_slider.width()/amount_sliders;
var slides_margin = parseInt($slide.css('marginLeft').replace('px', '')) + parseInt($slide.css('marginRight').replace('px', ''));
var steps_width = slides_width + slides_margin;
$shown_slides.css('width', steps_width*(amount_sliders+1) + 'px');
$slide.css('width', slides_width);
var interval;
// This function is responsible of the animation
function startSlider() {
$shown_slides.stop(false);
interval = setInterval(function() {
$shown_slides.animate({'margin-left': '-='+steps_width}, steps_animation_speed*steps_speed_factor, function() {
$('.shown_slides > li:last').after($('.shown_slides > li:first'));
$('.shown_slides').css('margin-left', '0');
});
}, steps_interval);
}
function pauseSlider() {
clearInterval(interval);
}
$container_slider.mouseleave(function(){
steps_interval = 3000;
$shown_slides.stop(true);
pauseSlider();
startSlider();
});
// $container_slider.mouseenter(function(){
// pauseSlider();
// });
$container_slider.mousemove(function(event){
pauseSlider();
var cursor_location = '';
if(event.pageX > 0 && event.pageX < 165){
cursor_location = "Cursor is on the left side";
// This is where i'm doing the tests that should work of changing animation's speed based on cursor position
if(steps_speed_factor !== (event.pageX / 165)){
steps_speed_factor = event.pageX / 165;
steps_speed_factor = (steps_speed_factor < 0.15 ? 0.15 : steps_speed_factor);
steps_interval = 0;
startSlider();
}
} else if(event.pageX > 165 && event.pageX < ($container_slider.width()-165)){
cursor_location = "Cursor is in the center (paused)";
// This stops animation, it could be achieved way better but i'm focusing on above's block of code.
steps_speed_factor = 1;
steps_interval = 3000;
$shown_slides.stop(true);
pauseSlider();
} else if(event.pageX > ($container_slider.width()-165) && event.pageX < $container_slider.width()) {
cursor_location = "Cursor is on the right side";
// This would be an exact copy (almost) of the left side, but since it doesn't work yet, this is pretty much a "blank" block of code
steps_interval = 0;
steps_speed_factor = ( event.pageX - ($container_slider.width() - 165) ) / 165;
}
$(".coordinates").html("X: " + event.pageX + " Y: " + event.pageY );
$(".cursor_location").html(cursor_location);
$(".speed_factor").html("Speed Factor is: "+steps_speed_factor);
});
startSlider();
Here is a codepen showing this javascript code "working".
--- EDIT
I forgot to explain propperly what happens in the codepen , since it is just an example didnt give it to much importance. Mainly what should happen is that the furthier the cursor is from the center, the tinier/faster the invervals of the animation should be without losing fluidness.
In this case i'm using a "speed factor" which I calculate by taking cursor's X position and then comparing it with a predefined area, converting it in a percentage (decimal) from 15% to 99%. But it isn't actually the important part. I'm clueless about how to achieve this and the more I try the messier my code gets, so as long as you can give me an example of changing animation's speed (in "real" time, i mean, smoothly/fluid) based on cursor's position as an example it would be perfect.
Hi Friends i am very very new to javascript and and J Query . now i want to create virtual mouse pad . i am created two div's one for mouse pad and second one is container in container i am taken another div for act as a cursor(class name is follower) .
in mouse pad div when ever mouse move follower div moving relative to the mouse position. now i want to generate click event using virtual cursor means click the buttons using follower.
Button1
Button2
MousePad
this is my js code
var mouseX = 0, mouseY = 0, limitX = 150-15, limitY = 150-15;
$('.container1').mousemove(function(e){
var offset = $('.container1').offset();
mouseX = Math.min(e.pageX - offset.left, limitX);
mouseY = Math.min(e.pageY - offset.top, limitY);
mouseX=mouseX*3;
mouseY=mouseY*3;
if (mouseX < 0) mouseX = 0;
if (mouseY < 0) mouseY = 0;
});
// cache the selector
var follower = $("#follower");
var xp = 0, yp = 0;
var loop = setInterval(function(){
// change 12 to alter damping higher is slower
xp += (mouseX - xp);
yp += (mouseY - yp) ;
follower.css({left:xp, top:yp});
}, 30);
$('.buttons span').bind('click',function(){
alert($(this).attr('title'));
});
JSbin Link
http://jsbin.com/AGAquhej/2/edit for code
http://jsbin.com/AGAquhej/1 Demo
i want generate click event using follower(moving in mouse pad)
can any one solve the problem how to generate fake click events
Thanks in advance
Using the some collision detection code from this SO answer https://stackoverflow.com/a/12180865/1481489 the following may work (untested, description is in the comments):
var overlaps = (function () { // this is the collision detection code
function getPositions( elem ) {
var pos, width, height;
pos = $( elem ).position();
width = $( elem ).width();
height = $( elem ).height();
return [ [ pos.left, pos.left + width ], [ pos.top, pos.top + height ] ];
}
function comparePositions( p1, p2 ) {
var r1, r2;
r1 = p1[0] < p2[0] ? p1 : p2;
r2 = p1[0] < p2[0] ? p2 : p1;
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function ( a, b ) {
var pos1 = getPositions( a ),
pos2 = getPositions( b );
return comparePositions( pos1[0], pos2[0] ) && comparePositions( pos1[1], pos2[1] );
};
})();
$('.container1').mousemove(function(e){
var offset = $('.container1').offset();
mouseX = Math.min(e.pageX - offset.left, limitX);
mouseY = Math.min(e.pageY - offset.top, limitY);
mouseX=mouseX*3;
mouseY=mouseY*3;
if (mouseX < 0) mouseX = 0;
if (mouseY < 0) mouseY = 0;
});
$('.container1').click(function(){
proxyTriggerEvent('click');
});
function proxyTriggerEvent(eventName) {
$('.container').find('a,input,.buttons span')
.each(function() { // and loop through them all for testing
if ( overlaps(follower,this) ) { // collision detection for each item
$(this).trigger(eventName); // click the specific element
return false; // break out of the loop
}
});
}
Update:
Fixed a bug where the selector was not targeting the buttons. I misread the tag as <span class="button1"> but it is really <span title="button1">. The selector is now .buttons span instead of .button1,.button2.
Removed the unnecessary filtering of follower with .not('#follower')
Moved the hit detection to the click handler of .container - this way it isn't being run on every single interval frame, only when it really counts.
Moved the event trigger proxy out of the click call, now any event can be triggered, and it can be called as a regular function, e.g.: proxyTriggerEvent('mouseup'); or proxyTriggerEvent('click');
I have seen this question but it wasn't answered.
I have a object on a webpage that I want you to be able to drag and scroll the page. Reason behind this is that I set it up to be a swipe'able window but on some mobile devices the window takes up most of the screen. So in addition to horizontal "swiping" I want you to be able to vertically scroll the page as well.
This works great on a PC with a mouse. Everything is smooth and as expected. However, once you go to a mobile device (I have tried on Safari on an iPhone and the native browser on an Android 4 and both have the same issue) vertical scrolling is very "jittery".
At first I thought that it had to do with the fact that after you scroll the page, the next touchmove / MSPointerMove event will return a Ycord that different even though your finger might not have moved (due to the scrolling). But trying to accomidate for this didn't help.
Anyway, a demo of the whole thing can be found at http://www.leecolpi.com/NEW/m/
The full javascript can be found at http://www.leecolpi.com/NEW/m/JAVASCRIPT/slide_window.js
The relivant javascript is (might be easier to read via the link above):
function mouseMoveTrigger(evt)
{
if (!isDragging) return;
if (!touchEvents && !pointerEvents)
if (window.event) evt=window.event;
if (evt.preventDefault)
evt.preventDefault();
else
evt.returnValue = false;
var newX;
var newY;
if (touchEvents)
{
newX = offsetX - evt.changedTouches[0].pageX;
offsetX = evt.changedTouches[0].pageX;
newY = offsetY - evt.changedTouches[0].pageY;
offsetY = evt.changedTouches[0].pageY;
}
else
{
newX = offsetX - evt.clientX;
offsetX = evt.clientX;
newY = offsetY - evt.clientY;
offsetY = evt.clientY;
}
var thingsToSlide = document.getElementById("pictureFrame").getElementsByTagName("li");
newX = parseInt(thingsToSlide[0].style.right.replace(/px/g,'')) + newX;
if (newX < 0)
newX = 0;
if (newX > ((thingsToSlide[0].offsetWidth * (thingsToSlide.length - 1))) + 30)
newX = (thingsToSlide[0].offsetWidth * (thingsToSlide.length - 1)) + 30;
window.scrollBy(0, newY);
for (var i=0; i<thingsToSlide.length; i++)
thingsToSlide[i].style.right = newX + "px";
return false;
}
As you can see, all I am doing is a scrollBy of the difference of the Yvalue for the current and previous "move" events. Again, this works like a champ on a computer which is exactly where I don't care if it works or not. Only problem is every mobile device I have tried it on.
I am using preventDefault() (or setting the return value = false if I can't do that), but could I be triggering another event and not knowing it? I tried with my init to only listen for certian events. Here is my init function (might be easier to read via the link above):
function initSlider()
{
var pageBody = document.getElementsByTagName("body")[0];
var thingsToSlide = document.getElementById("pictureFrame");
if (thingsToSlide)
{
var thingsToSlideList = document.getElementById("pictureFrame").getElementsByTagName("li");
for (var i=0; i<thingsToSlideList.length; i++)
thingsToSlideList[i].style.right = "0px";
if (touchEvents)
{
thingsToSlide.addEventListener("touchstart", onTouchStart, false);
}
else if (pointerEvents)
{
thingsToSlide.addEventListener("MSPointerDown", onTouchStart, false);
}
else
{
thingsToSlide.ondrag=function() { return false; };
thingsToSlide.onselectstart=function() { return false; };
thingsToSlide.onmousedown=function(event) { mouseDownTrigger(this,event); };
}
if (touchEvents)
{
pageBody.addEventListener("touchmove", mouseMoveTrigger, false);
pageBody.addEventListener("touchend", mouseUpTrigger, false);
pageBody.addEventListener("touchcancle", mouseUpTrigger, false);
}
else if (pointerEvents)
{
pageBody.addEventListener("MSPointerMove", mouseMoveTrigger, false);
pageBody.addEventListener("MSPointerUp", mouseUpTrigger, false);
pageBody.addEventListener("MSPointerCancel", mouseUpTrigger, false);
}
else
{
document.onmousemove = mouseMoveTrigger;
document.onmouseup = mouseUpTrigger;
}
}
}
Any help would be greatly appreciated. Thanks in advance
I have an application made in AngularJS which has arrow key navigation to switch views.
I want to implement this navigation using swipe for touch devices. I tried jGestures library but it doesn't go well with swipe.
I have been recommended NOT to use jquery mobile.
Is there any other way to implement swipe?
EDIT:
It does not detect swipe cleanly. I tested it on multiple devices, including iPad and it takes multiple swipes to do an action(routing in my case).
I made this function for my needs.
Feel free to use it. Works great on mobile devices.
function detectswipe(el,func) {
swipe_det = new Object();
swipe_det.sX = 0; swipe_det.sY = 0; swipe_det.eX = 0; swipe_det.eY = 0;
var min_x = 30; //min x swipe for horizontal swipe
var max_x = 30; //max x difference for vertical swipe
var min_y = 50; //min y swipe for vertical swipe
var max_y = 60; //max y difference for horizontal swipe
var direc = "";
ele = document.getElementById(el);
ele.addEventListener('touchstart',function(e){
var t = e.touches[0];
swipe_det.sX = t.screenX;
swipe_det.sY = t.screenY;
},false);
ele.addEventListener('touchmove',function(e){
e.preventDefault();
var t = e.touches[0];
swipe_det.eX = t.screenX;
swipe_det.eY = t.screenY;
},false);
ele.addEventListener('touchend',function(e){
//horizontal detection
if ((((swipe_det.eX - min_x > swipe_det.sX) || (swipe_det.eX + min_x < swipe_det.sX)) && ((swipe_det.eY < swipe_det.sY + max_y) && (swipe_det.sY > swipe_det.eY - max_y) && (swipe_det.eX > 0)))) {
if(swipe_det.eX > swipe_det.sX) direc = "r";
else direc = "l";
}
//vertical detection
else if ((((swipe_det.eY - min_y > swipe_det.sY) || (swipe_det.eY + min_y < swipe_det.sY)) && ((swipe_det.eX < swipe_det.sX + max_x) && (swipe_det.sX > swipe_det.eX - max_x) && (swipe_det.eY > 0)))) {
if(swipe_det.eY > swipe_det.sY) direc = "d";
else direc = "u";
}
if (direc != "") {
if(typeof func == 'function') func(el,direc);
}
direc = "";
swipe_det.sX = 0; swipe_det.sY = 0; swipe_det.eX = 0; swipe_det.eY = 0;
},false);
}
function myfunction(el,d) {
alert("you swiped on element with id '"+el+"' to "+d+" direction");
}
To use the function just use it like
detectswipe('an_element_id',myfunction);
detectswipe('an_other_element_id',my_other_function);
If a swipe is detected the function "myfunction" is called with parameter element-id and "l,r,u,d" (left,right,up,down).
Example: http://jsfiddle.net/rvuayqeo/1/
I (UlysseBN) made a new version of this script based on this one which use more modern JavaScript, it looks like it behaves better on some cases. If you think it should rather be an edit of this answer let me know, if you are the original author and you end up editing, I'll delete my answer.
Have you tried Hammerjs? It supports swipe gestures by using the velocity of the touch.
http://eightmedia.github.com/hammer.js/
There is also an AngularJS module called angular-gestures which is based on hammer.js:
https://github.com/wzr1337/angular-gestures
Shameless plug I know, but you might want to consider a jQuery plugin that I wrote:
https://github.com/benmajor/jQuery-Mobile-Events
It does not require jQuery Mobile, only jQuery.
NOTE: Greatly inspired by EscapeNetscape's answer, I've made an edit of his script using modern javascript in a comment. I made an answer of this due to user interest and a massive 4h jsfiddle.net downtime. I chose not to edit the original answer since it would change everything...
Here is a detectSwipe function, working pretty well (used on one of my websites). I'd suggest you read it before you use it. Feel free to review it/edit the answer.
// usage example
detectSwipe('swipeme', (el, dir) => alert(`you swiped on element with id ${el.id} to ${dir} direction`))
// source code
// Tune deltaMin according to your needs. Near 0 it will almost
// always trigger, with a big value it can never trigger.
function detectSwipe(id, func, deltaMin = 90) {
const swipe_det = {
sX: 0,
sY: 0,
eX: 0,
eY: 0
}
// Directions enumeration
const directions = Object.freeze({
UP: 'up',
DOWN: 'down',
RIGHT: 'right',
LEFT: 'left'
})
let direction = null
const el = document.getElementById(id)
el.addEventListener('touchstart', function(e) {
const t = e.touches[0]
swipe_det.sX = t.screenX
swipe_det.sY = t.screenY
}, false)
el.addEventListener('touchmove', function(e) {
// Prevent default will stop user from scrolling, use with care
// e.preventDefault();
const t = e.touches[0]
swipe_det.eX = t.screenX
swipe_det.eY = t.screenY
}, false)
el.addEventListener('touchend', function(e) {
const deltaX = swipe_det.eX - swipe_det.sX
const deltaY = swipe_det.eY - swipe_det.sY
// Min swipe distance, you could use absolute value rather
// than square. It just felt better for personnal use
if (deltaX ** 2 + deltaY ** 2 < deltaMin ** 2) return
// horizontal
if (deltaY === 0 || Math.abs(deltaX / deltaY) > 1)
direction = deltaX > 0 ? directions.RIGHT : directions.LEFT
else // vertical
direction = deltaY > 0 ? directions.UP : directions.DOWN
if (direction && typeof func === 'function') func(el, direction)
direction = null
}, false)
}
#swipeme {
width: 100%;
height: 100%;
background-color: orange;
color: black;
text-align: center;
padding-top: 20%;
padding-bottom: 20%;
}
<div id='swipeme'>
swipe me
</div>
Hammer time!
I have used Hammer JS and it work with gesture. Read details from here: https://hammerjs.github.io/
Good thing that it is much more light weight and fast then jQuery mobile. You can test it on their website as well.
I like your solution and implemented it on my site - however, with some little improvements. Just wanted to share my code:
function detectSwipe(id, f) {
var detect = {
startX: 0,
startY: 0,
endX: 0,
endY: 0,
minX: 30, // min X swipe for horizontal swipe
maxX: 30, // max X difference for vertical swipe
minY: 50, // min Y swipe for vertial swipe
maxY: 60 // max Y difference for horizontal swipe
},
direction = null,
element = document.getElementById(id);
element.addEventListener('touchstart', function (event) {
var touch = event.touches[0];
detect.startX = touch.screenX;
detect.startY = touch.screenY;
});
element.addEventListener('touchmove', function (event) {
event.preventDefault();
var touch = event.touches[0];
detect.endX = touch.screenX;
detect.endY = touch.screenY;
});
element.addEventListener('touchend', function (event) {
if (
// Horizontal move.
(Math.abs(detect.endX - detect.startX) > detect.minX)
&& (Math.abs(detect.endY - detect.startY) < detect.maxY)
) {
direction = (detect.endX > detect.startX) ? 'right' : 'left';
} else if (
// Vertical move.
(Math.abs(detect.endY - detect.startY) > detect.minY)
&& (Math.abs(detect.endX - detect.startX) < detect.maxX)
) {
direction = (detect.endY > detect.startY) ? 'down' : 'up';
}
if ((direction !== null) && (typeof f === 'function')) {
f(element, direction);
}
});
}
Use it like:
detectSwipe('an_element_id', myfunction);
Or
detectSwipe('another_element_id', my_other_function);
If a swipe is detected the function myfunction is called with parameter element-id and 'left', 'right', 'up' oder 'down'.
I looked at several solutions but all failed with scroll and select text being the biggest confusion. Instead of scrolling right I was closing boxes and such.
I just finished my implementation that does it all for me.
https://github.com/webdevelopers-eu/jquery-dna-gestures
It is MIT so do what you want - and yes, it is really simple - 800 bytes minified. You can check it out on my (under-development) site https://cyrex.tech - swiperight on touch-devices should dismiss popup windows.