// load Google JS library for translations. google.load("language", "1"); google.load("feeds", "1"); var set = "combined"; var row_height = 54; var spacing = 2; var hours_back = 12; var step = 1.5; var container_width = 720; var min_actions = 2; var step_pixels = parseInt((container_width - 55) / (hours_back / step)); var step_in_seconds = step * 60 * 60; var previous_first_step_time = 0; var use_canvas = true; var animation_speed = "normal"; var firehose = false; var ordering = "score"; var domain_filter = ""; var keyword_filter = ""; var term_filter = ""; var display_flat = true; var do_animations = true; var do_fancy = true; var request_key = false; // keep track of what data we're expecting back from the server. // read anchor from URI. var anchor = unescape(self.document.location.hash.substring(1)); if (anchor == "firehose") {step=0.125;hours_back=1;min_actions=2;firehose=true;} if (anchor == "1") {step=0.125;hours_back=1;min_actions=2;} if (anchor == "2") {step=0.25;hours_back=2;min_actions=2;} if (anchor == "4") {step=0.5;hours_back=4;min_actions=2;} if (anchor == "8") {step=1;hours_back=8;min_actions=2;} if (anchor == "12") {step=1.5;hours_back=12;min_actions=2;} if (anchor == "24") {step=3;hours_back=24;min_actions=2;} if (anchor == "48") {step=6;hours_back=48;min_actions=2;} if (anchor == "168") {step=24;hours_back=168;min_actions=2;} if (anchor == "336") {step=48;hours_back=336;min_actions=2;} if (anchor == "720") {step=96;hours_back=720;min_actions=2;} function fetch_data() { var currentTime = new Date(); request_key = currentTime.getTime(); // not a great unique id, but it'll do. $("#loading").show(); if (firehose) { // fetch firehose data. $.get("fetch_firehose.php", {}, function(data) {draw_firehose(eval("(" + data + ")"));}); } else if (display_flat) { $("#corner_piece").fadeOut(animation_speed); $.get("render_flat.php", { request_key: request_key, set: set, hours_back: hours_back, step: step, min_actions: min_actions, use_canvas: use_canvas, nocache: 0, firehose: firehose, ordering: ordering, domain_filter: escape(domain_filter), freetext_filter: escape(keyword_filter), term_filter: escape(term_filter) }, function(data) { draw_flat(data); }); } else { $("#corner_piece").fadeIn(animation_speed); $.get("fetch_matrix.php", { request_key: request_key, set: set, hours_back: hours_back, step: step, min_actions: min_actions, use_canvas: use_canvas, nocache: 0, firehose: firehose, ordering: ordering, domain_filter: escape(domain_filter), freetext_filter: escape(keyword_filter), term_filter: escape(term_filter) }, function(data) { draw_matrix(eval("(" + data + ")")); }); } hide_existing_views(); } $.fn.makeAbsolute = function() { return this.each(function() { var el = $(this); var pos = el.offset(); var pos = el.position(); el.css({ position: "absolute", marginLeft: 0, marginTop: 0, top: pos.top, left: pos.left }); }); } function hide_existing_views() { if (!do_animations) { $("#overlay_container").html(""); $("#container").html(""); return true; } $("#overlay_container").html(""); if (is_in_timeline_view()) { if (display_flat) { // todo: this transition doesn't seem to work. //$("#overlay_container").css("height", $(".row", "#overlay_container").length * (row_height + spacing)); $("#overlay_container").css("height", 1000); $(".row").each(function(i){ $(this).appendTo("#overlay_container"); }); $("#container").html(""); $(".row", "#overlay_container").each(function(i){ if (i < 10) { if (do_fancy) { $(this).delay(50 * i).animate({"left": 960, "opacity": 0}, animation_speed, "linear", function() {$(this).remove();}); } else { $(this).delay(50 * i).animate({"left": 960}, animation_speed, "linear", function() {$(this).remove();}); } } else { $(this).remove(); } }); $("#container").css("height", "auto"); $("#overlay_container").delay(1000, function() {$("#overlay_container").css("height", "auto");}); return true; } else { return true; } } $(".flat_row").each(function(i){ $(this).css("top", $(this).position().top); $(this).css("left", 0); $(this).css("width", $(this).width()); $(this).css("height", $(this).height()); $(this).appendTo("#overlay_container"); }).each(function(i) { if (i < 10) { $(this).css("position", "relative"); if (do_fancy) { $(this).delay(50 * i).animate({"left": 960, "opacity": 0}, animation_speed).delay(500 - (50 * i), function() {$(this).remove();}); } else { $(this).delay(50 * i).animate({"left": 960}, animation_speed).delay(500 - (50 * i), function() {$(this).remove();}); } } else { $(this).remove(); } }); //$("#overlay_container").delay(1000).animate({"height": 1}, 1, "linear", function() {$("#overlay_container").html("");}); // make sure there's nothing still in the container div. $("#container").html(""); return true; } function draw_flat(data) { // move container view to correct position. $("#container").css("left", 0); $("#container").css("top", 40); $("#overlay_container").css("left", 0); $("#overlay_container").css("top", 40); // check that this is the correct data by looking at the incoming request_key and seeing if it matches our one. var new_rows = document.createElement("div"); $(new_rows).css("width", $("#container").css("width")); $(new_rows).css("height", $("#container").css("height")); $(new_rows).css("left", "-960"); $(new_rows).css("top", 0); $(new_rows).css("position", "absolute"); $(new_rows).appendTo("body"); $(new_rows).html(data); var incoming_key = $("#request_key", new_rows).text(); if (incoming_key != request_key) {return;} // not the data that we're expecting. if ($(".flat_row", new_rows).size() == 0) { // show "sorry, no items" message. $("#container").html("
sorry, there's no relevant activity to display
"); } if (!do_animations) { $(new_rows).remove(); $("#container").html(data); finish_loading(); return true; } // bring in the new rows, one by one. $(".flat_row", new_rows).each(function(i){ $(this).css("left", -960); //$(this).css("top", $(this).position().top); $(this).css("width", $(this).width()); $(this).css("height", $(this).height()); }).each(function(i){ $(this).css("position", "relative"); if (i < 10) { $(this).appendTo("#container"); $(this).delay(50 * i).animate({"left": 0}, animation_speed, "linear", function() {}); } else { $(this).css("left", 0); $(this).appendTo("#container"); } }); $(new_rows).remove(); finish_loading(); } $(document).ready(function(){ // get items and their positions. fetch_data(); }); // from http://james.padolsey.com/javascript/jquery-delay-plugin/ $.fn.delay = function(time, callback){ jQuery.fx.step.delay = function(){}; return this.animate({delay:1}, time, callback); } function draw_firehose(data) { } function show_details(uri_hash) { $("#details").load("preview_details.php?uri_hash=" + uri_hash + "&step_in_seconds=" + step_in_seconds + "&random=" + Math.random() + "?step=" + step); $("#details").css("top", $("#" + uri_hash).css("top")); $("#details").show(); } function draw_previous_activity_gradient(item, boxleft) { var canvas = document.createElement("canvas"); canvas.id = "previous_activity_" + item.uri_hash; canvas.width = boxleft; canvas.height = row_height; $(canvas).addClass("graph"); $(canvas).addClass("previousgraph"); $(canvas).css("left", "55"); $(canvas).css("z-index", 2); if (!use_canvas) {return canvas;} if($.browser.msie) { // enable canvas on Internet Explorer G_vmlCanvasManager.initElement(canvas); } // draw gradient. if (canvas.getContext){ var ctx = canvas.getContext('2d'); var lineargradient = ctx.createLinearGradient(0,0,boxleft,0); lineargradient.addColorStop(0, 'rgba(255,255,255,0)'); //lineargradient.addColorStop(0.3,'#F2F1E4'); //lineargradient.addColorStop(0.5, 'rgba(255,255,255,0)'); //lineargradient.addColorStop(0.6, 'rgba(255,255,255,0)'); lineargradient.addColorStop(0.5,'#F2F1E4'); lineargradient.addColorStop(1,'#F2F1E4'); ctx.fillStyle = lineargradient; ctx.fillRect(0,0,container_width,row_height); } return canvas; } function draw_background_canvas(item) { var canvas = document.createElement("canvas"); canvas.id = "background_" + item.uri_hash; canvas.width = container_width; canvas.height = row_height; $(canvas).addClass("graph"); $(canvas).css("left", "55"); $(canvas).css("z-index", 0); if (!use_canvas) {return canvas;} if($.browser.msie) { // enable canvas on Internet Explorer G_vmlCanvasManager.initElement(canvas); } // draw background gradient. if (canvas.getContext){ var ctx = canvas.getContext('2d'); var lineargradient = ctx.createLinearGradient(0,0,0,row_height); lineargradient.addColorStop(0,'#F3F3F3'); lineargradient.addColorStop(0.6,'#FFFFFF'); ctx.fillStyle = lineargradient; ctx.fillRect(0,0,container_width,row_height); } return canvas; } function draw_activity_graph(item) { var canvas = document.createElement("canvas"); canvas.id = "graph_" + item.uri_hash; canvas.width = step_pixels * parseInt(hours_back / step); canvas.height = row_height; $(canvas).addClass("graph"); $(canvas).addClass("linegraph"); $(canvas).css("left", "55px"); $(canvas).css("top", "2px"); if (!use_canvas) {return canvas;} if($.browser.msie) { // enable canvas on Internet Explorer G_vmlCanvasManager.initElement(canvas); } // draw graph on the canvas. if (canvas.getContext){ var ctx = canvas.getContext('2d'); ctx.fillStyle = '#E0DEC5'; // todo: put this in config.xml ctx.beginPath(); ctx.globalAlpha = 0.8; for (var i=0; i < item.datapoints.length; i++) { if (i == 0) { ctx.moveTo(item.datapoints[i].x, item.datapoints[i].y); } else { ctx.bezierCurveTo( item.controlpoints[0][i - 1].x, item.controlpoints[0][i - 1].y, item.controlpoints[1][i - 1].x, item.controlpoints[1][i - 1].y, item.datapoints[i].x, item.datapoints[i].y ); } } ctx.lineTo(0,row_height); ctx.closePath(); ctx.fill(); //ctx.stroke(); // draw actual points too. /* for (var i=0; i < item.datapoints.length; i++) { ctx.beginPath(); ctx.arc(item.datapoints[i].x, item.datapoints[i].y, 2, 0, 360, false); ctx.fillStyle = '#336699'; ctx.closePath(); ctx.fill(); } */ } return canvas; } function animate_row(existing_row, item, steps_label, step_names) { // first off move it to the correct vertical position. var new_top = ((row_height + spacing) * item.row); $(existing_row).animate({"top": new_top}, animation_speed); // fetch existing components of the row. var box = $("#box_" + item.uri_hash); var labelbox = $("#labelbox_" + item.uri_hash); var new_left = 55 + (item.first_bucket * step_pixels); var new_width = (((item.last_bucket - item.first_bucket) + 1) * step_pixels); // pull out steps, put in new ones. $(".steps", existing_row).remove(); var row_steps = $(steps_label).clone(); // shade "previous activity exists" steps $(".previousgraph", existing_row).fadeOut(animation_speed,function(){$(this).remove();}); shade_previous_activity(existing_row, row_steps, step_names, box, item, parseInt(new_left)); $(row_steps).appendTo(existing_row); // redo activity graph. var existing_canvas = $(".linegraph", existing_row); $(existing_canvas).fadeOut(animation_speed, function(){$(this).remove();}); var canvas = draw_activity_graph(item); if (do_fancy) {$(canvas).css("opacity", 0);} $(canvas).appendTo(existing_row); if (do_fancy) {$(canvas).animate({"opacity": 1}, animation_speed);} $(box).animate({"left": new_left, "maxWidth": new_width, "width": new_width}, animation_speed); $(labelbox).animate({"left": new_left, "maxWidth": new_width - 8, "width": new_width - 8}, animation_speed); // we could make some of the more flashy animations optional to speed things up on slower machines. //$(box).css("left", new_left); //$(box).css("maxWidth", new_width); //$(box).css("width", new_width); //$(labelbox).css("left", new_left); //$(labelbox).css("maxWidth", new_width); //$(labelbox).css("width", new_width); } function shade_previous_activity(row, row_steps, step_names, box, item, checkleft) { var previous_activity = false; $(".step", row_steps).each(function(i){ if (((item.stats.first_activity <= step_names[i]['t']) && (item.stats.last_activity >= step_names[i]['t'])) && (parseInt($(this).css("left")) < checkleft)) { $(this).addClass("previous_activity"); $(this).addClass("previous_activity_borders"); previous_activity = true; } }); if (previous_activity) { var first_step = $(".step_label_0", row_steps)[0]; $(first_step).addClass("previous_label"); $(first_step).addClass("previous_activity"); $(first_step).html("First seen
" + item.stats.first_activity_text); } } function create_row(item, steps_label, step_names) { // create row var row = document.createElement("div"); row.id = item.uri_hash; $(row).addClass("row"); var top = ((row_height + spacing) * item.row); $(row).css("top", top); // create source thumbnail var thumbnail = document.createElement("div"); thumbnail.id = "thumbnail_" + item.uri_hash; $(thumbnail).addClass("thumbnail"); if (!item.portrait) {item.portrait = "assets/default.jpg";} $(thumbnail).html("
 
"); $(thumbnail).appendTo(row); // add step labels var row_steps = $(steps_label).clone(); // create the actual activity box. var left = 55 + (item.first_bucket * step_pixels); var box = document.createElement("div"); var width = (((item.last_bucket - item.first_bucket) + 1) * step_pixels); box.id = "box_" + item.uri_hash; $(box).addClass("box"); $(box).css("left", left); $(box).css("width", width); $(box).css("max-width", width); $(row_steps).appendTo(row); $(box).appendTo(row); if(!$.browser.msie) { //$(box).corner(); // this seems to be quite a slow operation... hmmm. } // shade "previous activity exists" steps shade_previous_activity(row, row_steps, step_names, box, item, parseInt($(box).css("left"))); // add canvas element showing activity graph var canvas = draw_activity_graph(item); $(canvas).appendTo(row); // add a second box. var labelbox = $(box).clone(); $(labelbox).html("" + item.domain + " " + item.title + ""); $(labelbox).attr("rel", "more_details"); $(labelbox).removeClass("box"); $(labelbox).addClass("labelbox"); $(labelbox).css("width", width - 8); $(labelbox).css("max-width", width - 8); $(labelbox).attr("id", "labelbox_" + item.uri_hash); $(labelbox).hover( function() { $("#box_" + item.uri_hash).addClass("label_hover"); $("#graph_" + item.uri_hash).css("opacity", "0.5"); $(this).css("border", "1px solid #EFEFEF"); }, function() { $("#box_" + item.uri_hash).removeClass("label_hover"); $("#graph_" + item.uri_hash).css("opacity", "1"); $(this).css("border", "1px solid #E0DEC5"); } ); //$(labelbox).click(function() {$("#labelbox_link_" + item.uri_hash).click(); return false;}); $(labelbox).appendTo(row); return row; } function is_in_timeline_view() { if ($(".row", "#container").length >= 1) {return true;} return false; } function draw_matrix(data) { // move container view to correct position. $("#container").css("left", 20); $("#container").css("top", 55); $("#overlay_container").css("left", 20); $("#overlay_container").css("top", 55); // check to see that the incoming request_key matches our one. // we need to set the container height manually. $(".container_message").fadeOut("normal", function(){$(this).remove();}); var items = data.items; var step_names = data.step_names; $("#container").animate({"height": items.length * (row_height + spacing)}, animation_speed); // update step_pixels step_pixels = parseInt((container_width - 55) / (hours_back / step)); // add time labels to the row. var steps_label = document.createElement("div"); $(steps_label).addClass("steps"); for (j in step_names) { var step_name = step_names[j]['s'][0]; var daybreak = step_names[j]['s'][1]; var step_label = document.createElement("div"); $(step_label).html("" + step_name + ""); $(step_label).addClass("step"); $(step_label).css("width", step_pixels); if (daybreak) { $(step_label).css("border-right", "1px dotted #DEDEDE"); $(step_label).css("width", step_pixels - 1); } $(step_label).css("left", 55 + (step_pixels * j)); $(step_label).addClass("step_label_" + j); $(step_label).appendTo(steps_label); } var first_step_time = step_names[0]['t']; // get rid of any existing rows that aren't in the new data matrix. var uri_hashes = new Object(); for (i in items) {uri_hashes[items[i].uri_hash] = true;} $(".row", "#container").each(function(i){ var uri_hash = $(this).attr("id"); if (!uri_hashes[uri_hash]) { // delete this row. if (do_fancy) { $(this).animate({"left": container_width * -0.5, "opacity": 0}, animation_speed, false, function() { $(this).remove() }); } else { $(this).animate({"left": 960}, animation_speed, false, function() { $(this).remove() }); } } }); for (i in items) { var item = items[i]; // if the row exists animate the change. If not create it. var existing_row = $("#" + item.uri_hash); if (existing_row.length) { animate_row(existing_row, item, steps_label, step_names); } else { var row = create_row(item, steps_label, step_names); // if we're going back in time push rows from the left. Otherwise push from the right. if (first_step_time >= previous_first_step_time) { // going back $(row).css("left", container_width * -0.5); } else { // going forward $(row).css("left", -1 * (container_width / 2)); } if (do_fancy) {$(row).css("opacity", 0);} $(row).appendTo("#container"); if (do_animations) { if (do_fancy) { $(row).animate({"left": 0, "opacity": 1}, animation_speed); } else { $(row).animate({"left": 0}, animation_speed); } } else { $(row).css("left", 0); $(row).css("opacity", 1); } $("#labelbox_" + item.uri_hash).colorbox({ href: $("#labelbox_link_" + item.uri_hash).attr("href"), transition: "fade", speed: 350, opacity: 0.6, initialWidth: 40, initialHeight: 40, preloading: false, rel: "item_details" }); } } previous_first_step_time = first_step_time; if (items.length == 0) { // show "sorry, no items" message. $("#container").html("
sorry, there's no relevant activity to display
"); } finish_loading(); } function finish_loading() { if (hours_back == 1) {set_page_description(60, "minutes");} else if (hours_back < 24) {set_page_description(hours_back, "hours");} else if (hours_back == 24) {set_page_description(24, "hours");} else if (hours_back > 24) {set_page_description(parseInt(hours_back / 24), "days");} else { set_page_description("few", "hours"); } $("#loading").hide(); } function set_page_description(number, scale) { $("#page_description").fadeOut("normal", function() { var message = "Activity from the past " + number + " " + scale; $.get("ajax_handler.php", {action: "draw_text", text: escape(message)}, function(data, textStatus) { $("#page_description").html(""); $("#page_description").fadeIn("normal"); }, "text"); }); }