Github Visualizer-GitHubを使用したリポジトリ履歴視覚化サービス

code_swarmgourceなどのリポジトリの視覚化ソフトウェア製品のファンであること。 ある日、 GitHubのリポジトリ統計を視覚化するオンラインサービスを作成するように促したミューズが私を訪問しました。

そして今日、私のGitHub Visualizer プロジェクトGitHubプロジェクト )を裁判所に持ち込みたいと思います。

これは予備的な知人のスクリーンキャストです。



そして、大きなGIFではありません

画像



使用されるもの






スケジュールとその実装の説明



このプロジェクトには、リポジトリに関する情報、その履歴、および定量的な指標を示す3つの主要な視覚化があります。



リポジトリリストの視覚化


リポジトリグラフ

リポジトリリスト




グラフを作成するために、 この例で提案したD3.Layout.Forceとクラスタリング手法が使用されました

例からのコード
var force = d3.layout.force() .nodes(nodes) .size([width, height]) .gravity(.02) .charge(0) .on("tick", tick) .start(); function tick(e) { circle .each(cluster(10 * e.alpha * e.alpha)) .each(collide(.5)) .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); } // Move d to be adjacent to the cluster node. function cluster(alpha) { var max = {}; // Find the largest node for each cluster. nodes.forEach(function(d) { if (!(d.color in max) || (d.radius > max[d.color].radius)) { max[d.color] = d; } }); return function(d) { var node = max[d.color], l, r, x, y, i = -1; if (node == d) return; x = dx - node.x; y = dy - node.y; l = Math.sqrt(x * x + y * y); r = d.radius + node.radius; if (l != r) { l = (l - r) / l * alpha; dx -= x *= l; dy -= y *= l; node.x += x; node.y += y; } }; } // Resolves collisions between d and all other circles. function collide(alpha) { var quadtree = d3.geom.quadtree(nodes); return function(d) { var r = d.radius + radius.domain()[1] + padding, nx1 = dx - r, nx2 = dx + r, ny1 = dy - r, ny2 = dy + r; quadtree.visit(function(quad, x1, y1, x2, y2) { if (quad.point && (quad.point !== d)) { var x = dx - quad.point.x, y = dy - quad.point.y, l = Math.sqrt(x * x + y * y), r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding; if (l < r) { l = (l - r) / l * alpha; dx -= x *= l; dy -= y *= l; quad.point.x += x; quad.point.y += y; } } return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; }); }; }
      
      









実際、これは私を訪ねたミューズでした。

関数は、いくつかの例外と追加を除いて実質的に変更されていません。

リポジトリのリストを視覚化するための関数の実装は、 repo.jslangHg.jsの 2つのファイルにあります




リポジトリ履歴の可視化


ユーザーリポジトリのリストに関する情報をダウンロードした後、2番目のステージパネルの列またはリポジトリのリストのいずれかで、目的のリポジトリを選択できます(分析用に最近のリビジョンの数をここで設定することもできます)。
ステージ2パネル
次に、「分析」ボタンを押して分析します。 分析中に、リポジトリ履歴のグラフが作成されます。 指定した最近のコミットの数に関する情報を表示します(デフォルトでは100コミット。リポジトリにある数より少ないかもしれません)。

履歴グラフ

画像




ダイアグラムを描画するために、私はd3.jsライブラリのいくつかのツールとそれらの組み合わせを使用しました。

面積の計算は、 d3.svg.area()コンポーネントによって実行されます( 積み上げ 面積の例)。 私は自分でスタックを検討していますが、他のすべてはd3jsにとって些細なことです。

スタックが考慮されるコード
 var layers = [ { color: colors.deletedFile, values: sorted.map(function (d) { return {t : 1, x: d.date, y0 : 0, y: (d.stats ? -d.stats.fd : 0)} }) }, { color: colors.modifiedFile, values: sorted.map(function (d) { return {x: d.date, y0 : 0, y: (d.stats ? d.stats.fm : 0)} }) }, { color: colors.addedFile, values: sorted.map(function (d) { return {x: d.date, y0: (d.stats ? d.stats.fm : 0), y : (d.stats ? d.stats.fa : 0)} }) } ] ; function interpolateSankey(points) { var x0 = points[0][0], y0 = points[0][1], x1, y1, x2, path = [x0, ",", y0], i = 0, n = points.length; while (++i < n) { x1 = points[i][0]; y1 = points[i][1]; x2 = (x0 + x1) / 2; path.push("C", x2, ",", y0, " ", x2, ",", y1, " ", x1, ",", y1); x0 = x1; y0 = y1; } return path.join(""); } var y1 = d3.scale.linear() .range([h6 * 4.5, h6 * 3, h6 * 1.5]) .domain([-data.stats.files, 0, data.stats.files]), area = d3.svg.area() .interpolate(interpolateSankey /*"linear" "basis"*/) .x(function(d) { return x(dx); }) .y0(function(d) { return y1(d.y0); }) .y1(function(d) { return y1(d.y0 + dy); }) ;
      
      







アークを構築するには、 d3.svg.arc()を使用します(このコンポーネントが使用される例は多数あります: Arc TweenPie Multiples )。

2つのコンポーネントd3.time.scale()およびd3.svg.axisを使用して、Xスケールの生成を行います。 実装は、このカスタム時間形式の例から取られています。

参加者の図は、 d3.layout.pack()円パッキングの例)によって計算されます。 円の並べ替えとサイズ変更を行うために、 並べ替え値のプロパティを変更します。

この視覚化のコードは、 stat.jsusercommit.jsの 2つのファイルにあります




動的な視覚化


このため、すべてがベンチャーでした。 code_swarmを使用してレンダリングするとどうなるかが気に入っていますが、毎回リポジトリをコンピューターに複製してからレンダリングするのは便利ではありません。

この視覚化では、code_swarmに適用されるすべてのアイデアを実装し、その場で設定を変更しようとしました。

Song-of-githubの視覚化、 LauncherリンクHabrahabrのSong-of-githubに関する記事

画像






物理計算は悪名高いD3.Layout.Forceによって実行されますが、わずかな省略を加えて2つあります。 1つはユーザーの位置を計算し、もう1つはユーザーの位置に応じてファイルの位置を考慮します。 これはどのように行われますか? 各ファイルにはauthor



プロパティがあり、このファイルが現在のコミットにある場合、現在のユーザー(コミット時間)が書き込みます。 上記のクラスタリング方法はそれを取得し、空間内の指定されたファイルの位置を考慮します。

クラスタリング機能
  function tick() { if (_force.nodes()) { _force.nodes() .forEach(cluster(0.025)); _forceAuthor.nodes( _forceAuthor.nodes() .filter(function(d) { blink(d, !d.links && setting.userLife > 0); if (d.visible && d.links === 0 && setting.userLife > 0) { d.flash = 0; d.alive = d.alive / 10; } return d.visible; }) ); } _forceAuthor.resume(); _force.resume(); } // Move d to be adjacent to the cluster node. function cluster(alpha) { authorHash.forEach(function(k, d) { d.links = 0; }); return function(d) { blink(d, setting.fileLife > 0); if (!d.author || !d.visible) return; var node = d.author, l, r, x, y; if (node == d) return; node.links++; x = dx - node.x; y = dy - node.y; l = Math.sqrt(x * x + y * y); r = radius(nr(d)) / 2 + (nr(node) + setting.padding); if (l != r) { l = (l - r) / (l || 1) * (alpha || 1); x *= l; y *= l; dx -= x; dy -= y; } }; }
      
      





そして、強制レイアウトの初期化の場所

 _force = (_force || d3.layout.force() .stop() .size([w, h]) .friction(.75) .gravity(0) .charge(function(d) {return -1 * radius(nr(d)); } ) .on("tick", tick)) .nodes([]) ; ..... _forceAuthor = (_forceAuthor || d3.layout.force() .stop() .size([w, h]) .gravity(setting.padding * .001) .charge(function(d) { return -(setting.padding + d.size) * 8; })) .nodes([]) ;
      
      







2つのスレッドが動作します(そう言えば)、1つはsetInterval



もう1つはrequestAnimationFrame



です。 最初は時間の移動を担当し、2番目はレンダリングを担当します。 しかし、実際には、forceにも独自のタイマーがあり、asyncForEach(適切なシステム応答があり、1つのコミットからのファイルが一度に飛び出さないようにする必要がありますが、少し遅れて)もsetTimeoutsを起動します。

コードはshow.jsファイルで確認できます。



データ検索



api.github.comからデータを取得します。

データはJSONPメソッド使用して受信されます。

GitHub APIによると Client_id



Client_Secret



が必要ですが、リクエストの制限は1時間あたり1 ipに対して60です。 そのため、GitHubのプロファイル設定でアプリケーションを作成し、必要な承認情報をリクエストに追加します。

それが私がすべてだということです...そして、この認証方法の制限が1時間あたり5000リクエストであるという事実に、 mcのようないくつかのリポジトリには豊富な歴史があります。 そして、あなたがそれをうまく歩けば、システムがあなたに言うように、制限はすぐに使い果たされます。 これが発生した場合、 システム設定メニューで、アプリケーションのclient_id



およびclient_secret



指定できます(まだ存在しない場合は以前に作成済み)。

GitHubには非常に優れたAPIがあります。リクエストを1つだけ完了するだけで十分です。たとえば、ユーザー情報のリクエスト api.github.com/users{user}



api.github.com/users{user}



他のすべてのリンクが応答します。 さらに、これが複数ページのリクエストである場合(たとえば、リポジトリのリストを取得する場合、応答には10個のリポジトリに関する情報のみが含まれます)、 meta



パラメーターの応答オブジェクトには、認可パラメーターの完全なセットを含む次のページへのリンクがあります。


一般に、私はAPIの開発者とAPIのドキュメントを書いた人々に感謝を表明します。彼らと一緒に仕事をすることは喜びです。

また、 D3js開発者には、 豊富な例のコレクション (これなしではおそらくこれに触発されなかっただろう)と、すべての説明を含む非常に完全なドキュメントに感謝します。



おわりに



私がプロジェクトを始めた当初、それは自分にとっておもちゃでしたが、実際はそうでした。 リポジトリフォークしてエラーの束を見つけたり、何か新しいものを台無しにしたりする場合は、プルリクエストを残すか、 Issuesに書き込んでください。

開発中、アプリケーションはGoogle Chrome dev-mでのみテストされました(もちろん、他のブラウザーで修正された妨害を明示的に修正しました)。お気に入りのブラウザーで正しく動作させる方法を知っているなら、私は無限に感謝します。

健康的な批判を待っています。

ご清聴ありがとうございました!





PS

いくつかの興味深いリポジトリ:






All Articles