├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── src ├── SparkLine.php ├── SparkLineEntry.php └── sparkLine.view.php └── test-server.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `php-sparkline` will be documented in this file. 4 | 5 | ## 2.0.0 6 | 7 | - Removed `SparkLine::new()`, use `new SparkLine()` instead 8 | - Removed `SparkLine::getPeriod()` 9 | - Removed dependencies on `spatie/period` and `laravel/collection` 10 | - Rename `SparkLineDay` to `SparkLineEntry` 11 | - Allow integers to be passed directly into a new `SparkLine` instead of requiring `SparkLineEntry` objects 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) brendt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Generate sparkline SVGs in PHP 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/brendt/php-sparkline.svg?style=flat-square)](https://packagist.org/packages/brendt/php-sparkline) 4 | [![Tests](https://github.com/brendt/php-sparkline/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/brendt/php-sparkline/actions/workflows/run-tests.yml) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/brendt/php-sparkline.svg?style=flat-square)](https://packagist.org/packages/brendt/php-sparkline) 6 | 7 | PHP-Sparkline generates GitHub style sparkline graphs. Read this guide to know how to use it. 8 | 9 | ## Installation 10 | 11 | You can install the package via composer: 12 | 13 | ```bash 14 | composer require brendt/php-sparkline 15 | ``` 16 | 17 | ## Usage 18 | 19 | ```php 20 | $sparkLine = new SparkLine(1, 2, 5, 10, 2); 21 | 22 | $total = $sparkLine->getTotal(); 23 | 24 | $svg = $sparkLine->make(); 25 | ``` 26 | 27 | ![](./.github/img/0.png) 28 | 29 | To construct a sparkline, you'll have to pass in an array of values. 30 | 31 | ### Customization 32 | 33 | You can pick any amount of colors and the sparkline will automatically generate a gradient from them: 34 | 35 | ```php 36 | $sparkLine = (new SparkLine($days))->withColors('#4285F4', '#31ACF2', '#2BC9F4'); 37 | ``` 38 | 39 | ![](./.github/img/1.png) 40 | 41 | You can configure the stroke width: 42 | 43 | ```php 44 | $sparkLine = (new SparkLine($days))->withStrokeWidth(4); 45 | ``` 46 | 47 | As well as the dimensions (in pixels): 48 | 49 | ```php 50 | $sparkLine = SparkLine::new($days)->withDimensions(width: 500, height: 100); 51 | ``` 52 | 53 | ![](./.github/img/2.png) 54 | 55 | ## Testing 56 | 57 | ```bash 58 | composer test 59 | ``` 60 | 61 | ## Changelog 62 | 63 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 64 | 65 | ## Security Vulnerabilities 66 | 67 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 68 | 69 | ## Credits 70 | 71 | - [Brent Roose](https://github.com/brendt) 72 | - [All Contributors](../../contributors) 73 | 74 | ## License 75 | 76 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 77 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brendt/php-sparkline", 3 | "description": "Generate sparkline SVGs in PHP", 4 | "keywords": [ 5 | "brendt", 6 | "php-sparkline" 7 | ], 8 | "homepage": "https://github.com/brendt/php-sparkline", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Brent Roose", 13 | "email": "brendt@stitcher.io", 14 | "role": "Developer" 15 | } 16 | ], 17 | "require": { 18 | "php": "^8.1", 19 | "ramsey/uuid": "^4.6" 20 | }, 21 | "require-dev": { 22 | "friendsofphp/php-cs-fixer": "^3.13", 23 | "larapack/dd": "^1.1", 24 | "phpunit/phpunit": "^9.5" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Brendt\\SparkLine\\": "src" 29 | } 30 | }, 31 | "autoload-dev": { 32 | "psr-4": { 33 | "Brendt\\SparkLine\\Tests\\": "tests" 34 | } 35 | }, 36 | "scripts": { 37 | "test": "vendor/bin/phpunit" 38 | }, 39 | "config": { 40 | "sort-packages": true, 41 | "allow-plugins": { 42 | "phpstan/extension-installer": true 43 | } 44 | }, 45 | "minimum-stability": "dev", 46 | "prefer-stable": true 47 | } 48 | -------------------------------------------------------------------------------- /src/SparkLine.php: -------------------------------------------------------------------------------- 1 | id = Uuid::uuid4()->toString(); 31 | 32 | $this->entries = array_map( 33 | fn (SparkLineEntry|int $entry) => is_int($entry) ? new SparkLineEntry($entry) : $entry, 34 | $entries 35 | ); 36 | 37 | $this->maxValue = $this->resolveMaxValue($this->entries); 38 | $this->maxItemAmount = $this->resolveMaxItemAmount($this->entries); 39 | $this->colors = $this->resolveColors(['#c82161', '#fe2977', '#b848f5', '#b848f5']); 40 | } 41 | 42 | public function getTotal(): int 43 | { 44 | return array_reduce( 45 | $this->entries, 46 | fn (int $carry, SparkLineEntry $entry) => $carry + $entry->count, 47 | 0 48 | ); 49 | } 50 | 51 | public function withStrokeWidth(int $strokeWidth): self 52 | { 53 | $clone = clone $this; 54 | 55 | $clone->strokeWidth = $strokeWidth; 56 | 57 | return $clone; 58 | } 59 | 60 | public function withDimensions(?int $width = null, ?int $height = null): self 61 | { 62 | $clone = clone $this; 63 | 64 | $clone->width = $width ?? $clone->width; 65 | $clone->height = $height ?? $clone->height; 66 | 67 | return $clone; 68 | } 69 | 70 | public function withMaxValue(?int $maxValue): self 71 | { 72 | $clone = clone $this; 73 | 74 | $clone->maxValue = $maxValue ?? $clone->resolveMaxValue($this->entries); 75 | 76 | return $clone; 77 | } 78 | 79 | public function withMaxItemAmount(?int $maxItemAmount): self 80 | { 81 | $clone = clone $this; 82 | 83 | $clone->maxItemAmount = $maxItemAmount ?? $clone->resolveMaxItemAmount($this->entries); 84 | 85 | return $clone; 86 | } 87 | 88 | public function withColors(string ...$colors): self 89 | { 90 | $clone = clone $this; 91 | 92 | $clone->colors = $this->resolveColors($colors); 93 | 94 | return $clone; 95 | } 96 | 97 | public function make(): string 98 | { 99 | ob_start(); 100 | 101 | include __DIR__ . '/sparkLine.view.php'; 102 | 103 | $svg = ob_get_contents(); 104 | 105 | ob_end_clean(); 106 | 107 | return $svg; 108 | } 109 | 110 | public function __toString(): string 111 | { 112 | return $this->make(); 113 | } 114 | 115 | private function getCoordinates(): string 116 | { 117 | $divider = min($this->width, $this->maxItemAmount); 118 | 119 | $step = floor($this->width / $divider); 120 | 121 | $coordinates = []; 122 | 123 | foreach ($this->entries as $index => $entry) { 124 | $coordinates[] = $index * $step . ',' . $entry->rebase($this->height - 5, $this->maxValue)->count; 125 | } 126 | 127 | return implode(' ', $coordinates); 128 | } 129 | 130 | private function resolveColors(array $colors): array 131 | { 132 | $percentageStep = floor(100 / count($colors)); 133 | 134 | $colorsWithPercentage = []; 135 | 136 | foreach ($colors as $i => $color) { 137 | $colorsWithPercentage[$i * $percentageStep] = $color; 138 | } 139 | 140 | return $colorsWithPercentage; 141 | } 142 | 143 | private function resolveMaxValue(array $entries): int 144 | { 145 | if ($entries === []) { 146 | return 0; 147 | } 148 | 149 | usort($entries, fn (SparkLineEntry $a, SparkLineEntry $b) => $a->count <=> $b->count); 150 | 151 | return $entries[array_key_last($entries)]->count; 152 | } 153 | 154 | private function resolveMaxItemAmount(array $entries): int 155 | { 156 | return max(count($entries), 1); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/SparkLineEntry.php: -------------------------------------------------------------------------------- 1 | count * ($base / $max)), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/sparkLine.view.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | colors as $percentage => $color) { 10 | echo << 12 | HTML; 13 | 14 | echo PHP_EOL; 15 | } 16 | ?> 17 | 18 | 19 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test-server.php: -------------------------------------------------------------------------------- 1 |