Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to make 52-week participation bar graphs like Github has done?

I'm trying to make bar graphs similar to how Github does it for showing how many commits or how many people are watching repositories, e.g, https://github.com/popular/watched.

Does anyone know what library they used to make it?

UPDATE I wanted to re-open this question if possible. Re-investigating this, the solutions below while awesome in their own right, seem a little too involved for what I'm looking for.

I've switched to using this nice Nettuts tutorial which draws a single bar graph but I'm having trouble adapting it to draw multiple bar graphs. http://net.tutsplus.com/tutorials/javascript-ajax/fun-with-canvas-create-a-jquery-graph-plugin/

I've made a fiddle where I've manually added code to deal with a 2nd graph but I believe I need some for loops to make this work for a variable number of graphs. Here's that fiddle: http://jsfiddle.net/trpeters1/zHH76/

might someone be able to edit this fiddle to tackle this question?

like image 830
tim peterson Avatar asked Feb 28 '12 19:02

tim peterson


1 Answers

Look into d3.js. There are several examples of how you can take an array in JavaScript and turn it into a graph like that.

Here is one (more advance) example: http://mbostock.github.com/d3/ex/population.html
And here is another example that is closer to what you want: http://mbostock.github.com/d3/tutorial/bar-2.html

EDIT

The actual code that Git Hub uses to create the graphs looks something like this:

GitHub.ParticipationGraph = (function(){
  function b(target){
    this.el = target;
    this.onSuccess = $.proxy(this.onSuccess, this);
    this.canvas = this.el.getContext("2d");
    this.refresh();
  }

  b.prototype.barWidth = 7;

  b.prototype.barMaxHeight = 20;

  b.prototype.getUrl = function(){
    return $(this.el).data("source");
  };

  b.prototype.setData = function(data){
    this.data = data;
    if (data == null || data.all == null || data.owner == null) {
      this.data = null;
    }
    this.scale = this.getScale(this.data);
  };

  b.prototype.getScale = function(data){
    var mx, i;
    if (data == null) return;
    mx = data.all[0];
    for(i = 0; i < data.all.length; i++) {
      if (data.all[i] > mx) {
        mx = data.all[i];
      }
    }
    return mx >= this.barMaxHeight ? (this.barMaxHeight-.1)/mx : 1;
  };

  b.prototype.refresh = function(){
    $.ajax({
      url: this.getUrl(),
      dataType: "json",
      success: this.onSuccess
    });
  };

  b.prototype.onSuccess = function(data){
    this.setData(data);
    this.draw();
  };

  b.prototype.draw = function(){
    if (this.data == null) return;
    this.drawCommits(this.data.all, "#cacaca");
    this.drawCommits(this.data.owner, "#336699");
  };

  b.prototype.drawCommits = function(data, color){
    var i, width, height, x, y;
    for (i = 0; i < data.length; i++) {
      width = this.barWidth;
      height = data[i] * this.scale;
      x = i * (this.barWidth + 1);
      y = this.barMaxHeight - height;
      this.canvas.fillStyle = color;
      this.canvas.fillRect(x, y, width, height);
    }
  };

  return b;
})();

Basically, they are calling the data-source tag located on the canvas, which returns some JSON that represents the amount of work/participation/watches (or whatever metric they are calculating) and then they go through each returned value and call this.canvas.fillRect with the predefined width ((Screensize.width/52) - (paddingLeft + paddingRight)) and the height from the JSON returned

like image 106
joe_coolish Avatar answered Oct 20 '22 10:10

joe_coolish