...

View Full Version : one last button toggling question



xelawho
12-15-2010, 09:25 PM
Hi,

I have two excellent pieces of code (thanks Old Pedant and jmrker) that I am trying to get to talk to each other. Basically I want to achieve the same button effect as here (http://www.xelawho.com/map/moving5.htm)

but with a group of buttons that get produced from xml via innerhtml.

here's the code I'm using to create the buttons:

sidebar_html += '<div id="category"><input type="checkbox" id="'+category+'" onclick="boxclick(this,\''+category+'\',\''+poly_num+'\');"></div><div id="label">' + label + '</div><div id="bus"><button onclick="startCar(this,' + poly_num + ')" style="height:24px; width:30px"> <img id=this,"pauseBtn" src="play2.png" ></button></div><br>';

and here's the code that attempts to toggle them between the play and pause symbol:


function startCar(btn,pnum,poly_num){
if (this.wasRun)
{
btnAction();
} else {
if( !this.wasRun )

toggleRun(btn, pnum);
btnAction();
this.wasRun = true;
}
}

function toggleRun(btn, pnum){
var inps = document.getElementsByTagName("input");
for ( var i = 0; i < inps.length; ++i ) {
var inp = inps[i];
if ( inp.value = "play2.png" ) inp.value = "pause2.png";
}
startAnimation(pnum);
}

function btnAction() {
var currentBtn = document.getElementById('pauseBtn').src;
var currentPath = currentBtn.substring(0,currentBtn.lastIndexOf('/'));
var currentInfo = currentBtn.substring(currentBtn.lastIndexOf('/')+1);

if (paused == true){
paused=false;
if (currentInfo == "play2.png") { currentInfo = 'pause2.png'; }
document.getElementById('pauseBtn').src = currentPath+'/'+currentInfo;
setTimeout("animate("+(continueStep)+")", tick);
} else {
paused=true;
if (currentInfo == "pause2.png") { currentInfo = 'play2.png'; }
document.getElementById('pauseBtn').src = currentPath+'/'+currentInfo;

}
}

The page I'm working on is here (http://www.xelawho.com/map/bus2.htm)

Everything works as it should except for the toggling between images.

Old Pedant
12-15-2010, 10:24 PM
You do know there is a bug in "main.js" don't you?

Firebug reports that in the line

l.Nb=function(a){return new N(this.j[a].lat(),this.j[a].lng())};
that this.j[a] is undefined.

You've got several bugs in the HTML.

You have

<div id="category">
<div id="label">
<div id="bus">
*REPEATED* for each of the routes. You should never give the same id to more than on object. Better, maybe, would have been to use classes instead of ids, if the purpose is to allow CSS styling.

And you have the same problem with your <img> tags. But worse.

You have

<img id="this,"pauseBtn"" ... />

for *all* of them.

So first of all, the *ACTUAL* ID of each as seen by HTML and thus by JS is simply

<img id="this," ... />

HTML has no idea what to do with the bogus pauseBtn"" and just throws it away.

But in any case, there is no way for JS to *UNIQUELY* identify any of those <img> tags, since they all have the same ID!!! So of course it can't do anything with them.

I have to ask why you used

<button ...>
<img ...>
</button>

in the first place.

If you had simply used

<input type="image" src="play.png" onclick="startBus(this,0); return false;" />

Then your startBus function could be written something like this;


function startBus( inp, num )
{
inp.src = "pause.png"; // see? no id needed!!!
...


Okay? That's just for starters.

Having said all that: I am very impressed with the overall concept of what you have done, and I really hope you can figure out how to get the restart to work. But it may be that the bug in the "main.js" will prevent you.

xelawho
12-16-2010, 12:18 AM
You do know there is a bug in "main.js" don't you?

yes I do, but I'm guessing that being that I don't get it when the codes are working separately (here (http://www.xelawho.com/map/bus.htm) and here (http://www.xelawho.com/map/moving5.htm)) that this is a problem that arises from trying to combine them...


You should never give the same id to more than on object. Better, maybe, would have been to use classes instead of ids, if the purpose is to allow CSS styling.

I'll give that a try, thanks. I have even less experience with CSS than I do with js :eek:


And you have the same problem with your <img> tags. But worse.

I see what you're saying here, and thanks for pointing it out. I'm guessing (without having tried it yet) that I can give them unique IDs by assigning them the poly_num variable that gets assigned to everything else...



I have to ask why you used

<button ...>
<img ...>
</button>

in the first place.

just lazy I guess - I wanted to use a button there and it seemed easier to use all the built-in functions (mouseover, mouseout, blahblah) of calling it a button rather than using an image and then having to assign all that stuff. But if the above doesn't work, I'll give your suggestion a go.


That's just for starters.
That's probably enough to go on for now :thumbsup:


I really hope you can figure out how to get the restart to work. But it may be that the bug in the "main.js" will prevent you.
Like I say, I think that bug will disappear once I get the above sorted. I've pretty much given up on finding a restart function. People who know far more about this stuff than I ever will appear to be stumped. Or disinterested. Or both. I've tried the Javascript forums and the google maps forums - it just seems to be one of those questions that's destined to fall between the gaps :(
Thanks once again for the pointers.

Old Pedant
12-16-2010, 12:21 AM
I wanted to use a button there and it seemed easier to use all the built-in functions (mouseover, mouseout, blahblah) of calling it a button rather than using an image and then having to assign all that stuff.
HUH???

Those all exist for <input> of *any* kind, most certainly including <input type=image>. None of them happen automagically, though. <button> or <input>, you have to supply them yourself.

Am I misunderstanding you????

xelawho
12-16-2010, 12:55 AM
Am I misunderstanding you????

A little. It's just that with the button they do happen automagically, whereas with the input image you have to code it all yourself (the way I understand it).

Anyway. poly_num as a button ID seemed not to work so I'm going with your suggestion. I think I'm a little lost, though. Are you saying that the sidebarhtml should be this:


sidebar_html += '<div class="category"><input type="checkbox" id="'+category+'" onclick="boxclick(this,\''+category+'\',\''+poly_num+'\');"></div><div class="label">' + label + '</div><div class="bus"><input type="image" src="play2.png" onclick="startCar(this,0); return false;" style="height:24px; width:30px"></div><br>';

and the other functions be like this:


function startCar(btn,pnum){
if (this.wasRun)
{
btnAction();
} else {
if( !this.wasRun )

toggleRun(btn, pnum);
btnAction();
this.wasRun = true;
}
}

function toggleRun(btn, pnum){
btn.src = "pause2.png";
var inps = document.getElementsByTagName("input");
for ( var i = 0; i < inps.length; ++i ) {
var inp = inps[i];
if ( inp.value = "play2.png" ) inp.value = "pause2.png";
}
startAnimation(pnum);
}

function btnAction() {
var currentBtn = document.getElementById('pauseBtn').src;
var currentPath = currentBtn.substring(0,currentBtn.lastIndexOf('/'));
var currentInfo = currentBtn.substring(currentBtn.lastIndexOf('/')+1);

if (paused == true){
paused=false;
if (currentInfo == "play2.png") { currentInfo = 'pause2.png'; }
document.getElementById('pauseBtn').src = currentPath+'/'+currentInfo;
setTimeout("animate("+(continueStep)+")", tick);
} else {
paused=true;
if (currentInfo == "pause2.png") { currentInfo = 'play2.png'; }
document.getElementById('pauseBtn').src = currentPath+'/'+currentInfo;

}
}

?

obviously not, cos that results in this (http://www.xelawho.com/map/bus2.htm)

(not worried about css styling at the mo'...)

Old Pedant
12-16-2010, 01:05 AM
No, this kind of stuff isn't going to work:


var currentBtn = document.getElementById('pauseBtn').src;

You have *THREE* buttons, and they can't *ALL* have an id of "pauseBtn"!

There are probably other errors, but clearly that's the kind of thing you have to avoid.

Let me try to rewrite your code so it is readable and then let's see what we can do to it:


sidebar_html +=
'<div class="category">'
+ '<input type="checkbox" id="'+category+'" '
+ ' onclick="boxclick(this,\''+category+'\',\''+poly_num+'\');">'
+ '</div>'
+ '<div class="label">' + label + '</div>'
+ '<div class="bus">'
+ '<input type="image" src="play2.png" onclick="startCar(this,0); return false;" '
+ ' style="height:24px; width:30px">'
+ '</div>'
+ '<br>';

Hmmmm....

Okay, so I will have to go look at when boxclick() looks like. Why does it need to pass anything but poly_num??

And what is the value of category?? Where does that come from?

xelawho
12-16-2010, 01:12 AM
boxclick (from the way I understand it) is the function that gets the lines and the arrows on the screen when a box is checked.

category is an xml attribute that is shared by the lines and the arrows, so when you show a line with a certain category, all the arrows that share that particular category are shown, too.

there are probably much easier ways to do all this stuff, but this is the way it came together, just muddling through...

xelawho
12-16-2010, 01:25 AM
No, this kind of stuff isn't going to work:


var currentBtn = document.getElementById('pauseBtn').src;

You have *THREE* buttons, and they can't *ALL* have an id of "pauseBtn"!



... which was why I thought that img id="pauseBtn'+poly_num+'" might fly...

but trying it out here (http://www.xelawho.com/map/bus3.htm) gets me a "document.getElementById("pauseBtn" + poly_num) is null" error on the var currentBtn line...

Old Pedant
12-16-2010, 01:43 AM
Okay, first simplification:


function boxclick( box, poly_num) {
if (box.checked) {
show( box.id );
gpolys[poly_num].show();
} else {
hide( box.id );
gpolys[poly_num].hide();
}
}

No reason to pass the category when the id of the checkbox is the same as the category.

Alternatively, pass the category but get rid of the id on the checkbox. What other purpose is it serving?

But let's concentrate on the play button click.

So when it is clicked on, you want to change it to "pause2.png", right? And when clicked on again, it goes to "play2.png". Etc.

And when the route is finished then *ALL* the buttons get changed to "Reload"??? Where's the image for that?

Here is the part I *REALLY REALLY REALLY* don't get:

function startCar(btn,pnum){
if (this.wasRun)
{
btnAction();
} else {
if( !this.wasRun )
toggleRun(btn, pnum);
btnAction();
this.wasRun = true;
}
}

(a) WHAT in the heck is this here???? THERE WON'T BE any this that I can see! Okay, I just verified that with FireBug. Indeed, this refers to the ENTIRE WINDOW at that point. So I guess it doesn't hurt, but it sure is confusing!
(b) First you do if (this.wasRun) and then you do else { if ( ! this.wasRun ) ...
Ummm...if the first if was false, then you get to the else, where *BY DEFINITION* this.wasRun *WILL* be false!!!! There is no point at all in checking it again.

**********

My head hurts. I'm still digging.

But no matter what, your function btnAction() { is just trash. It can't possibly work.
The very first line there
var currentBtn = document.getElementById('pauseBtn').src;gets an error and so the rest of the function never runs.

Old Pedant
12-16-2010, 01:46 AM
My head hurts more. It turns out that wasRun is NEVER DEFINED! The only place it exists is inside that startCar() function.

At least, I can't find it any place else.

Old Pedant
12-16-2010, 02:01 AM
I'm going to take a stab at this.

I want to replace *ALL* of your code for

function startCar(btn,pnum){
function toggleRun(btn, pnum){
function btnAction() {
function togglePause(){


I'll leave the checkbox stuff alone, for now.

xelawho
12-16-2010, 02:01 AM
My head hurts more.

ha! welcome to my world.

that whole wasrun function is all about getting the first click on the play button to start the startAnimation function and then any subsequent clicks to be either pause or plays (because remember firing the startAnimation function again gives undesired results).

you can see it working fine here (http://www.xelawho.com/map/moving5.htm)

although (again) there's probably a much more elegant way to do that.

Old Pedant
12-16-2010, 03:03 AM
Okay...here is my stab at it:


// runState can have 4 values:
// 0 -- never started
// 1 -- running
// 2 -- paused
// 3 -- ended
//
var runState = 0;


function playPause( btn, pnum )
{
// regardless of everything else, when ANY button is clicked on
// it disables and hides all other buttons.
var side = document.getElementById("sidebar");
var inps = side.getElementsByTagName("input");
for ( var i = 0; i < inps.length; ++i )
{
var inp = inps[i];
if ( inp.type == "image" && inp != btn )
{
// if it's an image button and not the one clicked on...
inp.style.display = "none"; // make it go away!!
}
}
// okay, now... what is the runState?
switch( runState )
{
case 0: /* never has been run before */
// use replace on btn.src so path of image stays same..
// only play ==>> pause
btn.src = btn.src.replace(/play/,"pause");
runState = 1; // we start running
paused = false;
startAnimation(pnum); // and start the animation
break;
case 1: /* already running...so pause it */
// use replace on btn.src so path of image stays same..
btn.src = btn.src.replace(/pause/,"play");
runstate = 2;
paused = true;
break;
case 2: /* paused, so unpause */
// use replace on btn.src so path of image stays same..
btn.src = btn.src.replace(/play/,"pause");
runstate = 1;
paused = false;
animate(continueStep); // and continue where we left off
break;
case 3: /* animation has ended */
location.reload(); // force a reload of the page
return false;
default:
alert("Invalid runState!");
}
}

*********

sidebar_html +=
'<div class="category">'
+ '<input type="checkbox" ' /* no reason for id on this */
+ ' onclick="boxclick(this,\''+category+'\',\''+poly_num+'\');">'
+ '</div>'
+ '<div class="label">' + label + '</div>'
+ '<div class="bus">'
+ '<input type="image" src="play2.png" '
+ ' onclick="playPause(this,' + poly_num " '); return false;" '
+ ' style="height:24px; width:30px">' /* style should be in css not here! */
+ '</div>'
+ '<br>';

xelawho
12-16-2010, 03:03 AM
I'm going to take a stab at this.

I want to replace *ALL* of your code for...

really? wouldn't it just be simpler to get the buttons to toggle here (http://www.xelawho.com/map/bus3.htm)?

xelawho
12-16-2010, 03:05 AM
Okay...here is my stab at it:


ups. you beat me to it. back in a minute...

Old Pedant
12-16-2010, 03:05 AM
You will need to add a line to set runState to 3 when the animation ends, so that another button push will force a reload of the page.

You could also, at that time, change the image to a "reload" image.

Old Pedant
12-16-2010, 03:06 AM
I'm out of here, probably for the night.

xelawho
12-16-2010, 03:17 AM
ok. thanks for this (http://www.xelawho.com/map/bus4.htm). I'll have a play. From what I've got so far there's a problem with playing after paused, but that may be the global variables (although they're unchanged from the example I gave...)

I like the disappearing buttons idea, btw. nice touch :thumbsup:

Old Pedant
12-16-2010, 05:17 AM
You should have FireBug'ged it a bit. Easy to find.

Two places I used runstate instead of runState. Find and change those.

Might be other typos, but that's a start. Don't be afraid to use FireBug and step through code one line at a time when you need to!

xelawho
12-16-2010, 07:10 PM
You should have FireBug'ged it a bit...


sadly enough, that qualifies as "playing" these days... I would have done it last night but I felt like my eyes were about to melt out of my head :eek:


Might be other typos, but that's a start.
Nope. Far as I can tell, it works like a dream with those ones fixed :thumbsup:

Now I just have to figure out that reload button and incorporate jmrker's mouseover mouseout code back into the deal.

Which means there may be one more button toggling question sometime in the near future...

thanks again for your help, Old Pedant. You really went above and beyond on this one :thumbsup:

xelawho
12-17-2010, 12:15 AM
well, I admit that was quick.

I can't even get past step 1 :(

but really... if

<input type="image" src="pause.png" onmouseover="src='pauseon.png'">

has worked in the past, how come

<input type="image" src="play2.png" onmouseover="src='play2on.png'"

gets me an "Unexpected identifier" error here (http://xelawho.com/map/bus4.htm)

and is that even step one, considering all the other toggling that goes on with the switch at lines 287 to 310? :confused:

Old Pedant
12-17-2010, 12:23 AM
Should be this.src='...' in the JS. Without the this, the word src refers to a (non-existent) global variable. That is, *as if* you had done:


<script type="text/javascript">
var src;
</script>
and were trying to change the contents of *THAT* variable.

Old Pedant
12-17-2010, 12:30 AM
On top of that, you are doing

+ '<input type="image" src="play2.png" onmouseover="src='play2on.png'"'
and that will *NEVER* work!!! You have 'xxx' *INSIDE* of '...'

Needs to be (notice the \'...\' to take care of embedding '...' inside of '...' !!!)

+ '<input type="image" src="play2.png" onmouseover="this.src=\'play2on.png\'"'

But that will STILL be wrong.

Because once the image becomes "pause2.png", you clearly don't want a mouseover to convert "pause2.png" to "play2on.png"!!!

Instead try this:


+ '<input type="image" src="play2.png" '
+ ' onmouseover="this.src=this.src.replace(/\.png/,\'on.png\');" '
+ ' onmouseout="this.src=this.src.replace(/on\.png/,\'.png\');" '

Do you see it? DO NOT TOUCH the "play" or "pause" part of the name because of mouseover/mouseout. Only change whether or no the "on" is there.

The OTHER code then, which changes play to pause or pause to play, changes *ONLY* the "play" or "pause" part. So that means that if the image *IS* "play2on.png" it will change to "pause2on.png", still keeping the "on" effect!

Old Pedant
12-17-2010, 12:36 AM
Personally, I would have opted for


+ '<input type="image" src="play2.png" '
+ ' onmouseover="over(this,true);" onmouseout="over(this,false);" '

And then you could add the over() function to your boiler plate script thus:


function over(image,onoff)
{
image.src = onoff
? image.src.replace(/\.png/,"on.png")
: image.src.replace(/on\.png/,".png");
}

xelawho
12-17-2010, 01:19 AM
Personally, I would have opted for...

yeah, that's what I was leaning towards as well ;)

I guess with only the reload to sort out we can all see what's coming, but I'm going to give it a shot anyway, just for kicks. Thanks again.

xelawho
12-17-2010, 03:47 PM
You will need to add a line to set runState to 3 when the animation ends, so that another button push will force a reload of the page.

You could also, at that time, change the image to a "reload" image.

Well that was actually easier than I had imagined, but as usual, solving one problem has smacked me into the wall of another.

This is the thing: at the moment, when it reaches the last point on the line, runState gets set to 3, like this:

if (lastVertex == poly.getVertexCount()) {
runState = 3;
}

but then if runState 3 has the reload instruction in it, clicking the pause button again gets you about 1 millisecond of reload button before the reload happens. It would be ideal to warn the user that a reload was about to happen, in case for some reason they don't want that. So I figure there are two options:

1) once the bus gets to the end of the line, somehow automagically swap the pause button for a reload button, then have the reload instruction in case3. This is preferable, but I have no idea where to start (I tried putting a btn.src.replace instruction in the if statement above, but it didn't like that), so I began working on:

2) make another click on the pause button change it to the reload button, and then a click on that would reload the page. I got halfway there on that one, but am lost on the syntax to force it to move from runState 3 to 4.

I tried some variations on the onclick = "runState = 4"; theme, but nothing really flew.

so, any ideas on either of the above would be most appreciated.

this is all still happening here (http://xelawho.com/map/bus4.htm), btw.

Old Pedant
12-17-2010, 06:37 PM
if (lastVertex == poly.getVertexCount()) {
runState = 3;
}
...
once the bus gets to the end of the line, somehow automagically swap the pause button for a reload button, then have the reload instruction in case3.
Clearly the right thing to do.

Dunno why you say "automagically". It's not hard.

Look at the code in playPause, where I change *all* the buttons. Just clone that...sort of.


if (lastVertex == poly.getVertexCount()) {
runState = 3;

var side = document.getElementById("sidebar");
var inps = side.getElementsByTagName("input");
for ( var i = 0; i < inps.length; ++i )
{
var inp = inps[i];
if ( inp.type == "image" ) inp.src = "reload.png";
}
}

See? Change *ALL* the buttons to say "reload", whether they are visible or not. Can't hurt.

xelawho
12-17-2010, 07:29 PM
Dunno why you say "automagically". It's not hard.

Not if you know what you're doing, obviously. Thanks again. You should be very proud of all your work on this page. I was glad to be able to contribute half a line of code, at least :thumbsup:



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum