Initial version of language distribution graph
Initial version of language distribution graph

--- a/include/controller/Controller_GraphData.class.php
+++ b/include/controller/Controller_GraphData.class.php
@@ -74,14 +74,51 @@
 	{
 		$head = $this->GetProject()->GetHeadCommit();
 
-		$data = array();
+		$data = null;
 
-		$log = new GitPHP_Log($this->GetProject(), $head, new GitPHP_LogLoad_Git($this->exe), 0, 0);
-		$cache = $this->GetProject()->GetObjectManager()->GetMemoryCache();
+		if ($this->params['graphtype'] == 'commitactivity') {
 
-		foreach ($log as $commit) {
-			$data[] = (int)$commit->GetCommitterEpoch();
-			$cache->Delete($commit->GetCacheKey());
+			$data = array();
+
+			$log = new GitPHP_Log($this->GetProject(), $head, new GitPHP_LogLoad_Git($this->exe), 0, 0);
+			$cache = $this->GetProject()->GetObjectManager()->GetMemoryCache();
+
+			foreach ($log as $commit) {
+				$data[] = (int)$commit->GetCommitterEpoch();
+				$cache->Delete($commit->GetCacheKey());
+			}
+
+		} else if ($this->params['graphtype'] == 'languagedist') {
+
+			$data = array();
+
+			include_once(GITPHP_GESHIDIR . "geshi.php");
+			$geshi = new GeSHi("",'php');
+
+			$files = explode("\n", $this->exe->Execute($this->GetProject()->GetPath(), 'ls-tree', array('-r', '--name-only', $head->GetTree()->GetHash())));
+			foreach ($files as $file) {
+				$filename = GitPHP_Util::BaseName($file);
+				$lang = GitPHP_Util::GeshiFilenameToLanguage($filename);
+				if (empty($lang)) {
+					$lang = $geshi->get_language_name_from_extension(substr(strrchr($filename, '.'), 1));
+					if (empty($lang)) {
+						$lang = 'Other';
+					}
+				}
+
+				if (!empty($lang) && ($lang !== 'Other')) {
+					$fulllang = $geshi->get_language_fullname($lang);
+					if (!empty($fulllang))
+						$lang = $fulllang;
+				}
+
+				if (isset($data[$lang])) {
+					$data[$lang]++;
+				} else {
+					$data[$lang] = 1;
+				}
+			}
+
 		}
 
 		$this->tpl->assign('data', json_encode($data));

--- /dev/null
+++ b/js/commitactivity.js
@@ -1,1 +1,17 @@
+/*
+ * GitPHP Javascript commit graph loader
+ * 
+ * Initialized script modules used on the commit activity graph
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Javascript
+ */
 
+define(["jquery", "modules/commitactivitygraph", "common"], function($, commitActivityGraph) {
+	$(function() {
+		commitActivityGraph.init('div#graph');
+	});
+});
+

--- /dev/null
+++ b/js/languagedist.js
@@ -1,1 +1,17 @@
+/*
+ * GitPHP Javascript language distribution graph loader
+ * 
+ * Initialized script modules used on the language distribution graph
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Javascript
+ */
 
+define(["jquery", "modules/languagedistgraph", "common"], function($, languageDistGraph) {
+	$(function() {
+		languageDistGraph.init('div#graph');
+	});
+});
+

--- /dev/null
+++ b/js/modules/commitactivitygraph.js
@@ -1,1 +1,36 @@
+/*
+ * GitPHP commit activity graph
+ * 
+ * Display commit activity history graph
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Javascript
+ */
 
+define(["modules/geturl", "modules/getproject", "d3"],
+	function(getUrl, getProject) {
+
+		var url = null;
+		var project = null;
+
+		var width = 960;
+		var height = 500;
+
+		var init = function(graphContainer) {
+
+			url = getUrl();
+			project = getProject();
+
+			d3.json(url + "?p=" + project + "&a=graphdata&g=commitactivity", function(data) {
+
+			});
+		};
+
+		return {
+			init: init
+		};
+	}
+);
+

--- /dev/null
+++ b/js/modules/languagedistgraph.js
@@ -1,1 +1,142 @@
+/*
+ * GitPHP language distribution graph
+ * 
+ * Display language distribution graph
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Javascript
+ */
 
+define(["modules/geturl", "modules/getproject", "d3"],
+	function(getUrl, getProject) {
+
+		var url = null;
+		var project = null;
+
+		var width = 600;
+		var height = 600;
+		var radius = 200;
+		var innerRadius = 100;
+		var growRadius = 20;
+
+		var pie = null;
+		var color = null;
+		var svg = null;
+
+		var arcGroup = null;
+		var arc = null;
+		var grownArc = null;
+
+		var placeholderGroup = null;
+		var placeholder = null;
+
+		var centerGroup = null;
+		var langLabel = null;
+		var countLabel = null;
+		var filesLabel = null;
+
+		var pieTween = function(d, i) {
+			var i = d3.interpolate({startAngle: 0, endAngle: 0}, {startAngle: d.startAngle, endAngle: d.endAngle});
+			return function(t) {
+				return arc(i(t));
+			};
+		};
+
+		var init = function(graphContainer) {
+
+			pie = d3.layout.pie().value(function(d) {
+				return d.value;
+			});
+
+			color = d3.scale.category20();
+
+			svg = d3.select(graphContainer).append("svg")
+				.attr("width", width)
+				.attr("height", height);
+
+			placeholderGroup = svg.append("g")
+				.attr("transform", "translate(" + (width/2) + "," + (height/2) + ")");
+
+			arcGroup = svg.append("g")
+				.attr("transform", "translate(" + (width/2) + "," + (height/2) + ")");
+
+			centerGroup = svg.append("g")
+				.attr("transform", "translate(" + (width/2) + "," + (height/2) + ")");
+
+			langLabel = centerGroup.append("text")
+				.attr("dy", -25)
+				.attr("font-size", "16")
+				.attr("text-anchor", "middle");
+
+			countLabel = centerGroup.append("text")
+				.attr("dy", 0)
+				.attr("text-anchor", "middle")
+				.attr("font-size", "20")
+				.text("Loading");
+
+			filesLabel = centerGroup.append("text")
+				.attr("dy", 20)
+				.attr("text-anchor", "middle")
+				.attr("fill", "gray")
+				.attr("font-size", "12")
+				.text("files");
+
+			placeholder = placeholderGroup.append("path")
+				.attr("fill", "#EFEFEF")
+				.attr("d", d3.svg.arc().innerRadius(innerRadius).outerRadius(radius).startAngle(0).endAngle(6.28318531)());
+
+			arc = d3.svg.arc().innerRadius(innerRadius).outerRadius(radius);
+			grownArc = d3.svg.arc().innerRadius(innerRadius).outerRadius(radius + growRadius);
+
+			url = getUrl();
+			project = getProject();
+
+			d3.json(url + "?p=" + project + "&a=graphdata&g=languagedist", function(data) {
+				var dataEntries = d3.entries(data);
+				var count = 0;
+				if (dataEntries.length > 0) {
+					dataEntries.forEach(function(d) {
+						count += d.value;
+					});
+				}
+				countLabel.text(count);
+
+				var paths = arcGroup.selectAll("path").data(pie(dataEntries));
+				
+				paths.enter().append("path")
+					.attr("stroke", "white")
+					.attr("stroke-width", 0.5)
+					.attr("fill", function(d, i) { return color(i); })
+					.transition()
+					.duration(750)
+					.attrTween("d", pieTween)
+					.each("end", function() {
+						placeholderGroup.remove();
+					});
+
+				arcGroup.selectAll("path").on("mouseover", function(d) {
+						d3.select(this).transition()
+							.duration(250)
+							.attr("d", grownArc);
+						langLabel.text(d.data.key);
+						countLabel.text(d.data.value);
+					})
+					.on("mouseout", function(d) {
+						d3.select(this).transition()
+							.duration(250)
+							.attr("d", arc);
+						langLabel.text("");
+						countLabel.text(count);
+					});
+
+			});
+		};
+
+		return {
+			init: init
+		};
+	}
+);
+

--- a/templates/graph.tpl
+++ b/templates/graph.tpl
@@ -7,6 +7,23 @@
  * @subpackage Template
  *}
 {extends file='projectbase.tpl'}
+
+{block name=javascriptpaths}
+GitPHPJSPaths.d3 = "ext/d3.v2.min"
+{if $graphtype=='languagedist' && file_exists('js/languagedist.min.js')}
+GitPHPJSPaths.languagedist = "languagedist.min";
+{elseif $graphtype=='commitactivity' && file_exists('js/commitactivity.min.js')}
+GitPHPJSPaths.commitactivity = "commitactivity.min";
+{/if}
+{/block}
+
+{block name=javascriptmodules}
+{if $graphtype}
+GitPHPJSModules = ['{$graphtype}'];
+{else}
+GitPHPJSModules = ['common'];
+{/if}
+{/block}
 
 {block name=main}
 
@@ -19,16 +36,18 @@
 {else}
   <a href="{$scripturl}?p={$project->GetProject()|rawurlencode}&amp;a=graph&g=commitactivity">{t}commit activity{/t}</a>
 {/if}
+|
+{if $graphtype=='languagedist'}
+  {t}language distribution{/t}
+{else}
+  <a href="{$scripturl}?p={$project->GetProject()|rawurlencode}&amp;a=graph&g=languagedist">{t}language distribution{/t}</a>
+{/if}
 </div>
 
 {include file='title.tpl'}
 
-{if $graphtype}
 <div id="graph">
 </div>
-{else}
-Select a graph type
-{/if}
 
 {/block}
 

comments