Email conversation
From | Philip Juel Borges |
To | Me |
Subject | Detecting My Position. |
Date | 4 July 2009 15:07 |
Hi!
I've looked in your mails and sample code of Static Logo and maybe you can
help me.
I have an html document that contain many paragraphs. Each paragraph is
nested within a div like so, <div id="vs23">Lorum ipsumLorum ipsum</div>.
The 'id' can range from 1-50.
What I would like is, as I scroll down the page a popup box displays, like
the one from Static Logo, a message telling me where I am. Like, "Verse 23".
So the javascript should be able to detect which div tag I'm presently at
and then show the popup box.
I hope this is clear enough. Thank you for your help.
/Philip
From | Me |
To | Philip Juel Borges |
Subject | Re: Detecting My Position. |
Date | 8 July 2009 09:29 |
Attachment | working example |
Philip,
> What I would like is, as I scroll down the page a popup box displays, like
the one from Static Logo, a message telling me where I am.
First, detect the scroll event. If your script is the only one using it,
just use:
window.onscroll = functionThatSetsPosition;
If other scripts are also going to want to detect that event, you can use
DOM events instead - it behaves like the load event in terms of what objects
detect it, so see the section called 'Detecting the load event' near the
bottom:
http://www.howtocreate.co.uk/tutorials/javascript/domevents
If you need to support browsers that do not support the onscroll event, use
an interval timer instead:
http://www.howtocreate.co.uk/tutorials/javascript/timers
You should also call that handler function onload, as the page may be
initially scrolled by some offset after a reload or if a fragment identifier
is used.
Now, on to the function itself. Firstly, it needs to work out how far the
page has been scrolled, which can be done using the function shown here:
http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
var scrolledFromTop = getScrollXY()[1];
Then it needs to loop through all those elements with the IDs you mentioned
- the easiest way is to use a 'for' loop that simply keeps counting until it
either finds the one that is at the top of the page, or fails to locate a
div.
var topposition, lastone, offsetFromTop, currentverse;
for(var i = 1, onediv; onediv = document.getElementById('vs'+i); i++) {
...
}
In the loop, work out the position of 'onediv' - use the simple findPosition
function from here:
http://www.howtocreate.co.uk/tutorials/javascript/browserspecific
topposition = findPosition(onediv)[1];
Simply subtract the scrolledFromTop from the topposition to get the offset
from the top of the page.
offsetFromTop = topposition - scrolledFromTop;
Then decide if it is the one at the 'top'. This is a little hard to
quantify, since it could be scrolled partly out of view of the top, but
still be the one taking most of the view at the top of the page. It could
also be a certain amount (20 pixels, for example, but you should tweak this
to suit your page) down from the top of the page, while still being the one
you would consider is at the top of the page. For this reason, you can't
work out if the current element is at the 'top' of the page until you have
checked the next one to work out if that one is at the 'top' instead -
that's what the lastone variable was for. There is also the special case
that the first verse will be the one at the 'top' even when it is pushed a
long way down the page by the content before the first verse.
Something like this:
if( i == 1 && offsetFromTop >= 0 ) {
//special case for the first verse - any non-negative offset
currentverse = i;
break; //don't waste time checking any more
}
if( offsetFromTop >= 0 && offsetFromTop <= 20 ) {
//within 20 pixels of the top - this is the right one
//this part is actually redundant, it will pick it up next loop
currentverse = i;
break; //don't waste time checking any more
}
if( offsetFromTop > 20 ) {
//over 20 pixels from the top - the last one should be called 'top'
currentverse = lastone;
break; //don't waste time checking any more
}
//store this as the last one for checking afterwards
lastone = i;
After the 'for' loop, it should then check if it has stepped off the end,
and if so, assume the 'lastone' is the current one.
if( !currentverse ) {
currentverse = lastone;
}
if( !currentverse ) {
//didn't find any verses on this page...
return;
}
So now currentverse holds the number of the verse that is currently at the
top of the page. You can then use DHTML/DOM to rewrite the contents of a div
to say what verse is at the top:
http://www.howtocreate.co.uk/tutorials/javascript/dhtml
http://www.howtocreate.co.uk/tutorials/javascript/dombasics
document.getElementById('sayverse').innerHTML = 'Verse '+currentverse;
If you make that div used position:fixed; with top:0; it will always appear
at the top of the page. If you need to support IE 6 (best to ignore it
unless you really *need* to support it), use regular position:absolute and
after writing the innerHTML, use this:
document.getElementById('sayverse').style.top = scrolledFromTop+'px';
Best to keep that div at the start of the page markup to make sure the
script will be able to find the 'sayverse' div if it scrolls before it has
fully loaded.
That should do it. I have attached a working example.
Mark 'Tarquin' Wilton-Jones - author of http://www.howtocreate.co.uk/
From | Philip Juel Borges |
To | Me |
Subject | Re: Detecting My Position. |
Date | 16 July 2009 12:27 |
> That should do it. I have attached a working example.
Hi Mark. Thanks for your mail. I've just returned from holiday so that's why
I haven't replied. I'm looking it over now, but the working example (Pushing
it down) is just text in my email (I'm using [brand] on my mac). Could you
attach it as file?
Thanks, Philip
From | Me |
To | Philip Juel Borges |
Subject | Re: Detecting My Position. |
Date | 27 July 2009 17:45 |
Philip,
> the working example (Pushing it down) is just text in my email
Your email client is broken, or there is some setting in your client (or
mail service provider) that converts it to text.
> Could you attach it as file?
I did. It's also here so you can see it over HTTP:
http://www.howtocreate.co.uk/emails/topelement.html
Tarquin
From | Philip Juel Borges |
To | Me |
Subject | Re: Detecting My Position. |
Date | 28 July 2009 17:46 |
> Your email client is broken
Weird. Anyway, I got it through the link. And thanks a million for your
help. It looks awesome and does what I was looking for. To expand on this
script, how would you make it so that the box only becomes visible when you
scroll and hide when you stop?
I'm thinking perhaps <body onScroll="function()"> could be a way.
/Philip
From | Me |
To | Philip Juel Borges |
Subject | Re: Detecting My Position. |
Date | 3 August 2009 08:33 |
Philip,
> One last thing: do you know if it possible to display the box only when
> you move the scrollbar?
JavaScript doesn't really know the difference between all of the
different methods of scrolling; scrollbar, arrow/page keys, mousewheel,
mouse panning, grab and scroll, voice commands, gestures, external UI,
mousepad scrollbars, etc.
Some browsers have events that can detect the mousewheel, but that is a
separate event and not part of the scroll event. The scroll event (which
the script uses) knows nothing about what caused the scrolling. It would
be possible to detect keypresses (or keydown) and use the keyCode of
those to determine if the key was an arrow/page key, but since those
events fire in a way that is not tied to the scroll event, you would
need to store something that says 'the user just pressed an arrow key',
and then if a scroll happens within a certain timeout after that, ignore
the scroll event and do not show the div.
That's all getting very complicated and really messy, for what is best
kept as a fairly simple script.
Tarquin
From | Philip Juel Borges |
To | Me |
Subject | Re: Detecting My Position. |
Date | 3 August 2009 20:05 |
Thanks Tarquin. I'll take a look at it and see if I can get it to work.
Thanks again for your help. Really appreciate it. :-)
Philip
From | Philip Juel Borges |
To | Me |
Subject | Re: Detecting My Position. |
Date | 6 August 2009 09:34 |
That worked like a charm! Your description was very easy to follow. Thanks a
lot! :-)
One last thing: do you know if it possible to display the box only when you
move the scrollbar?
Presently the box also appears when I press either the up or down key.
Philip
From | Me |
To | Philip Juel Borges |
Subject | Re: Detecting My Position. |
Date | 9 August 2009 08:33 |
Philip,
> One last thing: do you know if it possible to display the box only when
> you move the scrollbar?
JavaScript doesn't really know the difference between all of the
different methods of scrolling; scrollbar, arrow/page keys, mousewheel,
mouse panning, grab and scroll, voice commands, gestures, external UI,
mousepad scrollbars, etc.
Some browsers have events that can detect the mousewheel, but that is a
separate event and not part of the scroll event. The scroll event (which
the script uses) knows nothing about what caused the scrolling. It would
be possible to detect keypresses (or keydown) and use the keyCode of
those to determine if the key was an arrow/page key, but since those
events fire in a way that is not tied to the scroll event, you would
need to store something that says 'the user just pressed an arrow key',
and then if a scroll happens within a certain timeout after that, ignore
the scroll event and do not show the div.
That's all getting very complicated and really messy, for what is best
kept as a fairly simple script.
Tarquin
From | Philip Juel Borges |
To | Me |
Subject | Scroll Detection. |
Date | 27 August 2009 20:36 |
Hi Tarquin,
I've run into some problems with the script you sent provided for me, and
have been fiddling with it.
The script requires that I always start at number 1, but the starting number
varies. So, one html-file has a starting point at 4 and different html-file
starts at 798.
I didn't think this would cause a problem yet it did. Thanks for your help.
:-)
/Philip
P.S.: here's the link to the page,
http://www.howtocreate.co.uk/emails/topelement.html
From | Me |
To | Philip Juel Borges |
Subject | Re: Scroll Detection. |
Date | 13 September 2009 15:40 |
Philip,
> The script requires that I always start at number 1, but the starting
> number varies. So, one html-file has a starting point at 4 and different
> html-file starts at 798.
Since it cannot count forever (infinite script loops cause scripts to lock
up), the script keeps counting up until it fails to find the verse
corresponding to that number. On a page that does not start at 1, it fails
to find the first one, so it stops immediately.
If you need pages to start at numbers greater than 1, you will need to tell
the script what number to start at, so it knows where to find the first one.
You could just create a variable on each page that uses the script, and use
that to say what the first number should be:
var firstVerse = 798;
Then modify the script to use it. Change this:
for(var i = 1, onediv...
to this:
for(var i = firstVerse, onediv...
And then change this:
if( i == 1 && offsetFromTop >= 0 ) {
to this:
if( i == firstVerse && offsetFromTop >= 0 ) {
That should do it. It does mean that you have to manually set the start
index, but that's the simplest and most efficient way to do it. An
alternative would be a more significant modification that tells it to keep
looking until it finds the first one (with a maximum number that you allow
it to count to, just in case it never finds any verses and locks up), and
then keep going from that point onwards.
This can be done by (instead of defining firstVerse on every page), changing
this:
var topposition, lastone, offsetFromTop, currentverse;
to this (the number 10000 is the highest verse number that a page can start
at, plus 1):
var topposition, lastone, offsetFromTop, currentverse, firstVerse = 1;
while(!document.getElementById('vs'+firstVerse) && firstVerse < 10000) {
firstVerse++;
}
You will also need those two changes that tell the script to use the
firstVerse number, shown above.
I have updated the online demo (still at the same URL) to use this.
Tarquin
From | Philip Juel Borges |
To | Me |
Subject | Scroll Detection. |
Date | 14 September 2009 07:57 |
Thanks Tarquin!
That worked perfectly! What would really make it great is to make it able to
display the box only when you use the scrollbar to scroll and not when you
press the up or down key. Anyway, it works great and I think it's a nice way
to navigate in a document. At least for my needs.
Thanks again!
--Philip