首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP Libchart 圖表生成實戰:柱狀/折線/餅圖與中文亂碼完美解決

     編輯:PHP 相關知識

Libchart 簡介與安裝

Libchart 是純 PHP 圖表庫,無需 GD 扩展(內部使用 GD),支持柱狀、折線、餅圖、橫向柱狀等類型。通过 Composer 安裝:

composer require libchart/libchart

核心類架構

圖表類數據集類適用場景
VerticalBarChartXYDataSet垂直柱狀圖(單系列)
HorizontalBarChartXYDataSet水平柱狀圖
LineChartXYSeriesDataSet折線圖(支持多系列)
PieChartXYDataSet餅圖(標籤含數值)

統一封裝類:支援多圖表類型切換

<?php
require_once 'vendor/autoload.php';

use Libchart\Chart\VerticalBarChart;
use Libchart\Chart\HorizontalBarChart;
use Libchart\Chart\LineChart;
use Libchart\Chart\PieChart;
use Libchart\DataSet\XYDataSet;
use Libchart\DataSet\XYSeriesDataSet;
use Libchart\Point;
use Libchart\Plot;

class ChartRenderer {
    private $chart;
    private int $width;
    private int $height;

    public function __construct(int $type = 1, int $width = 800, int $height = 400) {
        $this->width = $width;
        $this->height = $height;
        $this->chart = match ($type) {
            1 => new VerticalBarChart($width, $height),
            2 => new LineChart($width, $height),
            3 => new PieChart($width, $height),
            default => new HorizontalBarChart($width, $height),
        };
    }

    /** 繪製單系列圖表(柱狀/餅圖/橫向柱狀) */
    public function renderSingleSeries(string $title, array $data): void {
        $dataSet = new XYDataSet();
        foreach ($data as $label => $value) {
            // 餅圖標籤顯示「標籤(值)」
            $pointLabel = ($this->chart instanceof PieChart) ? "$label ($value)" : $label;
            $dataSet->addPoint(new Point($pointLabel, $value));
        }
        $this->chart->setTitle($this->fixEncoding($title));
        $this->chart->setDataSet($dataSet);
        $this->output();
    }

    /** 繪製多系列折線圖 */
    public function renderMultiSeries(string $title, array $seriesData): void {
        if (!$this->chart instanceof LineChart) {
            throw new LogicException('Multi-series only for LineChart');
        }
        $dataSet = new XYSeriesDataSet();
        foreach ($seriesData as $seriesName => $points) {
            $xyData = new XYDataSet();
            foreach ($points as $x => $y) {
                $xyData->addPoint(new Point($x, $y));
            }
            $dataSet->addSerie($this->fixEncoding($seriesName), $xyData);
        }
        $this->chart->setTitle($this->fixEncoding($title));
        $this->chart->setDataSet($dataSet);
        $this->output();
    }

    /** 解決中文亂碼核心:輸出前統一轉 HTML 實體 */
    private function fixEncoding(string $text): string {
        return mb_convert_encoding($text, 'HTML-ENTITIES', 'UTF-8');
    }

    private function output(): void {
        header('Content-Type: image/png');
        $this->chart->render();
    }
}

// ========== 使用示例 ==========
// 1. 單系列柱狀圖
$renderer = new ChartRenderer(1, 800, 400);
$renderer->renderSingleSeries('月度銷售額', [
    '1月' => 120, '2月' => 150, '3月' => 180,
    '4月' => 210, '5月' => 240, '6月' => 270,
]);

// 2. 多系列折線圖
$renderer = new ChartRenderer(2, 800, 400);
$renderer->renderMultiSeries('產品線對比', [
    '產品A' => ['Q1'=>100, 'Q2'=>120, 'Q3'=>140, 'Q4'=>160],
    '產品B' => ['Q1'=>80, 'Q2'=>90, 'Q3'=>110, 'Q4'=>130],
]);

// 3. 餅圖
$renderer = new ChartRenderer(3, 600, 400);
$renderer->renderSingleSeries('市場佔有率', [
    '華東' => 35, '華南' => 25, '華北' => 20, '其他' => 20,
]);
?>

徹底解決中文亂碼:三步走策略

步驟 1:數據層編碼轉換(如上代碼)

所有傳入標題、標籤、圖例的字符串,統一用 mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8') 處理。

步驟 2:修改庫源碼 Chart.php — 標題編碼

文件:vendor/libchart/libchart/classes/view/chart/Chart.php

<?php
// 原代碼
public function setTitle($title) {
    $this->plot->setTitle($title);
}

// 修改為
public function setTitle($title) {
    $title = mb_convert_encoding($title, 'HTML-ENTITIES', 'UTF-8');
    $this->plot->setTitle($title);
}
?>

步驟 3:替換字體文件 — 關鍵!

Libchart 默認字體 DejaVuSansCondensed.ttf 不含中文字形。必須替換為中文字體(如微軟雅黑、思源黑體、Noto Sans SC)。

<?php
// 文件:vendor/libchart/libchart/classes/view/Text.php
// 第 47-48 行左右

// 原代碼
$this->fontCondensed = dirname(__FILE__) . '/../fonts/DejaVuSansCondensed.ttf';
$this->fontCondensedBold = dirname(__FILE__) . '/../fonts/DejaVuSansCondensed-Bold.ttf';

// 修改為(將字體文件放入 fonts/ 目錄)
$this->fontCondensed = dirname(__FILE__) . '/../fonts/NotoSansSC-Regular.otf';
$this->fontCondensedBold = dirname(__FILE__) . '/../fonts/NotoSansSC-Bold.otf';
?>

獲取字體:從 Google Fonts 下載 Noto Sans SC,或使用系統字體 C:/Windows/Fonts/msyh.ttc(Windows)//System/Library/Fonts/PingFang.ttc(macOS)。

進階:保存文件而非直接輸出

<?php
// render() 參數傳入路徑即保存文件
$chart->render(__DIR__ . '/storage/charts/sales_' . date('Ym') . '.png');

// 然後在頁面中引用
echo '<img src="/storage/charts/sales_' . date('Ym') . '.png" alt="銷售圖表">';
?>

常見問題排查

現象原因解決
圖片空白/錯誤GD 未安裝或版本過低php -m | grep gd,需 GD 2.0.1+
中文顯示方框/亂碼字體無中文字形必須完成步驟 3 替換字體
標題截斷標題過長超出畫布縮短標題或增大 width
餅圖標籤重疊數據項過多合併小項為「其他」或用圖例
坐標軸數字科學計數法大數值自動格式化預處理數值除以 10000 加「萬」單位

現代替代方案推薦

若項目需求複雜(動態交互、導出 SVG/PDF、實時更新),建議考慮:

  • pChart:功能更豐富,支持陰影、漸變、雷達圖等
  • Chart.js / ECharts:前端渲染,交互豐富,PHP 僅提供 JSON 數據
  • PHPSpreadsheet:若需嵌入 Excel 圖表

Libchart 適合「服務端生成靜態圖片、無交互、部署簡單」的輕量級場景。掌握編碼轉換與字體替換兩大核心,即可穩定產出專業中文圖表。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved