mitoteam/jpgraph
Composer package for the JpGraph 4.4.3 library with PHP 5.5–8.5 support. Provides a simple loader (MtJpGraph::load) to include JpGraph and selected modules (bar, line, etc.) anywhere in your code, avoiding duplicate loads.
composer require mitoteam/jpgraph
bar or line) in your Laravel controller or service:
use mitoteam\jpgraph\MtJpGraph;
MtJpGraph::load('bar');
$graph = new Graph(600, 400);
$graph->SetShadow();
$graph->SetMargin(40, 30, 30, 40);
$graph->SetScale('textlin');
$graph->title->Set('Sales Data');
Generate a Bar Chart for a Laravel Report
// In a Laravel controller or service
public function generateSalesChart()
{
MtJpGraph::load('bar');
$data = [10, 20, 30, 40, 50]; // Example sales data
$graph = new Graph(600, 400);
$graph->SetShadow();
$graph->SetMargin(40, 30, 30, 40);
$b1 = new BarPlot($data);
$graph->Add($b1);
$graph->title->Set('Monthly Sales');
$graph->yaxis->SetTitle('Revenue ($)');
// Output the chart to a file or stream
$graph->Stroke('sales_chart.png');
return response()->download(public_path('sales_chart.png'));
}
Modular Loading for Performance: Load only the modules you need to reduce memory usage and initialization time:
// Load only the 'pie' module for pie charts
MtJpGraph::load('pie');
// Load multiple modules (e.g., for a dashboard with mixed chart types)
MtJpGraph::load(['bar', 'line', 'pie']);
Dynamic Chart Generation in API Endpoints: Use Laravel’s routing to generate charts dynamically:
Route::get('/charts/revenue', function () {
MtJpGraph::load('line');
$data = [100, 200, 150, 300]; // Example revenue data
$graph = new Graph(600, 400);
$graph->Add(new LinePlot($data));
$graph->title->Set('Revenue Trend');
return $graph->Stroke('php://output', 'PNG');
});
Integrating with Laravel Queues: Generate charts asynchronously for reports or notifications:
// Dispatch a job to generate a chart
GenerateChartJob::dispatch('monthly_report.png', 'bar', $data);
// Job implementation
public function handle()
{
MtJpGraph::load('bar');
$graph = new Graph(600, 400);
$graph->Add(new BarPlot($this->data));
$graph->Stroke(storage_path('app/' . $this->filename));
}
Customizing JpGraph Globally: Override JpGraph constants before loading the library (e.g., for font paths or caching):
define('TTF_DIR', public_path('fonts'));
define('CACHE_FILE_GROUP', 'laravel_charts');
MtJpGraph::load('pie');
Extended Mode for Bug Fixes: Enable Extended Mode to apply patches for known JpGraph bugs (e.g., pie3d rendering issues):
MtJpGraph::load(['pie', 'bar'], true); // Enable Extended Mode
Laravel Service Providers: Register JpGraph as a service provider to load modules globally for specific routes or middleware:
// In AppServiceProvider
public function boot()
{
if (request()->is('admin/charts*')) {
MtJpGraph::load(['bar', 'line']);
}
}
Caching Charts: Cache generated charts to avoid reprocessing data:
$cacheKey = 'sales_chart_' . $month;
if (Cache::has($cacheKey)) {
return response()->file(Cache::get($cacheKey));
}
MtJpGraph::load('bar');
$graph = new Graph(600, 400);
$graph->Add(new BarPlot($data));
$graph->Stroke($filePath = temp_path('sales_chart.png'));
Cache::put($cacheKey, $filePath, now()->addHours(1));
return response()->file($filePath);
Testing: Disable JpGraph’s exception handler in tests to avoid conflicts with PHPUnit:
// In a test setup method
MtJpGraph::setSkipExceptionHandler(true);
MtJpGraph::load('pie');
Exception Handler Conflicts: JpGraph sets a global exception handler that can interfere with PHPUnit tests. Always disable it in test environments:
MtJpGraph::setSkipExceptionHandler(true); // Add this before loading in tests
Font Path Issues:
Ensure TTF_DIR is correctly defined, especially on Windows or shared hosting:
define('TTF_DIR', realpath(__DIR__ . '/../../resources/fonts'));
Idempotency:
While MtJpGraph::load() is idempotent, calling it repeatedly with different modules can lead to unexpected behavior. Load all required modules in a single call:
// Bad: Multiple calls may not load all dependencies
MtJpGraph::load('bar');
MtJpGraph::load('line');
// Good: Single call with all modules
MtJpGraph::load(['bar', 'line']);
Extended Mode Overhead: Extended Mode applies patches that may alter JpGraph’s behavior. Test thoroughly if you enable it:
MtJpGraph::load(['pie'], true); // Only enable if you’ve confirmed compatibility
Memory Limits: JpGraph can consume significant memory for large datasets. Optimize by:
Stroke() with a file stream instead of in-memory output.Check Loaded Modules: If a chart type isn’t working, verify the module was loaded:
MtJpGraph::load('pie'); // Ensure this matches the module name (case-sensitive)
Error Messages: JpGraph renders errors directly to the image. If you see a blank image, check:
Stroke() call.PHP Version Compatibility: While the package supports PHP 8.5, some older JpGraph features may not work. Test with:
if (version_compare(PHP_VERSION, '8.1', '<')) {
throw new RuntimeException('JpGraph requires PHP 8.1+');
}
Laravel Configuration:
Store JpGraph settings in config/jpgraph.php:
return [
'ttf_dir' => public_path('fonts'),
'cache_group' => 'laravel_charts',
];
Then load them before initializing JpGraph:
define('TTF_DIR', config('jpgraph.ttf_dir'));
define('CACHE_FILE_GROUP', config('jpgraph.cache_group'));
Dynamic Data Binding: Use Laravel’s Eloquent to fetch chart data dynamically:
$data = User::selectRaw('COUNT(*) as count, MONTH(created_at) as month')
->groupBy('month')
->pluck('count')
->toArray();
Output Optimization: Stream charts directly to the response to save disk space:
return response()->stream(function () use ($graph) {
$graph->Stroke('php://output', 'PNG');
}, 200, ['Content-Type' => 'image/png']);
Laravel Mix Integration: For client-side previews, use Laravel Mix to proxy chart generation:
// mix.js
Mix.post('/api/charts/preview', { data: chartData })
.then(response => {
document.getElementById('chart-preview').src = response;
});
Fallback for Missing Modules: Handle cases where a module isn’t available gracefully:
try {
MtJpGraph::load('pie');
$graph = new Graph(600, 400);
$graph->Add(new PiePlot($data
How can I help you explore Laravel packages today?