How to Create Timelines

Table of Contents:

Getting Started

Here are a few easy steps to create a simple timeline. Open up your favorite text or HTML editor and start creating an HTML file.

Step 1. Link to the API

In your HTML code, link to Timeline's Javascript API code as follows:

<html>
  <head>
    ...
    <script src="http://simile.mit.edu/timeline/api/timeline-api.js" type="text/javascript"></script>
    ...
  </head>
  <body>
    ...
  </body>
</html>

Step 2. Create a DIV Element

Create a div element in your HTML code, e.g.

<div id="my-timeline" style="height: 150px; border: 1px solid #aaa"></div>
You should give it an ID as well as fix its height. You can optionally set its borders—this usually makes the timeline look better.

Step 3. Call Timeline.create()

Add two event handlers, onload and onresize, to the body element:

  <body onload="onLoad();" onresize="onResize();">
    ...
  </body>
Then write the following code in a script block or a separate Javascript file:
function onLoad() {
    var tl;
    var theme = Timeline.ClassicTheme.create();
    theme.event.bubble.width = 350;
    theme.event.bubble.height = 300;
    
    var eventSource = new Timeline.DefaultEventSource();

    var d = Timeline.DateTime.parseGregorianDateTime("2020")
	var bandInfos = [
			 Timeline.createBandInfo({
				 timeZone:       -5,
				 width:          "30%", 
				 intervalUnit:   Timeline.DateTime.YEAR, 
				 eventSource:    eventSource, //ael
				 date:	d,
				 intervalPixels: 200,
				 theme:          theme,
				 overview:		true,
				 layout:         'overview'  // original, overview, detailed
				 
			     }),
			 Timeline.createBandInfo({
				 timeZone:       -5,
				 width:          "70%", 
				 intervalUnit:   Timeline.DateTime.MONTH, 
				 eventSource:    eventSource, //ael
				 trackHeight:    0.5,
				 trackGap:       0.2,
				 date:	d,
				 intervalPixels: 100,
				 theme:          theme,
				 layout:         'original'  // original, overview, detailed
			     })
			 ];
    
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
}

var resizeTimerID = null;
function onResize() {
    if (resizeTimerID == null) {
        resizeTimerID = window.setTimeout(function() {
            resizeTimerID = null;
            tl.layout();
        }, 500);
    }
}
Note that if we put the code to construct the timeline in the onload handler to make sure that when we start to use Timeline's API, all its code has been loaded. That code creates a horizontal timeline (below) with 2 bands: in the top band, a month spans 100 pixels (approximately, since a month here refers to 30 days while not every month is exactly 30 days long); and in the bottom band, a year spans 200 pixels. The top band takes up 70% of the timeline's height, and the bottom band 30%. Note that the two bands scroll independently.

To make the two bands scroll in synchrony, and then to make the bottom band highlights the visible time span of the top band, add the following code (highlighted) before creating the timeline:

function onLoad() {
...
  bandInfos[1].syncWith = 0;
  bandInfos[1].highlight = true;
  
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
}
If you try to pan one band, the other is scrolled as well. (The second band is also highlighted -- which removed the "shading" from the timeline above.)

Step 4. Add Events

To add events to the timeline, create an event source and load it with data from an XML file (example1.xml):

function onLoad() {
  var eventSource = new Timeline.DefaultEventSource();
  var bandInfos = [
    Timeline.createBandInfo({
        eventSource:    eventSource,
        date:           "Jun 28 2006 00:00:00 GMT",
        width:          "70%", 
        intervalUnit:   Timeline.DateTime.MONTH, 
        intervalPixels: 100
    }),
    Timeline.createBandInfo({
        eventSource:    eventSource,
        date:           "Jun 28 2006 00:00:00 GMT",
        width:          "30%", 
        intervalUnit:   Timeline.DateTime.YEAR, 
        intervalPixels: 200,
  overview:	true
    })
  ];
  bandInfos[1].syncWith = 0;
  bandInfos[1].highlight = true;
  
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
  Timeline.loadXML("example1.xml", function(xml, url) { eventSource.loadXML(xml, url); });
}
The date field is there to make sure the timeline starts out showing the events immediately without requiring the user to pan first. The overview setting is set to true so that the lower band only shows approximate positions of events seen in the upper band. Here is the resulting timeline with 3 events:

As shown in example1.xml, there are 3 types of events: a duration, an instantaneous event with an imprecise starting time, and an instantaneous event with a precise starting time. Click on the events to see how their bubbles are rendered based on the data in the XML file. For the exact format of such XML files, refer to the documentation on event sources. Note that loading XML files is only one way in which you can add events to timelines.

Differentiating the Two Bands

Looking at the previous timeline, it is obvious that the lower band looks denser, and it will become a lot denser a lot quicker than the upper band should we add more events. The lower band acts as a zoomed-out overview for the upper band and it does not have to show as much detail as the upper band. We can turn off the rendering of text as well as condense the event markings vertically:

function onLoad() {
  var eventSource = new Timeline.DefaultEventSource();
  var bandInfos = [
    Timeline.createBandInfo({
        eventSource:    eventSource,
        date:           "Jun 28 2006 00:00:00 GMT",
        width:          "70%", 
        intervalUnit:   Timeline.DateTime.MONTH, 
        intervalPixels: 100
    }),
    Timeline.createBandInfo({
        showEventText:  false,
        trackHeight:    0.5,
        trackGap:       0.2,
        eventSource:    eventSource,
        date:           "Jun 28 2006 00:00:00 GMT",
        width:          "30%", 
        intervalUnit:   Timeline.DateTime.YEAR, 
        intervalPixels: 200,
        overview:	true
    })
  ];
  bandInfos[1].syncWith = 0;
  bandInfos[1].highlight = true;
  
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
  Timeline.loadXML("example1.xml", function(xml, url) { eventSource.loadXML(xml, url); });
}
The lower band of the timeline below does not show text and its event markers are also smaller. But note that the third event is vertically aligned with the first event in the lower band, but it is on its own track in the upper band. We will address this problem later.

Understanding Initialization Settings

By now you must have realized that Timeline.createBandInfo() fills in default settings, which can be overridden, for constructing a band in a timeline. What Timeline.createBandInfo() does is something like this (in pseudo-code):

Timeline.createBandInfo = function(params) {
  return {
    width:          params.width,
    eventSource:    params.eventSource (or null by default),
    timeZone:       params.timeZone (or 0 by default),
    ether:          new Timeline.LinearEther({
                      interval:          the number of milliseconds in params.intervalUnit,
                      pixelsPerInterval: params.intervalPixels,
                      centersOn:         params.date (or the current date by default)
                    }),
    etherPainter:   new Timeline.GregorianEtherPainter({
                      unit:              params.intervalUnit,
                      theme:             params.theme (or the default theme)
                    }),
    eventPainter:   new Timeline.DurationEventPainter({
                      showText:          params.showEventText (or true by default),
                      theme:             the same theme above,
                      trackHeight:       params.trackHeight (or the default track height in the theme),
                      trackGap:          params.trackHeight (or the default track gap in the theme),
                      layout:            new Timeline.StaticTrackBasedLayout({
                                           eventSource: the same eventSource above,
                                           ether:       the same ether above,
                                           showText:    the same showText value above,
                                           theme:       the same theme above
                                         })
                    })
  }
};
In other words, Timeline.createBandInfo() takes an object whose fields store initialization settings and returns yet another object whose fields stores initialization settings that Timeline.create() can understand. Timeline.createBandInfo() does the work of routing each initialization setting that you give it to the appropriate place(s). For example, params.intervalUnit is used referenced twice above, once to construct an ether and once to construct an ether painter. Whatever default setting that Timeline.createBandInfo() doesn't provide is provided by the theme.

The ether of a band dictates how time is mapped onto the pixel space: how many pixels a time span takes up. The ether painter makes this mapping visible to the user by painting various markings on the background of the band, e.g., "Jun", "Jul", "2005", "2006". The event painter, obviously, paints the events that are fed to it by the ether source. The Timeline.DurationEventPainter uses a layout to determine how to distribute the events among several tracks such that events don't overlap one another.

Hot Zones

Now we load example2.xml, which contains a few more details for "Trip to Beijing" and discover that the days starting on August 2, 2006, are quite cramped:

To solve this problem, we will distort the time of those days, producing the effect of zooming in. Because we want time to flow differently than before—we want time spans to be mapped to pixels in a different way, we need a different kind of ether (and a different kind of ether painter to go with it):

function onLoad() {
  var eventSource = new Timeline.DefaultEventSource();
  var bandInfos = [
    Timeline.createHotZoneBandInfo({
        zones: [
            {   start:    "Aug 01 2006 00:00:00 GMT-0500",
                end:      "Sep 01 2006 00:00:00 GMT-0500",
                magnify:  10,
                unit:     Timeline.DateTime.WEEK
            },
            {   start:    "Aug 02 2006 00:00:00 GMT-0500",
                end:      "Aug 04 2006 00:00:00 GMT-0500",
                magnify:  7,
                unit:     Timeline.DateTime.DAY
            },
            {   start:    "Aug 02 2006 06:00:00 GMT-0500",
                end:      "Aug 02 2006 12:00:00 GMT-0500",
                magnify:  5,
                unit:     Timeline.DateTime.HOUR
            }
        ],
        timeZone:       -5,
        eventSource:    eventSource,
        date:           "Jun 28 2006 00:00:00 GMT",
        width:          "70%", 
        intervalUnit:   Timeline.DateTime.MONTH, 
        intervalPixels: 100
    }),
    Timeline.createBandInfo({
        timeZone:       -5,
        eventSource:    eventSource,
        date:           "Jun 28 2006 00:00:00 GMT",
        width:          "30%", 
        intervalUnit:   Timeline.DateTime.YEAR, 
        intervalPixels: 200,
        overview:	true
    })
  ];
  bandInfos[1].syncWith = 0;
  bandInfos[1].highlight = true;
  
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
  Timeline.loadXML("example1.xml", function(xml, url) { eventSource.loadXML(xml, url); });
}
In the resulting timeline below, the whole month of August 2006 is stretched out 10 times, showing weekly intervals; the two days of August 2nd and August 3rd are stretched out another 7 times; and then the time between 6am to noon on August 2nd is stretched out another 5 times, showing hourly intervals. All this stretching is done to the upper band only, so if you pan the upper band, observe how the lower band's highlight grows and shrinks.

Of course, panning the lower band over the hot zones of the upper band now makes the upper band a little jumpy. We can distort the lower band to reduce this effect:

function onLoad() {
  var eventSource = new Timeline.DefaultEventSource();
  var bandInfos = [
    Timeline.createHotZoneBandInfo({
        zones: [
            {   start:    "Aug 01 2006 00:00:00 GMT-0500",
                end:      "Sep 01 2006 00:00:00 GMT-0500",
                magnify:  10,
                unit:     Timeline.DateTime.WEEK
            },
            {   start:    "Aug 02 2006 00:00:00 GMT-0500",
                end:      "Aug 04 2006 00:00:00 GMT-0500",
                magnify:  7,
                unit:     Timeline.DateTime.DAY
            },
            {   start:    "Aug 02 2006 06:00:00 GMT-0500",
                end:      "Aug 02 2006 12:00:00 GMT-0500",
                magnify:  5,
                unit:     Timeline.DateTime.HOUR
            }
        ],
        timeZone:       -5,
        eventSource:    eventSource,
        date:           "Jun 28 2006 00:00:00 GMT",
        width:          "70%", 
        intervalUnit:   Timeline.DateTime.MONTH, 
        intervalPixels: 100
    }),
    Timeline.createHotZoneBandInfo({
        zones: [
            {   start:    "Aug 01 2006 00:00:00 GMT-0500",
                end:      "Sep 01 2006 00:00:00 GMT-0500",
                magnify:  20,
                unit:     Timeline.DateTime.WEEK
            }
        ],
        timeZone:       -5,
        eventSource:    eventSource,
        date:           "Jun 28 2006 00:00:00 GMT",
        width:          "30%", 
        intervalUnit:   Timeline.DateTime.YEAR, 
        intervalPixels: 200,
        overview:	true
    })
  ];
  bandInfos[1].syncWith = 0;
  bandInfos[1].highlight = true;
  
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
  Timeline.loadXML("example1.xml", function(xml, url) { eventSource.loadXML(xml, url); });
}

The resulting timeline below still needs a few more iteration to make it smooth. But I hope this has been a good starting point for you.

Mouse-wheel zooming and scrolling

Hot zones can be a challenge to create for dynamically generated data. They also can be somewhat confusing if there are many of them and they are distorting the timeline. An alternate approach is to enable the user to dynamically scale the interval presented on the timeline. A zoom feature has been created to enable this.

The mouse-wheel can be set for one of three modes:

The first step to enabling zoom is ensuring that it is enabled within your theme (the default theme is shown below):

Timeline.ClassicTheme._Impl = function() {
    ...
    
    this.mouseWheel = 'zoom'; // 'default', 'zoom', 'scroll'
};
Next you decide the intervalPixels/intervalUnit steps that you would like the user to be able to zoom to. The BandInfo object's intervalUnit and intervalPixels parameters must correspond with one of these steps, and the index of this default step must be passed along as the zoomIndex.
function onLoad() {
  var eventSource = new Timeline.DefaultEventSource();
  var bandInfos = [
        Timeline.createBandInfo({
            date:           "Jun 28 2006 00:00:00 GMT",
            width:          "70%", 
            intervalUnit:   Timeline.DateTime.MONTH, 
            intervalPixels: 100,
            eventSource:    eventSource,
            zoomIndex:      10,
            zoomSteps:      new Array(
              {pixelsPerInterval: 280,  unit: Timeline.DateTime.HOUR},
              {pixelsPerInterval: 140,  unit: Timeline.DateTime.HOUR},
              {pixelsPerInterval:  70,  unit: Timeline.DateTime.HOUR},
              {pixelsPerInterval:  35,  unit: Timeline.DateTime.HOUR},
              {pixelsPerInterval: 400,  unit: Timeline.DateTime.DAY},
              {pixelsPerInterval: 200,  unit: Timeline.DateTime.DAY},
              {pixelsPerInterval: 100,  unit: Timeline.DateTime.DAY},
              {pixelsPerInterval:  50,  unit: Timeline.DateTime.DAY},
              {pixelsPerInterval: 400,  unit: Timeline.DateTime.MONTH},
              {pixelsPerInterval: 200,  unit: Timeline.DateTime.MONTH},
              {pixelsPerInterval: 100,  unit: Timeline.DateTime.MONTH} // DEFAULT zoomIndex
            )
        }),
        Timeline.createBandInfo({
            date:           "Jun 28 2006 00:00:00 GMT",
            width:          "30%", 
            intervalUnit:   Timeline.DateTime.YEAR, 
            intervalPixels: 200,
            showEventText:  false, 
            trackHeight:    0.5,
            trackGap:       0.2,
            eventSource:    eventSource,
            overview:       true
        })
  ];
  bandInfos[1].syncWith = 0;
  bandInfos[1].highlight = true;
  
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
  Timeline.loadXML("example2.xml", function(xml, url) { eventSource.loadXML(xml, url); });
}
Try moving your mouse over the top band and scrolling your mouse wheel in and out. You will notice that the date where your cursor is hovering over as you zoom in and out stays static, meanwhile the rest of the timeline scales around it.

You can also enable zoom on the other bands in the same manner. Currently they zoom in and out independently of each other.