mukadi/chartjs-builder

直接从SQL查询生成漂亮的图表(PHP)

2.1.0 2023-03-07 00:51 UTC

This package is auto-updated.

Last update: 2024-09-26 13:14:49 UTC


README

直接从SQL查询生成漂亮和完全定制的图表。mukadi/chartjs-builder库使用Chart.js显示图表,并使用PDO查询数据库中的数据。

1. 安装

运行 php composer.phar require mukadi/chartjs-builder

如果您不使用composer管理依赖(您应该使用!),您可以直接从仓库下载库,并将库自动加载文件包含到您的代码中,所有包类都将可用

require 'path-to-the-library/autoload.php';

2. 工厂

Mukadi\Chart\Factory\ChartFactory 是用于从SQL查询创建图表的主要包类。此类需要一个有效的PDO连接作为构造函数参数

use Mukadi\Chart\Factory\ChartFactory;

$connection = new \PDO('sqlite:/Users/foo/Projects/bar.db');
$factory = new ChartFactory($connection);

2.1. 图表类型

一旦实例化Factory对象,您就可以开始构建您的图表。首先要做的事情是指定您想要的图表类型,支持的类型有:

  • 柱状图
  • 饼图
  • 极坐标面积图
  • 折线图
  • 环形图和
  • 雷达图
  • 散点图
  • 气泡图
$chart = $factory
    ->createChartBuilder()
    ->asBar() // asPie(), asPolarArea(), asLine() etc...
    ...

2.2. 查询

一旦实例化Factory对象,您可以为图表设置查询,该查询将生成图表

$chart = $factory
    ->createChartBuilder()
    ->asBar()
        ->query('SELECT COUNT(*) total, AVG(prix) prix, console FROM jeux_video GROUP BY console') // SQL query

2.3. 标签

在查询配置之后,您可以设置图表标签(显示在x轴上)

$chart = $factory
    ->createChartBuilder()
    ->asBar()
        ->query('SELECT COUNT(*) total, AVG(prix) prix, console FROM jeux_video GROUP BY console') // SQL query
    ->labels('console') // mapped to the console column
    
    # or you can provide array of predefined values
    ->labels(['NES', 'Game Cube', 'PSOne'])

    # you can also apply transformation to the labels before been displayed on the chart
    ->labels('console',  fn($c) => strtoupper($c)) // transform all console name to uppercase

注意:气泡图和散点图不支持标签,该方法对此类图表没有影响且不会抛出错误

2.4. 数据集

$chart = $factory
    ->createChartBuilder()
    ->asBar()
        ->query('SELECT COUNT(*) total, AVG(prix) prix, console FROM jeux_video GROUP BY console')
        ->labels('console')
        ->dataset("Total") # dataset labels
            ->data('total') # dataset mapped to the "total" column
            ->options([
                'backgroundColor' => RandomColorFactory::randomRGBColor()
            ])
        ->end()
        # you can add many datasets as you want
        ->dataset("Prix moyen")
            ->asLine() # you can set a different chart type to a dataset and create mixed chart
            ->data('prix')
            ->useRandomBackgroundColor() # dataset color helper
        ->end()
    # build and return the chart
    ->build()
    ->getChart()
    ;

散点图和气泡图的行为不同,以下是构建此类图表的方法

$scatter = $factory
    ->createChartBuilder()
    ->asScatter()
        ->query("SELECT  prix, nbre_joueurs_max, console  from jeux_video jv where console = :console")
            ->dataset("Prix")
                ->data("nbre_joueurs_max", "prix") # you have to specify the values mapped to the X and Y axis in that order
                ->useRandomBackgroundColor(false)
            ->end()
    # build and return the chart
    ->build()
    ->getChart()
    ;

$bubble = $factory
    ->createChartBuilder()
    ->asBubble()
        ->query("SELECT  prix, nbre_joueurs_max, ventes  from jeux_video jv where console = :console")
            ->dataset("Prix")
                ->data("nbre_joueurs_max", "prix", "ventes") # you have to specify the values mapped to the X, Y axis and the radius in that order
                ->options([
                    'backgroundColor' => RandomColorFactory::randomRGBColor(),
                ])
            ->end()
    # build and return the chart
    ->build()
    ->getChart()
    ;

通过指定:获取数据的列、用作数据集标签的文本以及可选的选项数组(有关可用选项,请参阅chart.js文档)来设置数据集。对于图表标签,只需设置查询数据的列或将字符串数组直接放入其中。

2.5. 数据集辅助工具

2.6. 构建并渲染图表

最后但同样重要的是,您必须在视图中构建和渲染图表。对于构建图表,提供一个ID并设置图表类型,可选地设置一些选项(有关可用选项,请参阅chart.js文档

# Build the chart 
$chart = $factory
    ->createChartBuilder()
    ...
    ->build()
    ->getChart()
    # or you can pass chart options like this
    ->getChart([
        'scales' => [
            'x' => [
                'grid' => ['offset' => true]
            ],
        ]
    ])
;

//You can also add or override the chart options after being built. In this example you remove the onClick behavior of legend
$chart->pushOptions([
    'legend' => [
        'onClick' => null,
    ]
]);

对于在页面中渲染图表,只需进行echo操作

echo $chart;

别忘了在您的页面上包含库

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.1/chart.umd.min.js"></script>
<script src="dist/mukadi.chart.min.js"></script>

就这样!

3. 高级主题

3.1. 使用参数化查询

use Mukadi\Chart\Factory\ChartFactory;

$connection = new \PDO('sqlite:/Users/foo/Projects/bar.db');
$factory = new ChartFactory($connection);

$chart = $factory
    ->createChartBuilder()
    ->asBar()
    ->query('SELECT COUNT(*) total, AVG(prix) prix, console FROM jeux_video WHERE possesseur = :possesseur GROUP BY console') # prepared statement
        ->labels('console')
        ->dataset("Total")
            ->data('total')->useRandomBackgroundColor()
        ->end()
        ->dataset("Prix moyen")
            ->data('prix')->useRandomBackgroundColor()
        ->end()
    ->build()
    # setting the parameters after the build() method invokation
    ->setParameter(':possesseur',"Kapiamba") 
    ->getChart()

3.2. 图表定义

在构建图表时,我们可能会很快就有很多代码行污染我们的控制器/页面(特别是如果它是一个仪表板,例如)。图表定义是一种优雅的方法,可以在单独的类中构建您的图表,因此您可以得到更易于阅读的代码,并且还可以重用图表(当与参数化查询结合使用时,这是一个非常强大的功能)。

每个图表定义都必须实现Mukadi\Chart\ChartDefinitionInterface接口(当然!:-D)

use Mukadi\Chart\ChartDefinitionBuilderInterface;

class VideoGame implements ChartDefinitionInterface {
    
    public function define(ChartDefinitionBuilderInterface $builder): void
    {
        $sql = "SELECT COUNT(*) total, AVG(prix) prix, console FROM jeux_video WHERE possesseur = :possesseur GROUP BY console";

        $builder
            ->asPolarArea()
            ->query($sql)
            ->labels('console')
            ->dataset("Total")
                ->data('total')->useRandomBackgroundColor()
            ->end()
            ->dataset("Prix moyen")
                ->data('prix')->useRandomBackgroundColor()
            ->end()
        ;
    }
}

在您的控制器/页面中,您只需编写以下内容:

...
$chart = $factory
            ->createFromDefinition(new VideoGame())
            ->setParameter(':possesseur', 'Florent')
            ->getChart()
        ;

# you can reuse the same definition for another owner just like this
$chart2 = $factory
            ->createFromDefinition(VideoGame::class) # you can also use the FQCN instead of an instance
            ->setParameter(':possesseur', 'Michel') # different parameter value
            ->getChart()
        ;

您可以直接在图表定义中设置查询参数和图表选项

use Mukadi\Chart\ChartDefinitionBuilderInterface;

class VideoGame implements ChartDefinitionInterface {
    
    public function define(ChartDefinitionBuilderInterface $builder): void
    {
        $sql = "SELECT COUNT(*) total, AVG(prix) prix, console FROM jeux_video WHERE possesseur = :possesseur GROUP BY console";

        $builder
            ->asPolarArea()
            ->query($sql)->setParameter(':possesseur', 'Michel') # set the parameters value
            ->labels('console')
            ->dataset("Total")
                ->data('total')->useRandomBackgroundColor()
            ->end()
            ->dataset("Prix moyen")
                ->data('prix')->useRandomBackgroundColor()
            ->end()
            # set the chart options
            ->setOptions([
                'plugins' => [
                    "title" => [
                        'display' => true,
                        'text' => "My video game chart",
                        'font' => ['size' => 16]
                    ]
                ]
            ])
        ;
    }
}

因此,在您的控制器/页面中,只需构建您的图表

...
$chart = $factory
            ->createFromDefinition(VideoGame::class)
            ->getChart()
        ;

3.3. 自定义定义提供者

在内部,Mukadi\Chart\Factory\ChartFactory 类使用一个实现 Mukadi\Chart\DefinitionProviderInterface 的类来通过完全限定类名(FCQN)检索图表定义,但这种实现非常简单,只能与不带参数构造函数的图表定义类一起工作。因此,如果你的定义类有依赖关系,我们必须自己构建它,并将实例提供给工厂。

在某些情况下,自己构建定义实例可能很复杂,或者当你将此任务委托给外部组件(例如依赖注入容器)时。在这种情况下,你可能希望工厂依赖于相同的组件来为你构建图表定义。

首先,实现 Mukadi\Chart\DefinitionProviderInterface 接口。

use Mukadi\Chart\ChartDefinitionInterface;
use Mukadi\Chart\DefinitionProviderInterface;

class MyCustomDefinitionProvider implements DefinitionProviderInterface {

    public function provide(string $fcqn): ChartDefinitionInterface
    {
        # implements your log here and return the instance

        return new $theChartDefinitionInstance;
    }
}

其次,重写默认实现。

$connection = new \PDO('sqlite:/Users/foo/Projects/bar.db');
$factory = (new ChartFactory($connection))->overrideDefinitionProvider($myCustomProviderInstance);

你可能还想将所有工厂纳入你的依赖注入策略中,为此,只需通过实现 Mukadi\Chart\ChartFactoryInterface 或扩展 Mukadi\Chart\Factory\AbstractChartFactory 来创建自己的工厂,你可以参考 MukadiChartJsBundle,这是一个针对 Symfony 框架的当前库的集成。