diff --git a/composer.json b/composer.json index fd3e72f..29ce682 100644 --- a/composer.json +++ b/composer.json @@ -1,47 +1,46 @@ { - "name": "atk4/chart", - "type": "library", - "description": "ChartJS for Agile UI", - "keywords": [ - "agile", - "data", - "framework", - "chart", - "chartjs" - ], - "homepage": "https://github.com/atk4/chart", - "license": "MIT", - "authors": [ - { - "name": "Romans Malinovskis", - "email": "romans@agiletoolkit.org", - "homepage": "https://nearly.guru/" - } - ], - "minimum-stability": "dev", - "prefer-stable": true, - "config": { - "sort-packages": true - }, - "require": { - "atk4/ui": "dev-develop" - }, - "require-release": { - "atk4/ui": "~2.3.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", - "phpunit/phpcov": "*", - "phpunit/phpunit": "*" - }, - "autoload": { - "psr-4": { - "Atk4\\Chart\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Atk4\\Chart\\Tests\\": "tests/" - } - } -} + "name" : "atk4/chart", + "type" : "library", + "description" : "ChartJS for Agile UI", + "keywords" : [ + "agile", + "data", + "framework", + "chart", + "chartjs" + ], + "homepage" : "https://github.com/atk4/chart", + "license" : "MIT", + "authors" : [{ + "name" : "Romans Malinovskis", + "email" : "romans@agiletoolkit.org", + "homepage" : "https://nearly.guru/" + } + ], + "minimum-stability" : "dev", + "prefer-stable" : true, + "config" : { + "sort-packages" : true + }, + "require" : { + "atk4/ui" : "dev-develop" + }, + "require-release" : { + "atk4/ui" : "~2.3.0" + }, + "require-dev" : { + "friendsofphp/php-cs-fixer" : "^2.16", + "phpunit/phpcov" : "*", + "phpunit/phpunit" : "*" + }, + "autoload" : { + "psr-4" : { + "Atk4\\Chart\\" : "src/" + } + }, + "autoload-dev" : { + "psr-4" : { + "Atk4\\Chart\\Tests\\" : "tests/" + } + } +} \ No newline at end of file diff --git a/demo/index.php b/demo/index.php index ea22262..f23c116 100644 --- a/demo/index.php +++ b/demo/index.php @@ -13,14 +13,16 @@ use Atk4\Ui\Columns; use Atk4\Ui\Layout; -$p = ['t' => [ - ['name' => 'January', 'sales' => 20000, 'purchases' => 10000], - ['name' => 'February', 'sales' => 23000, 'purchases' => 12000], - ['name' => 'March', 'sales' => 16000, 'purchases' => 11000], - ['name' => 'April', 'sales' => 14000, 'purchases' => 13000], -]]; -$m = new Model(new Array_($p), 't'); +$t = [ + 1 => ['name' => 'January', 'sales' => 20000, 'purchases' => 10000], + 2 => ['id' => 2, 'name' => 'February', 'sales' => 23000, 'purchases' => 12000], + 3 => ['id' => 3,'name' => 'March', 'sales' => 16000, 'purchases' => 11000], + 4 => ['id' => 4,'name' => 'April', 'sales' => 14000, 'purchases' => 13000]]; + +$m = new \Atk4\Data\Model(new \Atk4\Data\Persistence\Array_($t)); + $m->addFields(['name', 'sales', 'purchases', 'profit']); + $m->onHook($m::HOOK_AFTER_LOAD, function ($m) { $m->set('profit', $m->get('sales') - $m->get('purchases')); }); $app = new App('Chart Demo'); $app->initLayout([Layout\Centered::class]); diff --git a/src/Chart.php b/src/Chart.php index 84d5403..4fa5a83 100644 --- a/src/Chart.php +++ b/src/Chart.php @@ -31,10 +31,14 @@ class Chart extends View ['rgba(75, 192, 192, 0.2)', 'rgba(75, 192, 192, 1)'], ['rgba(153, 102, 255, 0.2)', 'rgba(153, 102, 255, 1)'], ['rgba(255, 159, 64, 0.2)', 'rgba(255, 159, 64, 1)'], + ['rgba(20, 20, 20, 0.2)', 'rgba(20, 20, 20, 1)'] ]; /** @var array Options for chart.js widget */ public $options = []; + + /** @var array Set stack id for each column, leave empty if no stacks */ + public $stacks = []; /** @var array Labels for axis. Fills with setModel(). */ protected $labels; @@ -123,14 +127,20 @@ public function setOptions(array $options) * * This component will automatically figure out name of the chart, * series titles based on column captions etc. + * + * Example for bar chart with two side-by side bars per category, and one of them stacked: + * + * $chart->setModel($model, ['month', 'turnover_month_shoes', 'turnover_month_shirts', 'turnover_month_trousers', 'turnover_month_total_last_year'], [0,0,0,1]); + * */ - public function setModel(Model $model, array $columns = []): Model + public function setModel(Model $model, array $columns = [], array $stacks = []): void { if (!$columns) { throw new Exception('Second argument must be specified to Chart::setModel()'); } $this->dataSets = []; + $this->stacks = $stacks; // Initialize data-sets foreach ($columns as $key => $column) { @@ -141,14 +151,20 @@ public function setModel(Model $model, array $columns = []): Model } $colors = array_shift($this->nice_colors); + $stack = array_shift($this->stacks); $this->dataSets[$column] = [ 'label' => $model->getField($column)->getCaption(), 'backgroundColor' => $colors[0], 'borderColor' => $colors[1], 'borderWidth' => 1, + 'stack' => $stack, 'data' => [], ]; + + if ($stacks != []) { + $this->setOptions(['scales' => ['yAxes' => [0 => ['stacked' => true]], 'xAxes' => [0 => ['stacked' => true]]]]); + } } // Prepopulate data-sets @@ -159,7 +175,6 @@ public function setModel(Model $model, array $columns = []): Model } } - return $model; } /** diff --git a/src/PieChart.php b/src/PieChart.php index f1f309a..db7972d 100644 --- a/src/PieChart.php +++ b/src/PieChart.php @@ -21,7 +21,7 @@ class PieChart extends Chart * This component will automatically figure out name of the chart, * series titles based on column captions etc. */ - public function setModel(Model $model, array $columns = []): Model + public function setModel(Model $model, array $columns = []): void { if (!$columns) { throw new Exception('Second argument must be specified to Chart::setModel()'); @@ -60,7 +60,6 @@ public function setModel(Model $model, array $columns = []): Model } } - return $model; } /**