src/graph/MGraph.php
<?php
/**
* JPGraph v4.0.3
*/
namespace Amenadiel\JpGraph\Graph;
use Amenadiel\JpGraph\Image;
use Amenadiel\JpGraph\Text;
use Amenadiel\JpGraph\Util;
/**
* File: JPGRAPH_MGRAPH.PHP
* // Description: Class to handle multiple graphs in the same image
* // Created: 2006-01-15
* // Ver: $Id: jpgraph_mgraph.php 1770 2009-08-17 06:10:22Z ljp $
* //
* // Copyright (c) Asial Corporation. All rights reserved.
*/
/**
* @class MGraph
* // Description: Create a container image that can hold several graph
*/
class MGraph
{
public $title;
public $subtitle;
public $subsubtitle;
protected $img;
protected $iCnt = 0;
protected $iGraphs = []; // image_handle, x, y, fx, fy, sizex, sizey
protected $iFillColor = 'white';
protected $iCurrentColor = 0;
protected $lm = 4;
protected $rm = 4;
protected $tm = 4;
protected $bm = 4;
protected $iDoFrame = false;
protected $iFrameColor = 'black';
protected $iFrameWeight = 1;
protected $iLineWeight = 1;
protected $expired = false;
protected $cache;
protected $cache_name = '';
protected $inline = true;
protected $image_format = 'png';
protected $image_quality = 75;
protected $iWidth;
protected $iHeight;
protected $background_image = '';
protected $background_image_center = true;
protected $backround_image_format = '';
protected $background_image_mix = 100;
protected $background_image_y;
protected $background_image_x;
private $doshadow = false;
private $shadow_width = 4;
private $shadow_color = 'gray@0.5';
public $footer;
// Create a new instane of the combined graph
public function __construct($aWidth = null, $aHeight = null, $aCachedName = '', $aTimeOut = 0, $aInline = true)
{
$this->iWidth = $aWidth;
$this->iHeight = $aHeight;
// If the cached version exist just read it directly from the
// cache, stream it back to browser and exit
if ($aCachedName != '' && READ_CACHE && $aInline) {
$this->cache = new Image\ImgStreamCache();
$this->cache->SetTimeOut($aTimeOut);
$image = new Image\Image();
if ($this->cache->GetAndStream($image, $aCachedName)) {
exit();
}
}
$this->inline = $aInline;
$this->cache_name = $aCachedName;
$this->title = new Text\Text();
$this->title->ParagraphAlign('center');
$this->title->SetFont(FF_FONT2, FS_BOLD);
$this->title->SetMargin(3);
$this->title->SetAlign('center');
$this->subtitle = new Text\Text();
$this->subtitle->ParagraphAlign('center');
$this->subtitle->SetFont(FF_FONT1, FS_BOLD);
$this->subtitle->SetMargin(3);
$this->subtitle->SetAlign('center');
$this->subsubtitle = new Text\Text();
$this->subsubtitle->ParagraphAlign('center');
$this->subsubtitle->SetFont(FF_FONT1, FS_NORMAL);
$this->subsubtitle->SetMargin(3);
$this->subsubtitle->SetAlign('center');
$this->footer = new Image\Footer();
}
// Specify background fill color for the combined graph
public function SetFillColor($aColor)
{
$this->iFillColor = $aColor;
}
// Add a frame around the combined graph
public function SetFrame($aFlg, $aColor = 'black', $aWeight = 1)
{
$this->iDoFrame = $aFlg;
$this->iFrameColor = $aColor;
$this->iFrameWeight = $aWeight;
}
// Specify a background image blend
public function SetBackgroundImageMix($aMix)
{
$this->background_image_mix = $aMix;
}
// Specify a background image
public function SetBackgroundImage($aFileName, $aCenter_aX = null, $aY = null)
{
// Second argument can be either a boolean value or
// a numeric
$aCenter = true;
$aX = null;
if (is_numeric($aCenter_aX)) {
$aX = $aCenter_aX;
}
// Get extension to determine image type
$e = explode('.', $aFileName);
if (!$e) {
Util\JpGraphError::RaiseL(12002, $aFileName);
//('Incorrect file name for MGraph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type');
}
$valid_formats = ['png', 'jpg', 'gif'];
$aImgFormat = strtolower($e[count($e) - 1]);
if ($aImgFormat == 'jpeg') {
$aImgFormat = 'jpg';
} elseif (!in_array($aImgFormat, $valid_formats, true)) {
Util\JpGraphError::RaiseL(12003, $aImgFormat, $aFileName);
//('Unknown file extension ($aImgFormat) in MGraph::SetBackgroundImage() for filename: '.$aFileName);
}
$this->background_image = $aFileName;
$this->background_image_center = $aCenter;
$this->background_image_format = $aImgFormat;
$this->background_image_x = $aX;
$this->background_image_y = $aY;
}
public function _strokeBackgroundImage()
{
if ($this->background_image == '') {
return;
}
$bkgimg = Graph::LoadBkgImage('', $this->background_image);
// Background width & Heoght
$bw = imagesx($bkgimg);
$bh = imagesy($bkgimg);
// Canvas width and height
$cw = imagesx($this->img);
$ch = imagesy($this->img);
if ($this->doshadow) {
$cw -= $this->shadow_width;
$ch -= $this->shadow_width;
}
if ($this->background_image_x === null || $this->background_image_y === null) {
if ($this->background_image_center) {
// Center original image in the plot area
$x = round($cw / 2 - $bw / 2);
$y = round($ch / 2 - $bh / 2);
} else {
// Just copy the image from left corner, no resizing
$x = 0;
$y = 0;
}
} else {
$x = $this->background_image_x;
$y = $this->background_image_y;
}
imagecopymerge($this->img, $bkgimg, $x, $y, 0, 0, $bw, $bh, $this->background_image_mix);
}
public function AddMix($aGraph, $x = 0, $y = 0, $mix = 100, $fx = 0, $fy = 0, $w = 0, $h = 0)
{
$this->_gdImgHandle($aGraph->Stroke(_IMG_HANDLER), $x, $y, $fx = 0, $fy = 0, $w, $h, $mix);
}
public function Add($aGraph, $x = 0, $y = 0, $fx = 0, $fy = 0, $w = 0, $h = 0)
{
$this->_gdImgHandle($aGraph->Stroke(_IMG_HANDLER), $x, $y, $fx = 0, $fy = 0, $w, $h);
}
public function _gdImgHandle($agdCanvas, $x, $y, $fx = 0, $fy = 0, $w = 0, $h = 0, $mix = 100)
{
if ($w == 0) {
$w = @imagesx($agdCanvas);
}
if ($w === null) {
Util\JpGraphError::RaiseL(12007);
//('Argument to MGraph::Add() is not a valid GD image handle.');
return;
}
if ($h == 0) {
$h = @imagesy($agdCanvas);
}
$this->iGraphs[$this->iCnt++] = [$agdCanvas, $x, $y, $fx, $fy, $w, $h, $mix];
}
public function SetMargin($lm, $rm, $tm, $bm)
{
$this->lm = $lm;
$this->rm = $rm;
$this->tm = $tm;
$this->bm = $bm;
}
public function SetExpired($aFlg = true)
{
$this->expired = $aFlg;
}
public function SetImgFormat($aFormat, $aQuality = 75)
{
$this->image_format = $aFormat;
$this->image_quality = $aQuality;
}
// Set the shadow around the whole image
public function SetShadow($aShowShadow = true, $aShadowWidth = 4, $aShadowColor = 'gray@0.3')
{
$this->doshadow = $aShowShadow;
$this->shadow_color = $aShadowColor;
$this->shadow_width = $aShadowWidth;
$this->footer->iBottomMargin += $aShadowWidth;
$this->footer->iRightMargin += $aShadowWidth;
}
public function StrokeTitle($image, $w, $h)
{
// Stroke title
if ($this->title->t !== '') {
$margin = 3;
$y = $this->title->margin;
if ($this->title->halign == 'center') {
$this->title->Center(0, $w, $y);
} elseif ($this->title->halign == 'left') {
$this->title->SetPos($this->title->margin + 2, $y);
} elseif ($this->title->halign == 'right') {
$indent = 0;
if ($this->doshadow) {
$indent = $this->shadow_width + 2;
}
$this->title->SetPos($w - $this->title->margin - $indent, $y, 'right');
}
$this->title->Stroke($image);
// ... and subtitle
$y += $this->title->GetTextHeight($image) + $margin + $this->subtitle->margin;
if ($this->subtitle->halign == 'center') {
$this->subtitle->Center(0, $w, $y);
} elseif ($this->subtitle->halign == 'left') {
$this->subtitle->SetPos($this->subtitle->margin + 2, $y);
} elseif ($this->subtitle->halign == 'right') {
$indent = 0;
if ($this->doshadow) {
$indent = $this->shadow_width + 2;
}
$this->subtitle->SetPos($this->img->width - $this->subtitle->margin - $indent, $y, 'right');
}
$this->subtitle->Stroke($image);
// ... and subsubtitle
$y += $this->subtitle->GetTextHeight($image) + $margin + $this->subsubtitle->margin;
if ($this->subsubtitle->halign == 'center') {
$this->subsubtitle->Center(0, $w, $y);
} elseif ($this->subsubtitle->halign == 'left') {
$this->subsubtitle->SetPos($this->subsubtitle->margin + 2, $y);
} elseif ($this->subsubtitle->halign == 'right') {
$indent = 0;
if ($this->doshadow) {
$indent = $this->shadow_width + 2;
}
$this->subsubtitle->SetPos($w - $this->subsubtitle->margin - $indent, $y, 'right');
}
$this->subsubtitle->Stroke($image);
}
}
public function Stroke($aFileName = '')
{
// Find out the necessary size for the container image
$w = 0;
$h = 0;
for ($i = 0; $i < $this->iCnt; ++$i) {
$maxw = $this->iGraphs[$i][1] + $this->iGraphs[$i][5];
$maxh = $this->iGraphs[$i][2] + $this->iGraphs[$i][6];
$w = max($w, $maxw);
$h = max($h, $maxh);
}
$w += $this->lm + $this->rm;
$h += $this->tm + $this->bm;
// User specified width,height overrides
if ($this->iWidth !== null && $this->iWidth !== 0) {
$w = $this->iWidth;
}
if ($this->iHeight !== null && $this->iHeight !== 0) {
$h = $this->iHeight;
}
if ($this->doshadow) {
$w += $this->shadow_width;
$h += $this->shadow_width;
}
$image = new Image\Image($w, $h);
$image->SetImgFormat($this->image_format, $this->image_quality);
if ($this->doshadow) {
$image->SetColor($this->iFrameColor);
$image->ShadowRectangle(0, 0, $w - 1, $h - 1, $this->iFillColor, $this->shadow_width, $this->shadow_color);
$w -= $this->shadow_width;
$h -= $this->shadow_width;
} else {
$image->SetColor($this->iFillColor);
$image->FilledRectangle(0, 0, $w - 1, $h - 1);
}
$image->SetExpired($this->expired);
$this->img = $image->img;
$this->_strokeBackgroundImage();
if ($this->iDoFrame && !$this->doshadow) {
$image->SetColor($this->iFrameColor);
$image->SetLineWeight($this->iFrameWeight);
$image->Rectangle(0, 0, $w - 1, $h - 1);
}
// Copy all sub graphs to the container
for ($i = 0; $i < $this->iCnt; ++$i) {
$image->CopyMerge(
$this->iGraphs[$i][0],
$this->iGraphs[$i][1] + $this->lm,
$this->iGraphs[$i][2] + $this->tm,
$this->iGraphs[$i][3],
$this->iGraphs[$i][4],
$this->iGraphs[$i][5],
$this->iGraphs[$i][6],
-1,
-1, /* Full from width and height */
$this->iGraphs[$i][7]
);
}
$this->StrokeTitle($image, $w, $h);
$this->footer->Stroke($image);
// Output image
if ($aFileName == _IMG_HANDLER) {
return $image->img;
}
//Finally stream the generated picture
$this->cache = new Image\ImgStreamCache();
$this->cache->PutAndStream($image, $this->cache_name, $this->inline, $aFileName);
}
}
// EOF