
I used Simile Timeline for the second time on ASP.NET the other day. The Simile Timeline documentation is a bit sparse, but the Google Group supporting it is good.
There's lots of stuff out there on Google about using Simile Timeline with ASP.NET specifically, but as usual much of it is wrong. As a probably pointless attempt to counter those who spend their time copying incorrect data around the internet, here's some correct data about using Simile Timeline on ASP.NET 3.5.
This stuff actually works, and I know because I built it and sold it to someone. If you're in the class of sad copiers, don't forget to correct my spelling mistakes when you steal this.
Loading
The standard Timeline distribution uses a body "OnLoad" JavaScript call to make everything happen. If you're two nested master pages down and inside a Timeline user control, you may think that's a bit of a problem. Well, the chaps on the 'net do.
It's not a problem. Just inject something which runs on some page load event which you do have access to. I'm already using jQuery so it's a simple matter to use jQuery(document).ready(), but there are plenty of alternatives including those from Microsoft, all of which are easy to inject. Forget the baroque stuff: just think about what it's doing and then do it in the most efficient way.
As it happens I'm not doing a straight page load. My content is Ajax lazy-loaded, not that it matters, but it would if you tried the sort of complicated solutions I've seen out there. My jQuery works fine in this scenario as you'd expect. Body OnLoad() events would not.
Deployment
Stick it all in a user control and make that inject the Timeline standard scripts and the preamble using whatever parameters you need. I'm using this in a complicated environment with multiple asynchronous data sources. If you don't keep things like this simple and contained then you have no hope of maintaining them.
Data Sources
I'm using a SQL Server 2008 database spewing out XML via "FOR XML PATH()". That's sucked out through a Stored Procedure by an ashx handler, which takes my parameters, passes them to the DB and returns the output as application/xml. Doing it this way makes it easy to test the XML separately from the rest.
Loading Message Defect
Using XML shows up one Timeline defect, which is that the "loading" message doesn't appear for XML data loads. Taking a look at the preamble JS it's pretty easy to see how to hack around that:
- Turn on the message explicitly just before you request the XML. The preamble makes an async call for the XML in the preamble, so whilst it's getting that XML in the background for you the message is on display.
- Turn off the message when the XML loads. Do it carefully so you're not burned if the XML should load faster than you expect.
I use jQuery to toggle the display attribute of the div with the class of .timeline-message-container, which is where the message is. If you can't work it out, mail me. I'll not put it here or some half-wit will copy it and republish it incorrectly, which is not what I'm trying to achieve.
Bubble Date Formats
The default date displayed for my date-only (no timestamp) events is eg: "10 Dec 2009 00:00:00" which implies more precision than my data have. Worse, if I run this on some machines, the result for the same date would be "09 Dec 2009 23:00:00". The JavaScript (or something else - it's not my database) appears to be doing some date format adjustment for daylight saving time. That's find and dandy, but it puts my events one day out, in some but not all circumstances. Weird. The solution to both problems is the same thing, replace the labelPrecise function in timeline-bundle.js with:
Timeline.GregorianDateLabeller.prototype.labelPrecise = function(date) {return date.format("dd MMM yyyy");};
Coloured Tapes
I tried changing the background images for the small tape at the bottom of the page, but that doesn't seem to work. However setting a "classname" on the items does work, with the priviso that the class is prefixed with "small-" for the tapes at the bottom. So set, for example: "journal", then pick it up with:
.timeline-band-events .small-journal { background: #ff0; }
Resizing
Timeline has an "onResize()" function which they also stick on the body tag by default. As above, that's not the best way to do it in many ASP.NET scenarios. I just stuck the whole Timeline into a jQuery().resizable() container, then made the "stop" function of that call the layout(); function of Timeline. So now I can ghost the panel as the user dynamically resizes it, constrain the maximum and minimum dimensions, and rapidly update the timeline when the user lets go.