<?php
include_once '../d3.classes.inc.php';
class d3GroupedBarChartData {
protected $username = "root";
protected $password = "";
protected $database = "northwind";
protected $host = "localhost";
protected $query = "SELECT IFNULL(country, 'other') AS country, IFNULL(jahr,'Total') as `year`, SUM(profit) as amount FROM sales GROUP BY country, year;";
public $results = array();
public function __construct($query=null, $conn=null){
if($query) $this->query = $query;
if(is_array($conn)){
foreach($conn as $key => $val){
if(property_exists($this, $key)){
$this->{$key} = $val;
}
}
}
}
protected function fetchData(){
$link=mysql_connect($this->host,$this->username,$this->password);
@mysql_select_db($this->database) or die( "Unable to select database");
$rs = mysql_query($this->query,$link) or die('Error: '.$this->query);
if(mysql_num_rows($rs)) {
$value = null;
$index = 0;
while($value = mysql_fetch_assoc($rs)) {
$this->results[$value["country"]][($value["year"]==""?"other":$value["year"])] = $value["amount"];
$this->results[$value["country"]]["country"] = $value["country"];
$index++;
}
}
mysql_close();
}
public function getBarValueName(){
return "amount";
}
public function getBarTitleName(){
return "country";
}
public function getResults(){
$results = array();
foreach($this->results as $row){
$results[] = $row;
}
return $results;
}
public function execute(){
$this->fetchData();
}
}
class d3GroupedBarChart {
/**
* @var d3GroupedBarChartData $data
*/
protected $data;
protected $config = array();
protected $stack = array();
protected $register = array();
protected $barTitleName;
protected $barValueName;
public function __construct(d3GroupedBarChartData $data, $config = array()){
$this->data = $data;
$this->prepareConfig($config);
}
protected function has($name){
return array_key_exists($name, $this->register);
}
protected function get($name){
return $this->register[$name];
}
protected function set($name, $value){
$this->register[$name] = $value;
return $this;
}
protected function add($value){
$this->stack[] = $value;
return $this;
}
protected function prepareConfig($config){
$this->config = array(
"width" => 960, "height" => 500,
"margin" => array("top" => 20, "right" => 20, "bottom" => 30, "left" => 40),
"color" => array("#ff0000", "#00ff00", "#0000ff", "#ffff00"),
);
$this->config = array_merge_recursive($this->config, $config);
}
protected function prepareDataSet(){
$this->data->execute();
$this->barTitleName = $this->data->getBarTitleName();
$this->barValueName = $this->data->getBarValueName();
$this->set("dataset", d3::variable(d3::unescape( json_encode($this->data->getResults()) ),"data"));
$this->add( $this->get("dataset") );
}
protected function prepareDimensions(){
$this->set("margin", d3::variables(array("margin" => o3($this->config["margin"]))) );
$this->add( $this->get("margin") );
$this->set("width", d3::variable(d3::unescape( $this->config["width"]."-margin.left-margin.right"), "width") );
$this->set("height", d3::variable(d3::unescape( $this->config["height"]."-margin.top-margin.bottom"), "height") );
$this->add( $this->get("width") );
$this->add( $this->get("height") );
}
protected function prepareOrdinalScale(){
$this->set("x0", d3()
->scale(d3::property)
->ordinal()->rangeRoundBands(array(0, $this->get("width")->getVar()), 0.1)->returnVar("x0")
);
$this->add( $this->get("x0") );
$this->set("x1", d3()
->scale(d3::property)
->ordinal()->returnVar("x1")
);
$this->add( $this->get("x1") );
$this->set("y", d3()
->scale(d3::property)
->linear()->range(array($this->get("height")->getVar(), 0))->returnVar("y")
);
$this->add( $this->get("y") );
}
protected function prepareColorSet(){
$this->set("color", d3()
->scale(d3::property)
->ordinal()->range($this->getColors())
->returnVar("color")
);
$this->add( $this->get("color") );
}
protected function getColors(){
foreach($this->config["color"] as $index => $color){
$this->config["color"][$index] = d3::escape($color);
}
return $this->config["color"];
}
protected function prepareAxis(){
$this->set("xAxis", d3()->svg(d3::property)->axis()
->scale($this->get("x0")->getVar())->orient("bottom")->returnVar("xAxis")
);
$this->add( $this->get("xAxis") );
$this->set("yAxis", d3()->svg(d3::property)->axis()
->scale($this->get("y")->getVar())
->orient("left")->tickFormat(d3()->format(".2s"))->returnVar("yAxis")
);
$this->add( $this->get("yAxis")->linebreak() );
}
protected function prepareCanvas(){
$this->set("svg", d3()
->select("body")->append("svg")->linebreak()->tab()
->attr("width", d3::unescape( $this->get("width")->getVar()."+margin.left+margin.right"))->linebreak()->tab()
->attr("height", d3::unescape( $this->get("height")->getVar()."+margin.top+margin.bottom"))->linebreak()->tab()
->append("g")->attr("transform" , d3::unescape('"translate("+margin.left+ "," + margin.top + ")"'))->returnVar("svg")
);
$this->add( $this->get("svg")->linebreak() );
}
protected function prepareChart(){
$this->prepareChartMethods();
$this->prepareChartBarAxes();
$this->prepareChartBarColumn();
$this->prepareChartLegend();
}
protected function prepareChartMethods(){
$this->set("amountNames", d3()->keys(d3::unescape("data[1]"))->filter(function($key){return $key !== "country";})->createVar("amountNames"));
$this->add( $this->get("amountNames"));
$this->add(
$this->get("dataset")->get()->forEach(d3::unescape("function(d) {d.amounts = amountNames.map(function(name) { return {name: name, value: parseInt((!+d[name]?0:+d[name]))}; });}"))
->colon()
);
$this->add(
$this->get("x0")->get()->domain($this->get("dataset")->get()->map(function($d){return $d->country;}))->colon()
);
$this->add(
$this->get("x1")->get()->domain($this->get("amountNames")->getVar())->rangeRoundBands(array(0, $this->get("x0")->get()->rangeBand()))->colon()
);
$this->add(
$this->get("y")->get()->domain(
array(
0,
d3::unescape("d3.max(data,function(d){return d3.max(d.amounts,function(d){return d.value;});})")
)
)->colon()->linebreak()
);
}
protected function prepareChartBarAxes(){
$this->add(
$this->get("svg")->get()
->append("g")->linebreak()->tab()
->attr("class", "x axis")->linebreak()->tab()
->attr("transform", d3::unescape('"transform(0, "+height+")"'))->linebreak()->tab()
->call($this->get("xAxis")->getVar())
->colon()
);
$this->add(
$this->get("svg")->get()
->append("g")->linebreak()->tab()
->call($this->get("yAxis")->getVar())->linebreak()->tab()
->append("text")->linebreak()->tab()
->attr("transform", "rotate(-90)")->linebreak()->tab()
->attr("y", 6)->linebreak()->tab()
->attr("dy", ".71em")->linebreak()->tab()
->style("text-anchor","end")->linebreak()->tab()
->text($this->barValueName)
->colon()->linebreak()
);
}
protected function prepareChartBarColumn(){
$this->set($this->barTitleName,
$this->get("svg")->get()
->selectAll(".".$this->barTitleName)->linebreak()->tab()
->data($this->get("dataset")->getVar())->linebreak()->tab()
->enter()->append("g")->linebreak()->tab()
->attr("class","g")->linebreak()->tab()
->attr("transform", function($d){return "translate(".$x0($d->country).",0)";})
->createVar($this->barTitleName)
);
$this->add( $this->get($this->barTitleName));
$this->add(
$this->get($this->barTitleName)->get()
->selectAll("rect")->linebreak()->tab()
->data(function($d){return $d->amounts;})->linebreak()->tab()
->enter()->append("rect")->linebreak()->tab()
->attr("width", $this->get("x1")->get()->rangeBand())->linebreak()->tab()
->attr("height", function($d){return $height-$y($d->value);})->linebreak()->tab()
->attr("x", function($d){return $x1($d->name);})->linebreak()->tab()
->attr("y", function($d){return $y($d->value);})->linebreak()->tab()
->style("fill", function($d){return $color($d->name);})->linebreak()
);
}
protected function prepareChartLegend(){
$this->set("legend", $this->get("svg")->get()
->selectAll(".legend")->linebreak()->tab()
->data($this->get("amountNames")->get()->slice()->reverse())->linebreak()->tab()
->enter()->append("g")->linebreak()->tab()
->attr("class", "legend")->linebreak()->tab()
->attr("transform", function($d, $i){return "translate(0," . $i * 20 . ")";})
->createVar("legend")
);
$this->add( $this->get("legend"));
$this->add(
$this->get("legend")->get()->append("rect")->linebreak()->tab()
->attr("y", d3::unescape($this->get("height")->getVar()."/2"))->linebreak()->tab()
->attr("x", d3::unescape($this->get("width")->getVar()."-28"))->linebreak()->tab()
->attr("width", 18)->linebreak()->tab()
->attr("height", 18)->linebreak()->tab()
->attr("fill", $this->get("color")->getVar())
->colon()
);
$this->add(
$this->get("legend")->get()->append("text")->linebreak()->tab()
->attr("x", d3::unescape($this->get("width")->getVar()."-30"))->linebreak()->tab()
->attr("y", d3::unescape($this->get("height")->getVar()."/2 +9"))->linebreak()->tab()
->attr("dy", ".35em")->linebreak()->tab()
->style("text-anchor", "end")->linebreak()->tab()
->text(function($d){return $d;})
->colon()
);
}
protected function init(){
$this->prepareDataSet();
$this->prepareDimensions();
$this->prepareOrdinalScale();
$this->prepareColorSet();
$this->prepareAxis();
$this->prepareCanvas();
$this->prepareChart();
$this->stack[] = "\n";
$this->object = implode("\n", $this->stack);
}
public function render() {
$this->init();
$this->stack[] = "\n";
return $this->object;
}
}
?><!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<div id="viz"></div>
<script type="text/javascript">
<?php
$script = new d3GroupedBarChart(new d3GroupedBarChartData());
echo $script->render();
?>
</script>
</body>
</html>
|