Is it possible in jQuery to have an element continuously move when the key is held down?
I've tried a few ways but they always have a break in between animation calls. The code I currently have:
$(document).keydown(function (e) {
if (e.which == 37) {
$('#you').stop().animate({
left: '-=16px'
}, 10);
}
});
$(document).keyup(function (e) {
$('#you').stop();
});
.animate() isn't always the best way.
// cache jQuery objects for performance
var you = $( "#you" )
, doc = $( document )
// variable to hold motion state
, activeMotion
// goDown motion, adjust numbers to taste
, goDown = function(){
you.css( "left" , you.css( "left" ) - 16 );
if ( activeMotion === goDown ) {
setTimeout( goDown , 10 );
}
}
doc.keydown( function( e ) {
if ( e.which === 37 && activeMotion !== goDown ) {
activeMotion = goDown;
goDown();
}
// all directions can go here in seperate if/else statements
// be sure to include "activeMotion !== goDown" else every time
// keydown event fires, it will start a new goDown loop.
} );
doc.keyup( function () {
// simply ends any motion that checked activeMotion
activeMotion = null;
} );
Instead of animating the element, rather just move it by some amount of pixels. 16 will probably be too much because it will go too fast.
I think you are seeing the break between animation calls because of your timing.
If you look at your operating systems keyboard repeat time interval, it should be around 35 milliseconds - test it here.
On top of that you are animating every 10ms, not counting the time it takes to run all the animation functions, etc. So why not simplify the animation and not worry about time intervals (try this demo):
var block = $('.block'),
leftPos;
$(document).keydown(function (e) {
leftPos = block.position().left;
leftPos += (e.which == 37) ? -5 : 0;
leftPos += (e.which == 39) ? 5 : 0;
block.css('left', leftPos);
});
Related
I have built a simple vertical scrollable website that snaps the view to divs when the user scrolls up or down the page. You cans see a demo here: http://dev.driz.co.uk/snap.html
The JS is fairly simple:
var currentScreen = 0;
var scrollReady = false;
var screens = new Array( 'one',
'two',
'three');
function scrollNext() {
if( currentScreen < screens.length-1 && scrollReady == true ) {
currentScreen++;
performScroll();
}
}
function scrollPrev() {
if( currentScreen > 0 && scrollReady == true ) {
currentScreen--;
performScroll();
}
}
function performScroll() {
scrollReady = false;
var newYPos = Math.ceil($('#'+screens[currentScreen]).offset().top);
$('.snap').animate({scrollTop: newYPos }, 500, function() { scrollReady = true; });
}
$(document).ready(function() {
scrollReady = true;
$('.snap').bind('mousewheel', function (event, aS, aQ, deltaY) {
event.preventDefault();
if (deltaY > 0) {
scrollPrev();
} else {
if (deltaY < 0) {
scrollNext();
}
}
return false;
});
$(document).bind('keyup', function (event) {
if (event.keyCode == 40 || event.keyCode == 38) {
event.preventDefault();
if (event.keyCode == 40) {
if (scrollReady == true) {
scrollNext();
}
} else {
if (event.keyCode == 38) {
if (scrollReady == true) {
scrollPrev();
}
}
}
}
});
$(document).bind('keydown', function (event) {
if (event.keyCode == 40 || event.keyCode == 38 ) {
event.preventDefault();
}
});
});
However I can only scroll to the first two divs and can't get to the third one... Any ideas why this is happening? I can't see issues that would cause this that wouldn't effect the first two from working...
Update: Sometimes you can get it to scroll to the third div (scrolling up and down until it does), but it skips the second div and then when the user scrolls up again, it jumps all the way to the top... so something weird is happening.
Update 2: I've noticed that currentScreen is incorrectly 2 when you scroll to the second div which is why you can't scroll to the third div. Any ideas why though?
Update 3: It seems that the scrollReady variable isn't preventing the functions from being called multiple times in places, as if you scroll up and down a few times, you find that sections are scrolled passed multiple times. Which shouldn't happen, you should only be able to scroll up one and down one at a time.
Store the values of section offsets in variable and then try, it will work.
check this on codepen.
http://codepen.io/sandeshdamkondwar/pen/veGko?editors=100
In scrollNext() function Your conditional checking is wrong
on second screen this condition will be false and therefore it is not moving to third screen.
It should be
currentScreen < screens.length
Good day all.
I'm having some problems with hoverintent.js a jquery plugin that handle the mouseOver events in a different way than normal.
Due to some complications, I can't modifiy anything but the js of this plugin, but I need to make it compliant with touch events and not only with mouseOver and mouseLeave.
after some debugs, I have managed to recognize this part of the code to be the one to modify:
var handleHover = function(e) {
// next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut
var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }
if ( p == this ) { return false; }
// copy objects to be passed into t (required for event object to be passed in IE)
var ev = jQuery.extend({},e);
var ob = this;
// cancel hoverIntent timer if it exists
if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
// else e.type == "onmouseover"
if (e.type == "mouseover") {
// set "previous" X and Y position based on initial entry point
pX = ev.pageX; pY = ev.pageY;
// update "current" X and Y position based on mousemove
$(ob).bind("mousemove",track);
// start polling interval (self-calling timeout) to compare mouse coordinates over time
if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
// else e.type == "onmouseout"
} else {
// unbind expensive mousemove event
$(ob).unbind("mousemove",track);
// if hoverIntent state is true, then call the mouseOut function after the specified delay
if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
}
}
};
// bind the function to the two event listeners
return this.mouseover(handleHover).mouseout(handleHover);
what I've done so far is to make the function working different with mobiles:
var handleHover = function(e) {
isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
if(isMobile){
console.log("Ismobile");
}else{
... Same code as before here ...
}
// bind the function to the two event listeners
return this.mouseover(handleHover).mouseout(handleHover);
and now i'm struck. I would like it to "change" its behavior to handle the touch, and not the mouse over event, so on mobiles I will need to touch the element, instead to hovering on it. May someone give me an help? Am I on the right way? Is it the right way to think of it?
unluckily I have only the possibility to change this file and some few more.
Recently i bumped into several problems with changing hoverIntent.js, and ended up in writing my own plugin: hoverDelay.js (much simpler, and less code). see if you can use it, and modify it to your own needs (and maybe contribute the mobile code to it :-)
Checked out other posts, no help...
I'm using asdw to move an object around within a limited space. I'm trying to figure out how to allow the object to move around while the key is pressed, without the momentary delay at the beginning.
Thanks...
$(document).ready(function(){
var longitude = 0;
var latitude = 0;
$('body#sense').keypress(function(){
if(event.which == 65 || event.which == 97){
// Left
if(longitude != 0){
longitude = longitude + 10;
$('img#map').css('margin-left', longitude);
}
}
else (event.which == 68 || event.which == 100){
// Right
if(longitude > -200){
longitude = longitude - 10;
$('img#map').css('margin-left', longitude);
}
}
});
});
The web page
<body id="sense">
<h2><center>Use your 'asdw' keys to move the map around</center></h2>
<div id="box">
<img id="map" src="http://www.toronto.ca/culture/victoria-square/images/ch0/Victoria-Square-map-t.gif" alt="" />
</div>
</body>
The holding the image has a set width and height, both smaller than the image. The is set to overflow:hidden, so the javascript moves the image around within the div so different parts are visible.
The CSS
div#box {
margin:0px auto;
width:225px;
height:225px;
overflow:hidden;
}
div#box img {
}
Use the keyDown event and then start your own timer interval to control your own repeat interval (ignore the system repeat interval) and then cancel the timer on keyUp. Ignore the other key events. You can pick your own repeat time in the setInterval calls.
var timer = null;
function increaseLongitude() {
// your code here
}
function decreaseLongitude() {
// your code here
}
$("#sense").keyDown(function(e) {
if (!timer) {
if (e.which == 65 || e.which == 97) {
timer = setInterval(increaseLongitude, 100);
increaseLongitude();
} else if (e.which == 68 || e.which == 100) {
timer = setInterval(decreaseLongitude, 100);
decreaseLongitude();
}
}
});
$("#sense").keyUp(function(e) {
if (timer) {
clearInterval(timer);
timer = null;
}
});
Try using the keydown event instead
Checkout this version of your code. it can be done with 'keydown' event. I believe this is the ideal way it should be done.
http://jsfiddle.net/valllabh/yFxDN/10/
I'm trying to detect orientation changes on mobile devices and trigger a function once an orientation has been completed, but the code inside the function is continuously firing in Android and I'm not sure why. Here's my code:
var supportsOrientationChange = "onorientationchange" in window;
var orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";
window.addEventListener(orientationEvent,
function() { alert ('orientation changed'); },
false
);
Does anyone know how to write this so that it only triggers once, after orientation change has been completed?
I used a work-around for this in my app. I added an event listener for orientationchange and then set a timeout so the orientationchange could occur and I could get a new width value that actually reflected the width after the orientation change.
var device_width = 0;
$(document).ready(function () {
var oc_timer;
$(window).bind('orientationchange', function () {
clearTimeout(oc_timer);
oc_timer = setTimeout(function () {
device_width = $(window).width();
}, 500);
});
});
I am not positive this will solve your continuously firing function problem but this is a solution I found to work.
I found a way to do this in case others are still having the same issue, check it out:
function onOrientationChange() {
if (typeof(this.orientation) === "undefined"){
if (window.orientation == -90 || window.orientation == 90) {
this.orientation = "landscape";
} else {
this.orientation = "portrait";
}
// alert ("in 1");
// you code here for change
}
if ((window.orientation == -90 || window.orientation == 90) && (this.orientation == "portrait")) {
this.orientation = "landscape";
// alert ("in 2");
// you code here for change
}
if ((window.orientation == 0 || window.orientation == 180) && (this.orientation == "landscape")) {
this.orientation = "portrait";
// alert ("in 3");
// you code here for change
}
}
Simple solution for less detailed applications
//bind orientation change event
$(window).bind("orientationchange", orientationChange);
//later,
function orientationChange(){
//whatever needs to happen when it changes.
alert("changed");
}
You could also use $.on() instead if you need to pass information.
In browsers that do not support it, the event does not fire. You could then write a custom detection script as a fallback to fire the event if the orientation changes on a device that does not support onorientationchange.
I have a custom CMS and would like to add a "shortcuts menu" triggered by the pressing of the Ctrl key twice within, say, 300 milliseconds.
I use prototype, so my starting point obviously is:
Event.observe(document, 'keypress', function(event)
{ if(event.keyCode == Event.KEY_XYZ) { show_shortcuts});
My approach at the moment would be populating a global variable with the current time in milliseconds, and checking on each keypress whether a keypress has happened less than 300 milliseconds ago.
But maybe there is a more elegant solution?
This should work. Maybe add some further checking if not some other key like Alt or Shift are pressed at the same time. Hope it is self explanatory, if not just ask and I provide clarification.
var dblCtrlKey = 0;
Event.observe(document, 'keydown', function(event) {
if (dblCtrlKey != 0 && event.ctrlKey) {
alert("Ok double ctrl");
dblCtrlKey = 0;
} else {
dblCtrlKey = setTimeout('dblCtrlKey = 0;', 300);
}
});
https://jsfiddle.net/3tc26g7x/
function doubleControlEvent() {
if (event.key === 'Control') {
timesCtrlClicked++
if (timesCtrlClicked >= 2) {
console.log('Double control')
// Double Crtl is clicked add your code here
}
setTimeout(() => (timesCtrlClicked = 0), 200)
}
}
let timesCtrlClicked = 0;
document.addEventListener('keyup', doubleControlEvent, true)