I'm a beginner in JavaScript, and trying to make a simple script that pushes a box using the mouse pointer, but unfortunately it isn't working for some reason, I hope you can help me out.
(This script is really primitive, only pushes the box from the left till now).
index.html :
<html>
<head>
<title>Chase the box</title>
<style>
body {
}
.css-box{
width : 100px;
height : 100px;
margin : auto;
background-color : blue;
}
</style>
</head>
<body>
<div id="box" class="css-box"></div>
<script type="text/javascript" src="script.js"></script>
</body>
script.js :
var box = document.getElementById("box");
var pushBox = function(e){
if(e.pageX == box.offsetLeft){
box.style.left = box.style.left + 1 + "px";
}
};
document.addEventListener("mousemove" , pushBox);
A JQuery version but accomplishes the same as you're trying to do
http://jsfiddle.net/3mxC3/1/
The main problem I can see with your script is that e.pageX == box.offsetLeft would mean that it's only going to be triggered when the pageX is exactly the offsetLeft.
The mousemove event won't be firing every pixel so this approach won't work. The easiest way to accomplish it is to set the mousemove onto the actual box instead (so it'll only fire if the user mouse overs the box)
Secondly, setting the left attribute on the box was doing nothing as the left/right-ness was being set by the margin: auto. Changing this to position: absolute makes it actually pay attention to the left attribute.
box.style.left is a string. And in JavaScript if you do string + int the int will be type casted to a string and you get string + string. For instance, if box.style.left is 10px you get:
'10px' + 1 + 'px'
int typecasted to string
'10px' + '1' + 'px'
create one string
'10px1px'
And that will be the value of box.style.left. That isn't what you want...
To solve this you can use parseInt(), which parses a string into an int:
box.style.left = parseInt(box.style.left) + 1 + "px";
And your if is only matching when the X position of the cursor is exactly the same pixel as box.offsetLeft. That's almost impossible, I don't know what you are trying to do with that if?
At least, box.style.left has no value the first time. You need to set the value at first to 0 and then use the event.
A working example will be: http://jsfiddle.net/WouterJ/enLwh/ (please note that I have added position: relative; because we can't use the left property on the current position)
Some more tips, since you are new to JS:
If you do something like this:
X = X + 12;
You can short that up as:
X += 12;
You need to set a CSS position property other than static to the element so CSS left property can work.
.css-box{
position: absolute;
width : 100px;
height : 100px;
margin : auto;
background-color : blue;
}
Lastly you are better off adding stuff onload instead of having the script live in the body
Here is a script that lives in the head of the page, the rest of the issues are already solved by other ppl here
var pushBox = function(e){
if(e.pageX >= box.offsetLeft){
box.style.left = (parseInt(box.style.left,10) + 1) + "px";
}
},box;
window.onload=function() {
box = document.getElementById("box");
document.addEventListener("mousemove" , pushBox);
}
Related
This is how I detect the top margin of a div and increase/decrease it:
var oldm = $("#bdi").css("margin-top").replace("px", "");
var addm = 1;
$("#bdi").css({
'margin-top': '-='+addm+'px'
})
But I need to do the same with background position.
detect the actual top position of a background image
increase/decrease the top margin of a background image
For example:
background-position: center 5px;
How do I detect "5px" and increase/decrease it?
Thanks
You can get it using background-position-y like this :
var bgPositionY = ($("#bdi").css('background-position-y'))
var addPos = 5;
$("#bdi").css({
'background-position-y': '-='+addPos+'px'
})
https://jsfiddle.net/IA7medd/aLkok1n4/
You don't need jQuery for this...
var el = document.getElementById('bdi'),
currentYPosition = getComputedStyle(el)['backgroundPositionY'],
increment = 1,
newYPosition = 'calc(' + currentYPosition + ' + ' + increment + 'px)';
// Set new backgroundPositionY
el.style.backgroundPositionY = newYPosition;
The use of calc() above ensures the value is properly incremented, even if a percentage position value is used.
As of jQuery 1.6, .css() accepts relative values similar to .animate(). Relative values are a string starting with += or -= to increment or decrement the current value. Link
For example like this
$("div").css("background-position-x", "+=10px");
$("div").css("background-position-Y", "-=10px");
If you want to do other operation on css value use this
$("div").css("background-position-x", function(index) {
return index * 10;
});
You can see demo at bottom
$("#increaseX").click(function(){
$("#image").css("background-position-x", "+=10px");
});
$("#decreaseX").click(function(){
$("#image").css("background-position-x", "-=10px");
});
$("#increaseY").click(function(){
$("#image").css("background-position-y", "+=10px");
});
$("#decreaseY").click(function(){
$("#image").css("background-position-y", "-=10px");
});
#image {
width: 100px;
height: 100px;
background-image: url("https://assets.servedby-buysellads.com/p/manage/asset/id/28536");
background-position: 0px 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="image"></div>
<button id="increaseX">increaseX</button>
<button id="decreaseX">decreaseX</button>
<br />
<button id="increaseY">increaseY</button>
<button id="decreaseY">decreaseY</button>
Firefox doesn't support background-position-x and background-position-y. If you want to do your target work in firefox, see jsfiddle
You can
If you're using jQuery, the simplest option is to use incremental notation inline:
$("#bdi").css('background-position-y', '+=5px');
(This is a follow-up on my previous question if anybody is interested in the background story for entertainment purposes. It will probably not help you understand this question.)
Here are two elements <aside> and <main> who have got their width and height via JavaScript so that their combined width is the width of your screen (note that their display is inline-block). If you run this code in your web browser (a maximized browser so that the width of your browser equals the width of your screen) you might note that the body surprisingly does not properly fit the elements:
<!DOCTYPE html>
<html>
<body>
<aside></aside><!-- comment to remove inline-block whitespace
--><main></main>
<script>
var h = screen.height/100;
var w = screen.width/100;
var e = document.getElementsByTagName("aside")[0].style;
e.display = "inline-block";
e.backgroundColor = "lightblue";
e.width = 14*w + "px";
e.height = 69*h + "px";
e.marginRight = 0.5*w + "px";
e = document.getElementsByTagName("main")[0].style;
e.display = "inline-block";
e.backgroundColor = "green";
e.width = 85.5*w + "px";
e.height = 69*h + "px";
e = document.getElementsByTagName("body")[0].style;
e.margin = e.padding = "0";
e.backgroundColor = "black";
</script>
</body>
</html>
If you however give the JavaScript a delay, the elements are rendered properly. This suggests that the body somehow "needs time" to figure out its correct width:
<script>
setTimeout(function() {
[...]
}, 200);
</script>
It is also possible to give the body the specified width of screen.width instead of introducing the delay, by adding the following line. This supports the previous guess that the body does not immediately know its correct width (unless specified):
<script>
[...]
e.width = 100*w + "px";
</script>
Even though I have taken the freedom to throw wild guesses to explain this, I do not actually have a clue to what is going on.
Why are the elements not placed properly in the first place, and why do these two solutions work?
(Note: It is also possible to fix this by setting the whitespace of the body to nowrap with e.whiteSpace = "nowrap";, but I suspect this does not do the same thing as the other two. Instead of creating space for the elements inside the body, this simply forces the elements to be next to each other even though there is not enough room in the body.)
You should wait for the DOM to be available before running your code, see here: pure JavaScript equivalent to jQuery's $.ready() how to call a function when the page/dom is ready for it. That is possibly why setTimeout works. Also you should assign seperate variable names for your different elements.
// self executing function before closing body tag
(function() {
// your code here
// the DOM will be available here
})();
Is there a reason you are using Javascript and not CSS to accomplish this task? I suggest giving your elements css ids ie id="aside", then set your css styles:
html,body {
width: 100%;
height: 100%;
}
#aside {
display:inline-block;
position: relative;
float: left;
width: 14%;
height: 69%;
background: blue;
}
#main {
display:inline-block;
position: relative;
float: left;
width: 86%;
height: 31%;
background: azure;
}
Is there a way to check positioning of two elements?
For example:
.bigBox {
width: 100%;
height: 200px;
}
.btn {
position: fixed
display: none;
top: 10px;
right: 0;
}
There is a big box over the whole website. And i have a button with positioning fixed and display none. The button should fadeIn() if it is 100px under the .bigBox.
First thing, the the position of .bigBox's dimensions:
var bottomBigBox = $(".bigBox").offset().top + $(".bigBox").height();
var topOfBtn = $(".btn").offset().top;
// Check the condition and fade it.
if (bottomBigBox + 100 == topOfBtn)
$(".btn").fadeIn();
You can use position() or offset() methods to know the position of the element relative to the parent or relative to the document respectively.
$('.element').position().top; // returns the top value relative to parent
$('.element').position().left; // returns the left value relative to parent
$('.element').offset().top; // returns the top value relative to document
$('.element').offset().left; // returns the left value relative to document
See more:
http://api.jquery.com/offset/
https://api.jquery.com/position/
You can get an element position with offset(). Then you can sum its computed .height() and the desired margin by 100:
var bb = $(".bigBox");
var o = bb.offset();
var h = bb.height();
$(".btn").css("top", o.top + h + 100).fadeIn();
Working demo
Why use height() ? It will get the element computed height, so if you change on CSS or even if you use an relative value, it will work.
With plain Javascript
var bb = document.querySelector(".bigBox");
var t = bb.offsetTop;
var h = bb.offsetHeight;
document.querySelector(".btn").style.top = t + h + 100 + "px";
$(".btn").fadeIn(); // jQuery only for fadeIn effect
Working demo
I've been trying to move a red box 20px on mouseover. But instead of adding 20px to the current position it just goes to position "20px".
I got the idea for this here: Move an image with the arrow keys using JavaScript
But it's not working for me :/
Thanks!
<html>
<head>
<meta charset="UTF-8">
<style>
#element {
position: absolute;
left:100px;
top:100px;
height: 140px;
width: 60px;
background-color: red;
}
</style>
</head>
<body>
<div id="element"></div>
<script>
window.addEventListener('load', function () {
boxElement = document.getElementById('element');
if (boxElement) {
boxElement.addEventListener('mouseover', function () {
boxElement.style.left += 20 + 'px';
});
}
});
</script>
</body>
</html>
boxElement.style.left returns a string which looks like "123px".
The first time you execute
boxElement.style.left += 20 + 'px';
it will be fine, since boxElement.style.left will be an empty string. But the second time, you are trying to set style.left to 20px20px (string concatenation!), so the browser simply ignores the new value, and keep the old one, 20px.
You have to parse the position out of the value first, using parseInt and then add to it:
var left = boxElement.style.left;
boxElement.style.left = (parseInt(left, 10) + 20) + 'px';
The other problem is that boxElement.style.left won't return the initial value which was inherited from the CSS class. For that you can use getComputedStyle and set it once before you bind the event handler:
var boxElement.style.left =
window.getComputedStyle(boxElement,null).getPropertyValue("left");
If you read the code of the linked question properly, you can see that that's exactly what was done there:
element.style.left = parseInt(element.style.left) - 5 + 'px';
You're adding a string "20px" to an empty string, which is effectively setting the style property of the boxElement to "left: 20px", overriding the stylesheet.
You could get the current computed style of the element each time and add to it, or you could keep a closure-scoped variable with the position, like this:
window.addEventListener('load', function () {
var x=window.getComputedStyle(boxElement,null).getPropertyValue("left");
boxElement = document.getElementById('element');
if (boxElement) {
boxElement.addEventListener('mouseover', function () {
x+=20;
boxElement.style.left = x + 'px';
});
}
});
Dang, I figured it out... See below. The div layer I was querying was hidden via CSS then revealed in JS after my position query. Since I never saw it hidden I didn't realize it was, and that's why jQuery returned 0,0.
I feel like an idiot.
The code below was just meant to be illustrative and included all the code I thought was necessary, but it left out a critical CSS definition and a critical JS call:
I've got a div layer with some sub-div layers for menu items.
<div id="menuItems">
<div id="menuItem0">Menu Item 0</div>
<div id="menuItem1">Menu Item 1</div>
</div>
The position and dimensions are defined in an external CSS.
#menuItem0 { top: 0px; left: 100px; height: 40px; width: 200px; background-color: green;}
#menuItem1 { top: 0px; left: 350px; height: 40px; width: 200px; background-color: red;}
And on load the script is supposed to show the positions and dimensions of the menu items:
$(window).load(function () {
prepareMenuItems();
});
function prepareMenuItems() {
var numberOfMenuItems = $("#menuItems").children().length;
for (var i=0; i<numberOfMenuItems; i++) {
console.log("left: "+$("#menuItem" + i).position().left +
" top:" + $("#menuItem" + i).position().top +
" w:" + $("#menuItem" + i).width() +
" h:"+ $("#menuItem" + i).height());
}
}
In my live demo what I see in Google Chrome (latest) is:
left: 0 top: 0 w: 200 h: 40
left: 0 top: 0 w: 200 h: 40
The left and top are ZERO when they should not be.
If I force a break once the page has loaded and had a moment the Chrome debugger will evaluate a watch on $("#menuItem0").position().left properly. But why doesn't it on load? It spits out the right width and height, so the CSS has clearly been loaded. And it knows the answers later since a forced break gives the right answer so this isn't me looking at the wrong thing's position.
Help! It's driving me mad.
(Sorry about the earlier typos I was trying to be illustrative rather than literal and I didn't realize people would test the given code. Magritte did so via Fiddler and the code works as expected, so it must have something to do with external references to the CSS or JS or something...).
I figured it out... I was an idiot... I didn't realize one of the CSS rules was making a parent div hidden at the start and code milliseconds later would make it visible. So at the time jQuery was querying it for position the layer was hidden and jQuery's behavior is (I didn't realize) to return 0 when a div is hidden. Milliseconds later the layer is shown and now on break the jQuery worked as expected. The secret was, of course, to not have that parent div layer hidden at the start.
Thank you to you guys who responded. You guys were awesome to look at it, fix my stupid typos, and force me to look further into it to make a working demo to better prove my point (which led me to the solution).
Seems to work for me, you have a few typos: http://jsfiddle.net/MQfqA/1/
function prepareMenuItems() {
var numberOfMenuItems = $("#menuItems").children().length;
for (var i=0; i<numberOfMenuItems; i++) {
console.log("left: "+$("#menuItem" + i).position().left +
" top:" + $("#menuItem" + i).position().top +
" w:" + $("#menuItem" + i).width() +
" h:"+ $("#menuItem" + i).height());
}
}
your syntax was wrong. This now works
$(document).ready(function () {
prepareMenuItems();
});
function prepareMenuItems() {
var numberOfMenuItems = $("#menuItems").children().length;
for (var i=0; i<numberOfMenuItems; i++) {
console.log("left: "+$("#menuItem" + i).position().left +
" top:"+$("#menuItem" + i).position().top+
" w:"+$("#menuItem" + i).width() +
" h:"+ $("#menuItem" + i).height());
}
}
My impression or did you forget to close a quotation on line 11?