Ryan Kanno: The diary of an Enginerd in Hawaii

Everything you've ever thought, but never had the balls to say.

My LinkedIn Profile
Follow @ryankanno on Twitter
My Feed

Installing MIT Simile’s Timeline locally (w/ Rails integration)

Update: 5/24/2009

If you’re using a newer version of Simile’s Timeline, 2.3.1 as of this writing, and want to run it on your own local server, check out the comment made by Biju. Thanks Biju!

Update: 12/5/2007

Apparently, I’m still a rookie blogger and I forgot to mention that I was pulling from trunk (-r 8642). Don’t use the tags if you want the code below to work. :) Sorry about that neilo!

Since my past few blogs have been for the Django community, I’ll switch it up a little and talk about a visualization widget from those uber-smart kids at MIT.

Timeline

For one of my Rails prototypes at work, I decided to integrate Timeline; a pretty neat DHTML-based AJAXy widget for visualizing time-based events. Using a visual timeline is not only a lot ‘purrrrrtier’ than the mundane list-style displays, but it also gives a better relative perspective of how events overlap, their duration, etc.

In any case, I liked loved it, and I really wanted to use it.

Since I typically don’t have access to the Internet at work (I know, I know… a pseudo-developer without Internet access; welcome to my so-called life), I often have to download libraries and install them locally. Searching Timeline’s mailing list archives, I found one thread concerning the local installation of Exhibit.

Yet, nothing about Timeline.

So with that said, here’s the edits I made (kudos to Firebug developers). I would’ve created a patch file, but I was too lazy and the edits were too easy (sorry). :) Search for the following line in timeline-api.js (located in src/webapp/api directory in the downloadable distribution).

var url = useLocalResources ?
            "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
            "http://static.simile.mit.edu/ajax/api-2.0/simile-ajax-api.js";

and edit it to the following:

//var url = useLocalResources ?
//            "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
//            "http://static.simile.mit.edu/ajax/api-2.0/simile-ajax-api.js";
var url = (document.location.toString().indexOf('https://') != -1 ? "https" : "http") + "://" + window.location.href.split("/")[2] + "WEB_URL_TO /src/ajax/api/simile-ajax-api.js?bundle=false";

Basically, instead of using the supplied Jetty webserver, we’re just editing the url to your local installation of the file. Remember to change WEB_URL_TO to the path to the simile-ajax-api.js file in your own environment. Typically, one would put this file in a publicly accessible web folder named js, javascript, etc.

Voila!

As an added bonus, nowhere in Timeline’s documentation or examples does it indicate how to load inline event data. When I say inline, I mean dynamic data produced as a result of an action; in this case a search query. I want to be able to query on a set of dates and produce all event data points between those dates. Timeline’s typical use case is to load data from a javascript (.js) file. Personally, since the data is dynamic, I didn’t feel like writing a temp file publicly accessible by the web server or creating a REST action exposing the dynamic data; both of which are viable solutions, the latter more ideal than the former. I just wanted to write JSON inside of the rendered html file and load the Timeline. To do so, instead of coding the following (like in their cubism example):

      tl = Timeline.create(document.getElementById("tl"), bandInfos, Timeline.HORIZONTAL);
      tl.loadJSON("cubism.js", function(json, url) {
           eventSource.loadJSON(json, url);
      });

Using a rails example, this is what I included in my view:

<% if @include_timeline %>
    <%= javascript_include_tag 'PATH_TO/timeline-api.js?timeline-use-local-resources=true' %> 
    <script>
      var tl;
 
      var events = {
        <% if @events %>
        'dateTimeFormat': 'iso8601',
        'events': [
          <% @events.each_with_index do |event, i| %>
          {
            <% if event.start and event.end %>
             'start': '<%= event.start.iso8601 %>',
             'end'  : '<%= event.end.iso8601 %>',
            <% else %>
             'start': '<%= event.occurred.iso8601 %>',
            <% end %>
            'title': '<%= event.headline %>',
            'description': '<%= event.description %>'
          }<% if i != @events.length - 1 -%>, <% end -%>
          <% end %>
        ]
        <% end %>       
      };
 
      function onLoad() {
        var eventSource = new Timeline.DefaultEventSource(); 
        var theme = Timeline.ClassicTheme.create();
        theme.event.label.width = 250;
        theme.event.bubble.width=320;
        theme.event.bubble.height=220;
        var bandInfos = [
          Timeline.createBandInfo({
              width: "20%",
              intervalUnit: Timeline.DateTime.DAY,
              intervalPixels: 100,
              eventSource: eventSource,
              theme:theme
          }),
          Timeline.createBandInfo({
              width: "50%",
              intervalUnit: Timeline.DateTime.MONTH,
              intervalPixels: 100,
              eventSource: eventSource,
              theme:theme
          }),
          Timeline.createBandInfo({
              width: "30%",
              intervalUnit: Timeline.DateTime.YEAR,
              intervalPixels: 200,
              eventSource: eventSource,
              theme:theme
          })
        ];
        bandInfos[1].syncWith = 0;
        bandInfos[2].syncWith = 0;
        bandInfos[2].highlight = true;
        tl = Timeline.create(document.getElementById("timeline"), bandInfos);
        eventSource.loadJSON(events, '');
      }
      var resizeTimerID = null;
      function onResize() {
          if (resizeTimerID == null) {
              resizeTimerID = window.setTimeout(function() {
                  resizeTimerID = null;
                  tl.layout();
              }, 500);
          }
      }
    </script>
  <% end %>

Things that you should take note of:

  • I used Ruby’s DateTime iso8601 message to help pass a date that Timeline could understand.
  • I called eventSource.loadJSON(events, ”); where I passed in the events JSON array.

Hopefully, these two pointers can help you save some time integrating Timeline into your project! Since this is on my blog, feel totally free to take/use/steal/distribute/copy/modify any code you see fit. All I ask is if you find any bugs, have any comments, or can think of ways to make my ugly code cleaner – I’d love to hear from you. :)

Enjoy!

Popularity: 41% [?]

  1. Dude! Can this be the answer for that better world clock/battle rhythm thingy I’ve complained about in the past (and on my intranet blog)? Could be…

  2. Eerie: I’m currently working on a Ruby project in which we are dying to use SIMILE, and our team went through the very same thought process yesterday. Hmmm… of course we will want to dynamically pull the data points. So, if there’s no documentation to cover that, I’ll just create my own JSON loader.

    I imagine my work would look shockingly similar. KUDOS to you.

    – T

  3. Hi,

    This looks good – and I’m using very similar code – but getting no events displayed and and following alert:

    Failed to load json data from [object Object]
    Not Found

    Any ideas?
    thx

  4. You should try to inspect the object with Firebug, but having played with the widget a bit, I suspect it’s because you’re passing in an invalid json object. Check the brackets, commas, and parantheses. (But that’s purely conjecture) :)

  5. Ok, thx, have now tried that – but still getting the same lack of events – heres the code – json is very simple!:

    var tl;
    var events = {
    ‘dateTimeFormat’: ‘iso6801′,
    ‘events’: [
    { 'start': '1912',
    'title': 'xxxxx',
    'description': 'desc'
    }
    ]
    };

    function onLoad() {
    var eventSource = new Timeline.DefaultEventSource();

    var theme = Timeline.ClassicTheme.create();
    theme.event.bubble.width = 320;
    theme.event.bubble.height = 220;
    var d = Timeline.DateTime.parseGregorianDateTime(“1900″)
    var bandInfos = [
    Timeline.createBandInfo({
    width: "100%",
    intervalUnit: Timeline.DateTime.DECADE,
    intervalPixels: 200,
    eventSource: eventSource,
    date: d,
    theme: theme
    })
    ];

    tl = Timeline.create(document.getElementById(“timeline-default”), bandInfos);
    tl.loadJSON( events, ” );
    }

    var resizeTimerID = null;
    function onResize() {
    if (resizeTimerID == null) {
    resizeTimerID = window.setTimeout(function() {
    resizeTimerID = null;
    tl.layout();
    }, 500);
    }
    }

    Also, tried to run timeline locally using your instructions – but can’t find the useLocalResources line to change in timeline-api.js – using v1.2 – did you use an earlier version maybe? I downloaded the source into my html directory – runs fine via jetty.

    Sorry to bother – any help gratefully appreciated!

    n

  6. I’m sorry Neilo.

    I totally forgot to mention in my post that I was pulling from trunk (-r 8924), the 1.2 tag doesn’t have the code. This is also probably where you’re getting your errors. :)

    http://simile.mit.edu/repository/timeline/trunk/src/webapp/api/timeline-api.js

  7. Ah ok, trunk works. But still getting the json error – and I don’t see how I can make it any simpler?

    var events = {
    ‘dateTimeFormat’: ‘iso6801′,
    ‘events’: [
    { ’start’: ‘1912′,
    ‘title’: ‘xxxxx’,
    ‘description’: ‘desc’
    }
    ]
    };

    Was looking for an online json validator – do you know of one?

  8. @neilo -

    Looking at how your code is appearing on my blog, I’m wondering what character you are using for your apostrophes. In both instances, I’m not sure what character that is, but the Json spec only allows for a particular grammar though I know some parsers are a little more forgiving.

    Read this post –> http://tech.groups.yahoo.com/group/json/message/810

    http://www.jslint.com might be what you’re looking for.

  9. Hi,
    i use http://simile.mit.edu/repository/timeline/trunk/src/webapp/api/timeline-api.js
    and change
    //var url = useLocalResources ?
    // “http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false” :
    // “http://static.simile.mit.edu/ajax/api-2.0/simile-ajax-api.js”;
    var url = (document.location.toString().indexOf(‘https://’) != -1 ? “https” : “http”) + “://” + window.location.href.split(“/”)[2] + “WEB_URL_TO /src/ajax/api/simile-ajax-api.js?bundle=false”

    but it say Timeline is not defined
    [Break on this error] var eventSource = new Timeline.DefaultEventSource();

    if i don’t change that file (/timeline-api.js ) it say like Neilo. [object Object]
    ** my code is similar Neilo very simple.

    will waiting for you thank for ideas.

  10. @pop -

    I hope you didn’t copy that line verbatim. The WEB_URL_TO is meant to represent the web path to where you keep the simile-ajax-api.js file on your own web server. It’ll probably be something different for each person. Could that possibly be your problem? :)

  11. Thx for that. Switched to double quotes and json validates fine, but still getting that error: Failed to load json data from [object Object]
    Not Found

    Printed out values from the object as alerts, so seems problem is with the loadJson fn. Think I may have to resort to writing xml files, which is a shame! :(

  12. thank for help but same problem (timeline no property) when i use this line:
    var url = (document.location.toString().indexOf(‘https://’) != -1 ? “https” : “http”) + “://” + window.location.href.split(“/”)[2] + “127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false”;

    any idea for me ?
    thank alot.

  13. @neilo

    That’s interesting. Check your email. I sent you an email. Send me your code and I’ll help you debug. I hate when I read other developer’s blogs and things don’t work out, so the least I can do is help you debug. :)

  14. @pop

    If you put this url in your web browser does anything load?

    http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false

    If nothing loads, then the path to your simile-ajax-api.js file is bad. Basically, what my edit does is change the url to the simile-ajax-api.js file to a path on your own web server. If you can’t hit the above url, you must change it to a web url that exists and is serving up that file. :)

  15. yes this link direct to my simile-ajax-api.js file. that is my problem why it say no property
    because url is correct. :(

    thanks for idea.

  16. oh ryankanno
    i have other way to use dynamic database to show on timeline.
    thanks for your help.

  17. [...] I found a few other articles that were helpful, including a couple from LifeCycle Solutions and Ryan Kanno. Then it was just a matter of trying it [...]

  18. Excellent … the instructions were easy to follow and had the local server serving up a timeline in half an hour. Just one thought tho’. In the last 2 mnths I’ve been converted to php from c#. I’ve no experience with rails and I just don’t want to go there at the moment. Any way to convert your dynamic event example to a simple php script ?

  19. @John -

    Send me an email and when I have free time, I’ll convert it to a php script.

  20. @neilo

    You should use ” eventSource.loadJSON(events, ”); “, not ” tl.loadJSON( events, ” ); “…

  21. I want to make a Timeline that can be run from one HTML file with all of the javascript in a single block. I have tried placing the contents of timeline-bundle.js and simile-ajax-bundle.js into the script block. The error I’m getting is that Timeline is undefined. Do you have any thoughts on how to fix this?

    Thanks!

  22. @Micajah – If you install Firebug (http://www.getfirebug.com/), it’ll most likely help solve your problem. That’s what I used to figure out what was being called by the javascript – using its debugger.

  23. if i put this url in my web browser,

    http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false

    i am able to load the js file.

    But my problem is i am not able to view the events..i am able to view the timeline

    Its throwing the js error like “Failed to create view Terms”. Terms is the label i have given like in the div-> ex:label=”Terms”

    Please help me in this issue.

  24. @rkiran –

    It’s been a while since I’ve looked at the library, but I suspect that your JSON is probably incorrect – I remember having this issue when I didn’t use a valid iso8601 date/time format. Could this be the source of your error?

  25. [...] I found a few other articles that were helpful, including a couple from LifeCycle Solutions and Ryan Kanno. Then it was just a matter of trying it [...]

  26. Hi,

    I hate to bring up an old topic, but I followed your guide (the first part, not the rails part), and there were more steps. simile-ajax-api.js pointed to some other external javascript files and after downloading those, it works, but there’s one thing in particular i’m trying to accomplish:

    Instead of calling a bubble when an event is clicked, i want to call a lightbox event. I had this working before (making it local) by changing the Timeline.OriginalEventPainter.prototype._showBubble function in “original-painter.js” on line 489 to contain my own call to a lightbox event.

    Unfortunately, it looks like the local copy doesn’t even look at this file (“original-painter.js”) and I was wondering if you knew where the new code is that calls the bubble event. Any ideas?

    Thank you so much!

    Keith

  27. Worked perfectly, great job!

  28. this is like 99% there… how can I create and run a timeline without access to the Internet on my stand-alone machine – NO WEB SERVER. The above instructions do not work!!

    I am replacing “WEB_URL_TO /src/ajax/api/simile-ajax-api.js?bundle=false”; with “../../ajax/api/simile-ajax-api.js?bundle=false”;

    Any ideas why??

  29. @Tim

    Sorry, I haven’t looked at Simile in a little while. However, with no web server, have you tried using the file:/// URI syntax? I don’t see why the relative path wouldn’t work either, but I’m suspecting they are using the base domain for something and maybe that’s throwing everything else off. Does Firebug indicate that the script even loaded?

  30. Great info..

    I was just going through timeline_2.3.1, what they say is in the html page, where we need to include timline, add the following

    Timeline_ajax_url=”http://YOUR_SERVER/javascripts/timeline/timeline_ajax/simile-ajax-api.js”;
    Timeline_urlPrefix=’http://YOUR_SERVER/javascripts/timeline/timeline_js/’;
    Timeline_parameters=’bundle=true’;

    So no need to edit timeline js files in newer versions.

Please leave a reply »

Powered by Wordpress. Stalk me.