bakame/period-visualizer

此包已被废弃且不再维护。作者建议使用league/period包。

League Period的可视化工具。

0.6.0 2019-09-20 21:03 UTC

This package is auto-updated.

Last update: 2024-06-28 06:54:14 UTC


README

Author Build Status Total Downloads Latest Stable Version Software License

此包包含League Period的可视化工具。

它受到@thecrypticace在以下PRVisualization Helper的工作的启发。

<?php

use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\GanttChart;
use League\Period\Datepoint;
use League\Period\Period;
use League\Period\Sequence;

$sequence = new Sequence(
    Datepoint::create('2018-11-29')->getYear(Period::EXCLUDE_START_INCLUDE_END),
    Datepoint::create('2018-05-29')->getMonth()->expand('3 MONTH'),
    Datepoint::create('2017-01-13')->getQuarter(Period::EXCLUDE_ALL),
    Period::around('2016-06-01', '3 MONTHS', Period::INCLUDE_ALL)
);
$dataset = Dataset::fromSequence($sequence);
$dataset->append('gaps', $sequence->gaps());
(new GanttChart())->stroke($dataset);

结果

 A                                          (--------------------]
 B                                            [-----------)       
 C                     (----)                                     
 D    [---------]                                                 
 gaps           (------]    [---------------]  

系统要求

您需要

  • PHP >= 7.2,但推荐使用最新稳定版PHP
  • League/Period 4.4+,但推荐使用最新稳定版

安装

$ composer require bakame/period-visualizer

使用

基本使用

生成一个简单的图表。

要生成图表,您需要向Dataset构造函数提供一个对列表。每个对是一个包含2个值的array

  • 0的值表示标签
  • 1League\Period\PeriodLeague\Period\Sequence对象
<?php

use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\GanttChart;
use League\Period\Period;

$dataset = new Dataset([
    ['A', new Period('2018-01-01', '2018-02-01')],
    ['B', new Period('2018-01-15', '2018-02-01')], 
]);
(new GanttChart())->stroke($dataset);

结果

 A [----------------------------------------------)
 B                      [-------------------------)

追加要显示的项目

如果您想显示一个Sequence及其一些操作。您可以使用Dataset::append方法追加操作结果。

<?php

use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\GanttChart;
use League\Period\Period;
use League\Period\Sequence;

$sequence = new Sequence(
    new Period('2018-01-01', '2018-03-01'),
    new Period('2018-05-01', '2018-08-01')
);
$dataset = new Dataset();
$dataset->append('A', $sequence[0]);
$dataset->append('B', $sequence[1]);
$dataset->append('GAPS', $sequence->gaps());
(new GanttChart())->stroke($dataset);

结果

 A    [-------------)                                                         
 B                               [----------------)
 GAPS               [------------)    

Dataset实现了CountableIteratorAggregate接口。它还公开了以下方法

<?php
public function Dataset::fromSequence(Sequence $sequence, ?LabelGenerator $labelGenerator = null): self; //Creates a new Dataset from a Sequence and a LabelGenerator.
public function Dataset::fromCollection(iterable $collection): self; //Creates a new Dataset from a generic iterable structure.
public function Dataset::appendAll(iterable $pairs): void; //adds multiple pairs at once.
public function Dataset::isEmpty(): bool; //Tells whether the collection is empty.
public function Dataset::labels(): string[]; //the current labels used
public function Dataset::items(): Sequence[]; //the current objects inside the Dataset
public function Dataset::boundaries(): ?Period;  //Returns the collection boundaries or null if it is empty.
public function Dataset::labelMaxLength(): int;  //Returns the label max length.
public function Dataset::withLabels(LabelGenerator $labelGenerator): self; //Update the labels used for the dataset.

设置数据集标签

默认情况下,您必须为添加到Dataset对象中的每个项目提供一个标签。此包提供了一种简单的生成和创建可视化标签的LabelGenerator接口。

需要实现以下方法的LabelGenerator

  • Dataset::fromSequence,从Sequence对象创建一个新实例;
  • Dataset::withLabels,更新当前实例中的关联标签;

默认情况下,当使用Dataset::fromSequence时,如果没有提供LabelGenerator类,将使用LatinLetter标签生成器。

当前包附带以下LabelGenerator实现类

LatinLetter

根据拉丁字母生成标签。

<?php

use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\GanttChart;
use Bakame\Period\Visualizer\LatinLetter;
use League\Period\Period;
use League\Period\Sequence;

$dataset = Dataset::fromSequence(
    new Sequence(new Period('2018-01-01', '2018-02-01'), new Period('2018-01-15', '2018-02-01')),
    new LatinLetter('aa')
);
(new GanttChart())->stroke($dataset);

结果

 aa [-----------------------------------)
 ab [----------)

LatinLetter还公开了以下方法

<?php

public function LatinLetter::startingAt(): string; //returns the first letter to be used
public function LatinLetter::startsWith(): self;  //returns a new object with a new starting letter

DecimalNumber

根据十进制数系统生成标签。

<?php

use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\DecimalNumber;
use Bakame\Period\Visualizer\GanttChart;
use League\Period\Period;
use League\Period\Sequence;

$dataset = Dataset::fromSequence(
    new Sequence(new Period('2018-01-01', '2018-02-01'), new Period('2018-01-15', '2018-02-01')),
    new DecimalNumber(42)
);
(new GanttChart())->stroke($dataset);

结果

 42 [-----------------------------------)
 43 [----------)

DecimalNumber还公开了以下方法

<?php

public function DecimalNumber::startingAt(): string; //returns the first decimal number to be used
public function DecimalNumber::startsWith(): self;  //returns a new object with a new starting decimal number

RomanNumber

使用 DecimalNumber 标签生成器类来生成罗马数字标签。

<?php

use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\DecimalNumber;
use Bakame\Period\Visualizer\GanttChart;
use Bakame\Period\Visualizer\RomanNumber;
use League\Period\Period;
use League\Period\Sequence;

$labelGenerator = new RomanNumber(new DecimalNumber(5), RomanNumber::LOWER);

$dataset = Dataset::fromSequence(
    new Sequence(new Period('2018-01-01', '2018-02-01'), new Period('2018-01-15', '2018-02-01')),
    $labelGenerator
);
(new GanttChart())->stroke($dataset);

结果

 v  [-----------------------------------)
 vi [----------)

RomanNumber 还公开了以下方法

<?php
const RomanNumber::UPPER = 1;
const RomanNumber::LOWER = 2;
public function RomanNumber::startingAt(): string; //returns the first decimal number to be used
public function RomanNumber::startsWith(): self;  //returns a new object with a new starting decimal number
public function RomanNumber::withLetterCase(int $lettercase): self;  //returns a new object with a new letter casing
public function RomanNumber::isUpper(): bool;  //Tells whether the roman letter is upper cased.
public function RomanNumber::isLower(): bool;  //Tells whether the roman letter is lower cased.

附加标签

使用任何实现了 labelGenerator 类来添加前缀和/或后缀字符串到生成的标签。

<?php

use Bakame\Period\Visualizer\AffixLabel;
use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\DecimalNumber;
use Bakame\Period\Visualizer\GanttChart;
use Bakame\Period\Visualizer\RomanNumber;
use League\Period\Period;
use League\Period\Sequence;

$labelGenerator = new AffixLabel(
    new RomanNumber(new DecimalNumber(5), RomanNumber::LOWER),
    '*', //prefix
    '.)'    //suffix
);
$dataset = Dataset::fromSequence(
    new Sequence(new Period('2018-01-01', '2018-02-01'), new Period('2018-01-15', '2018-02-01')),
    $labelGenerator
);
(new GanttChart())->stroke($dataset);

结果

 * v .)  [-----------------------------------)
 * vi .) [----------)

AffixLabel 还公开了以下方法

<?php

public function AffixLabel::prefix(): string; //returns the current prefix
public function AffixLabel::suffix(): string;  //returns the current suffix
public function AffixLabel::withPrefix(string $prefix): self;  //returns a new object with a new prefix
public function AffixLabel::withSuffix(string $suffix): self;  //returns a new object with a new suffix

反转标签

使用任何实现了 labelGenerator 类来反转生成的标签顺序。

<?php

use Bakame\Period\Visualizer\AffixLabel;
use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\DecimalNumber;
use Bakame\Period\Visualizer\GanttChart;
use Bakame\Period\Visualizer\ReverseLabel;
use Bakame\Period\Visualizer\RomanNumber;
use League\Period\Period;
use League\Period\Sequence;

$labelGenerator = new DecimalNumber(5);
$labelGenerator = new RomanNumber($labelGenerator, RomanNumber::LOWER);
$labelGenerator = new AffixLabel($labelGenerator, '', '.');
$labelGenerator = new ReverseLabel($labelGenerator);

$dataset = Dataset::fromSequence(
    new Sequence(new Period('2018-01-01', '2018-02-01'), new Period('2018-01-15', '2018-02-01')),
    $labelGenerator
);
(new GanttChart())->stroke($dataset);

结果

 vi. [-----------------------------------)
 v.  [----------)

自定义标签生成器

您可以通过实现 Bakame\Period\Visualizer\LabelGenerator 接口来创建自己的标签生成器,如下所示

<?php

use Bakame\Period\Visualizer\AffixLabel;
use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\GanttChart;
use Bakame\Period\Visualizer\LabelGenerator;
use League\Period\Period;
use League\Period\Sequence;

$samelabel = new class implements LabelGenerator {
    public function generate(int $nbLabels): array
    {
        return array_fill(0, $nbLabels, $this->format('foobar'));
    }
        
    public function format($str): string
    {
        return (string) $str;
    }
};

$labelGenerator = new AffixLabel($samelabel, '', '.');
$dataset = Dataset::fromSequence(
    new Sequence(new Period('2018-01-01', '2018-02-01'), new Period('2018-01-15', '2018-02-01')),
    $labelGenerator
);
(new GanttChart())->stroke($dataset);

结果

 foobar. [-----------------------------------)
 foobar. [----------)

显示数据集

GanttChart 类通过实现控制台的 Graph 接口,负责从 Dataset 生成图表。

GanttChart::stroke 方法期望一个唯一的 Dataset 对象作为其参数。

如果您想在另一个媒介上展示图表,如网页或图片,您需要实现您自己的接口。

<?php

use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\GanttChart;
use League\Period\Period;

$graph = new GanttChart();
$graph->stroke(new Dataset([
    ['first', new Period('2018-01-01 08:00:00', '2018-01-01 12:00:00')],
    ['last', new Period('2018-01-01 10:00:00', '2018-01-01 14:00:00')],
]));

结果

 first [---------------------------)
 last            [------------------------------)

自定义图表外观

GanttChart 类可以通过提供 GanttChartConfig 来自定义,该配置定义了

  • 输出媒介通过实现 OutputWriter 类。
  • 图表设置。(如何绘制间隔)
    • 设置图表宽度
    • 设置图表颜色
    • 设置标签与行之间的间隔
    • 设置标签对齐方式
  • 输出设置(如何创建间隔)
    • 设置单个字符表示边界类型
    • 设置单个字符表示主体和空格

您可以使用像 League CLImateSymfony Console 这样的库轻松地创建一个实现 OutputWriter 类。如果没有,该包附带了最小化的 ConsoleOutput 类,如果未提供自己的实现,则使用该类。

<?php

use Bakame\Period\Visualizer\AffixLabel;
use Bakame\Period\Visualizer\ConsoleOutput;
use Bakame\Period\Visualizer\Dataset;
use Bakame\Period\Visualizer\DecimalNumber;
use Bakame\Period\Visualizer\GanttChart;
use Bakame\Period\Visualizer\GanttChartConfig;
use Bakame\Period\Visualizer\ReverseLabel;
use Bakame\Period\Visualizer\RomanNumber;
use League\Period\Datepoint;
use League\Period\Period;
use League\Period\Sequence;

$config = GanttChartConfig::createFromRainbow()
    ->withOutput(new ConsoleOutput(STDOUT))
    ->withStartExcluded('🍕')
    ->withStartIncluded('🍅')
    ->withEndExcluded('🎾')
    ->withEndIncluded('🍔')
    ->withWidth(30)
    ->withSpace('💩')
    ->withBody('😊')
    ->withGapSize(2)
    ->withLeftMarginSize(1)
    ->withLabelAlign(GanttChartConfig::ALIGN_RIGHT)
;

$labelGenerator = new DecimalNumber(42);
$labelGenerator = new RomanNumber($labelGenerator, RomanNumber::UPPER);
$labelGenerator = new AffixLabel($labelGenerator, '', '.');
$labelGenerator = new ReverseLabel($labelGenerator);

$sequence = new Sequence(
    Datepoint::create('2018-11-29')->getYear(Period::EXCLUDE_START_INCLUDE_END),
    Datepoint::create('2018-05-29')->getMonth()->expand('3 MONTH'),
    Datepoint::create('2017-01-13')->getQuarter(Period::EXCLUDE_ALL),
    Period::around('2016-06-01', '3 MONTHS', Period::INCLUDE_ALL)
);
$dataset = Dataset::fromSequence($sequence, $labelGenerator);
$dataset->append($labelGenerator->format('gaps'), $sequence->gaps());
$graph = new GanttChart($config);
$graph->stroke($dataset);

结果

   XLV.  💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩🍕😊😊😊😊😊😊😊😊😊🍔
  XLIV.  💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩🍅😊😊😊😊😊🎾💩💩💩
 XLIII.  💩💩💩💩💩💩💩💩🍕😊😊🎾💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩
  XLII.  🍅😊😊😊😊🍔💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩
  GAPS.  💩💩💩💩💩🍕😊😊🍔💩💩🍅😊😊😊😊😊😊😊🍔💩💩💩💩💩💩💩💩💩💩

在符合 POSIX 的控制台上,所有行都有不同的颜色

GanttChartConfig 类公开了以下额外的常量和方法

<?php
const GanttChartConfig::ALIGN_LEFT = 1;
const GanttChartConfig::ALIGN_RIGHT = 0;
const GanttChartConfig::ALIGN_CENTER = 2;
public function GanttChartConfig::__construct(OutputWriter $output);
public function GanttChartConfig::output(): OutputWriter;  //Returns the OutputWriter instance.
public function GanttChartConfig::startExcluded(): string; //Retrieves the excluded start block character.
public function GanttChartConfig::startIncluded(): string; //Retrieves the included start block character.
public function GanttChartConfig::endExcluded(): string;   //Retrieves the excluded end block character.
public function GanttChartConfig::endIncluded(): string;   //Retrieves the included end block character.
public function GanttChartConfig::width(): int;            //Retrieves the max size width.
public function GanttChartConfig::body(): string;          //Retrieves the body block character.
public function GanttChartConfig::space(): string;         //Retrieves the space block character.
public function GanttChartConfig::colors(): string[];      //The selected colors for each row.
public function GanttChartConfig::gapSize(): int;          //Retrieves the gap sequence between the label and the line.
public function GanttChartConfig::labelAlign(): int;       //Returns how label should be aligned.
public function GanttChartConfig::leftMarginSize(): int;   //Retrieves the margin between the label and the console left side.

GanttChartConfig 是不可变的,修改其属性将返回一个具有更新值的新的实例。

变更日志

请参阅 CHANGELOG 了解最近更改的详细信息。

贡献

欢迎贡献,并将得到充分认可。请参阅 CONTRIBUTING 了解详细信息。

测试

该库有一个

  • 一个 PHPUnit 测试套件
  • 一个使用 PHP CS Fixer 的编码风格合规性测试套件。
  • 一个使用 PHPStan 的代码分析合规性测试套件。

要运行测试,请从项目文件夹运行以下命令。

$ composer test

安全

如果您发现任何安全相关的问题,请通过电子邮件 nyamsprod@gmail.com 而不是使用问题跟踪器。

鸣谢

许可证

MIT 许可证(MIT)。请参阅许可证文件以获取更多信息。