--- a/web/app/assets/javascripts/application.js Thu Jun 20 22:40:07 2013 +0200
+++ b/web/app/assets/javascripts/application.js Thu Jun 20 23:31:53 2013 +0200
@@ -14,8 +14,16 @@
//= require jquery.ui.all
//= require twitter/bootstrap
//= require jquery_ujs
+//= require flot/jquery.flot
+//= require flot/jquery.flot.pie
+//= require flot/jquery.flot.time
+//= require flot/jquery.flot.stack
+//= require charts
//= require_self
+jQuery.fn.exists = function() {
+ return this.length>0;
+}
function notify_success(message) {
show_flash(message, "success");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/assets/javascripts/charts.js Thu Jun 20 23:31:53 2013 +0200
@@ -0,0 +1,408 @@
+
+/**
+ * global variables
+ */
+var globalDayNames = ['Ned\u011ble', 'Pond\u011blí', 'Úterý', 'St\u0159eda', '\u010ctvrtek', 'Pátek', 'Sobota'];
+var globalDayNamesShort = ['Ne', 'Po', 'Út', 'St', '\u010ct', 'Pá', 'So'];
+var globalMonthNames = ['Leden', 'Únor', 'B\u0159ezen', 'Duben', 'Kv\u011bten', '\u010cerven', '\u010cervenec',
+'Srpen', 'Zá\u0159í', '\u0158íjen', 'Listopad', 'Prosinec'];
+var globalMonthNamesShort = ['Led', 'Úno', 'B\u0159e', 'Dub', 'Kv\u011b', '\u010cern', '\u010cerc',
+'Srp', 'Zá\u0159', '\u0158íj', 'Lis', 'Pro'];
+var ua = {};
+//array with objects {plot: flot, data: data}
+ua.flots = new Array();
+
+/**
+ * Display charts by Piety plug-in
+ */
+function pietyCharts() {
+ $(".piety.pie-chart").each(function(){
+ var chart = $(this);
+ if(processMultipleCall(chart)){
+ chart.peity("pie",{
+ diameter: chart.width(),
+ colours: ["#fff4dd", "#ff9900","#ADCCDA","#CCAA00"]
+ });
+ }
+ });
+ $(".piety.line-chart").each(function(){
+ var chart = $(this);
+ if(processMultipleCall(chart)){
+ chart.peity("line",{
+ width: chart.width()
+ });
+ }
+ });
+ $(".piety.bar-chart").each(function(){
+ var chart = $(this);
+ if(processMultipleCall(chart)){
+ chart.peity("bar",{
+ width: chart.width()
+ });
+ }
+ });
+
+ /**
+ * find out whether chart was already generated. If no or is empty, generates new one
+ */
+ function processMultipleCall(object) {
+ if(!object.children("canvas").exists() || parseInt(object.children("canvas").attr("width"))==0){
+ if(object.children("canvas").exists()){
+ object.children("canvas").remove();
+ }
+ return true;
+ }
+ else{
+ return false;
+ }
+ }
+}
+
+/**
+ * Display charts by Flot plug-in
+ */
+function flotCharts() {
+ //render pie chart
+ $(".flot.pie-chart").each(function(){
+ var chart = $(this);
+ chart.css("min-height",(chart.width()*.75)+"px");
+ var showValues = chart.attr("data-show-values") != undefined ? true : false;
+ var dataArray = loadData(chart);
+ var options = {
+ series: {
+ pie: {
+ show: true
+ }
+ },
+ grid: {
+ hoverable: showValues
+ }
+ };
+ $.plot(chart, dataArray,options);
+ //whether we want to show values -> add value placeholder and bind it
+ showChartValues(chart);
+ ua.flots.push({
+ placeholder: chart,
+ data:dataArray,
+ options:options
+ });
+
+ });
+
+ //rendre line chart
+ $(".flot.line-chart").each(function(){
+ var chart = $(this);
+ // if(chart.height() == 0){
+ chart.css("min-height",(chart.width()*1/2)+"px");
+ // }
+ var dataArray = loadData(chart);
+ var options = {
+ xaxis: {},
+ grid: {
+ hoverable: true
+ }
+ };
+ if(chart.hasClass("time-chart")){
+ options.xaxis.mode = "time";
+ }
+ $.plot(chart, dataArray,options);
+ var previousPoint = null;
+ chart.on("plothover", function(event, pos, obj){
+ if (obj) {
+ if (previousPoint != obj.dataIndex) {
+ previousPoint = obj.dataIndex;
+ $("#js-chart-tooltip").remove();
+ showTooltip(obj.pageX, obj.pageY,obj.series.data[obj.dataIndex][1]);
+ }
+ }
+ else {
+ $("#js-chart-tooltip").remove();
+ previousPoint = null;
+ }
+ });
+ ua.flots.push({
+ placeholder: chart,
+ data:dataArray,
+ options:options
+ });
+ });
+
+
+ //rendre line chart
+ $(".flot.bar-chart").each(function(){
+ var chart = $(this);
+ // if(chart.height() == 0){
+ chart.css("min-height",(chart.width()*1/2)+"px");
+ // }
+ var dataArray = loadData(chart);
+ var plot,options = {
+ series:{
+ bars: {
+ barWidth: .9,
+ align: "center"
+ },
+ stack: true
+ }
+ };
+ if(chart.attr("data-stack").bool()){
+ options.series.stack = true;
+ }
+ $.plot(chart, dataArray,options);
+ ua.flots.push({
+ placeholder: chart,
+ data:dataArray,
+ options:options
+ });
+ });
+
+ /*
+ *loads data from DOM object. Data can be in data- attributes or in table
+ */
+ function loadData(object){
+ var labels, data, types;
+ //data in table
+ if(object.children("table").exists()){
+ var table = object.children("table");
+ //load labels
+ labels = [];
+ data = new Array();
+ types = new Array();
+ //choose all colums except first one -> not describing data
+ table.find("thead th").not(":first-child").each(function(){
+ labels.push($(this).text());
+ data.push(new Array());
+ //whether lines or bars (set by data-type)
+ //default is according chart type
+ var def = "lines";
+ if (object.hasClass("line-chart")) {
+ def = "lines";
+ }
+ else if(object.hasClass("bar-chart")){
+ def = "bars";
+ }
+ types.push($(this).attr("data-type") != undefined ? $(this).attr("data-type"): def);
+ });
+ var row,index;
+ //load data
+ var isTime = object.hasClass("time-chart");
+ table.find("tbody tr").each(function(){
+ row = $(this);
+ if(isTime){
+ index = parseInt(row.children("th").attr("data-timestamp"))*1000; //*1000 because timestamp in JS is in ms
+ }else{
+ index = parseInt(row.children("th").text());
+ }
+ var j = 0;
+ row.children("td").each(function(){
+ data[j].push([index,parseInt($(this).text())]);
+ j++;
+ });
+ });
+ var resultData = new Array();
+ var showLines, showBars;
+ for(var i = 0;i<labels.length;i++){
+ showBars = types[i] == "bars" ? true : false;
+ showLines = types[i] == "lines" ? true : false;
+ resultData.push({
+ label: labels[i],
+ data: data[i],
+ lines: {
+ show: showLines
+ },
+ bars: {
+ show: showBars
+ },
+ points: {
+ show: showLines //points only on-lines
+ }
+
+ });
+ }
+ return resultData;
+ }
+ //data in data- attrs
+ else{
+ labels = object.attr("data-labels").split(";");
+ data = object.attr("data-values").split(";");
+ if(labels.length != data.length){
+ console.log("Jiný počet prvků v poli popisků a v poli dat");
+ return [];
+ }
+ var dataArray = [];
+ for( var i = 0; i<labels.length; i++){
+ dataArray[i] = {
+ label: labels[i],
+ data: parseInt(data[i])
+ }
+ }
+ return dataArray;
+ }
+ }
+
+ /**
+ *shows chart point tooltip
+ *from: http://people.iola.dk/olau/flot/examples/interacting.html
+ */
+ function showTooltip(x, y, contents) {
+ $('<div id="js-chart-tooltip">' + contents + '</div>').css( {
+ position: 'absolute',
+ display: 'none',
+ top: y + 5,
+ left: x + 5,
+ border: '1px solid #fdd',
+ padding: '2px',
+ 'background-color': '#fee',
+ opacity: 0.80
+ }).appendTo("body").fadeIn(200);
+ }
+
+}
+
+/**
+ * shows values on pie chart
+ */
+function showChartValues(chart) {
+ chart.append($("<div class='value-placeholder'> </div>"));
+ chart.on("plothover", function(event, pos, obj){
+ if (!obj){
+ return;
+ }
+ var percent = parseFloat(obj.series.percent).toFixed(2);
+ //this == chart
+ $(this).find(".value-placeholder").html(obj.series.data[0][1] + ' <small>('+percent+'%)</small>').fadeIn();
+ });
+}
+
+/**
+ * refresh flot chart
+ */
+function refreshCharts() {
+ var flot;
+ for(var i = 0; i<ua.flots.length;i++){
+ flot = ua.flots[i];
+ $.plot(flot.placeholder, flot.data,flot.options);
+ }
+ //bind showing values again
+ $(".pie-chart.flot[data-show-values='true']").each(function(){
+ showChartValues($(this));
+ });
+}
+
+/**
+ * Manage remove prompts
+ */
+function removePrompt() {
+ $("body").on("click",".js-remove-prompt",function(e){
+ e.preventDefault();
+ var prompt = $("<div class='ua-prompt ua-remove-prompt'>"+
+ "<a href='" + $(this).attr("data-target") + "' class='btn btn-danger btn-mini icon-trash'>Smazat</a>"+
+ "<a href='#close' class='btn btn-link btn-mini'>Zrušit</a>"+
+ "</div>");
+ prompt.find("a[href='#close']").one("click",function(e){
+ e.preventDefault();
+ hidePrompt(prompt);
+ });
+ prompt.find("a[href='"+$(this).attr("data-target")+"']").one("click",function(){
+ //cannot use the same method as for #close button - propagation is needed here
+ hidePrompt(prompt);
+ });
+ prompt.appendTo("body");
+ var x, y;
+ x = $(this).offset().left + $(this).width() - prompt.width();
+ y = $(this).offset().top-5; //to make it nicier
+ prompt.css({
+ left: x+"px",
+ top:y+"px"
+ });
+ prompt.show("slide", {
+ direction:"right"
+ },300);
+ });
+
+ /**
+ * hide prompt and remove it from DOM
+ */
+ function hidePrompt(prompt) {
+ prompt.hide("slide", {
+ direction:"right"
+ },500,function(){
+ prompt.remove();
+ });
+ }
+}
+
+/**
+ * Functions which changes running time
+ */
+function runningTime() {
+ var currentTime = new Date().getTime();
+ var time;
+ $(".ua-time-running[data-start]").each(function(){
+ time = new Date(currentTime - parseInt($(this).attr("data-start")) - 3600000); //-1h = 60*60*1000
+ $(this).html(time.toLocaleTimeString());
+ });
+}
+
+/**
+ * Bootstrap pop-over handlers
+ */
+function popovers() {
+ $("body").on("click",".popover-link",function(){
+ var clicked = $(this);
+ clicked.popover({
+ html:true
+ });
+ clicked.popover("show");
+ //any click will close the popover
+ $("body").one("click",function(){
+ clicked.popover("hide");
+ });
+ });
+}
+
+/**
+ * Extend default Bootstrap tabs behavior
+ */
+function tabs() {
+ //re-run piety charts init when tab is shown
+ $('.shows-charts[data-toggle="tab"]').on('shown', function (e) {
+ pietyCharts();
+ })
+
+ //if there's a tab with id from url, show it
+ if($("a[href='"+window.location.hash+"']")){
+ $("a[href='"+window.location.hash+"']").tab("show");
+ }
+}
+
+
+/**
+ * Calls all methods which shoul be called after screen si resized
+ */
+function viewportResized() {
+ refreshCharts();
+ convertMenu();
+}
+
+/**
+ * Bind jQuery chosen plug-in
+ */
+function chosen() {
+ //pokud bude vic polozek jak 10, zobrazi i vyhledavani
+ $("select.js-chosen:visible").chosen({
+ disable_search_threshold: 10
+ });
+}
+
+
+$(document).ready(function(){
+ pietyCharts();
+ flotCharts();
+ setInterval("runningTime()",1000);
+ removePrompt();
+ popovers();
+ tabs();
+ viewportResized();
+ $(window).on("debouncedresize", viewportResized);
+});
+
--- a/web/app/controllers/index_controller.rb Thu Jun 20 22:40:07 2013 +0200
+++ b/web/app/controllers/index_controller.rb Thu Jun 20 23:31:53 2013 +0200
@@ -1,4 +1,33 @@
class IndexController < ApplicationController
def index
+ @current_results = fake_data
+ end
+
+ private
+
+ def fake_data
+ [ {"benchmark"=> {
+ "class"=> "BenchmarkMicro",
+ "selector"=> "ackermann" },
+ "times"=> [1281,1359,1437,1391,1500],
+ "parameters"=> {}},
+
+ {"benchmark"=> {
+ "class"=> "BenchmarkMicro",
+ "selector"=> "ary"},
+ "times"=> [1059,1056,1059,1059,1057],
+ "parameters"=> {}},
+
+ {"benchmark"=> {
+ "class"=> "BenchmarkMicro",
+ "selector"=> "hsh"},
+ "times"=> [1422,1438,1421,1407,1422],
+ "parameters"=> {}},
+
+ {"benchmark"=> {
+ "class"=> "BenchmarkMicro",
+ "selector"=> "strcat"},
+ "times"=> [1312,1203,1125,984,1188],
+ "parameters"=> {}}]
end
end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/views/index/_benchmarks_table.html.erb Thu Jun 20 23:31:53 2013 +0200
@@ -0,0 +1,22 @@
+<div class="<%= "line-chart flot bar-chart" if make_chart %>" data-stack="false" >
+ <table class="table table-condensed">
+ <thead>
+ <tr>
+ <th>Benchmarks</th>
+ <% results.each do |result| %>
+ <th><%= "#{result["benchmark"]["selector"]}" %></th>
+ <% end %>
+ </tr>
+ </thead>
+ <tbody>
+ <% 5.times do |index| %>
+ <tr>
+ <th><%= index + 1 %></th>
+ <% results.each do |result| %>
+ <td><%= result["times"][index] %></td>
+ <% end %>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+</div>
--- a/web/app/views/index/index.html.erb Thu Jun 20 22:40:07 2013 +0200
+++ b/web/app/views/index/index.html.erb Thu Jun 20 23:31:53 2013 +0200
@@ -1,8 +1,14 @@
<%= currently_at "index" %>
-<h1>Calipel</h1>
-<p>
-Simple micro-benchmarking framework inspired by SUnit a Caliper
-</P>
+<%= image_tag "logo.png", width: '400px', class: "pull-right" %>
-<h2>Current Test Results</h2>
+<div class="span6">
+ <h1>Calipel</h1>
+ <p>
+ Simple micro-benchmarking framework inspired by SUnit a Caliper
+ </P>
+ <h2>Current Test Results</h2>
+
+ <%= render 'index/benchmarks_table', results: @current_results, make_chart: false %>
+ <%= render 'index/benchmarks_table', results: @current_results, make_chart: true %>
+</div>
--- a/web/example.results Thu Jun 20 22:40:07 2013 +0200
+++ b/web/example.results Thu Jun 20 23:31:53 2013 +0200
@@ -1,4 +1,4 @@
-{"outcomes": [
+[
{"benchmark": {
"class": "BenchmarkMicro",
"selector": "ackermann" },
@@ -21,4 +21,4 @@
"class": "BenchmarkMicro",
"selector": "strcat"},
"times": [1312,1203,1125,984,1188],
- "parameters": {}}]}
+ "parameters": {}}]