Getting a button's position

Y

Ynot

I want to simulate a cursor moving across the Web page and pushing a button.
I wrote some JavaScript functions to move a graphic image. Works fine.
However, I hard-coded the x and y coordinates where the graphic image starts
(at a position below the button) and ends (at a position on the button) with
literal values, which is bad because not everyone uses the same screen
resolution I'm using.

I wrote more functions to calculate where to put the graphic image at the
beginning and where to move it to. Unfortunately, I'm getting an "error on
page" after I try to use document.getElementById( ) in my code. I've tried
several alternatives, including calling another function called findPosY( ).
I'm getting nowhere with that. It gives me "error on page," too.

Here is the HTML for the button. It's in the body, not inside a form or div
element.

<INPUT id=btn type=button value="OK">

Here's my code (located as a JavaScript script between <head> and </head>),
along with a few alternatives I've tried and commented out. I can assign
the document.getElementById('btn') to a variable successfully, but every
"num =" assignment I tried afterwards using that variable failed. Can
anyone please point out what I'm doing wrong and explain how to fix it?
Thanks.

function getStartPosTop()
{
//return 250; // works, but it's hard-coded.

var num;
var obj = document.getElementById('btn'); // can't I use this element
as an object?
num = obj.style.top + 150; // put the graphic 150 px below the btn
to push.
//num = obj.offsetTop + 150;
//num = obj.style.top;
//num = obj.offsetTop;
//num = obj.style.offsetTop;
//num = findPosY(obj);
return num;
}

function findPosY(obj)
{
var curtop = 0;
if(obj.offsetParent)
while(1)
{
curtop += obj.offsetTop;
if(!obj.offsetParent)
break;
obj = obj.offsetParent;
}
else if(obj.y)
curtop += obj.y;
return curtop;
}
 
S

Sister Ray

   var num;
   var obj = document.getElementById('btn');    // can't I use this element
as an object?
   num = obj.style.top + 150;        // put the graphic 150px below the btn

the obj.style.top returns a string that ending with "px", when you add
a number to it, that number will parsed to string before adding.
 
Y

Ynot

the obj.style.top returns a string that ending with "px", when you add
a number to it, that number will parsed to string before adding.

Thanks. When I wrote code to parse out the "px" from the string to add the
numbers together, I still received an error. When I tested the string, I
found obj.style.top is a zero-length string. Any idea what is causing this?

Thanks.
 
G

Gregor Kofler

Ynot meinte:
Thanks. When I wrote code to parse out the "px" from the string to add the
numbers together, I still received an error. When I tested the string, I
found obj.style.top is a zero-length string. Any idea what is causing this?

Thanks.

The position was never set before either by assigning a value to
element.style.top or setting top with CSS. The "real" position can be
obtained by retrieving element.offsetTop and iterating through its
offsetParent elements.

Gregor
 
Y

Ynot

The position was never set before either by assigning
a value to
element.style.top or setting top with CSS. The "real" position can be
obtained by retrieving element.offsetTop and iterating through its
offsetParent elements.

Thanks. Got it working now.
 
G

Garrett Smith

Gregor said:
Ynot meinte:

The position was never set before either by assigning a value to
element.style.top or setting top with CSS. The "real" position can be
obtained by retrieving element.offsetTop and iterating through its
offsetParent elements.

Ah, if only that really worked.

offsetTop:
| Retrieves the calculated top position of the object relative to the
| layout or coordinate parent, as specified by the offsetParent
| property.

offsetParent:
| offsetParent Property
|
| Retrieves a reference to the container object that defines the
| offsetTop and offsetLeft properties of the object.

Chicken and the egg.

Since a "layout or coordinate parent" is not defined, we can't really be
certain what the offsetTop is measured from.

There are many inconsistencies and offsetTop is not generally reliable.

Capability tests can determine what offsetTop returns in different
scenarios.

The border-top-width of the offsetParent must also be added. This is
exposed as "clientTop" in IE, where currentStyle.borderTop might be
"auto". There is also a clientLeft property, but no clientRight or
clientBottom.

Method getBoundingClientRect is less trouble, where supported.

Garrett
 
D

David Mark

Ah, if only that really worked.

offsetTop:
| Retrieves the calculated top position of the object relative to the
| layout or coordinate parent, as specified by the offsetParent
| property.

offsetParent:
| offsetParent Property
|
| Retrieves a reference to the container object that defines the
| offsetTop and offsetLeft properties of the object.

Chicken and the egg.

Since a "layout or coordinate parent" is not defined, we can't really be
certain what the offsetTop is measured from.

There are many inconsistencies and offsetTop is not generally reliable.

Capability tests can determine what offsetTop returns in different
scenarios.

The border-top-width of the offsetParent must also be added. This is
exposed as "clientTop" in IE, where currentStyle.borderTop might be
"auto". There is also a clientLeft property, but no clientRight or
clientBottom.

Method getBoundingClientRect is less trouble, where supported.

The answer is to measure only as far as a positioned ancestor. Leave
borders out of it and the solution reduces to one or two lines. If
your containing elements may have borders, there is a trivial feature
test for that. Anything that attempts to measure from the tip of the
documentElement is folly in comparison.
 
A

Aaron Watters

HEY! I'm interested in this problem too...

The answer is to measure only as far as a positioned ancestor.  Leave
borders out of it and the solution reduces to one or two lines.  If
your containing elements may have borders, there is a trivial feature
test for that.  Anything that attempts to measure from the tip of the
documentElement is folly in comparison.

Sounds great! Do you have any pointers to a good
function implementation that does that?

Thanks, Aaron Watters
http://aaron.oirt.rutgers.edu/myapp/docs/W1500.whyIsWhiffCool

===
less is more
 
D

David Mark

HEY! I'm interested in this problem too...



Sounds great!  Do you have any pointers to a good
function implementation that does that?

That does what exactly? I am guessing you envision a scenario where
you will have an element with a positioned ancestor and you want to
add up offsetLeft/Top properties, starting with the former and ending
at the latter. Some or all of these elements may have borders
(something you can easily design out of the system.) Do you need help
with the loop or the feature test for borders? The function should
look something like:

function elementOffsets(el, elAncestor) {
...
}

Of course, you won't need a loop in cases where the element is a child
of its positioned ancestor. In that case, barring borders, the
offsetLeft/Top properties suffice. Now there is a case to shoot for
at the design stage.

In contrast, the popular alternative of measuring everything from the
document "origin" and adjusting for every known variation and browser
quirk is clearly something to avoid at the design stage.

http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/9ba20706f3b3fc73#

Trying to solve every conceivable problem for every conceivable case
is an inconceivable waste of time (not to mention space.) Hard to
understand why neophytes who can't deal with the problems on their own
plate would try to solve similar issues for everybody else. The
phenomenon is not relegated solely to browser scripting, it is just
the worst sort of discipline to withstand such hubris.
 
A

Andrew Poulos

David said:
The answer is to measure only as far as a positioned ancestor. Leave
borders out of it and the solution reduces to one or two lines. If
your containing elements may have borders, there is a trivial feature
test for that. Anything that attempts to measure from the tip of the
documentElement is folly in comparison.

How do you test whether or not a browser has included borders in its
calculations?

Andrew Poulos
 
D

David Mark

How do you test whether or not a browser has included borders in its
calculations?

Well, you will need to create two DIV's.

var el = document.createElement('div');
var elContainer = document.createElement('div');

Position them both absolutely.

el.style.position = elContainer.style.position = 'absolute';

Position both at (0, 0):

el.style.left = elContainer.style.left = '0';
el.style.top = elContainer.style.top = '0';

Clear margins:

el.style.margin = elContainer.style.margin = '0';

Give one a border:

elContainer.style.border = 'solid 1px';

Append one to the other.

elContainer.appendChild(el);

Append the container to the body:

document.body.appendChild(elContainer);

Before proceeding, ensure that the offset* properties are featured as
expected.

if (typeof el.offsetTop == 'number') {

(I'm sure you can figure out what to check at this point.)

Remove the temporary element. It won't have been rendered at this
point and it is best to keep it that way. Call a function during this
process and it will render, which requires setting its visibility to
hidden.

document.body.removeChild(elContainer);

Also, it never hurts (and may help) to discard objects when finished:

el = elContainer = null;

There is a version of this in my library, as well as a less
generalized implementation in an earlier popup menu script that was
posted here in 2007. There is also a nearly identical homage (in
somewhat less proficient script) in the new jQuery:

rules = { position: 'absolute', top: 0, left: 0, margin: 0, border:
0, width: '1px', height: '1px', visibility: 'hidden' };
for ( prop in rules ) container.style[prop] = rules[prop];

container.innerHTML = html;
body.insertBefore(container, body.firstChild);
innerDiv = container.firstChild, checkDiv = innerDiv.firstChild, td =
innerDiv.nextSibling.firstChild.firstChild;

this.doesNotAddBorder = (checkDiv.offsetTop !== 5);

Creates an extraneous DIV, adds dimensions to the container and
inexplicably uses insertBefore rather than appendChild. And, of
course, it bets everything on the unpredictable and non-standard
innerHTML property. (!) I did something similar with the style
assignments, but I am sure the for-in loop was *filtered*.

Their pre-epiphany version(s) use $.browser.opera or some such
nonsense. I guess we know where they go for epiphanies.
Unfortunately, they botched the translation again.
 
A

Andrew Poulos

David said:
Well, you will need to create two DIV's.

var el = document.createElement('div');
var elContainer = document.createElement('div');

Position them both absolutely.

el.style.position = elContainer.style.position = 'absolute';

Position both at (0, 0):

el.style.left = elContainer.style.left = '0';
el.style.top = elContainer.style.top = '0';

Clear margins:

el.style.margin = elContainer.style.margin = '0';

Give one a border:

elContainer.style.border = 'solid 1px';

Append one to the other.

elContainer.appendChild(el);

Append the container to the body:

document.body.appendChild(elContainer);

Before proceeding, ensure that the offset* properties are featured as
expected.

if (typeof el.offsetTop == 'number') {

(I'm sure you can figure out what to check at this point.)

This is one of things that is obvious, once I've seen it. Thanks.

Andrew Poulos
 
G

Gregor Kofler

Garrett Smith meinte:
Gregor Kofler wrote:

Ah, if only that really worked.

[snip]

Agreed. I had rather focused onto the "issue" that element.style.top is
empty.

Gregor
 
Y

Ynot

SAM said:
And ... may we see it ?

Good idea. I'll clean up the code and post it on my friend's new site I'm
building these apps for, then post a link to it here. Might take a week or
more. My friend is still negotiating a price for the domain name. The
owner has been squatting on it for 11 years and never built a site. I think
she's never sold it because she wants too much money.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top