Category Archives: AJAX

Google Calendar on a Simile Timeline

At Falafel Software Google calendar is a core tool used by the company. I’ve been working to leverage the data calendar in a number of interesting ways such as in the DIV below rendered using JavaScript based on calendar data from Falafel training calendar displaying upcoming training events over the next 120 days.

February 2

Telerik Advanced RadGrid Data Editing and Validation
FREE! (Click to register)

February 23

Telerik Advanced RadGrid Paging, Sorting, and Filtering
FREE! (Click to register)

March 1

Telerik Sitefinity Online Training
$399/person

I’ve mentioned the above example before from Google’s playground and I found another example which uses $g(MIT’s Simile) project Timeline control to render calendar data. As you can see from that example it’s not actually working so I thought I’d post an update with some changes I made to get it working. Here is my example. I’ve made changes to get the import of the data working though there remains a number of other improvements that could be made. I’ve yet to determine if this timeline view is really all that useful and haven’t settled on a view that I really like. At any rate, here is the code, again take a look at the source for my example above for a complete working page.

var gEventSource;
 
function loadGDataCallback(json) {
  var entries = json.feed.entry;
  var timelinerEntries = [];
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    if(entry["gd$when"] == null) continue;
    var when = entry["gd$when"][0];
    var start = convertFromGDataDate(when.startTime);
    var end = convertFromGDataDate(when.endTime);
    var webContent = null;
    var links = entry.link;
    for (var j = 0; j < links.length; ++j) {
      if (links[j].rel == "alternate") {
        webContent = links[j];
        break;
      }
    }
    var title = entry.title.$t;
    var link = entry.link;
    var icon = entry.link[0].href;

    var description = '<img src="' + link + '">';
    timelinerEntries.push(new Timeline.DefaultEventSource.Event(
      start,
      end, // end - when not set, event displayed with icon (looks better)
      null, // latestStart
      null, // latestEnd
      false, // not isDuration
      entry.title.$t,
      entry.content.$t,
      icon, // image
      entry.link[0].href, // link - destination when clicking on title
      entry.link[0].href,
      undefined, // color
      undefined  // textColor
    ));
  }
  gEventSource.addMany(timelinerEntries);
};
 
function zeroPad(n) {
  if (n < 0) throw new Error('n is negative');
  return (n < 10) ? '0' + n : n;
}
 
function convertToGDataDate(/*Date*/ date) {
  return date.getFullYear() + '-' +
         zeroPad(date.getMonth() + 1) + '-' +
         zeroPad(date.getDate());
}
 
function convertFromGDataDate(/*string<YYYY-MM-DD>*/ date) {
  var match = date.match(/(\d{4})-(\d{2})-(\d{2})/);
  return new Date(parseInt(match[1], 10), parseInt(match[2], 10) - 1, parseInt(match[3], 10));
}
 
function onLoad() {
  gEventSource = new Timeline.DefaultEventSource();
 
  var theme = Timeline.ClassicTheme.create();
  theme.event.bubble.width = 320;
  theme.event.bubble.height = 180;
 
  // centering the timeline three months previous makes it look nicer on load
  var threeDaysFromNow =
      new Date(((new Date).getTime()) + 3 * 24 * 60 * 60 * 1000);
  var bandInfos = [
    Timeline.createBandInfo({
        eventSource:    gEventSource,
        date:           threeDaysFromNow,
        width:          "40%", 
        intervalUnit:   Timeline.DateTime.WEEK, 
        intervalPixels: 300,
        theme:          theme
    }),
    Timeline.createBandInfo({
        eventSource:    gEventSource,
        date:           threeDaysFromNow,
        width:          "60%", 
        intervalUnit:   Timeline.DateTime.MONTH, 
        intervalPixels: 550,
        theme:          theme
    })
/*    ,
    Timeline.createBandInfo({
        showEventText:  false,
        trackHeight:    0.5,
        trackGap:       0.2,
        eventSource:    gEventSource,
        date:           threeDaysFromNow,
        width:          "10%", 
        intervalUnit:   Timeline.DateTime.YEAR, 
        intervalPixels: 200
    })
*/    
  ];
  bandInfos[1].syncWith = 0;
  bandInfos[1].highlight = true;
/*  
  bandInfos[2].syncWith = 0;
  bandInfos[2].highlight = true;
*/  
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
 
  // Atom feed from a Google calendar
  var feedUrl = "http://www.google.com/calendar/feeds/4u13qtkl3bcpao0ofgod94s960@group.calendar.google.com/public/full";
 
  var startDate = new Date((new Date).getDate());
  var endDate = new Date(((new Date).getTime()) + 3 * 30 * 24 * 60 * 60 * 1000);

 
  var getParams = '?start-min=' + convertToGDataDate(startDate) +
                  '&start-max=' + convertToGDataDate(endDate) +
                  '&alt=json-in-script' +
                  '&callback=loadGDataCallback' +
                  '&max-results=5000'; // choose 5000 as an arbitrarily large number
  feedUrl += getParams;
  var scriptTag = document.createElement('script');
  scriptTag.src = feedUrl;
  document.body.appendChild(scriptTag);
}
 
var resizeTimerID = null;
function onResize() {
    if (resizeTimerID == null) {
        resizeTimerID = window.setTimeout(function() {
            resizeTimerID = null;
            tl.layout();
        }, 500);
    }
}

I’m interested in any other ways people are using Google’s calendar data so let me know if you done/seen anything cool!