From 6ea3829a7606fd621833d547fb5fa91f38af3213 Mon Sep 17 00:00:00 2001
From: alvaro <alvaro@graves.cl>
Date: Tue, 19 Mar 2013 15:00:10 -0700
Subject: [PATCH] Added line and stacked columncharts

---
 .../Haanga/Extension/Filter/D3linechart.php   | 156 ++++++++++++++++
 .../Extension/Filter/D3stackedcolumnchart.php | 172 ++++++++++++++++++
 2 files changed, 328 insertions(+)
 create mode 100644 lib/Haanga/lib/Haanga/Extension/Filter/D3linechart.php
 create mode 100644 lib/Haanga/lib/Haanga/Extension/Filter/D3stackedcolumnchart.php

diff --git a/lib/Haanga/lib/Haanga/Extension/Filter/D3linechart.php b/lib/Haanga/lib/Haanga/Extension/Filter/D3linechart.php
new file mode 100644
index 00000000..67245a7e
--- /dev/null
+++ b/lib/Haanga/lib/Haanga/Extension/Filter/D3linechart.php
@@ -0,0 +1,156 @@
+<?php
+
+class Haanga_Extension_Filter_D3LineChart{
+  public $is_safe = TRUE;
+  static function main($obj, $varname){
+  	$data = array();
+  	$i = 0;
+    $options = array();
+  	$randId = rand();
+  	$firstColumn = true;
+  	$names = explode(",", $varname);
+  	$j = 0;
+  	$data['series']=array();
+  	$data['dict']=array();
+  	
+  	$fieldCounter=0;
+  	$varList = array();
+  	foreach($names as $v){
+  	  if(strpos($v,"=")){
+  	    break;
+  	  }
+  	  $variable['name'] = $v;
+  	  $variable['value'] = 'value';
+  	  if(strpos($v, ".")){
+  	    $aux = explode(".", $v);
+  	    $variable['name'] = $aux[0];
+  	    $variable['value'] = $aux[1];
+  	  }
+  	  if($fieldCounter > 0){array_push($data['dict'], $variable['name']);}
+  	  $fieldCounter++;
+  	  array_push($varList, $variable);
+  	}
+
+  	$series = array();
+  	foreach($obj as $k){  	
+  	  $series = array();
+  	  foreach($varList as $v){
+  	    $name = $v['name'];
+  	    $val = $v['value'];
+
+  	  	if($j==0){
+  	  	  $series['key'] = $k->$name->$val;
+  	  	  //$newItem[$j]['x'] = $value;
+  	  	}else{
+  	  	  $series['values'][] = $k->$name->$val;
+  	  	}
+  	  	$j++;
+  	  } 
+  	  $i++;
+  	  $j=0;
+ 	  	array_push($data['series'], $series);
+  	}
+  	
+  	//Getting options
+  	$options['height'] = 500;
+  	$options['width'] = 1000;
+  	$options['padding'] = 20;
+  	$options['chartProportion'] = 0.8;
+  	$options['legendSpace'] = 15;
+  	$options['intermediateLines'] = 4;
+    for($z=$fieldCounter; $z < count($names); $z++){
+      $pair = explode("=", $names[$z]);
+      $key = trim($pair[0], "\" '");
+      $value = trim($pair[1], "\" '");
+      $options[$key] = $value;     
+    }
+
+  	$divId = uniqid("d3linechart_div");
+  	$pre = "<div id='".$divId."'></div>
+  	<script src='http://d3js.org/d3.v2.min.js?2.9.3'></script>
+    <script type='text/javascript'>
+    var options_$divId = ".json_encode($options)."; 
+    var dataset_$divId = ".json_encode($data).";
+    var color = d3.scale.category10();
+    var stroke = function(d){
+      s = ['', '5,5', '5,10', '10,5'];
+      return s[d%s.length];
+    }
+    
+    var maxValue_$divId = getMax(dataset_".$divId."['series']);
+    var svg = d3.selectAll('#".$divId."').append('svg').attr('width', options_$divId.width).attr('height', options_$divId.height);
+    var maxHeight_$divId = options_$divId.chartProportion*options_$divId.height;
+
+
+    function getMax(d){
+      maxValue = 0;
+      for(var i in d){
+        e = d[i];
+        for(var j in e.values){
+          aux = parseInt(e.values[j]);
+         if(maxValue < aux){
+           maxValue = aux;
+         }
+       }
+     }
+     return maxValue+1;
+   }    
+//Axis
+  var xaxis = svg.append('g');
+    xaxis.append('line').style('stroke', 'black').style('stroke-width', '2px').attr('x1',  1+options_$divId.legendSpace).attr('y1', maxHeight_$divId).attr('x2', options_$divId.width+options_$divId.padding+ options_$divId.legendSpace).attr('y2', maxHeight_$divId)
+    xaxis.selectAll('line.stub')
+    var labels_$divId = xaxis.selectAll('text.xaxis')
+        .data(dataset_".$divId."['dict'])
+        .enter().append('text').text(function(d){return d})
+        .style('font-size', '12px').style('font-family', 'sans-serif')
+        .attr('class', 'xaxis')        
+        .attr('x', function(d, i){return options_$divId.chartProportion*i*(parseInt(options_$divId.width)/ dataset_".$divId."['series'].length) + 4*options_$divId.padding + options_$divId.legendSpace})
+        .attr('y', function(d, i){return maxHeight_$divId+30;})
+        .attr('transform', function(d){return 'translate(-'+(this.getBBox().width/2)+')'});
+
+        
+   var yaxis = svg.append('g');
+    yaxis.append('line').style('stroke', 'black').style('stroke-width', '2px').attr('x1', 1+options_$divId.padding + options_$divId.legendSpace).attr('y1', maxHeight_$divId).attr('x2', 1+options_$divId.padding + options_$divId.legendSpace).attr('y2', 1)
+   for(i=0; i<options_$divId.intermediateLines; i++){
+    yaxis.append('line').style('stroke', 'grey').style('stroke-width', '1px').attr('x1', 1 + options_$divId.legendSpace).attr('y1', maxHeight_$divId*(i/options_$divId.intermediateLines)+1).attr('x2', options_$divId.width).attr('y2', maxHeight_$divId*(i/options_$divId.intermediateLines))
+   } 
+
+    
+//Values
+var line = d3.svg.line()
+    .x(function(d, i){return options_$divId.chartProportion*i*(parseInt(options_$divId.width) / dataset_".$divId."['series'].length) + 4*options_$divId.padding + options_$divId.legendSpace})
+    .y(function(d, i) { return (1-d/maxValue_$divId)*maxHeight_$divId; });
+
+for(var k in dataset_".$divId."['series']){
+  svg.append('path').attr('class', 'line')
+        .datum(dataset_".$divId."['series'][k].values)
+        .attr('d', line)
+        .style('opacity', 0.8)
+        .style('stroke', function(d, i){return color(k)})
+        .style('stroke-width', '2px')
+        .style('stroke-dasharray', stroke(k))
+        .style('fill', 'none');
+}
+
+        d3.selectAll('rect.bar')
+        .on('mouseover', function(){
+        d3.select(this).style('opacity', 1); 
+        }).on('mouseout', function(){
+        d3.select(this).style('opacity', 0.8); 
+        });
+//Scale        
+   for(i=0; i<options_$divId.intermediateLines; i++){
+    yaxis.append('text')
+         .attr('x', 1)
+         .attr('y', maxHeight_$divId*(i/options_$divId.intermediateLines)+1)
+         .attr('font-family', 'sans-serif')
+         .attr('font-size', '10px')
+         .text(maxValue_$divId*(1-i/options_$divId.intermediateLines))
+         .attr('transform', 'translate(0,10)');
+   } 
+    </script>
+    ";
+    
+    return $pre;
+  }
+}
diff --git a/lib/Haanga/lib/Haanga/Extension/Filter/D3stackedcolumnchart.php b/lib/Haanga/lib/Haanga/Extension/Filter/D3stackedcolumnchart.php
new file mode 100644
index 00000000..374df100
--- /dev/null
+++ b/lib/Haanga/lib/Haanga/Extension/Filter/D3stackedcolumnchart.php
@@ -0,0 +1,172 @@
+<?php
+
+class Haanga_Extension_Filter_D3StackedColumnChart{
+  public $is_safe = TRUE;
+  static function main($obj, $varname){
+  	$data = array();
+  	$i = 0;
+    $options = array();
+  	$randId = rand();
+  	$firstColumn = true;
+  	$names = explode(",", $varname);
+  	$j = 0;
+
+  	
+  	
+  	$fieldCounter=0;
+  	$varList = array();
+  	foreach($names as $v){
+  	  if(strpos($v,"=")){
+  	    break;
+  	  }
+  	  $variable['name'] = $v;
+  	  $variable['value'] = 'value';
+  	  if(strpos($v, ".")){
+  	    $aux = explode(".", $v);
+  	    $variable['name'] = $aux[0];
+  	    $variable['value'] = $aux[1];
+  	  }
+  	  $fieldCounter++;
+  	  array_push($varList, $variable);
+  	}
+
+  	$series = array();
+  	foreach($obj as $k){  	
+  	  $newItem = array();
+  	  foreach($varList as $v){
+  	    $name = $v['name'];
+  	    $val = $v['value'];
+
+  	  	if($j==0){
+  	  	  //$newItem[$j]['x'] = $value;
+  	  	}else{
+  	  	  $series[$name]['key'] = $name;
+  	  	  $series[$name]['values'][] = $k->$name->$val;
+  	  	}
+  	  	$j++;
+  	  } 
+  	  $i++;
+  	  $j=0;
+// 	  	array_push($data, $newItem);
+  	}
+    foreach($series as $v){
+      $data[] = $v;
+    }
+  	
+  	//Getting options
+  	$options['height'] = 300;
+  	$options['width'] = 1000;
+  	$options['padding'] = 20;
+  	$options['barsProportion'] = 0.8;
+  	$options['legendSpace'] = 15;
+  	$options['intermediateLines'] = 4;
+    for($z=$fieldCounter; $z < count($names); $z++){
+      $pair = explode("=", $names[$z]);
+      $key = trim($pair[0], "\" '");
+      $value = trim($pair[1], "\" '");
+      $options[$key] = $value;     
+    }
+
+  	$divId = uniqid("columnchart_div");
+  	$pre = "<div id='".$divId."'>
+  	</div>
+  	<script src='http://d3js.org/d3.v2.min.js?2.9.3'></script>
+    <script type='text/javascript'>
+    var options_$divId = ".json_encode($options)."; 
+    var dataset_$divId = ".json_encode($data).";
+    var color = d3.scale.category10();
+    
+    var maxValue_$divId = getMax(dataset_$divId);
+    var svg = d3.selectAll('#".$divId."').append('svg').attr('width', options_$divId.width).attr('height', options_$divId.height);
+    var maxHeight_$divId = options_$divId.barsProportion*options_$divId.height;
+
+
+   function getMax(d){
+     maxValues = [];
+     for(var i in d){
+       e = d[i];
+       for(var j in e.values){
+         if(maxValues[e.key] == undefined){
+          maxValues[e.key] = 0;
+         }
+         maxValues[e.key] += parseInt(e.values[j]);
+       }
+     }
+     r = 0;
+     for(var i in maxValues){
+     aux = parseInt(maxValues[i]);
+       if(aux > r){
+         r = aux;
+       }
+     }
+     return r+1;
+   }    
+   
+//Axis
+  var xaxis = svg.append('g');
+    xaxis.append('line').style('stroke', 'black').style('stroke-width', '2px').attr('x1',  1+options_$divId.legendSpace).attr('y1', maxHeight_$divId).attr('x2', options_$divId.width+options_$divId.padding+ options_$divId.legendSpace).attr('y2', maxHeight_$divId)
+    xaxis.selectAll('line.stub')
+    var labels_$divId = xaxis.selectAll('text.xaxis')
+        .data(dataset_$divId)
+        .enter().append('text').text(function(d){return d.key})
+        .style('font-size', '12px').style('font-family', 'sans-serif')
+        .attr('class', 'xaxis')        
+        .attr('x', function(d, i){return (options_$divId.width / dataset_$divId.length - 4*options_$divId.padding)/2+options_$divId.barsProportion *i* (parseInt(options_$divId.width) / dataset_$divId.length) + 4*options_$divId.padding + options_$divId.legendSpace})
+        .attr('y', function(d, i){return maxHeight_$divId+30;})
+        .attr('transform', function(d){return 'translate(-'+this.getBBox().width/2+')'});
+
+        
+   var yaxis = svg.append('g');
+    yaxis.append('line').style('stroke', 'black').style('stroke-width', '2px').attr('x1', 1+options_$divId.padding + options_$divId.legendSpace).attr('y1', maxHeight_$divId).attr('x2', 1+options_$divId.padding + options_$divId.legendSpace).attr('y2', 1)
+   for(i=0; i<options_$divId.intermediateLines; i++){
+    yaxis.append('line').style('stroke', 'grey').style('stroke-width', '1px').attr('x1', 1 + options_$divId.legendSpace).attr('y1', maxHeight_$divId*(i/options_$divId.intermediateLines)+1).attr('x2', options_$divId.width).attr('y2', maxHeight_$divId*(i/options_$divId.intermediateLines))
+   } 
+
+   
+//Values
+baseline = [];
+for(var k in dataset_$divId){
+key = dataset_".$divId."[k].key;
+  baseline[key] = maxHeight_$divId;
+  svg.selectAll('d.series')
+     .data(dataset_".$divId."[k].values).enter()
+     .append('rect').attr('class', 'bar')
+        .attr('x', function(d, i) {
+			   		return options_$divId.barsProportion *k* (parseInt(options_$divId.width) / dataset_$divId.length) + 4*options_$divId.padding + options_$divId.legendSpace;
+			   })
+			   .attr('y', function(d, i){
+			   r = maxHeight_$divId*(1-parseInt(d)/maxValue_$divId) - (maxHeight_$divId-baseline[key]);			   
+			   baseline[key] = r;
+			   return r;
+
+			   })
+			   .attr('width', options_$divId.width / dataset_$divId.length - 4*options_$divId.padding)
+			   .attr('height', function(d){ 
+			   return maxHeight_$divId*d/maxValue_$divId
+			   })
+        .style('opacity', 0.8).style('fill', function(d, i){return color(i)});
+}
+
+ 
+//Tooltip
+tooltip_$divId = svg.append('text').style('opacity', 0).style('font-family', 'sans-serif').style('font-size', '12px').style('fill', 'white').style('stroke-width', '.5');
+
+//Events
+d3.selectAll('rect.bar')
+        .on('mouseover', function(e){
+        newX =  parseFloat(d3.select(this).attr('x')) + .5*parseFloat(d3.select(this).attr('width'));
+        newY =  parseFloat(d3.select(this).attr('y'));
+        tooltip_$divId.style('opacity', 1).attr('y', newY+10).attr('x', newX).text(e);
+        d3.select(this).style('opacity', 1); 
+        }).on('mouseout', function(){
+        d3.select(this).style('opacity', 0.8); 
+        });
+        
+   for(i=0; i<options_$divId.intermediateLines; i++){
+    yaxis.append('text').attr('x', 1).attr('y', maxHeight_$divId*(i/options_$divId.intermediateLines)+1).attr('font-family', 'sans-serif').attr('font-size', '10px').text(maxValue_$divId*(1-i/options_$divId.intermediateLines)).attr('transform', 'translate(0,10)');
+   } 
+    </script>
+    ";
+    return $pre;
+  }
+}
-- 
GitLab