Timeline API

J

jshanman

I am working on a timeline API that devevelopers can use to add a
dynamic timeline to their sites.

Here is a *working* demo of the basic interface. (it works for me
anyway on ie6 & firefox 1.5)

http://www.endeavorpub.com/wiki/timeline.html

Please tear apart my code and tell me what I'm doing wrong so far...

Eventually, I would like this to be cross-browser compatible, give the
deveoper the ability to set colors, ranges, sizes, positions, and set
markers & event ranges.

- JS
http://www.endeavorpub.com
 
J

jshanman

jshanman said:
I am working on a timeline API that devevelopers can use to add a
dynamic timeline to their sites.

Here is a *working* demo of the basic interface. (it works for me
anyway on ie6 & firefox 1.5)

http://www.endeavorpub.com/wiki/timeline.html

Please tear apart my code and tell me what I'm doing wrong so far...

Eventually, I would like this to be cross-browser compatible, give the
deveoper the ability to set colors, ranges, sizes, positions, and set
markers & event ranges.

- JS
http://www.endeavorpub.com

You mean to tell me all the experts in this group found absolutly no
problems in my code!

I found a problem : In firefox, I get this message : Error: Error in
parsing value for property 'left'. Declaration dropped.

In IE (when the try catch is removed), I get "Object Error".

Here is the code:

if (document.getElementById("marker"+IconName)) {
document.getElementById("marker"+IconName).style.visibility =
"visible";
var p = (typeof
document.getElementById("marker"+IconName).style.left) ? "px":0;
try {
document.getElementById("marker"+IconName).style.left =
XPos+p;
} catch(e) {}
} else {
this["Markers"]["marker"+IconName] =
this.document.createElement("DIV");
this["Markers"]["marker"+IconName].className =
"MarkerClass";
this["Markers"]["marker"+IconName].title = LabelText;
this["Markers"]["marker"+IconName].id = "marker"+IconName;
var p = (typeof
this["Markers"]["marker"+IconName].style.left == 'string') ? "px":0;
try {
this["Markers"]["marker"+IconName].style.left = XPos+p;
} catch(e) {}
this["Markers"]["marker"+IconName].style.top =
parseInt(this.height/2,10)-(h-AnchorY))+p;
this["Markers"]["marker"+IconName].style.width = w+p;
this["Markers"]["marker"+IconName].style.height = h+p;
document.getElementById(Target.id+"LabelDiv").appendChild(this["Markers"]["marker"+IconName]);
}

I used the recommended ?"px":0; trick that I discovered while searching
the group, but why is it causing errors? Note: All the markers are
still drawn in their correct positions, these errors just fill up the
console as I drag the map.

- JS
 
T

Thomas 'PointedEars' Lahn

jshanman said:
You mean to tell me all the experts in this group found absolutly no
problems in my code!

| This is Usenet. It is a discussion group, not a helpdesk. You post
| something, we discuss it. If you have a question and that happens to get
| answered in the course of the discussion, then great. If not, you can
| have a full refund of your membership fees. -- Mark Parnell in alt.html
I found a problem : In firefox, I get this message : Error: Error in
parsing value for property 'left'. Declaration dropped.

That is a CSS (layout engine) error, not a script (engine) error. Install
Console^2, FireBug, or both, to filter console messages (since Firefox
1.5/Gecko 1.8b1).
In IE (when the try catch is removed), I get "Object Error".

Probably it says in which line of the code.

Here is the code:

if (document.getElementById("marker"+IconName)) {
^
Identifiers should start uppercase only if they refer to constructors.
document.getElementById("marker"+IconName).style.visibility =
"visible";
var p = (typeof
document.getElementById("marker"+IconName).style.left) ? "px":0;
try {
document.getElementById("marker"+IconName).style.left =
XPos+p;
} catch(e) {}

OMG. You definitely want to optimize here:

var marker = document.getElementById("marker" + IconName);
if (marker)
{
marker.style.visibility = "visible";

// `typeof something' always evaluates to a non-empty string,
// therefore `true' in a boolean expression; you want to compare
// it against a string. And still there would be no point in this.
var p = (typeof marker.style.left) ? "px": 0;
try
{
marker.style.left = XPos+p;
}
catch(e) {}
}

Now that redundancy has been removed and thereby efficiency has been
increased, you want to reconsider your approach: Not risking the error and
attempting to handle it later, but attempting to prevent it in the first
place instead, by doing feature tests prior to access.

<URL:http://pointedears.de/scripts/test/whatami#inference>

// from types.js
function isMethod(a)
{
var t;
return (a && ((t = typeof a) == "function" || t == "object"));
}

// from dhtml.js
function setStyleProperty(o, s, v)
{
if (typeof o.style != "undefined"
&& typeof o.style != "undefined")
{
o.style = v;
return (o.style == v);
}

return false;
}

if (typeof document != "undefined"
&& isMethod(document.getElementById))
{
var marker = document.getElementById("marker" + iconName);
if (marker)
{
setStyleProperty(marker, "visibility", "visible");
setStyleProperty(marker, "left", XPos + "px");
} else {
this["Markers"]["marker"+IconName] =
this.document.createElement("DIV");

The W3C DOM Level 2 HTML Specification states that element type identifiers
passed to DOM methods should be lowercase.
this["Markers"]["marker"+IconName].className =
"MarkerClass";
this["Markers"]["marker"+IconName].title = LabelText;
this["Markers"]["marker"+IconName].id = "marker"+IconName;
var p = (typeof
this["Markers"]["marker"+IconName].style.left == 'string') ? "px":0;

That's a workaround for old buggy Geckos -- do you really want to support
them? Furthermore in the following you assume that if `left' is a number,
the rest must be a number, too. Reasoning?
try {
this["Markers"]["marker"+IconName].style.left = XPos+p;
} catch(e) {}
this["Markers"]["marker"+IconName].style.top =
parseInt(this.height/2,10)-(h-AnchorY))+p;
^^^^^^^^^^^^^^^^^^^^^^^^^^
If this.height is a string, you cannot divide it by 2 without a NaN result.
First convert, then calculate, not vice-versa.
this["Markers"]["marker"+IconName].style.width = w+p;
this["Markers"]["marker"+IconName].style.height = h+p;
document.getElementById(Target.id+"LabelDiv").appendChild(this["Markers" ["marker"+IconName]);
}

Same here. Can it possibly be more inefficient and ugly than the above?

}
else
{
// Are you sure you want this.document.createElement() here,
// and not simply document.createElement() instead?
if ((marker = this["Markers"]["marker" + iconName]
= this.document.createElement("div")))
{
// you may also want to do feature tests for those
marker.className = "MarkerClass";
marker.title = labelText;
marker.id = "marker" + iconName;

// As I said above, this is considered obsolete
var p = (typeof marker.style.left == 'string') ? "px" : 0;

setStyleProperty(marker, "left", xPos + p);
setStyleProperty(marker, "top",
parseInt(this.height, 10) / 2 - (h - anchorY)) + p);
setStyleProperty(marker, "width", w + p);
setStyleProperty(marker, "height", h + p);

var oTarget = document.getElementById(target.id + "LabelDiv");
if (oTarget && isMethod(oTarget.appendChild))
{
oTarget.appendChild(marker);
}
}
}
I used the recommended ?"px":0; trick that I discovered while searching
the group,

Must be posted several years ago, I suppose.
but why is it causing errors?

Probably because your first comparison and your calculation were wrong.
Note: All the markers are still drawn in their correct positions, these
errors just fill up the console as I drag the map.

Firefox 1.5 supports W3C DOM Level 2 Style, where non-zero lengths must have
a unit, as specified in CSS. Hence the _CSS_ error message if you attempt
to omit the unit.


HTH

PointedEars
 
J

jshanman

Thomas said:
Firefox 1.5 supports W3C DOM Level 2 Style, where non-zero lengths must have
a unit, as specified in CSS. Hence the _CSS_ error message if you attempt
to omit the unit.


HTH

PointedEars

Thank you for your help!

I implemented your suggestions and I still ended up with the same
problem. It ended being because if a date was < 4000BC, xPos was
false, and therefore it was trying to add "falsepx" as the left
value... But your code is cleaner and more efficient anyway.

Another Question: Is there a better way of referencing a local object
(this) in a window.setTimeout ?

Code:
if (this.timeline.NextDraw)
window.clearTimeout(this.timeline.NextDraw);
this.timeline.NextDraw =
window.setTimeout("document.getElementById('"+this.id+"').timeline.DrawLabels()",50);

I read previous posts that state a setTimeout runs in the Global
Context. Is there a *better* way then my example above? I don't want
any global variables or functions.

- JS
 
R

Randy Webb

Thomas 'PointedEars' Lahn said the following on 4/25/2006 9:53 AM:
| This is Usenet. It is a discussion group, not a helpdesk. You post
| something, we discuss it. If you have a question and that happens to get
| answered in the course of the discussion, then great. If not, you can
| have a full refund of your membership fees. -- Mark Parnell in alt.html

When quoting something, specify it as a quote.
That is a CSS (layout engine) error, not a script (engine) error. Install
Console^2, FireBug, or both, to filter console messages (since Firefox
1.5/Gecko 1.8b1).


Probably it says in which line of the code.

And probably not. If you had any knowledge at all of IE error messages
you would know that. IE is very well known to spit out cryptic error
messages.
^
Identifiers should start uppercase only if they refer to constructors.

Pure 100% unadulterated bullshit. You can name a variable anything you
want as long as it isn't already reserved/used. Naming them lowercase
beginning is nothing more than a coding style.


It doesn't. But that is typical of your posts here.
 
T

Thomas 'PointedEars' Lahn

jshanman said:
Another Question: Is there a better way of referencing a local object
(this) in a window.setTimeout ?

Code:
if (this.timeline.NextDraw)

This may not be sufficient. Unfortunately, it is not specified what value
window.setTimeout() returns, only that this value can be passed to
window.clearTimeout(); it could be 0, which would evaluate to `false' in a
boolean expression. It would be best if you initialized
this.timeline.NextDraw (note the capitalized identifier again) with a value
that is unlikely to be returned by window.setTimeout() to indicate that it
has not been assigned that. I have found `null' to be suitable for this.
You then could test for it with

if (this.timeline.NextDraw == null)

(0 != null).
window.clearTimeout(this.timeline.NextDraw);
this.timeline.NextDraw =
window.setTimeout("document.getElementById('"+this.id+"').timeline.DrawLabels()",50);

I read previous posts that state a setTimeout runs in the Global
Context. Is there a *better* way then my example above? I don't want
any global variables or functions.

Certainly there is a better way. However, a globally available object is
required for that, as you need a method to be called in order to avoid
spaghetti code.

Please trim your quotes to the part(s) you are actually referring to.


PointedEars
 
R

RobG

jshanman said on 25/04/2006 10:46 PM AEST:
You mean to tell me all the experts in this group found absolutly no
problems in my code!

No one has told you anything, you should not presume that no response
means there is nothing to respond about (noting that Thomas has
subsequently replied with some tips).

I looked briefly at your code - it is very inefficient, unnecessarily
complicated and lacks comments. No documentation is provided about what
it is supposed to do or how it is supposed to do it. For example, you
have arrays of month names and day numbers that don't appear on the
page. Is that an error or isn't that functionality implemented yet?

There are efficient ways of determining the number of days in the month
and adding the ordinal suffix (st, nd, rd, and so on) without creating
literal arrays with all of the values in them.

I don't have the time to wade through the code to find the answer or
provide useful assistance. These issues are obvious and hint that there
are many, many more.

e.g. (my wrapping)

this.labels.style.left =
String(
-1*this.GetPos(
DtObj.getFullYear(),
DtObj.getMonth(),
DtObj.getDate(),
DtObj.getHours()
) + 400
) + "px"

Seems silly, why not pass the date object to the function and have it
return the value? Why explicitly convert the returned value to a
number, then convert it back to a string? Appending 'px' to a number
will convert the value to a string without using a String object, so:

this.labels.style.left = '-' + (GetPos(DtObj) + 400) + 'px';


would be far simpler. Then the getPos() function can do its thing with
the date parts as required. Incidentally, getPos() seems far more
complex than it needs to be, for example:

with (D = new Date(0)) {
setFullYear(year, month, day);
setHours(hour);
}

Why not:

var D = new Date(year, month, day, hours);

Which just creates a copy of the date object above - DtObj. Since D
(which isn't declared anywhere and so is global) isn't modified, why not
just pass a reference to DtObj and use that directly?


As a general hint, if you ask a specific, clearly presented problem you
will usually get timely and worthwhile assistance - posting a page that
very likely has many basic design flaws (given that no design is
provided) and poor coding practices will likely deter everyone from
offering any help at all.

[...]
 
J

jshanman

RobG said:
jshanman said on 25/04/2006 10:46 PM AEST:

No one has told you anything, you should not presume that no response
means there is nothing to respond about (noting that Thomas has
subsequently replied with some tips).

I know, that statement was meant to provoke a response. A harsh one
with a little helpful content is better then no response at all. I
don't mind being told my code is *wrong* or ineffecient. How else will
I learn?
I looked briefly at your code - it is very inefficient, unnecessarily
complicated and lacks comments. No documentation is provided about what
it is supposed to do or how it is supposed to do it.

When it is completed, I will create a full set of documentation.
For example, you
have arrays of month names and day numbers that don't appear on the
page. Is that an error or isn't that functionality implemented yet?

It will be used to display the text labels, which is now partially
implemented.
There are efficient ways of determining the number of days in the month
and adding the ordinal suffix (st, nd, rd, and so on) without creating
literal arrays with all of the values in them.

Link or example? that would be very useful. I will probably end up
figuring out a differant way to do it.
I don't have the time to wade through the code to find the answer or
provide useful assistance. These issues are obvious and hint that there
are many, many more.

e.g. (my wrapping)

this.labels.style.left =
String(
-1*this.GetPos(
DtObj.getFullYear(),
DtObj.getMonth(),
DtObj.getDate(),
DtObj.getHours()
) + 400
) + "px"

Seems silly, why not pass the date object to the function and have it
return the value?

That makes sense, the reason I didn't just send a date object is
because in other places, that function will be used to position dates
from a database that may be in julian or gregorian (as actual
year/month/date/hour, not # ms), so a direct date object would not
represent those properly.

Why explicitly convert the returned value to a
number, then convert it back to a string? Appending 'px' to a number
will convert the value to a string without using a String object, so:

this.labels.style.left = '-' + (GetPos(DtObj) + 400) + 'px';

I was getting desperate will a css error I was getting and was basicly
troubleshooting why it wasn't applying the values... I figured out it
was a differant reason and haven't bothered to remove the extra
functions yet.
would be far simpler. Then the getPos() function can do its thing with
the date parts as required. Incidentally, getPos() seems far more
complex than it needs to be, for example:

with (D = new Date(0)) {
setFullYear(year, month, day);
setHours(hour);
}

Why not:

var D = new Date(year, month, day, hours);

Thise does not work for dates preceeding 100 AD, it would just return
the milliseconds for "1901" instead of "01"AD
Which just creates a copy of the date object above - DtObj. Since D
(which isn't declared anywhere and so is global) isn't modified, why not
just pass a reference to DtObj and use that directly?


As a general hint, if you ask a specific, clearly presented problem you
will usually get timely and worthwhile assistance - posting a page that
very likely has many basic design flaws (given that no design is
provided) and poor coding practices will likely deter everyone from
offering any help at all.

[...]

I am aware of that and will continue to do that as well.

Javascript is very fun to learn and I am all *ears*...

My next question involves disabling the drag and drop in IE. If you
try to drag the timeline in IE, if you move your mouse to fast, it will
turn into the "no can do" cursor and will not continue to move the
timeline until the mouse is released. How can I cause IE to ignore the
drag > drop events ?

Also in IE, when you are able to move the timeline successfully (from
one end to the other very quickly, every other text label ends up being
highlighted... wierd.

Thanks again,

- JS
 
R

Richard Cornford

jshanman said:
I know, that statement was meant to provoke a response.
<snip>

Couldn't you have waited at least 24 hours before trying to provoke a
response (the questionable wisdom of which not withstanding)? This is an
international group and it would take at least 24 hours for everyone in
the world just to get an opportunity to see your first post.

Richard.
 
M

Matt Kruse

jshanman said:
When it is completed, I will create a full set of documentation.

Just my opinion - In order for something to be evaluated, a person needs to
have some overview of what it's supposed to do and what problem it is
intended to solve. Then, they need to know what features it is trying to
implement to solve those problems and how they should attempt to use it.

You don't need to write detailed API documentation at the beginning. But you
should at least write some introductory text if you want to get any useful
feedback from people.

I visited your page, had no idea what I was looking at, and closed my
browser. Thus, no response here :)
 
J

jshanman

Matt said:
Just my opinion - In order for something to be evaluated, a person needs to
have some overview of what it's supposed to do and what problem it is
intended to solve. Then, they need to know what features it is trying to
implement to solve those problems and how they should attempt to use it.

You don't need to write detailed API documentation at the beginning. But you
should at least write some introductory text if you want to get any useful
feedback from people.

I visited your page, had no idea what I was looking at, and closed my
browser. Thus, no response here :)

You point is well taken. (as is the 24 hour previous point). I will
add some backgournd information about the project to the page. I'd be
happy if you were willing to look again!

Also, I've added a formatDate.js file and removed all those month & day
& hour arrays.

I've also fixed the IE drag issue by placing a return false in the
ondragstart and onselectstart attributes of the body tag.

- JS
 
T

Thomas 'PointedEars' Lahn

jshanman said:
I've also fixed the IE drag issue by placing a return false in the
ondragstart and onselectstart attributes of the body tag.

The `body' _element_ has no such attributes in any HTML version, so your
markup is not Valid. It would be Valid and acceptable if you scripted
the corresponding properties instead, though.


PointedEars
 
R

RobG

jshanman said on 26/04/2006 11:04 PM AEST:
RobG wrote: [...]

When it is completed, I will create a full set of documentation.

If you don't have a clear idea of what you are trying to build, you
won't get a very good result. No one expects full documentation
up-front, but at this stage you should have documented a high-level view
of the purpose and basic functionality to be delivered.

Setting down your thoughts in a clear statement of functionality will
not only help you to organise your thoughts, but will allow you to
easily explain to others what is supposed to be going on.

You will also find many more people able to discuss your application
based on a simple description than if required to read and understand
hundreds of lines of code.

It will be used to display the text labels, which is now partially
implemented.

I didn't see any in any browser I tested (though I didn't test IE).

Link or example? that would be very useful. I will probably end up
figuring out a differant way to do it.

I am presuming that you will only show a couple of dates at a time with
suffixes, they are normally only used when writing the date in full:

Thursday, 27th April, 2006.


There is a lot of stuff here:

<URL:http://www.merlyn.demon.co.uk/js-dates.htm>


There is a good thread on adding ordinal suffixes here (subject:
"Ordinal (st, nd, rd, th) dates in javascript")

<URL:
http://groups.google.co.uk/group/co...al+suffix+1st+2nd+3rd&rnum=1#14e1ef776161b7e4
[...]
 
R

Randy Webb

Thomas 'PointedEars' Lahn said the following on 4/26/2006 3:29 PM:
The `body' _element_ has no such attributes in any HTML version, so your
markup is not Valid.

So what? The browser that it is intended for supports it, it is not
needed in any other browser. That means it does *exactly* what it was
used to do. The fact that the W3C will burp and say "Hey, that isn't
valid HTML" is irrelevant. I would rather have a properly functioning
page than a broken page that is "valid HTML"

Too much, way too much, is made of being "Valid HTML" sometimes.
 
J

jshanman

RobG said:
jshanman said on 26/04/2006 11:04 PM AEST:
RobG wrote: [...]

When it is completed, I will create a full set of documentation.

If you don't have a clear idea of what you are trying to build, you
won't get a very good result. No one expects full documentation
up-front, but at this stage you should have documented a high-level view
of the purpose and basic functionality to be delivered.

Setting down your thoughts in a clear statement of functionality will
not only help you to organise your thoughts, but will allow you to
easily explain to others what is supposed to be going on.

You will also find many more people able to discuss your application
based on a simple description than if required to read and understand
hundreds of lines of code.

I've create a statement of purpose on the site for the sake of
visitors. I already know exactly how I want it to work because I have
a working example: http://www.endeavorpub.com/wiki/map.php

However, this example is written using Google Maps APIv1 code.
I didn't see any in any browser I tested (though I didn't test IE).

In Firefox 1.5 and IE6 it shows the text labels over the date interval
markers (years, months, days, or hours)
I am presuming that you will only show a couple of dates at a time with
suffixes, they are normally only used when writing the date in full:

Thursday, 27th April, 2006.


There is a lot of stuff here:

<URL:http://www.merlyn.demon.co.uk/js-dates.htm>

Great site, Dr John Stockton helped me get this going originally using
Google Maps
There is a good thread on adding ordinal suffixes here (subject:
"Ordinal (st, nd, rd, th) dates in javascript")

<URL:
http://groups.google.co.uk/group/co...al+suffix+1st+2nd+3rd&rnum=1#14e1ef776161b7e4

I deceided to use this: http://www.svendtofte.com/code/date_format/
Which worked perfectly for my application

any other suggestions, ideas or "feature requests" would be great!

- JS
 
D

Dr John Stockton

JRS: In article <[email protected]>
, dated Wed, 26 Apr 2006 06:04:12 remote, seen in
news:comp.lang.javascript said:
Thise does not work for dates preceeding 100 AD, it would just return
the milliseconds for "1901" instead of "01"AD

IIRC, it will work for most dates before 100 AD, though not for all of
them;
e.g. new Date(-999, 0, 1, 1) seems fine.

IIRC, new Date(1000, 12*Y+M-12001, D) will work for a sufficiently
wide year range.


If these are just civil dates, it will be more efficient to use the UTC
functions; and one should be aware that the non-UTC functions will apply
Summer Time for all years, even before the first use of Summer Time in
1915.


It might in the end be simpler to store dates as CJD or similar
(functions to convert to/from Julian/Gregorian are available via below)
and use Greg/Jul only for I/O.
 
J

jshanman

Dr said:
JRS: In article <[email protected]>
, dated Wed, 26 Apr 2006 06:04:12 remote, seen in


IIRC, it will work for most dates before 100 AD, though not for all of
them;
e.g. new Date(-999, 0, 1, 1) seems fine.

IIRC, new Date(1000, 12*Y+M-12001, D) will work for a sufficiently
wide year range.


If these are just civil dates, it will be more efficient to use the UTC
functions; and one should be aware that the non-UTC functions will apply
Summer Time for all years, even before the first use of Summer Time in
1915.

How would this make a differance for a program that plots out every
hour as a marker? Are you saying it would plot 25 hours in one day in
the spring, and plot 23 hours in one day in the fall? Are the UTC
functions actually *faster*?
It might in the end be simpler to store dates as CJD or similar
(functions to convert to/from Julian/Gregorian are available via below)
and use Greg/Jul only for I/O.
I used several of your julian functions in my previous timeline and
will transfer them to this one as well...

CJD? is that Julian Day? Why would this be more efficient?

- JS
 
D

Dr John Stockton

JRS: In article <[email protected]>
, dated Thu, 27 Apr 2006 13:50:10 remote, seen in
news:comp.lang.javascript said:
Dr John Stockton wrote:

How would this make a differance for a program that plots out every
hour as a marker? Are you saying it would plot 25 hours in one day in
the spring, and plot 23 hours in one day in the fall? Are the UTC
functions actually *faster*?

If you want to plot *every hour*, in local civil time, then you MUST do
that 23/25 business. And the added/removed hour-of-year depends on year
and location. Note that, by specification, the Date Object has access
to only the *local* *current* Summer Time Rules, as held in the OS.

(And remember that the USA changed to Gregorian some hours UTC after
Britain did.)

The UTC functions are often faster than the corresponding non-UTC ones,
because they need to do less work. Algorithms using numbers rather than
a Date Object can be quicker still, where they avoid repeating work.

I used several of your julian functions in my previous timeline and
will transfer them to this one as well...

CJD? is that Julian Day? Why would this be more efficient?

You need to have read the references provided in my previous signature
(repeated). CJD is Chronological Julian Date, changing at civil
midnight. Today is CJD 2453854, from inception at the eastmost zone
west of the Date Line to extinction at the westmost zone East of the
Line.

I wrote "simpler", which is not the same as "more efficient".


With Civil Time, you'll need to allow for such things as Alaska having
had (once) two Fridays in one week; and Sweden 1700-1753.
 

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,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top