Get Scrollbar Position

J

Jeff Johnson

Hi All,

I'm setting a <div> on a page on a lengthy page with a great deal of
text. I want the div to land where the user can see it. I need to
capture the vertical scrollbar position and use that integer to set
the 'Y' coordinate for the div.

Can this be done? If so, how?

If not, any other suggestions?

Thanks,

Jeff
 
D

DJ WIce

: I'm setting a <div> on a page on a lengthy page with a great deal of
: text. I want the div to land where the user can see it. I need to
: capture the vertical scrollbar position and use that integer to set
: the 'Y' coordinate for the div.

let x, y be the mouse position.
let zoom_factor be the % in MSIE that the body content is zoomed
(
document.body.style.setAttribute('zoom', zoom_factor+'%');
).
let 'contextmenu' be the ID of your DIV.

xOff = parseInt(document.getElementById('contenxtmenu').style.width) -
(document.all?document.body.scrollLeft:window.pageXOffset);
yOff = parseInt(document.getElementById('contenxtmenu').style.height) -
(document.all?document.body.scrollTop:window.pageYOffset);
document.getElementById("contenxtmenu").style.top =
Math.min(parseInt(y/zoom_factor*100),document.body.clientHeight-yOff)+"px";;
document.getElementById("contenxtmenu").style.left =
Math.min(parseInt(x/zoom_factor*100),document.body.clientWidth-xOff)+"px";


Then your div will be placed next to the mouse, but always fully on screen.
If you don't zoom and don't mind the mouse; replace y/zoom_factor*100
and x/zoom_factor*100 by the prefered y and x location of your
<div> on your page.

Wouter
 
D

DU

DJ said:
: I'm setting a <div> on a page on a lengthy page with a great deal of
: text. I want the div to land where the user can see it. I need to
: capture the vertical scrollbar position and use that integer to set
: the 'Y' coordinate for the div.

let x, y be the mouse position.
let zoom_factor be the % in MSIE that the body content is zoomed
(
document.body.style.setAttribute('zoom', zoom_factor+'%');

zoom is only supported by MSIE 5.5 and MSIE 6.
).
let 'contextmenu' be the ID of your DIV.

xOff = parseInt(document.getElementById('contenxtmenu').style.width) -
(document.all?document.body.scrollLeft:window.pageXOffset);

As written, you will only support backward compatible rendering mode in
MSIE 6 where the root element is not the body. Your script might be
interesting but it has limited scope/support among current browsers.

DU
 
D

DJ WIce

: As written, you will only support backward compatible rendering mode in
: MSIE 6 where the root element is not the body. Your script might be
: interesting but it has limited scope/support among current browsers.
Well, it's tested in Mozilla 1.3 and MSIE 5+ ...
And also om NN 7 and MSIE 6
(see http://www.djwice.com/contextmenu.html )

The zoom_factor value is default set to 100, so when the zoom function is
not implemented, it will not be changed, and the position values stay
(nearly) unchanged.

Wouter
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
news:comp.lang.javascript said:
: I'm setting a <div> on a page on a lengthy page with a great deal of
: text. I want the div to land where the user can see it. I need to
: capture the vertical scrollbar position and use that integer to set
: the 'Y' coordinate for the div.

Eschew non-standard quotemarks.

xOff = parseInt(document.getElementById('contenxtmenu').style.width) -
(document.all?document.body.scrollLeft:window.pageXOffset);
yOff = parseInt(document.getElementById('contenxtmenu').style.height) -
(document.all?document.body.scrollTop:window.pageYOffset);
document.getElementById("contenxtmenu").style.top =
Math.min(parseInt(y/zoom_factor*100),document.body.clientHeight-yOff)+"px";;
document.getElementById("contenxtmenu").style.left =
Math.min(parseInt(x/zoom_factor*100),document.body.clientWidth-xOff)+"px";


ISTM that the FAQ should have something on when parseInt should not be
used.

AFAICS, the first two superfluously call for conversion to Number (the
subtraction does that, if it is needed); and the second two should be
Math.floor.

AFAICS, I've only once found a case where parseInt is worthwhile, other
than where the base is a variable :

var T = parseInt(new Date(2e9).toLocaleString()) // ~ 1970-01-24
T = T<9 ? "US" : T>99 ? "ISO" : "UK" // US MDY, UK DMY, ISO YMD
 
R

Richard Cornford

ISTM that the FAQ should have something on when parseInt
should not be used.

AFAICS, the first two superfluously call for conversion to
Number (the subtraction does that, if it is needed); and the
second two should be Math.floor.
<snip>

:) Done. The notes I wrote for section 4.21 (actually a more general
discussion of type-converting with JavaScript) currently include the
paragraph:-

|parseInt is occasionally used as a means of turning a
|floating point number into an integer. It is very ill suited
|to that task because if its argument is of numeric type it
|will first be converted into a string and then parsed as a
|number, very inefficient. This can produce very wrong
|results with numbers such as 2e-200, for which the nearest
|integer is zero, but with which parseInt returns 2. For
|rounding numbers to integers one of Math.round, Math.ceil
|and Math.floor are preferable, and for a desired result
|that can be expressed as a 32 bit signed integer the
|bitwise operation described below might also suite.

(There are additional notes on how the parsing is done, etc. in the
section on parseFloat)

The bitwise operation mentioned is OR zero. Which truncates floating
point numbers to integers but might be well suited to the situation in
the preceding posted code as the output is expected to be screen
co-ordinates so a result restricted to a 32 bit signed integer would be
expected anyway and it is quicker to execute than Math.floor.

Richard.
 
D

DJ WIce

: >: the 'Y' coordinate for the div.
: Eschew non-standard quotemarks.
Ah? It's better to use " in JavaScript?

: > xOff = parseInt(document.getElementById('contenxtmenu').style.width) -
: >(document.all?document.body.scrollLeft:window.pageXOffset);
: AFAICS, the first two superfluously call for conversion to Number (the
: subtraction does that, if it is needed);
I did not know that the substraction would eliminate the px behind the
width and convert it to a number. Thanks.

: > document.getElementById("contenxtmenu").style.left =
:
Math.min(parseInt(x/zoom_factor*100),document.body.clientWidth-xOff)+"px";
: and the second two should be
: Math.floor.
Yeah, I was looking for trunc or something, but floor == trunc :)

Strangely I never saw Number before, parseInt is more common used so it
seems.
Is Number implemented later in the JavaScript interpreter? Or is it just not
the right function name why it's not that much used?
I mean wat Number? I first though it generate a random number.


Thanks,
Wouter
 
D

DJ WIce

: > xOff = parseInt(document.getElementById('contenxtmenu').style.width) -
: >(document.all?document.body.scrollLeft:window.pageXOffset);
: > yOff = parseInt(document.getElementById('contenxtmenu').style.height) -
: >(document.all?document.body.scrollTop:window.pageYOffset);

: AFAICS, the first two superfluously call for conversion to Number (the
: subtraction does that, if it is needed);

Sorry, I have to tell you it's not true for MSIE 6.028, XP:

When I remove parseInt in the above lines it assigns NaN to xOff and yOff.
When I replace parseInt in the above lines with Number the same happens.

Wouter
 
D

DU

DJ said:
: As written, you will only support backward compatible rendering mode in
: MSIE 6 where the root element is not the body. Your script might be
: interesting but it has limited scope/support among current browsers.
Well, it's tested in Mozilla 1.3 and MSIE 5+ ...
And also om NN 7 and MSIE 6
(see http://www.djwice.com/contextmenu.html )

The zoom_factor value is default set to 100, so when the zoom function is
not implemented, it will not be changed, and the position values stay
(nearly) unchanged.

Wouter

I'm still convinced your script for zooming could be better. As coded,
it will not support MSIE 6 for windows in standards compliant rendering
mode. When you go:

xOff = parseInt(document.getElementById('contenxtmenu').style.width) -
(document.all?document.body.scrollLeft:window.pageXOffset);

then you are not off since the root element is not the body element but
the html element in standards compliant rendering mode for MSIE 6.

Anyway, I failed to see why you would or should need to know the zooming
factor of the document. The scrolled portion of the document can be
gotten reliably with cross-browser code without any reference to the
text zoom.

DU
 
D

DJ WIce

: I'm still convinced your script for zooming could be better. As coded,
: it will not support MSIE 6 for windows in standards compliant rendering
: mode. When you go:

Ah, sorry I did not understand you.
I tought you said the code does not work.
I see you mean that the code for MSIE 6 can be optimized so it will be
interpreted faster, am I right?

So document.scrollLeft when it's MSIE6 and else document.body.scrollLeft
when it's lower?
Sorry I'm very new to differant types of rendering;
"standards compiliant rendereing" as oposite of .. rendering ?

: Anyway, I failed to see why you would or should need to know the zooming
: factor of the document. The scrolled portion of the document can be
: gotten reliably with cross-browser code without any reference to the
: text zoom.
Because I want to place the menu under the mouse cursor position (x, y in my
code).
The mouse cursor position in MSIE 6 is returned as value of the 100% mode,
even if it's in 150% zoomed mode.
So one needs to correct that to let the menu show up close to the cursor if
it's on the righthand side of the document.
(the error on the lefthand side is not very big of cause).

Wouter
 
D

DJ WIce

: I'm still convinced your script for zooming could be better. As coded,
: it will not support MSIE 6 for windows in standards compliant rendering
: mode. When you go:
:
: xOff = parseInt(document.getElementById('contenxtmenu').style.width) -
: (document.all?document.body.scrollLeft:window.pageXOffset);

So it should be like this (?):

xOff = parseInt(document.getElementById('contenxtmenu').style.width) -
document.documentElement?document.documentElement.scrollLeft:(document.all?d
ocument.body.scrollLeft:window.pageXOffset);

Or will that still triger the compilent mode?
But will MSIE 6 then return 0 if it's in non strict mode?
Where can I read about degenerated elements, so I can optimize the code?

Thanks,
Wouter
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
Richard Cornford
The bitwise operation mentioned is OR zero. Which truncates floating
point numbers to integers but might be well suited to the situation in
the preceding posted code as the output is expected to be screen
co-ordinates so a result restricted to a 32 bit signed integer would be
expected anyway and it is quicker to execute than Math.floor.

After checking, note that OR truncates towards zero and Math.floor
towards minus infinity.


A list of "Maths Tricks" might be useful, including such as
n = n & (n-1)
which I think clears the least 1 bit, and can be looped for one-bit-
counting. And, of course, the "default" operator.


I'd not seen that DJW's .style.width had a trailing px.
ISTM that there's probably nothing better than parseInt.

Is it guaranteed that the numeric part has no leading zero, even if
there is a leading zero in the source file?


ISTM that you've probably done enough already, by a large margin, to
justify a new release of the FAQ proper with an added note simply
linking to your own index of the relevant branch of your WWW site tree;
or to post such a note as a weekly FU to the FAQ.
 
R

Richard Cornford

After checking, note that OR truncates towards zero and
Math.floor towards minus infinity.

Yes that distinction does need to be noted, but positioning co-ordinates
will tend to be >= zero as well as restricted to the 32 bit range so the
bitwise operation seems well suited to that task.
A list of "Maths Tricks" might be useful, including such as
n = n & (n-1)
which I think clears the least 1 bit, and can be looped for
one-bit-counting. And, of course, the "default" operator.

I like that idea, there isn't really a context to put that type of
information into yet but there could be.
I'd not seen that DJW's .style.width had a trailing px.
ISTM that there's probably nothing better than parseInt.

For a width property on a style object there probably isn't, but an
interest in the display dimensions of an element might be better
initially directed at the offsetWidth/Height properties of the element
itself (where supported), which is a numeric pixel value to start with.
Is it guaranteed that the numeric part has no leading zero,
even if there is a leading zero in the source file?

A quick experiment with IE 6 has setting a style.width to "021px"
returning "21px" when read, but I doubt that it could be guaranteed that
values assigned as strings would be normalised and stripped of
superfluous leading zeros. I would be surprised to see leading zeros
added to the string read from a style property (at least for
non-floating point (e.g. with em units) values).

OTOH if parseInt is going to be used for this task it probably should
still be provided with the radix argument as even if the string can
reasonably be expected to be in an unambiguous decimal format it should
still be quicker to execute the function when it doesn't have to
consider interpreting the string with any other radix. It doesn't save
much work if it is the ECMAScript algorithm that is implemented but it
will still be able to skip a couple of steps.
ISTM that you've probably done enough already, by a large
margin, to justify a new release of the FAQ proper with an
added note simply linking to your own index of the relevant
branch of your WWW site tree; or to post such a note as a
weekly FU to the FAQ.

It is certainly getting close, though a new version should be presented
to the group for comment prior to updating the FAQ itself. And the notes
will be going on Jim's server in the long term.

Richard.
 
D

DJ WIce

: OTOH if parseInt is going to be used for this task it probably should
: still be provided with the radix argument as even if the string can
: reasonably be expected to be in an unambiguous decimal format it should
: still be quicker to execute the function when it doesn't have to
: consider interpreting the string with any other radix. It doesn't save
: much work if it is the ECMAScript algorithm that is implemented but it
: will still be able to skip a couple of steps.

So I should use:

parseInt(document.getElementById('contenxtmenu').style.width,10) ?

I think if I would implement ParseInt that I would by default compile the
first argument as a 10-base number. So giving a second argument and setting
it to 10-base would then result in more checks.
(I did not yet test the speed differance).

Wouter
 
D

DJ WIce

: OTOH if parseInt is going to be used for this task it probably should
: still be provided with the radix argument as even if the string can
: reasonably be expected to be in an unambiguous decimal format it should
: still be quicker to execute the function when it doesn't have to
: consider interpreting the string with any other radix. It doesn't save
: much work if it is the ECMAScript algorithm that is implemented but it
: will still be able to skip a couple of steps.

According to
http://www.devguru.com/Technologies/ecmascript/quickref/parseint.html
<quote>If no radix argument is provided or if it is assigned a value of 0,
the function tries to determine the base. If the string starts with a 1-9,
it will be parsed as base 10. If the string starts with 0x or 0X it will be
parsed as a hexidecimal number. If the string starts with a 0 it will be
parsed as an octal number. (Note that just because a number starts with a
zero, it does not mean that it is really octal.)<quote>

The result will be 10-base. So I see parseInt is a nice function to convert
from base x to base 10. (if above stated is true in all browsers of cause)
:)

Wouter
 
R

Richard Cornford

According to
http://www.devguru.com/Technologies/ecmascript/quickref/parseint.html
<quote>If no radix argument is provided or if it is assigned a
value of 0, the function tries to determine the base. If the
string starts with a 1-9, it will be parsed as base 10. If the
string starts with 0x or 0X it will be parsed as a hexidecimal
number. If the string starts with a 0 it will be parsed as an
octal number. (Note that just because a number starts with a
zero, it does not mean that it is really octal.)<quote>

The result will be 10-base.

The result will depend entirely on the arguments used with parseInt, but
it will be a number.
So I see parseInt is a nice function to convert from base x to
base 10.

With JavaScript having only one number type and that being an IEEE
double precision floating point number, there is no meaningful concept
of converting between bases. The numbers are stored as 64 bits, in
binary.

parseInt is useful as a means of reading numeric values stored as
strings in various base formats and returning numeric values from them.
(if above stated is true in all browsers of cause)

ECMA 262 formalised pre-existing behaviour for parseInt so
implementations can be expected to be consistent (but only with the ECMA
262 algorithm).

Richard.
 
R

Richard Cornford

So I should use:

parseInt(document.getElementById('contenxtmenu').style.width,10) ?

Probably. Though repetitively reading/parsing a value that will not
change unless you actively re-set it is wasteful in itself. As is
re-resolving the object reference whenever it is used.
I think if I would implement ParseInt that I would by default
compile the first argument as a 10-base number.

I think if I were implementing parseInt I would be attempting to fulfil
the requirements of ECMA 262. There is not much point inventing a new
scripting language for use in a context where a well-standardised
language already exists and is in common use.
So giving a second argument and setting
it to 10-base would then result in more checks.
(I did not yet test the speed differance).

The behaviour of any new scripting language you decide to implement is
OT here.

Richard.
 
D

DJ WIce

: >parseInt(document.getElementById('contenxtmenu').style.width,10) ?
:
: Probably. Though repetitively reading/parsing a value that will not
: change unless you actively re-set it is wasteful in itself. As is
: re-resolving the object reference whenever it is used.

Oh.. if I do understand you correct:

var MenuObject = document.getElementById('contenxtmenu');
xOff = parseInt(MenuObject.style.width,10) -
(document.all?document.body.scrollLeft:window.pageXOffset);
yOff = parseInt(MenuObject.style.height,10) -
(document.all?document.body.scrollTop:window.pageYOffset);
MenuObject.style.top =
Math.min(Math.floor(y/zoom_factor*100),document.body.clientHeight-yOff)+"px"
;;
MenuObject.style.left =
Math.min(Math.floor(x/zoom_factor*100),document.body.clientWidth-xOff)+"px";

Will be faster then without replacing
document.getElementById('contenxtmenu')
by
MenuObject
?

Does the same hold for
document.getElementById('contenxtmenu').style
?

Because that's the only object I'll use of the
document.getElementById('contenxtmenu') element.

And is it smart to replace:
document.body.scrollLeft
by
document.body.scrollLeft + document.documentElement.scrollLeft
?


Thanks!
Wouter
 
J

Jim Ley

parseInt(document.getElementById('contenxtmenu').style.width,10) ?

Nope, 100% 10em 33px or ...

I'd pick something a little safer :) Of course that's a lot more
complicated.

Also watch out for user stylesheets overriding your contenxtmenu's
width.

Jim.
 
D

DJ WIce

: >parseInt(document.getElementById('contenxtmenu').style.width,10) ?
:
: Nope, 100% 10em 33px or ...
:
: I'd pick something a little safer :) Of course that's a lot more
: complicated.

How can I convert a 100% to pixels for example (and the same question for em
to px, ect.)?

Wouter
 

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,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top