jQuery Move div with arrow keys
There are two things you need to do:
- Your
<div>
needsposition: absolute
or yourtop
andleft
properties won't do anything. - jQuery doesn't know what
'-= 10'
means but it does understand'-=10'
. You might want to go all the way to'-=10px'
as that's more common but thepx
isn't necessary.
Updated fiddle: http://jsfiddle.net/ambiguous/N5Ltt/2/
You're seeing the animation stop when you hold down an arrow key because you call .stop
on each keydown and that stops the animation. The animation works using a timer and .stop
stops the timer; if the keyboard's repeat rate is faster than the first iteration of the timer then no animation happens when you hold down an arrow key. You're only moving by 10px at a time so you could just do a straight non-animated move by 10px using .css
:
$div.css('left', $div.offset().left - 10);
Non-animated version: http://jsfiddle.net/ambiguous/N5Ltt/3/
Continously move div with arrow keys
This could be an approach for you:
var pressed = false;
$(document).keydown(function(e) {
if(!pressed){ //only start animation once
width = $(this).width();
height = $(this).height();
switch (e.which) {
case 37:
$('div').stop().animate({
left: '-=' + width //allow the user the move the div over the whole doc
}, 2000); //left arrow key
break;
// and so on
}
}
pressed = true;
}).keyup(function(){
$('div').stop(); // stop the current animation
pressed = false;
});
perhaps you have to change the variables width
and height
to fit in your needs.
DEMO
how to move a div with arrow keys
var pane = $('#pane'),
box = $('#box'),
w = pane.width() - box.width(),
d = {},
x = 3;
function newv(v,a,b) {
var n = parseInt(v, 10) - (d[a] ? x : 0) + (d[b] ? x : 0);
return n < 0 ? 0 : n > w ? w : n;
}
$(window).keydown(function(e) { d[e.which] = true; });
$(window).keyup(function(e) { d[e.which] = false; });
setInterval(function() {
box.css({
left: function(i,v) { return newv(v, 37, 39); },
top: function(i,v) { return newv(v, 38, 40); }
});
}, 20);
#pane {
position: relative;
width: 300px;
height: 300px;
border: 2px solid red;
}
#box {
position: absolute;
top: 140px;
left: 140px;
width: 20px;
height: 20px;
background-color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="pane">
<div id="box"></div>
</div>
Move elements with arrow keys
i'm not sure if you still need a solution or not but you can check this one out:
http://jsfiddle.net/ft2PD/41/
here is the html
<div id='div1'>
<input type='text' value='hello' />
</div>
<div id='div2'>
<label> World</label>
</div>
and here is the javascript:
$(document).ready(function(){
$('#div1,#div2').click(function(){
$('div.selected').removeClass('selected');
$(this).addClass('selected');
})}).keyup(function(e){
var div = $('div.selected');
console.log(div);
console.log(e.which);
switch (e.which) {
case 37:
$(div).stop().animate({
left: '-=10'
}); //left arrow key
break;
case 38:
$(div).stop().animate({
top: '-=10'
}); //up arrow key
break;
case 39:
$(div).stop().animate({
left: '+=10'
}); //right arrow key
break;
case 40:
$(div).stop().animate({
top: '+=10'
}); //bottom arrow key
break;
}
});
and last the CSS
#div1
{
position: absolute;
width:100px;
height:100px;
margin:15px;
padding:15px;
border: thin solid #D2D2D2;
}
#div2
{
position: absolute;
width:50%;
margin:15px;
padding:15px;
border: thin solid #D2D2D2;
}
.selected
{
border: 1px dashed #cccccc !important;
}
How to use arrow keys to move selected elements
If you use $this.position()
for getting position, your code will work just fine.
function getpos(e) { return { X: e.pageX, Y: e.pageY };}
function Rect(start, stop) { this.left = Math.min(start.X, stop.X); this.top = Math.min(start.Y, stop.Y); this.width = Math.abs(stop.X - start.X); this.height = Math.abs(stop.Y - start.Y);}
$(function() { var startpos; var selected = $([]), offset = { top: 0, left: 0 }; $(".designer-verticalline, .designer-rectangle, .designer-field, .designer-image").resizable();
// http://stackoverflow.com/questions/705250/is-there-a-jquery-plugin-which-combines-draggable-and-selectable#8643716 // teha: seal on ka mousedown mis andis viga, kaseda kasutada var $liigutatavad = $(".designer-verticalline, .designer-horizontalline, .designer-rectangle, .designer-field, .designer-image, .designer-label"); $liigutatavad.draggable({ start: function(event, ui) { var $this = $(this);
if ($this.hasClass("ui-selected")) { // if this is selected, attach current offset // of each selected element to that element selected = $(".ui-selected").each(function() { var el = $(this); el.data("offset", el.offset()); }); } else { // if this is not selected, clear current selection selected = $([]); $liigutatavad.removeClass("ui-selected"); } offset = $this.offset(); },
drag: function(event, ui) { // drag all selected elements simultaneously var dt = ui.position.top - offset.top, dl = ui.position.left - offset.left; selected.not(this).each(function() { var $this = $(this); var elOffset = $this.data("offset"); $this.css({ top: elOffset.top + dt, left: elOffset.left + dl }); });
// this does not fix the issue: //$(".designer-verticalline, .designer-rectangle, .designer-field, .designer-image").resizable(); } });
// ...but manually implement selection to prevent interference from draggable() $(".designer-panel-body").on("click", "div", function(e) { if ( /*!e.metaKey &&*/ !e.shiftKey && !e.ctrlKey) { // deselect other elements if meta/shift not held down $(".designer-panel-body").removeClass("ui-selected"); $(this).addClass("ui-selected"); } else { if ($(this).hasClass("ui-selected")) { $(this).removeClass("ui-selected"); } else { $(this).addClass("ui-selected"); } }
//var selectable = $("#container").data("selectable"); //selectable.refresh(); //$( ".designer-panel-body" ).data("selectable")._mouseStop(null); });
$(".designer-panel-body").selectable({ selected : function() { $(".ui-selected").first().focus(); } });
$(".designer-panel-body").keydown(function(e) { switch (e.which) { case 37: // left $(".ui-selected").each(function() { var $this = $(this); var $position = $this.position(); $this.css({ left: $position.left - 2 }); }); break;
case 38: // up $(".ui-selected").each(function() { var $this = $(this); var $position = $this.position(); $this.css({ top: $position.top - 2 }); }); break;
case 39: // right $(".ui-selected").each(function() { var $this = $(this); var $position = $this.position(); $this.css({ left: $position.left + 2 }); }); break;
case 40: // down $(".ui-selected").each(function() { var $this = $(this); var $position = $this.position(); $this.css({ top: $position.top + 2 }); }); break;
default: return; // exit this handler for other keys } e.preventDefault(); // prevent the default action (scroll / move caret) });
});
.designer-panel-body { min-height: 1px; overflow: hidden; margin: 0; padding: 0;}.panel-footer { background-color: inherit;}.designer-panel,.designer-resetmargins { margin: 0; padding: 0;}.designer-verticalline,.designer-horizontalline,.designer-rectangle { font-size: 1pt; border: 1px solid #000000;}.designer-field { border: 1px solid lightgray; white-space: pre; overflow: hidden;}.ui-selecting { background-color: lightskyblue; color: white;}.ui-selected { background-color: lightskyblue; border-color: darkblue; color: white;}.designer-label { white-space: pre; /*overflow: hidden;*/}.designer-field,.designer-label { font-family: "Times New Roman"; font-size: 10pt; z-index: 2;}.designer-verticalline,.designer-horizontalline,.designer-rectangle,.designer-field,.designer-image,.designer-label { position: absolute;}
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script><script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script><div class='panel designer-panel'> <div class='panel-body designer-panel-body panel-warning' style='height:9.37cm'>
<div class='designer-field' contenteditable='true' style='top:2.30cm;left:5.84cm;width:10.24cm;height:0.63cm;font-family:Arial;font-size:14pt;font-weight:bold;'>vnimi+' '+dok.tasudok</div> <div class='designer-field' contenteditable='true' style='top:2.30cm;left:16.37cm;width:2.68cm;height:0.61cm;font-size:14pt;'>DOK.kuupaev</div> <div class='rectangle' style='border-width: 1px;background-color:#FFFFFF;top:2.99cm;left:1.34cm;width:18.05cm;height:5.29cm'></div> <div class='designer-field' contenteditable='true' style='top:3.01cm;left:1.53cm;width:9.71cm;height:0.55cm;font-size:12pt;'>m.FIRMA</div> <div class='designer-field' contenteditable='true' style='top:3.01cm;left:12.13cm;width:3.13cm;height:0.53cm;font-size:12pt;'>ise.telefon</div> <div class='designer-field' contenteditable='true' style='top:3.01cm;left:17.11cm;width:1.89cm;height:0.55cm;font-size:12pt;text-align:right;'>ise.regnr</div> <div class='designer-label' contenteditable='true' style='top:3.04cm;left:11.39cm;text-align:right;font-size:12pt;'>Tel.</div> <div class='designer-label' contenteditable='true' style='top:3.04cm;left:15.71cm;font-size:12pt;'>Reg.Nr</div> <div class='designer-field' contenteditable='true' style='top:3.62cm;left:1.55cm;width:9.45cm;height:0.55cm;font-size:12pt;'>ise.tanav</div> <div class='designer-field' contenteditable='true' style='top:3.70cm;left:15.16cm;width:3.37cm;height:0.55cm;font-size:12pt;'>ise.vatpayno</div> <div class='designer-label' contenteditable='true' style='top:3.72cm;left:12.89cm;text-align:right;font-size:12pt;'>KMKR nr</div> <div class='designer-field' contenteditable='true' style='top:4.30cm;left:1.58cm;width:9.08cm;height:0.55cm;font-size:12pt;'>rtri(ise.postiindek)+' '+rtri(ise.piirkond)</div> <div class='designer-field' contenteditable='true' style='top:4.30cm;left:14.66cm;width:4.34cm;height:0.55cm;font-size:12pt;text-align:right;'>aarve(dok.arvekonto, 'konto.arveldusar')</div> <div class='designer-label' contenteditable='true' style='top:4.33cm;left:13.89cm;font-size:12pt;'>A/A</div> <div class='designer-horizontalline' style='border-width: 1px;top:4.96cm;left:1.34cm;width:18.03cm;height:0.00cm'></div> <div class='designer-field' contenteditable='true' style='top:5.04cm;left:17.13cm;width:1.89cm;height:0.55cm;font-size:12pt;text-align:right;'>klient.regnr</div> <div class='designer-field' contenteditable='true' style='top:5.06cm;left:4.18cm;width:12.71cm;height:0.55cm;font-size:12pt;'>klient.nimi</div> <div class='designer-label' contenteditable='true' style='top:5.06cm;left:15.74cm;font-size:12pt;'>Reg.Nr</div> <div class='designer-label' contenteditable='true' style='top:5.09cm;left:1.63cm;font-size:12pt;'>Maksja</div> <div class='designer-field' contenteditable='true' style='top:5.72cm;left:1.53cm;width:11.68cm;height:0.55cm;font-size:12pt;'>klient.tanav</div> <div class='designer-field' contenteditable='true' style='top:5.72cm;left:15.18cm;width:3.37cm;height:0.55cm;font-size:12pt;'>klient.vatpayno</div> <div class='designer-label' contenteditable='true' style='top:5.75cm;left:12.92cm;text-align:right;font-size:12pt;'>KMKR nr</div> <div class='designer-field' contenteditable='true' style='top:6.38cm;left:1.53cm;width:11.84cm;height:0.55cm;font-size:12pt;'>rtri(klient.postiindek)+' ' +rtri(klient.piirkond)</div> <div class='designer-field' contenteditable='true' style='top:6.38cm;left:13.47cm;width:3.37cm;height:0.55cm;font-size:12pt;'>sql("sele transfld('nimetus', 'riik', rapopref()) from riik where kood=klient.riik2", '' )</div> <div class='designer-field' contenteditable='true' style='top:6.99cm;left:3.71cm;width:12.16cm;height:1.16cm;font-size:12pt;'>klient.aadress</div> <div class='designer-label' contenteditable='true' style='top:7.01cm;left:1.45cm;text-align:right;font-size:12pt;'>Postiaadress</div> <div class='designer-field' contenteditable='true' style='top:8.33cm;left:3.95cm;width:2.11cm;height:0.55cm;font-size:12pt;'>dok.tasukuup</div> <div class='designer-field' contenteditable='true' style='top:8.33cm;left:6.08cm;width:8.05cm;height:0.55cm;font-size:12pt;'>eval( 'maksetin.' +left(rapopref()+'tingimus',10))</div> <div class='designer-label' contenteditable='true' style='top:8.35cm;left:1.45cm;font-size:12pt;'>Maksetähtaeg</div> <div class='designer-field' contenteditable='true' style='top:8.91cm;left:1.45cm;width:13.66cm;height:0.45cm;'>iif(!empty(dok.saaja), IR("Saaja: ")+sql('sele rtri(nimi)+" "+rtri(tanav)+" "+rtri(piirkond)+" "+rtri(postiindek) from klient where kood=dok.saaja',''),'')</div> </div> <div class='bg-warning'> <div class='panel-footer'><i class='glyphicon glyphicon-chevron-up'></i> GroupHeader 1: str(dokumnr)+str(koopia,2)</div> </div></div>
How to move selected elements using arrow keys
This is an example of how to "drag" DOM elements with arrow key's without using jQuery UI draggable
.
In this example jQuery .before()
and .after()
functions are used to place elements to a new location.
$('.el').click(function(){ $('.el').removeClass('active'); $(this).addClass('active'); });
$('body').on('keyup',function(e){
switch(e.which) { case 37: // left var tmp_id = $('.el.active').prev().attr('id'); $('#' + tmp_id).animate({ opacity: 0 }, 100, function(){ $('.el.active').after($('.el.active').prev()); }); $('#' + tmp_id).animate({ opacity: 1 }, 300); break;
case 38: // up var active_index = $('.el.active').index(); var index_min = $('.el.active').parent().children().first().index(); var index_max = $('.el.active').parent().children().last().index(); var next_element = $('.el.active').parent().prev().children(':eq('+active_index+')'); if(index_min === active_index){ var prev_el = next_element.next(); $('.el.active').before(next_element); $(prev_el).before($('.el.active')); } if(index_max === active_index || (active_index > index_min && active_index < index_max )){ var prev_el = next_element.prev(); $('.el.active').before(next_element); $(prev_el).after($('.el.active')); } break;
case 39: // right var tmp_id = $('.el.active').next().attr('id'); $('#' + tmp_id).animate({ opacity: 0 }, 100, function(){ $('.el.active').before($('.el.active').next()); }); $('#' + tmp_id).animate({ opacity: 1 }, 300); break;
case 40: // down var active_index = $('.el.active').index(); var index_min = $('.el.active').parent().children().first().index(); var index_max = $('.el.active').parent().children().last().index(); var next_element = $('.el.active').parent().next().children(':eq('+active_index+')'); var prev_el = next_element.prev(); if(index_min === active_index){ var prev_el = next_element.next(); $('.el.active').before(next_element); $(prev_el).before($('.el.active')); } if(index_max === active_index || (active_index > index_min && active_index < index_max )){ var prev_el = next_element.prev(); $('.el.active').before(next_element); $(prev_el).after($('.el.active')); } break;
default: return; // exit this handler for other keys } e.preventDefault();
});
.container{ width: 100%; }
div[id^="el-wr"]{ width: 280px; margin: 0 auto; }
.el{ width: 60px; height: 60px; background-color: #aaa; margin: 5px; float: left; cursor: pointer; text-align: center; line-height: 60px; font-size: 28px; color: white;}
.active{ background-color: #525252; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container">
<div id="el-wr0">
<div class="el" id="index1">1</div>
<div class="el" id="index2">2</div>
<div class="el" id="index3">3</div> <div class="el" id="index4">4</div>
</div> <div id="el-wr1">
<div class="el" id="index5">5</div>
<div class="el" id="index6">6</div>
<div class="el" id="index7">7</div> <div class="el" id="index8">8</div>
</div> <div id="el-wr2">
<div class="el" id="index9">9</div>
<div class="el" id="index10">10</div>
<div class="el" id="index11">11</div> <div class="el" id="index12">12</div>
</div>
</div>
Moving element with arrow keys jquery
Assuming the problem is that the element does not move (you don't really make the problem clear in your question), the reason is that the element is not positioned correctly.
Add position: absolute
or position: relative
to your CSS.
Here's an updated fiddle.
Navigate into layer using arrow key
Here's a workaround to get your goal achieved :
Q1 : "When you arrow down the window also scrolls down with it even though I added prevent default"
A : a long answer that can be applied (parts of it) to the other question. That's the logic behavior to occur when pressing arrow keys and you have attached a keyup
listener but that event can't be undone as the key is already pressed :
keyup
can catch arrow keys but can't be undone==>
not an option.keypress
can be undone but can't catch arrow keys==>
not an option.keydown
can catch arrow keys and can be undone==>
what we need, perfect.So
keydown
is the qualified event but so let's assume you changed the events tokeydown
:imagine you have focused the
textarea#searchTerm
and pressed the down arrow to start navigating in the autocomplete box, the event won't trigger (due topreventDefault
call).we can't even start navigating with arrow keys after calling
preventDefault
.
A solution is to think a bit wisely :
- attach a
keydown
handler to thewindow
that checks if the current focused element in the page ($(document.activeElement)
) is either theform#searchForm
or one of its children (like the autocomplete items) and the key that being pressed is the up/down arrow then we prevent that event thus no scrolling down when scrolling into the autocomplete list. - attach a
keydown
handler to theform#searchForm
that sees if the key pressed isn't up/down arrow then stop the event propagation to prevent getting bubbled to thewindow
thus allowing us to write and navigate in the autocomplete list (remember we havepreventDefault
called in the handler for thewindow
that can prevent us from writing). - a final handler for
keydown
attached totextarea#searchTerm
(even though aninput[type="text"]
seems to be more suitable preventing line breaks, that may appear in atextarea
, at least) that has a simple and important task which is while focusing (writing in) the field and the up arrow gets pressed we don't allow the autocomplete list last item to be selected.
the ordering when adding these handlers is very important : first attch
form#searchForm
handler,textarea#searchTerm
's and then the handler for thewindow
.
Q2 : "When you get to the end of the list it loops back round. It needs to stop at the end"
A : in the Navigate
function we see if the displayBoxIndex
variable (that tracks which item to be selected) has reached the last item and the down arrow was pressed then we just return
to quit the function.
Q3 : "When you go back to the first element in the list - then the next UP action - should take you back into the input box"
A : also in the Navigate
function we check if displayBoxIndex
variable is at the first item and the up arrow was pressed then we trigger focus
for the text field, remove the selected
class from the autocomplete items, reset displayBoxIndex
variable to -1
(ensuring we start from the first item when the down arrow gets pressed while typing) and finally return
to halt the function.
this line
displayBoxIndex += diff
must appear after the above two condition in order to get correct calculation for which element we're selecting and the next one to be selected.
So, here's a demo to illustrate, it contains a wealth of helpful comments that may assist you while reading, also some covers some changes made into the code that I didn't cover above :
const form = $('#searchForm'),
searchTerm = $('#searchTerm'),
autoc = $('#autoComplete'),
jqWin = jQuery(window),
oBoxCollection = jQuery('.ac-list'),
cssClass = 'selected',
Navigate = diff => {
/** focus the text field when in the first item and the up arrow was pressed **/
if (displayBoxIndex === 0 && diff === -1) {
searchTerm.trigger('focus');
oBoxCollection.removeClass(cssClass);
displayBoxIndex = -1;
return;
}
/** prevent looping back when reached the last item in the autocomplete box **/
if (displayBoxIndex === oBoxCollection.length - 1 && diff == 1) return;
/** make the navigation **/
displayBoxIndex += diff;
oBoxCollection.removeClass(cssClass)
.eq(displayBoxIndex)
.addClass(cssClass)
.children('a')
.focus();
};
let displayBoxIndex = -1;
/** attaching events with respect of ordering **/
/** 1: keydown listener on the form **/
form.on('keydown', e => {
const upOrDown = [38, 40].indexOf(e.which) != -1;
/** is it the up/down key **/
!upOrDown && (e.stopPropagation());
/** if no (another key) just stop the event propagation so the one attached to the window won't be fired **/
upOrDown && (Navigate(e.which == 40 ? 1 : -1));
/** if yes we call we call Navigate (if we gets here to the ternary operator the e.which is either 40 or 38) **/
e.which == 27 && (autoc.slideUp(400, () => {
searchTerm.blur();
displayBoxIndex = -1;
oBoxCollection.removeClass(cssClass);
}));
});
/** 2: keydown listener on the text field **/
/** prevent going to the list box bottom when pressing up arrow **/
searchTerm.on({
keydown: e => {
e.which == 38 && (e.stopPropagation());
},
focus: e => {
/** show the autocomplete box if is hidden **/
autoc.is(':hidden') && (autoc.slideDown(400));
displayBoxIndex = -1;
} /** reset navigation position (resets to the first item in the autocomplete box) when the text field is focus **/
});
/** 3: keydown listener on the window **/
jqWin.on('keydown', e => {
const focus = $(document.activeElement);
/** get the current focused element in the page **/
[38, 40].indexOf(e.which) != -1 && (focus.is('#searchForm') ||
form.has(focus).length) && (e.preventDefault());
/** prevent scroll when navigating in the autocomplete box (the scrolling you asked about in your first question) **/
});
/** basic styling to appear like a real autocomplete box. Doesn't affect the main functionality required **/
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 300vh;
}
.wrapper {
position: relative;
display: flex;
width: 250px;
justify-content: center;
align-items: flex-start;
margin: 15px auto;
}
.wrapper textarea {
display: block;
width: 100%;
height: 35px;
padding: 8px 4px;
border: 2px solid #181818;
resize: none;
transition: all .4s 0s ease;
}
.wrapper textarea:focus {
background-color: #ccc;
}
.wrapper #autoComplete {
position: absolute;
width: 100%;
max-height: 150px;
overflow-y: auto;
top: 100%;
left: 0;
box-shadow: 0 8px 25px -8px rgba(24, 24, 24, .6);
}
.wrapper ul {
list-style-type: none;
background-color: #181818;
}
.wrapper ul li {
display: block;
margin-bottom: 4px;
transition: all .4s 0s ease;
}
.wrapper ul li:last-child {
margin-bottom: 0;
}
.wrapper ul li:hover,
.selected {
background-color: #f00;
}
.wrapper ul li a {
display: block;
padding: 4px 15px;
color: #fff;
text-decoration: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- added a wrapper div in the form just to simplify the styling it has nothing related to the functionality -->
<form id="searchForm">
<div class="wrapper">
<textarea placeholder="Enter search terms..." id="searchTerm" name="searchTerm"></textarea>
<div id="autoComplete">
<ul>
<li class="ac-list"><a href="#">autocomplete item 1</a></li>
<li class="ac-list"><a href="#">autocomplete item 2</a></li>
<li class="ac-list"><a href="#">autocomplete item 3</a></li>
<li class="ac-list"><a href="#">autocomplete item 4</a></li>
<li class="ac-list"><a href="#">autocomplete item 5</a></li>
<li class="ac-list"><a href="#">autocomplete item 6</a></li>
<li class="ac-list"><a href="#">autocomplete item 7</a></li>
<li class="ac-list"><a href="#">autocomplete item 8</a></li>
<li class="ac-list"><a href="#">autocomplete item 9</a></li>
<li class="ac-list"><a href="#">autocomplete item 10</a></li>
</ul>
</div>
</div>
</form>
How do I enable arrow navigation on keyboard for a list of Div using jQuery
You need to bind keyboard events keyup/keydown
and then change the css accordingly to give a feel of move up
or move down
:
use keyup
if you want a single move even on a key press no matter the key is long pressed.
use keydown
if you want to move in a cycle fashion as long as user holds the key.
$("#search").keyup(function(e)
{
if (e.keyCode == 40)
{
Navigate(1);
}
if(e.keyCode==38)
{
Navigate(-1);
}
});
Check complete code @fiddle: http://jsfiddle.net/MKZSE/77/
Move a div within another div with arrow keys
I have tested the code and found that when you are near the borders it's not working properly (Perhaps this was the original question?). On this i tested another simpler solution: I just changed your moveSquare function to only do work when you are inside your bounds (I mean, you shouldn't be always incrementing/decrementing position and then check if you are out of bounds to correct it).
Related Topics
How to Change the Style of Elements with Same Class Name
Change Svg Text to CSS Word Wrapping
How to Generate Image Sprites in Ember-Cli Using Compass
How to Host Material Icons Offline
Get All CSS Root Variables in Array Using JavaScript and Change the Values
Include CSS and JavaScript in My Django Template
Make the on Scroll Growing <Path> to Dashed Line
Get the Height of an Element Minus Padding, Margin, Border Widths
How to Get the Opacity of an Element Using JavaScript
How to Set Active Class to Nav Menu from Twitter Bootstrap
Highcharts: Make the Legend Symbol a Square or Rectangle
Serving High Res Images to Retina Display
Customize Ng-Repeat in Angularjs for Every Nth Element
Cross Browser Rgba Transparent Background While Keeping Content (Text & Images) Non-Transparent
How to Give This Spaceship Acceleration
How to Redefine CSS Classes with JavaScript
How to Make Bootstrap Off Canvas Nav Overlap Content Instead of Move It