timeline.js

#

Global Timeline variable

var tl;
#

This file contains the timeline functions for initializing and creating the Timeline visualisation

#

Timeline visualisation creation

function init_timeline() {
	
	var tl_el,
	eventSource1,
	eventData,
	dateStart,
	dateStop,
	d,
	u,
	o,
	url,
	bandInfos,
	theme1,
	viewUnit,
	overviewUnit;
	
#

Timeline container is not yet visible

	var div = $('#div_timeline');
		div.css('display', 'inherit').css('visibility', 'visible');
		
#

preparing the timeline data

	tl_el = document.getElementById("timeline");
	eventSource1 = new Timeline.DefaultEventSource();
	eventData = create_timeline_data(mainpipe);
	
#

find the start and stop dates of the events to create the correct view

	dateStart = eventData.events[0].start;
	dateStop = eventData.events[0].start;
	
	for (i = 0; i < eventData.events.length; i++) {
		if (eventData.events[i].start < dateStart)
			dateStart = eventData.events[i].start;
		if (eventData.events[i].start > dateStop)
			dateStop = eventData.events[i].start;
	}
	
	dateStart.setYear(dateStart.getYear() - 10 );
	dateStop.setYear(dateStop.getYear() + 10 );
	
	u = GetSelectedText('MainViewUnit');
	o = GetSelectedText('OverViewUnit');
	
#

Helper functions to convert to input from the UI into the correct format, supported the the timeline API

	switch (u) {
	case "MINUTE":
		viewUnit = Timeline.DateTime.MINUTE;
		break;
	case "HOUR":
		viewUnit = Timeline.DateTime.HOUR;
		break;
	case "DAY":
		viewUnit = Timeline.DateTime.DAY;
		break;
	case "WEEK":
		viewUnit = Timeline.DateTime.WEEK;
		break;
	case "MONTH":
		viewUnit = Timeline.DateTime.MONTH;
		break;
	case "YEAR":
		viewUnit = Timeline.DateTime.YEAR;
		break;
	}
	switch (o) {
	case "MINUTE":
		overviewUnit = Timeline.DateTime.MINUTE;
		break;
	case "HOUR":
		overviewUnit = Timeline.DateTime.HOUR;
		break;
	case "DAY":
		overviewUnit = Timeline.DateTime.DAY;
		break;
	case "WEEK":
		overviewUnit = Timeline.DateTime.WEEK;
		break;
	case "MONTH":
		overviewUnit = Timeline.DateTime.MONTH;
		break;
	case "YEAR":
		overviewUnit = Timeline.DateTime.YEAR;
		break;
	}
	
	theme1 = Timeline.ClassicTheme.create();
	theme1.event.highlightColors[0] = "#FCE912";
	theme1.event.highlightColors[1] = "#F2A90C";
	theme1.event.highlightColors[2] = "#3383F2";
	theme1.event.highlightColors[3] = "#31DE6D";
#

settings for the timeline visualisation

	bandInfos = [
		Timeline.createBandInfo({
				width : "85%", // set to a minimum, autoWidth will then adjust
				intervalUnit : viewUnit,
				intervalPixels : 100,
				eventSource : eventSource1,
				theme : theme1,
				layout : 'original'// original, overview, detailed
			}),
		Timeline.createBandInfo({
				width : "15%", // set to a minimum, autoWidth will then adjust
				intervalUnit : overviewUnit,
				intervalPixels : 200,
				eventSource : eventSource1,
				theme : theme1,
				layout : 'overview'// original, overview, detailed
			})
	];
	
#

synchronize the band views

	bandInfos[1].syncWith = 0;
	bandInfos[1].highlight = true;
	
#

displays the Timeline in the UI

	tl = Timeline.create(tl_el, bandInfos, Timeline.HORIZONTAL);
	
	url = '.';
#

loads the data into the timeline

	eventSource1.loadJSON(eventData, url); 
	tl.layout();
	
#

initiates the controls for highlighting & filtering the data

	setupFilterHighlightControls(document.getElementById("timelineControls"), tl, [0,1], theme1);
	
}
#

Helper function for resizing.

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

Get the pubDate, link, title and description values and prepares the data format for the Timeline.

function create_timeline_data(pipe) {
	
	var json = {},
	i,
	items,
	ev;
	
	json.datTimeFormat = 'iso8601';
	json.wikiSection = pipe.value.title;
	json.wikiURL = pipe.value.link;
	json.events = [];
	
	items = pipe.flatItems;
	
	
#

Check if the items in the data have the required attributes.

	if( items[0].hasOwnProperty('pubDate') && items[0].hasOwnProperty('title') && items[0].hasOwnProperty('link') && items[0].hasOwnProperty('description') ) {
		for (i = 0; i < items.length; i++) {
			json.events[i] = {};
			item = items[i];
			
			json.events[i].start = item.pubDate;
			json.events[i].title = item.title;
			json.events[i].description = item.description;
			json.events[i].image = item.url;
			json.events[i].link = item.link;
			json.events[i].durationEvent = false;
		}
	}
#

update status text in UI

	else {
		update_status_text("Data not RSS standard. Please provide following items: title, link, description &amp; pubDate"); 
	}
#

data format used for init_time function

	return json; 
	
}
#

Setup for the UI controls highlighting & filtering

function setupFilterHighlightControls(div, timeline, bandIndices, theme) {
    var table = document.createElement("table");
    var tr = table.insertRow(0);
    
    var td = tr.insertCell(0);
    td.innerHTML = "Filter:";
    
    td = tr.insertCell(1);
    td.innerHTML = "Highlight:";
    
    var handler = function(elmt, evt, target) {
        onKeyPress(timeline, bandIndices, table);
    };
    
    tr = table.insertRow(1);
    tr.style.verticalAlign = "top";
    
    td = tr.insertCell(0);
    
    var input = document.createElement("input");
    input.type = "text";
    SimileAjax.DOM.registerEvent(input, "keypress", handler);
    td.appendChild(input);
    
    for (var i = 0; i < theme.event.highlightColors.length; i++) {
        td = tr.insertCell(i + 1);
        
        input = document.createElement("input");
        input.type = "text";
        SimileAjax.DOM.registerEvent(input, "keypress", handler);
        td.appendChild(input);
        
        var divColor = document.createElement("div");
        divColor.style.height = "0.5em";
        divColor.style.background = theme.event.highlightColors[i];
        td.appendChild(divColor);
    }
    
    td = tr.insertCell(tr.cells.length);
    var button = document.createElement("button");
    button.innerHTML = "Clear All";
    SimileAjax.DOM.registerEvent(button, "click", function() {
        clearAll(timeline, bandIndices, table);
    });
    td.appendChild(button);
    
	if( document.getElementById("timelineControls").innerHTML == '' ) {
		div.appendChild(table);
	} else {
		div.replaceChild(table, div.firstChild );
	}
	
}

var timerID = null;
#

Utility function for the Timeline filter UI

function onKeyPress(timeline, bandIndices, table) {
    if (timerID != null) {
        window.clearTimeout(timerID);
    }
    timerID = window.setTimeout(function() {
        performFiltering(timeline, bandIndices, table);
    }, 300);
}

function cleanString(s) {
    return s.replace(/^\s+/, '').replace(/\s+$/, '');
}
#

Filter the visualised data according to the user input

function performFiltering(timeline, bandIndices, table) {
    timerID = null;
    
    var tr = table.rows[1];
    var text = cleanString(tr.cells[0].firstChild.value);
    
    var filterMatcher = null;
    if (text.length > 0) {
        var regex = new RegExp(text, "i");
        filterMatcher = function(evt) {
            return regex.test(evt.getText()) || regex.test(evt.getDescription());
        };
    }
    
    var regexes = [];
    var hasHighlights = false;
    for (var x = 1; x < tr.cells.length - 1; x++) {
        var input = tr.cells[x].firstChild;
        var text2 = cleanString(input.value);
        if (text2.length > 0) {
            hasHighlights = true;
            regexes.push(new RegExp(text2, "i"));
        } else {
            regexes.push(null);
        }
    }
    var highlightMatcher = hasHighlights ? function(evt) {
        var text = evt.getText();
        var description = evt.getDescription();
        for (var x = 0; x < regexes.length; x++) {
            var regex = regexes[x];
            if (regex != null && (regex.test(text) || regex.test(description))) {
                return x;
            }
        }
        return -1;
    } : null;
    
    for (var i = 0; i < bandIndices.length; i++) {
        var bandIndex = bandIndices[i];
        timeline.getBand(bandIndex).getEventPainter().setFilterMatcher(filterMatcher);
        timeline.getBand(bandIndex).getEventPainter().setHighlightMatcher(highlightMatcher);
    }
    timeline.paint();
}
#

Timeline reset function

function clearAll(timeline, bandIndices, table) {
    var tr = table.rows[1];
    for (var x = 0; x < tr.cells.length - 1; x++) {
        tr.cells[x].firstChild.value = "";
    }
    
    for (var i = 0; i < bandIndices.length; i++) {
        var bandIndex = bandIndices[i];
        timeline.getBand(bandIndex).getEventPainter().setFilterMatcher(null);
        timeline.getBand(bandIndex).getEventPainter().setHighlightMatcher(null);
    }
    timeline.paint();
}