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

PHP GD 繪製智能 3D 柱狀圖:報表可視化完整實現

     編輯:PHP 相關知識

效果特性

  • 偽 3D 立體效果:頂面、側面、正面三個面不同亮度
  • 自動縮放:根據最大值計算柱高比例
  • 智能佈局:自動計算畫布高度、標籤換行、圖例佈局
  • 網格線、刻度、坐標軸完整
  • 支援自定義顏色、標題、標籤

核心類結構

SingleBar - 單個柱子幾何計算與繪製

<?php
class SingleBar {
    private $_x, $_y, $_h, $_l = 50, $_w = null;
    private $_srcPoints = [], $_points = [];

    public function __construct($x, $y, $h, $l = 50, $w = null) {
        $this->_x = $x; $this->_y = $y; $this->_h = $h;
        $this->_l = $l; $this->_w = $w;
        $this->_srcPoints = $this->getSrcPoints();
        $this->_points = $this->getPoints();
    }

    // 8 個關鍵頂點 (偽 3D: x, y, 偏移)
    private function getSrcPoints() {
        $x = $this->_x; $y = $this->_y; $h = $this->_h; $l = $this->_l;
        return [
            [$x, $y],                           // 0: 左下
            [$x + $l, $y],                      // 1: 右下
            [$x + 1.35*$l, $y - 0.35*$l],       // 2: 右下側面
            [$x + 0.35*$l, $y - 0.35*$l],       // 3: 左下側面
            [$x, $y + $h],                      // 4: 左上
            [$x + $l, $y + $h],                 // 5: 右上
            [$x + 1.35*$l, $y + $h - 0.35*$l],  // 6: 右上側面
            // [$x + 0.35*$l, $y + $h - 0.35*$l] // 7: 左上側面 (內部隱藏)
        ];
    }

    private function getPoints() {
        $points = [];
        foreach ($this->_srcPoints as $p) { $points[] = $p[0]; $points[] = $p[1]; }
        return $points;
    }

    public function getTopPoints() { return array_slice($this->_points, 0, 8); } // 0-3
    public function getBelowPoints() { return array_merge(array_slice($this->_points, 0, 4), array_slice($this->_points, 8, 4), array_slice($this->_points, 4, 4)); }
    public function getRightSidePoints() { return array_merge(array_slice($this->_points, 4, 4), array_slice($this->_points, 12, 4), array_slice($this->_points, 8, 4)); }

    // 繪製三個面
    public function draw($image, $topColor, $belowColor, $sideColor, $borderColor = null, $type = 'LEFT') {
        $borderColor = $borderColor ?? 0xCCCCCC;
        $topColor = $this->allocateColor($image, $topColor);
        $belowColor = $this->allocateColor($image, $belowColor);
        $sideColor = $this->allocateColor($image, $sideColor);

        imagefilledpolygon($image, $this->getTopPoints(), 4, $topColor);
        imagepolygon($image, $this->getTopPoints(), 4, $borderColor);
        imagefilledpolygon($image, $this->getBelowPoints(), 4, $belowColor);
        imagepolygon($image, $this->getBelowPoints(), 4, $borderColor);
        if ($type === 'LEFT') {
            imagefilledpolygon($image, $this->getRightSidePoints(), 4, $sideColor);
            imagepolygon($image, $this->getRightSidePoints(), 4, $borderColor);
        }
    }

    private function allocateColor($image, $hex) {
        $rgb = $this->hexToRgb($hex);
        return imagecolorallocate($image, $rgb['R'], $rgb['G'], $rgb['B']);
    }

    private function hexToRgb($hex) {
        $hex = hexdec($hex);
        return ['R' => ($hex>>16)&0xFF, 'G' => ($hex>>8)&0xFF, 'B' => $hex&0xFF];
    }
}
?>

Bar - 圖表容器:坐標系、網格、標題、圖例、多柱子繪製

<?php
class Bar {
    private $_W, $_H, $_bgColor = 'FFFFFF';
    private $_barHeights = [], $_barTexts = [], $_barColors = [];
    public $_title, $_paddingTop = 30, $_paddingBottom = 100, $_paddingLeft = 45, $_paddingRight = 2, $_barL = 50;
    public $image;

    public function __construct($imgW, $imgH, array $barHeights, array $barTexts = null, array $barColors = null) {
        $this->_W = $imgW; $this->_H = $imgH;
        $this->_barHeights = $barHeights;
        $this->_barTexts = $barTexts ?? array_keys($barHeights);
        $this->_barColors = $barColors ?? $this->generateColors(count($barHeights));
        $this->_paddingBottom = $this->calcPaddingBottom();
        $this->_H = $this->calcHeight();
        $this->image = imagecreatetruecolor($this->_W, $this->_H);
    }

    public function stroke() {
        $this->drawBg();
        $this->drawBars();
        $this->drawTitle();
        $this->drawLegend();
        header('Content-Type: image/jpeg');
        imagejpeg($this->image);
        imagedestroy($this->image);
    }

    private function drawBg() {
        // 背景、邊框、側面陰影、網格線、Y軸刻度值
        // ... (完整代碼見原文,含 10 等分網格、最大值刻度)
    }

    private function drawBars() {
        $count = count($this->_barHeights);
        $everyW = ($this->_W - $this->_paddingLeft - $this->_paddingRight) / $count;
        $barL = min($this->_barL, $everyW/1.35 - 6);
        $maxH = max($this->_barHeights);
        $rulerH = $this->_H - $this->_paddingTop - $this->_paddingBottom;
        $standerH = $rulerH * 10/11; // 留 1/11 頂部空間

        foreach ($this->_barHeights as $i => $val) {
            $h = ($standerH / $maxH) * $val;
            $x = $this->_paddingLeft + $everyW * $i + ($everyW - $barL*1.35)/2;
            $y = $this->_H - $this->_paddingBottom + 10 - $h;
            
            $bColor = $this->_barColors[$i];
            $rgb = $this->hexToRgb($bColor);
            $tColor = $bColor; // 頂面同色
            $sColor = sprintf('%02X%02X%02X', $rgb['R']*0.7, $rgb['G']*0.7, $rgb['B']*0.7); // 側面暗 30%
            
            $bar = new SingleBar($x, $y, $h, $barL);
            $bar->draw($this->image, $tColor, $bColor, $sColor);
        }
    }

    private function drawTitle() {
        if (!$this->_title) return;
        $font = 5; $fontW = imagefontwidth($font);
        $len = strlen($this->_title);
        $x = ($this->_W + $this->_paddingLeft - $this->_paddingRight)/2 - ($len*$fontW)/2;
        $y = ($this->_paddingTop - $fontW)/2 + 12;
        imagettftext($this->image, 12, 0, $x, $y, 0x000000, 'c:/windows/fonts/simhei.ttf', $this->_title);
    }

    private function drawLegend() {
        // 底部圖例:顏色方塊 + 文字,自動換行
        // ... (完整代碼見原文)
    }

    private function calcPaddingBottom() {
        // 根據圖例總寬度計算所需行數及高度
    }

    private function calcHeight() {
        return max(222 + $this->_paddingBottom, $this->_H);
    }

    private function generateColors($n) {
        $base = ['FF','00','33','66','99','CC'];
        $colors = [];
        for($i=0;$i<6;$i++) for($j=0;$j<6;$j++) for($k=0;$k<6;$k++) $colors[] = $base[$i].$base[$j].$base[$k];
        $ret = [];
        for($i=1;$i<216 && count($ret)<$n;$i+=4) $ret[] = $colors[$i];
        return $ret;
    }

    private function hexToRgb($hex) { /* 同上 */ }
    
    public function setTitle($t) { $this->_title = $t; }
    public function setBg($c) { $this->_bgColor = $c; }
}
?>

使用示例

<?php
require 'BarChart.php'; // 包含上述兩個類

$bar = new Bar(
    800, 400,                    // 畫布寬高
    [600, 300, 30, 500, 400, 250, 350, 360], // 數據
    ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月'] // 標籤
);
$bar->setTitle('2024 年月度銷售額統計');
$bar->stroke(); // 直接輸出 JPEG 圖片
?>

Web 頁面嵌入

<img src="chart.php" alt="銷售柱狀圖" style="max-width:100%; height:auto;">
<!-- chart.php 即上述使用示例 -->

現代替代方案對比

方案優點缺點適用場景
GD/PHP 原生無依賴、服務端渲染、適合郵件/PDF 嵌入代碼複雜、無交互、性能受限於 PHP報表郵件、PDF 導出、簡單靜態圖表
Chart.js / ECharts前端渲染、交互豐富、動畫、響應式、生態成熟需前端配合、SEO 需額外處理儀表板、管理後台、數據大屏
Highcharts / ApexCharts商業級功能、導出圖片/PDF、無障礙支援商業項目需授權費企業級報表系統
QuickChart.io (API)URL 參數生成圖表圖片、無代碼部署外部依賴、頻率限制、數據敏感性快速原型、郵件模板、Serverless

總結

GD 繪製 3D 柱狀圖展示了 PHP 服務端圖形繪製能力,核心在於幾何座標計算、顏色亮度分層、自動佈局算法。現代 Web 應用強烈建議採用 **前端圖表庫 (ECharts/Chart.js)**,服務端僅提供 JSON 數據接口。GD 方案保留價值:郵件嵌入圖片、PDF 報表生成、無前端環境的 CLI 腳本、舊系統維護。

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