Рисуем плавную кривую в PHP с использованием GD

В данном уроке мы выведем график на PHP с использованием  библиотеки GD. Кривая будет сглаживаться с помощью интерполяции кубическими сплайнами.

 

Шаг 1. Разметка HTML

Разметка для демонстрации достаточно проста.

<!DOCTYPE html>
<html lang="ru" >
    <head>
        <meta charset="utf-8" />
        <title>Плавная кривая на PHP и GD | Материалы сайта RUSELLER.COM</title>

        <link href="/css/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <div class="container">
            <img src="/smooth_graph.php" alt="" />
        </div>
        <footer>
            <h2>Плавная кривая на PHP и GD</h2>
            <a href="http://www.ruseller.com" target="_blank" class="stuts">Материалы сайта <span>RUSELLER.COM</span></a>
        </footer>
    </body>
</html>

В качестве источника для элемента изображения выступает PHP файл, который генерирует график.

 

Шаг 2. CSS

Для демонстрации используются обычные правила:

css/main.css

*{
    margin:0;
    padding:0;
}

body {
    background-repeat:no-repeat;
    background-color:#bababa;
    background-image: -webkit-radial-gradient(600px 200px, circle, #eee, #bababa 40%);
    background-image: -moz-radial-gradient(600px 200px, circle, #eee, #bababa 40%);
    background-image: -o-radial-gradient(600px 200px, circle, #eee, #bababa 40%);
    background-image: radial-gradient(600px 200px, circle, #eee, #bababa 40%);
    color:#fff;
    font:14px/1.3 Arial,sans-serif;
    min-height:600px;
}

footer {
    background-color:#212121;
    bottom:0;
    box-shadow: 0 -1px 2px #111111;
    display:block;
    height:70px;
    left:0;
    position:fixed;
    width:100%;
    z-index:100;
}

footer h2{
    font-size:22px;
    font-weight:normal;
    left:50%;
    margin-left:-400px;
    padding:22px 0;
    position:absolute;
    width:540px;
}

footer a.stuts,a.stuts:visited{
    border:none;
    text-decoration:none;
    color:#fcfcfc;
    font-size:14px;
    left:50%;
    line-height:31px;
    margin:23px 0 0 110px;
    position:absolute;
    top:0;
}

footer .stuts span {
    font-size:22px;
    font-weight:bold;
    margin-left:5px;
}

.container {
    border:3px #111 solid;
    margin:20px auto;
    padding:20px;
    position:relative;
    width:550px;
    height:430px;

    border-radius:15px;
    -moz-border-radius:15px;
    -webkit-border-radius:15px;
}

 

Шаг 3. PHP

График генерируется серверной стороной:

smooth_graph.php

<?php
set_time_limit(100);

define('GRAPH_WIDTH',  500);
define('GRAPH_HEIGHT', 400);

include_once ('classes/Plot.php');
include_once ('classes/CubicSplines.php');

$iPoints = 15;
$dx = (GRAPH_WIDTH - 40) / ($iPoints - 1);
$x = 20;

for ($i = 0; $i < $iPoints; $i++) {
    $y = rand(20, GRAPH_HEIGHT - 20);
    $aCoords[$x] = $y;
    $x+= $dx;
}

$vImagegHeight = GRAPH_HEIGHT + 30;
$vImage = imagecreatetruecolor(GRAPH_WIDTH + 50, $vImagegHeight);

$vBgColor = imagecolorallocate($vImage, 160, 160, 160);
$vTextColor = imagecolorallocate($vImage, 0, 0, 0);
$vAxisColor = imagecolorallocate($vImage, 0, 0, 0);
$vDotColor  = imagecolorallocate($vImage, 192, 64, 64);

imagefill($vImage, 0, 0, $vBgColor);

$oPlot = new Plot($aCoords);
$oPlot->drawDots($vImage, $vDotColor, 10, GRAPH_HEIGHT, 8);

$oCurve = new CubicSplines();
$vColor = imagecolorallocate($vImage, 225, 64, 64);

$iStart = microtime(1);
if ($oCurve) {
    $oCurve->setInitCoords($aCoords, 1);
    $r = $oCurve->processCoords();
    if ($r)
        $curveGraph = new Plot($r);
    else
        continue;
} else {
    $curveGraph = $oPlot;
}

$curveGraph->drawLine($vImage, $vColor, 10, GRAPH_HEIGHT);

// unset($oCurve);
$sTime = sprintf("%1.4f", microtime(1) - $iStart);

imagefilledrectangle($vImage, 0, GRAPH_HEIGHT, GRAPH_WIDTH + 50, $vImagegHeight, $vBgColor);
$oPlot->drawAxis($vImage, $vAxisColor, 10, GRAPH_HEIGHT);
$iPanelY = GRAPH_HEIGHT;

imagefilledrectangle($vImage, 10, $iPanelY + 10, 20, $iPanelY + 20, $vColor);
imagerectangle($vImage, 10, $iPanelY + 10, 20, $iPanelY + 20, $vAxisColor);
imagettftext($vImage, 10, 0, 30, $iPanelY + 20, $vTextColor, 'Ds-digib.ttf', 'Кубические сплайны в PHP:         ' . $sTime . ' sec');

header("Content-type: image/png");
imagepng($vImage);
imagedestroy($vImage);

?>

Формируется массив $aCoords точек, который заполняется случайным образом. Затем данный массив используется для построения плавной кривой, которая проходит через все его точки.

В файле используются 2 класса, которые оформлены в отдельных файлах.

Класс для вывода элементов графики (линий, точек и осей):

classes/Plot.php

<?php

class Plot {
    private $aCoords;

    function __construct(&$aCoords) {
        $this->aCoords = &$aCoords;
    }

    public function drawLine($vImage, $vColor, $iPosX = 0, $iPosY = false) {
        if ($iPosY === false)
            $iPosY = imagesy($vImage);

        reset($this->aCoords);
        list($iPrevX, $iPrevY) = each($this->aCoords);

        while (list ($x, $y) = each($this->aCoords)) {
            imageline($vImage, $iPosX + round($iPrevX), $iPosY - round($iPrevY), $iPosX + round($x), $iPosY - round($y), $vColor);
            $iPrevX = $x;
            $iPrevY = $y;
        }
    }

    public function drawDots($vImage, $vColor, $iPosX = 0, $iPosY = false, $iDotSize = 1) {
        if ($iPosY === false)
            $iPosY = imagesy($vImage);

        $vBorderColor = imagecolorallocate($vImage, 0, 0, 0);
        foreach ($this->aCoords as $x => $y) {
            imagefilledellipse($vImage, $iPosX + round($x), $iPosY - round($y), $iDotSize, $iDotSize, $vColor);
            imageellipse($vImage, $iPosX + round($x), $iPosY - round($y), $iDotSize, $iDotSize, $vBorderColor);
        }
    }

    public function drawAxis($vImage, $vColor, $iPosX = 0, $iPosY = false) {
        if ($iPosY === false)
            $iPosY = imagesy($vImage);

        $vImageWidth = imagesx($vImage);
        imageline($vImage, $iPosX, $iPosY, $iPosX, 0, $vColor);
        imageline($vImage, $iPosX, $iPosY, $vImageWidth, $iPosY, $vColor);

        imagefilledpolygon($vImage, array($iPosX, 0, $iPosX - 3, 5, $iPosX + 3, 5), 3, $vColor);
        imagefilledpolygon($vImage, array($vImageWidth, $iPosY, $vImageWidth - 5, $iPosY - 3, $vImageWidth - 5, $iPosY + 3), 3, $vColor);
    }
}

?>

И класс для формирования плавной кривой с помощью кубических сплайнов:

classes/CubicSplines.php

<?php

class CubicSplines {
    protected $aCoords;
    protected $aCrdX;
    protected $aCrdY;
    protected $aSplines = array();
    protected $iMinX;
    protected $iMaxX;
    protected $iStep;

    protected function prepareCoords(&$aCoords, $iStep, $iMinX = -1, $iMaxX = -1) {
        $this->aCrdX = array();
        $this->aCrdY = array();
        $this->aCoords = array();

        ksort($aCoords);
        foreach ($aCoords as $x => $y) {
            $this->aCrdX[] = $x;
            $this->aCrdY[] = $y;
        }

        $this->iMinX = $iMinX;
        $this->iMaxX = $iMaxX;

        if ($this->iMinX == -1)
            $this->iMinX = min($this->aCrdX);
        if ($this->iMaxX == -1)
            $this->iMaxX = max($this->aCrdX);

        $this->iStep = $iStep;
    }

    public function setInitCoords(&$aCoords, $iStep = 1, $iMinX = -1, $iMaxX = -1) {
        $this->aSplines = array();

        if (count($aCoords) < 4) {
            return false;
        }

        $this->prepareCoords($aCoords, $iStep, $iMinX, $iMaxX);
        $this->buildSpline($this->aCrdX, $this->aCrdY, count($this->aCrdX));
    }

    public function processCoords() {
        for ($x = $this->iMinX; $x <= $this->iMaxX; $x += $this->iStep) {
            $this->aCoords[$x] = $this->funcInterp($x);
        }

        return $this->aCoords;
    }

    private function buildSpline($x, $y, $n) {
        for ($i = 0; $i < $n; ++$i) {
            $this->aSplines[$i]['x'] = $x[$i];
            $this->aSplines[$i]['a'] = $y[$i];
        }

        $this->aSplines[0]['c'] = $this->aSplines[$n - 1]['c'] = 0;
        $alpha[0] = $beta[0] = 0;
        for ($i = 1; $i < $n - 1; ++$i) {
            $h_i = $x[$i] - $x[$i - 1];
            $h_i1 = $x[$i + 1] - $x[$i];
            $A = $h_i;
            $C = 2.0 * ($h_i + $h_i1);
            $B = $h_i1;
            $F = 6.0 * (($y[$i + 1] - $y[$i]) / $h_i1 - ($y[$i] - $y[$i - 1]) / $h_i);
            $z = ($A * $alpha[$i - 1] + $C);
            $alpha[$i] = - $B / $z;
            $beta[$i] = ($F - $A * $beta[$i - 1]) / $z;
        }

        for ($i = $n - 2; $i > 0; --$i) {
            $this->aSplines[$i]['c'] = $alpha[$i] * $this->aSplines[$i + 1]['c'] + $beta[$i];
        }

        for ($i = $n - 1; $i > 0; --$i) {
            $h_i = $x[$i] - $x[$i - 1];
            $this->aSplines[$i]['d'] = ($this->aSplines[$i]['c'] - $this->aSplines[$i - 1]['c']) / $h_i;
            $this->aSplines[$i]['b'] = $h_i * (2.0 * $this->aSplines[$i]['c'] + $this->aSplines[$i - 1]['c']) / 6.0 + ($y[$i] - $y[$i - 1]) / $h_i;
        }
    }

    private function funcInterp($x) {
        $n = count($this->aSplines);
        if ($x <= $this->aSplines[0]['x'])  {
            $s = $this->aSplines[1];
        } else {
            if ($x >= $this->aSplines[$n - 1]['x']) {
                $s = $this->aSplines[$n - 1];
            } else {
                $i = 0;
                $j = $n - 1;
                while ($i + 1 < $j) {
                    $k = $i + ($j - $i) / 2;
                    if ($x <= $this->aSplines[$k]['x']) {
                        $j = $k;
                    } else {
                        $i = $k;
                    }
                }

                $s = $this->aSplines[$j];
            }
        }

        $dx = ($x - $s['x']);
        return $s['a'] + ($s['b'] + ($s['c'] / 2.0 + $s['d'] * $dx / 6.0) * $dx) * $dx;
    }
}

?>

Источник: http://feedproxy.google.com/~r/ruseller/CdHX/~3/xYHMI6vEHao/lessons.php

Читать комменты и комментировать

Добавить комментарий / отзыв



Защитный код
Обновить

Рисуем плавную кривую в PHP с использованием GD | | 2012-06-19 12:00:51 | | Статьи Web-мастеру | | В данном уроке мы выведем график на PHP с использованием  библиотеки GD. Кривая будет сглаживаться с помощью интерполяции кубическими сплайнами. Шаг 1. Разметка HTMLРазметка для демонстрации | РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
 
Поделиться с друзьями: