Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for stacked bar chart #17

Merged
merged 7 commits into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions demos/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Atk4\Chart\BarChart;
use Atk4\Chart\ChartBox;
use Atk4\Chart\LineChart;
use Atk4\Chart\PieChart;
use Atk4\Data\Model;
use Atk4\Data\Persistence;
Expand All @@ -18,7 +19,7 @@
$t = [
1 => ['name' => 'January', 'sales' => 20000, 'purchases' => 10000],
2 => ['name' => 'February', 'sales' => 23000, 'purchases' => 12000],
3 => ['name' => 'March', 'sales' => 16000, 'purchases' => 11000],
3 => ['name' => 'March', 'sales' => 16000, 'purchases' => 25000],
4 => ['name' => 'April', 'sales' => 14000, 'purchases' => 13000],
];

Expand All @@ -30,17 +31,43 @@
$app = new App(['title' => 'Chart Demo']);
$app->initLayout([Layout\Centered::class]);

// split in columns
// split in columns - basic charts
$columns = Columns::addTo($app->layout);

// lets put your chart into a box
$cb = ChartBox::addTo($columns->addColumn(8), ['label' => ['Demo Bar Chart', 'icon' => 'book']]);
$cb = ChartBox::addTo($columns->addColumn(8), ['label' => ['Bar Chart', 'icon' => 'book']]);
$chart = BarChart::addTo($cb);
$chart->setModel($m, ['name', 'sales', 'purchases', 'profit']);
$chart->withCurrency('$'); // tweak our chart to support currencies better

$cb = ChartBox::addTo($columns->addColumn(8), ['label' => ['Bar Chart Horizontal', 'icon' => 'book']]);
$chart = BarChart::addTo($cb);
$chart->setHorizontal();
$chart->setModel($m, ['name', 'sales', 'purchases', 'profit']);
$chart->withCurrency('$');

// split in columns - stacked charts
$columns = Columns::addTo($app->layout);

$cb = ChartBox::addTo($columns->addColumn(8), ['label' => ['Bar Chart Stacked', 'icon' => 'book']]);
$chart = BarChart::addTo($cb);
$chart->setModel($m, ['name', 'sales', 'purchases', 'profit'], ['Stack 1', 'Stack 2', 'Stack 1']); // Stack 1 => sales + profit, Stack 2 => purchases
$chart->withCurrency('$');

// tweak our chart to support currencies better
$cb = ChartBox::addTo($columns->addColumn(8), ['label' => ['Demo Pie Chart', 'icon' => 'book']]);
$cb = ChartBox::addTo($columns->addColumn(8), ['label' => ['Bar Chart Stacked', 'icon' => 'book']]);
$chart = BarChart::addTo($cb);
$chart->setModel($m, ['name', 'sales', 'purchases', 'profit'], [1, 1, 1]); // 1 => sales + purchases + profit
$chart->withCurrency('$');

// split in columns - more charts
$columns = Columns::addTo($app->layout);

$cb = ChartBox::addTo($columns->addColumn(8), ['label' => ['Pie Chart', 'icon' => 'book']]);
$chart = PieChart::addTo($cb);
$chart->setModel($m, ['name', 'purchases']);
$chart->withCurrency('$');

$cb = ChartBox::addTo($columns->addColumn(8), ['label' => ['Line Chart', 'icon' => 'book']]);
$chart = LineChart::addTo($cb);
$chart->setModel($m, ['name', 'profit']);
$chart->withCurrency('$');
11 changes: 11 additions & 0 deletions src/BarChart.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,15 @@
class BarChart extends Chart
{
public $type = 'bar';

/**
* Set this chart to be horizontal.
*/
public function setHorizontal(): void
{
$this->type = 'horizontalBar';

// in chartjs 3.9.1 replace with
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to upgrade to the latest lib now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do

// $this->setOptions(['indexAxis' => 'y']);
}
}
27 changes: 25 additions & 2 deletions src/Chart.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
use Atk4\Ui\JsExpression;
use Atk4\Ui\View;

/**
* ChartJS 2.7.x documentation https://www.chartjs.org/docs/2.7.3/
* ChartJS 3.9.1 documentation https://www.chartjs.org/docs/3.9.1/.
*/
class Chart extends View
{
/** @var string HTML element type */
Expand All @@ -28,6 +32,7 @@ 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)'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this come from some design guide? can this can abstracted for unlimited colors?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current Colour scheme looks nice and can well be used, I would not abstract or generalize it: devs should change if they prefer other colour coding

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems the original colors come from https://www.chartjs.org/docs/3.9.1/#creating-a-chart example /wo any specific design guide/logic

];

/** @var array<string, mixed> Options for chart.js widget */
Expand Down Expand Up @@ -115,9 +120,18 @@ 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'],
* [1, 1, 1, 2] // 1 => shoes+shirts+trousers, 2 => total last year
* );
*
* @param array<int, string> $columns
* @param array<int, mixed> $stacks
*/
public function setModel(Model $model, array $columns = []): void
public function setModel(Model $model, array $columns = [], array $stacks = []): void
{
if ($columns === []) {
throw new Exception('Second argument must be specified to Chart::setModel()');
Expand All @@ -130,10 +144,11 @@ public function setModel(Model $model, array $columns = []): void
if ($key === 0) {
$titleColumn = $column;

continue; // skipping labels
continue; // skipping label column
}

$colors = array_shift($this->niceColors);
$stack = array_shift($stacks);

$this->datasets[$column] = [
'label' => $model->getField($column)->getCaption(),
Expand All @@ -142,6 +157,14 @@ public function setModel(Model $model, array $columns = []): void
'borderWidth' => 1,
'data' => [],
];

if ($stack !== null) {
$this->datasets[$column]['stack'] = $stack;
}
}

if ($stacks !== []) {
$this->setOptions(['scales' => ['yAxes' => [0 => ['stacked' => true]], 'xAxes' => [0 => ['stacked' => true]]]]);
}

// prepopulate data-sets
Expand Down
10 changes: 10 additions & 0 deletions src/LineChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Atk4\Chart;

class LineChart extends Chart
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This complicates any extension in user projects... Not sure if different chart type that does not need additional modifications needs a custom class.

Copy link
Member

@DarkSide666 DarkSide666 Aug 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There can be modifications in future is someone will be ready to contribute them :)
I think each chart type should have it's own class even if it is mostly empty. Also maybe some parts from generic Chart class should go to extended chart classes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with this for now.

{
public $type = 'line';
}
2 changes: 1 addition & 1 deletion src/PieChart.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class PieChart extends Chart
/** @var string Type of chart */
public $type = 'pie';

public function setModel(Model $model, array $columns = []): void
public function setModel(Model $model, array $columns = [], array $stacks = []): void
{
if ($columns === []) {
throw new Exception('Second argument must be specified to Chart::setModel()');
Expand Down