var timeline = function() { // CONFIG VALUES this.public_instance = ''; // THE STAGE OBJECT HOLDS REFERENCES TO THE HTML ELEMENTS USED IN THE TIMELINE this.stage = { 'root': '', 'canvas': '', 'context': '', 'notes': '', 'years': '', 'teams': '', 'titles': '' } // THE TIMELINE OBJECT HOLDS THE DATA PULLED OUT OF THE HTML this.timeline = { 'data': [], 'start_year': 1980, 'end_year': 2010 } // INIT FUNCTION this.init = function(el) { this.stage.root = el; // set a reference in the global space if (typeof(window.timelines) == "undefined") { window.timelines = []; } window.timelines.push(this); this.public_instance = window.timelines[window.timelines.length-1]; this.stage.teams = this.stage.root.find('UL#timeline-data LI'); this.set_timeline_data(); this.stage.root.addClass('timeline-display'); this.set_timeline_width(); var t = this; // THIS IS A BIT OF A HACK, WAIT 5ms BEFORE RUNNING BUILDING THE TIMELINE BAR AND DRAWING THE LINKS. ON SOME BROWSERS THE WIDTHS GET ALL SCREWED UP WHEN YOU TRY TO DO IT ALL AT ONCE setTimeout(function(){ t.setup_timeline_bar(); t.setup_timeline_actions(); t.draw_all_timeline_links(); }, 50); } // SET THE WIDTH OF THE TEAMS LI ELEMENTS SO THEY TAKE UP 100% OF THE GRAPHIC this.set_timeline_width = function() { this.stage.teams.width(this.stage.root.width() / this.timeline.data.length); } // ATTACH ACTIONS TO THE LI ELEMENTS this.setup_timeline_actions = function() { public_instance = this.public_instance; this.stage.teams.hover(function() { public_instance.draw_timeline_links(this); }); this.stage.years.find('LI').hover(function() { public_instance.draw_matchup(this); }); } // PART OF THE INIT FUNCTION. CAPTURE THE DATA FROM THE HTML MARKUP AND STORE IT FOR FASTER ACCESS. this.set_timeline_data = function() { this.timeline.data = this.stage.teams.map(function() { var timeline_item = {'el': $(this), 'wins': [], 'losses': [], 'notes':[] }; $(this).find('.timeline .win').each(function(){ var d = new Date($(this).attr('title')); timeline_item.wins.push(d); }); $(this).find('.timeline .lose').each(function(){ var d = new Date($(this).attr('title')); timeline_item.losses.push(d); }); $(this).find('.timeline .note').each(function(){ var d = new Date($(this).attr('title')); timeline_item.notes.push({'date':d, 'note': $(this).text()}); }); return timeline_item; }); } // SET UP THE EXTRA HTML THAT WILL BE USED BY THE VISUALIZATION this.setup_timeline_bar = function() { this.stage.root.append(''); this.stage.root.append('

'); this.stage.titles = this.stage.root.find('DIV.timeline-titles H3'); this.stage.years = this.stage.root.find('UL.timeline-bar'); var current_year = this.timeline.start_year + 0; while (current_year <= this.timeline.end_year) { this.stage.years.append('
  • '+ current_year.toString().substring(2,4) +'
  • '); current_year++; } this.stage.canvas = this.stage.root.find('canvas').get(0); this.stage.years.find('LI').width(this.stage.years.width()/this.stage.years.find('LI').length); this.stage.root.append('
    '); this.stage.notes = this.stage.root.find('DIV.timeline-notes'); } // GET AND RETURN THE CONTEXT OF THE CANVAS FOR THIS TIMELINE this.ctx = function() { if (this.stage.context == '') { this.stage.context = this.stage.canvas.getContext('2d'); } return this.stage.context; } this.draw_all_timeline_links = function() { var t = this; this.stage.teams.each(function() { t.draw_timeline_links(this,false); }); } // DRAW A LINK BETWEEN A TEAM AND ANY YEARS THEY WERE IN THE FINALS this.draw_timeline_links = function(el, clear) { if (typeof(clear) == 'undefined') { clear = true; } // clear the canvas and any previously selected years. if (clear) { this.clear_data(); } $(el).addClass('selected'); var id = this.stage.teams.index(el); var t = this; jQuery.each(this.timeline.data[id].wins, function(i,d) { var year = d.getFullYear(); t.draw_connection($(t.stage.teams[id]), t.stage.years.find('LI#y' + year), '#0000ff'); // also, highlight the years that are pointed to by the canvas. t.stage.years.find('LI#y'+year).addClass('selected win'); }); jQuery.each(this.timeline.data[id].losses, function(i,d) { var year = d.getFullYear(); t.draw_connection($(t.stage.teams[id]), t.stage.years.find('LI#y' + year), '#ff0000'); // also, highlight the years that are pointed to by the canvas. t.stage.years.find('LI#y'+year).addClass('selected lose'); }); // only show notes and titles if we're not showing ALL of them if (clear) { var t = this; jQuery.each(this.timeline.data[id].notes, function(i,note) { t.draw_note(note); }); this.stage.titles.text(this.timeline.data[id].el.find('h3').text()); } } // DRAW A LINK BETWEEN A YEAR AND THE TWO TEAMS THAT PLAYED IN THE FINALS THAT YEAR this.draw_matchup = function(el) { year = $(el).attr('id').substring(1); // find the winner var winner = this.stage.teams.find('SPAN.win[title*=' + year + ']').parents('LI').get(0); var winner_id = this.stage.teams.index(winner); var loser = this.stage.teams.find('SPAN.lose[title*=' + year + ']').parents('LI').get(0); var loser_id = this.stage.teams.index(loser); this.clear_data(); $(el).addClass('selected'); if (typeof(winner) != 'undefined') { $(this.stage.teams[winner_id]).addClass('selected'); this.draw_connection($(this.stage.teams[winner_id]), this.stage.years.find('LI#y' + year), '#0000ff'); } if (typeof(loser) != 'undefined') { $(this.stage.teams[loser_id]).addClass('selected'); this.draw_connection($(this.stage.teams[loser_id]), this.stage.years.find('LI#y' + year), '#ff0000'); } if (typeof(loser) != 'undefined' && typeof(winner) != 'undefined') { this.stage.titles.html('' + $(this.stage.teams[winner_id]).find('h3').text() + ' vs. ' +$(this.stage.teams[loser_id]).find('h3').text() + ''); } } // DRAW A NOTE ON THE GRAPHIC this.draw_note = function(note) { var year = note.date.getFullYear(); if (this.stage.years.find('LI#y' + year).length == 1) { var year_pos = this.stage.years.find('LI#y' + year).position().left; var h = $(this.stage.canvas).height(); this.ctx().strokeStyle = '#00ff00'; this.ctx().globalAlpha = 1; this.ctx().beginPath(); this.ctx().moveTo(year_pos, 0); this.ctx().lineTo(year_pos,h); this.ctx().stroke(); this.stage.notes.append('
    '+ note.note + '
    '); } } // GENERIC FUNCTION TO DRAW A CONNECTION BETWEEN A SINGLE YEAR AND A SINGLE TEAM, USED BY OTHER FUNCTIONS this.draw_connection = function(team,year,color) { this.ctx().globalAlpha = 0.2; this.ctx().fillStyle = color; var l1 = team.position().left; var l2 = year.position().left var r1 = l1 + team.width(); var r2 = year.width() + year.position().left; var h = $(this.stage.canvas).height(); this.ctx().beginPath(); this.ctx().moveTo(l1,0); this.ctx().lineTo(r1,0); this.ctx().lineTo(r2,h); this.ctx().lineTo(l2,h); this.ctx().fill(); } // CLEAR THE DATA this.clear_data = function() { this.ctx().clearRect(0,0,$(this.stage.canvas).width(),$(this.stage.canvas).height()); this.stage.years.find('li').removeClass('selected win lose'); this.stage.teams.removeClass('selected'); this.stage.notes.html(''); this.stage.titles.html(''); } }