ресурс для начинающих веб-разработчиков
комплексные веб-услуги по созданию сайтов

Справочный материал по основным языкам программирования и верстки сайтов.

Готовая методика создания простых и сложных динамичных сайтов, с использованием PHP и MySQL.

Использование веб-редактора Adobe Dreamweaver в разработке сайтов.

Использование графических редакторов Adobe Flash, Adobe Photoshop, Adobe Fireworks в подготовке веб-графики.

Разработка веб-сайтов под "ключ".

Разработка отдельных фрагментов сайтов, консультации по вопросам верстки веб-страниц и веб-программирования.

Создание фигур и построение графиков голосования. Вывод результатов голосования

Создание фигур

А теперь создадим систему голосования, где пользователи определят свое мнение по каким-то конкретным позициям освещения тем, рассматриваемых на сайте. Результаты опроса будут храниться в базе данных, и по ним с помощью графических функций будет строиться гистограмма.

Одно из основных применений функций работы с изображениями — вычерчивание графиков. Данными могут быть объемы продаж, количество посещений веб-сайта, да и вообще все, что угодно. Для этого создадим базу данных, а если БД уже существует, то создадим в ней таблицу poll_results, состоящую из двух столбцов: subject — имя темы или раздела сайта и num_votes — количество голосов отданных за освещение темы.

Таблица poll_results

CREATE TABLE poll_results (
object varchar(30) character set utf8 NOT NULL,
num_votes` int(11) NOT NULL );

INSERT INTO poll_results VALUES
('HTML и CSS ', 0),
('JavaScript', 0),
('PHP и MySQL', 0);

Эта таблица содержит информацию о трех разделах сайта и пользователю предстоит выбрать, какой из разделов требует дополнительного освещения.

vote.php —здесь посетители могут проголосовать

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Голосование</title>
</head>

<body>
<h1>Голосуем, голосуем, голосуем ...</h1>
<p>Какой из предложенных разделов, на ваш взгляд, требует дополнительного освещения на страницах сайта?</p>
<form action="showpoll.php" method="post">
<input name="vote" type="radio" value="HTML и CSS"> HTML и CSS <br>
<input name="vote" type="radio" value="JavaScript">JavaScript
<br>
<input name="vote" type="radio" value="PHP и MySQL">PHP и MySQL
<br>
<br>
<input name="" type="submit" value="Результаты">
</form>
</body>
</html>

В окне веб-браузера это будет выглядеть ТАК.

Общая идея такова: когда пользователь щелкает на кнопке Результаты, его голос добавляется в базу данных, затем оттуда считывается все голоса и выводятся гистограмма текущего состояния результатов.

Типичный пример вывода после нескольких голосования будет выглядеть так.

Результаты голосования

Сценарий, создающий изображение, достаточно длинен. Поэтому он разбит на четыре части, которые обсуждаются по отдельности.

Большая часть сценария выглядит знакомой, поскольку ранее приводилось много похожих примеров работы с MySQL, а также одноцветной заливки фонового холста и вывода на нем текстовых меток.

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

showpoll.php —часть 1сценария обновляет базу данных и извлекает из нее новые результаты

<?php
//Запрос к базе данных для получения информации для голосования
///////////////////////////////////////////////////////////////
//Получение значения из формы
$vote = $_REQUEST['vote'];
//Регистрация в базе данных
if (!$db_conn =new mysqli('localhost', 'user_name', 'pass', 'db_name'))
{

echo " Ошибка доступа к базе данных<br>";
exit;
}

if (!empty ($vote)) //если форма заполнена, добавить голос
{
$vote = addslashes ($vote);
$query = "UPDATE poll_results
set num_votes = num_votes+1
where object = '$vote'"
;
if(!($result = $db_conn->query($query)))
{
echo "Ошибка допуска к базе данных <br>";
exit;
}
}

//При использовании русских букв могут возниктуть проблемы, поэтому устанавливаем кодировку UTF8
mysqli_query($db_conn, "SET NAMES utf8");
//Запрос текущих результатов голосования независимо от того,
//проголосовал ли данный пользователь
$query = "SELECT * FROM poll_results";

if(!($result = $db_conn->query($query)))
{
echo "Ошибка допуска к базе данных <br>";
exit;
}

$num_object = $result->num_rows;

//Подсчет общего количества голосов
$total_votes = 0;
while ($row = $result->fetch_object())
{
$total_votes += $row->num_votes;
}
$result->data_seek(0); //сброс указателя $result

Код части 1 подключается к базе данных MySQL, обновляет данные на основе пользовательского ввода и запрашивает обновленные данные. Располагая этой информацией, можно произвести расчеты, необходимые для построения графика.

showpoll.php — в части 2 сценария вычисляются все переменные, необходимые для рисования

////////////////////////////////////////////////////
//Предварительные расчеты для построения графика
///////////////////////////////////////////////////
//Установка необходимых констант
$width=500; //ширина изображения в пикселях
$left_margin = 50; //отступ слева от графика
$right_margin = 50; //отступ справа от графика
$bar_height = 40;
$bar_spacing = $bar_height/2;
$font = 'C:/WINDOWS/Fonts/arial.ttf';
$title_size = 16; //в пунктах
$main_size = 12; //в пунктах
$small_size =12; //в пунктах
$text_indent = 10; //позияция текстовых меток от края изображения
//Установка начальной точки рисования
$x =$left_margin + 60; //место базовой линии рисунка
$y = 50; //то же
$bar_unit = ($width - ($x + $right_margin))/100; //одна точка на гистограмме
//Подсчет высоты прямоугольника плюс промежуток плюс поле
$height = $num_object*($bar_height + $bar_spacing)+50;

В части 2 расчитываются переменные, необходимые для вычерчивания графика.

Вычисление значений этих переменных несколько утомительно, однако предварительная прикидка, как должно выглядеть окончательное изображение, существенно упростит процесс рисования. Используемые здесь значения были получены с помощью эскиза и приближенной оценки требуемых пропорций.

Переменная $width содержит общую ширину изображения, $left_margin и $right_margin —отступы слева и справа соответственно, $bar_height и $bar_spacing —толщину полос и расстояние между ними, $font, $title_size, $main_size, $small_size, $text_indent — шрифт, его размеры и положение меток.

По этим базовым значениям можно рассчитать остальные величины. Вначале необходимо нарисовать базовую линию, от которой будут начинаться все полосы гистограммы: отступ слева плюс место для текстовых меток по координате х, а также приближенную оценку на основе эскиза по координате у.

Далее определяются два важных значения: первое — расстояние на гистограмме, изображающее единицу:

$bar_unit = ($width - ($x + $right_margin))/100;

Это максимальная длина полосы — от базовой линии до отступа справа — деленная на 100, так как график отображает значение в процентах.

Второе значение — полная высота изображения:

$height = $num_object*($bar_height + $bar_spacing)+50;

Это высота полосы, умноженная на их количество, плюс место под заголовок.

showpoll.php —часть 3 сценария готовит все данные для вывода графика

/////////////////////////////////////////////////////////////
//Создание базового изображения
////////////////////////////////////////////////////////////
//Создание пустого холста
$im = ImageCreateTrueColor ($width, $height);
//Назначение цветов
$white = ImageColorAllocate ($im, 255, 255, 255);
$blue = ImageColorAllocate($im, 0, 64, 128);
$black = ImageColorAllocate ($im, 0, 0, 0);
$pink =ImageColorAllocate ($im, 255, 78, 243);

$text_color = $black;
$percent_color = $black;
$bg_color = $white;
$line_color = $black;
$bar_color = $blue;
$number_color = $pink;

//Создание фона для рисования
ImageFilledRectangle($im, 0, 0, $width, $height, $bg_color);
//Контур фонового изображения
ImageRectangle ($im, 0, 0, $width-1, $height-1, $line_color);

//Вывод заголовка
$title = "Результаты голосования";
//Преобразовываем текст из кодировки windows-1251 в UTF-8
$title = iconv("windows-1251", "UTF-8", $title);
$title_dimensions = imagettfbbox($title_size, 0, $font, $title);
$title_length = $title_dimensions[2] - $title_dimensions[0];
$title_height = abs($title_dimensions[7] - $title_dimensions[1]);
$title_above_line = abs($title_dimensions[7]);
$title_x = ($width - $title_length)/2; //центрование по x
$title_y = ($y - $title_height)/2 + $title_above_line; //центрование по y
ImageTTFText ($im, $title_size, 0, $title_x, $title_y, $text_color, $font, $title);
//Вычеркивание базовой линии, начиная чуть выше первой полоски и завершая чуть ниже последней
ImageLine($im, $x, $y-5, $x, $height-15, $line_color);

В части 3 выполняется подготовка базового изображения, назначение цветов и вывод части графика.

На этот раз заливка фона осуществляется следующим образом:

ImageFilledRectangle($im, 0, 0, $width, $height, $bg_color);

Функция ImageFilledRectangle(), как можно предположить по названию, выводит прямоугольник с заливкой. Как всегда первый параметр — идентификатор изображения. За ним следуют координаты х и у начальной и конечных точек, то есть, соответственно, левого верхнего и правого нижнего углов прямоугольника. В данном случае холст заливается цветом фона — белым, который является последним параметром функции.

Затем происходит следующий вызов:

ImageRectangle ($im, 0, 0, $width-1, $height-1, $line_color);

которая обеспечивает прорисовку контура по краю изображения. Эта функция выводит прямоугольник с контуром и имеет такие же параметры. Обратите внимание, что конечная точка имеет координаты $width-1 и $height-1. Если бы они были равны $width и $height, прямоугольник вышел бы за пределы холста.

Для центрирования и вывода заголовка гистограммы применяется та же логика и те же функции, что и в предыдущем сценарии.

И, наконец выводится базовая линия:

ImageLine($im, $x, $y-5, $x, $height-15, $line_color);

Функция ImageLine() вычерчивает линию цвета $line_color на заданном изображении $im, от точки ($x, $y-5) до точки ($x, $height-15).

В нашем случае базовая линия начинается чуть выше первой полосы и проходит вниз почти до конца холста.

Теперь все готово к выводу данных.

showpoll.php —часть 4 сценария выводит на графике подготовленные данные и выполняет заключительные операции

//////////////////////////////////////////////////////////////////////////////////////
//Вывод данных в виде графика
/////////////////////////////////////////////////////////////////////////////////////
//Получение всех данных из базы и отображение соответствующих полос
while($row = $result->fetch_object())
{
if($total_votes > 0)
$percent = intval(($row->num_votes/$total_votes)*100);
else
$percent = 0;
//Вывод процентов для данного значения
$percent_dimensions = ImageTTFBBox($main_size, 0, $font, $percent.'%');
$percent_length = $percent_dimensions[2] - $percent_dimensions[0];
ImageTTFText($im, $main_size, 0, $width-$percent_length-$text_indent, $y + ($bar_height/2), $percent_color, $font, $percent.'%');

//Длина полосы для данного значения
$bar_length = $x + ($percent * $bar_unit);

//Вывод полосы для данного значения
ImageFilledRectangle ($im, $x, $y-2, $bar_length, $y+$bar_height, $bar_color);

//Вывод заголовка для данного значения
ImageTTFText ($im, $main_size, 0, $text_indent, $y + ($bar_height/2), $text_color, $font, "$row->object");

//Прорисовка контура, соответствующего 100%
ImageRectangle ($im, $bar_length+1, $y-2, ($x + (100*$bar_unit)), $y+$bar_height, $line_color);
//Вывод чисел
ImageTTFText($im, $small_size, 0, $x+(100*$bar_unit)-50, $y+($bar_height/2), $number_color, $font, $row->num_votes.'/'.$total_votes);

//Спуск к следующей полосе
$y=$y+($bar_height+$bar_spacing);
}
//////////////////////////////////////////////////////////////////////////////
//Вывод готового изображения
Header ('Content-type: image/png');
ImagePNG($im);
//Освобождение ресурсов
ImageDestroy($im);
?>

В части 4 из базы данных поочередно выбираются данные по каждой позиции, вычисляется процент голосов, а затем выводятся полосы и поясняющие надписи.

Как и ранее, текст выводится при помощи функции ImageTTFTex(). Заполненные прямоугольники выводятся функцией ImageFilledRectangle():

ImageFilledRectangle ($im, $x, $y-2, $bar_length, $y+$bar_height, $bar_color);

Контуры, соответствующие 100%, выводятся функцией ImageRectangle():

ImageRectangle ($im, $bar_length+1, $y-2, ($x + (100*$bar_unit)), $y+$bar_height, $line_color);

После вывода всех полос изображение пересылается в браузер с помощью функции ImagePNG(), а затем посредством функции ImageDestroy() освобождаются все ресурсы.

Хотя это довольно-таки объемный сценарий, тем не менее, его несложно адаптировать под свои нужды. Важным свойством сценария является то, что в нем нет "противообманного" механизма. Пользователи смогут очень обнаружить, что можно проголосовать несколько раз, что сделает результаты, по сути, бессмысленными.

Если вы достаточно хорошо владеете математикой, то можете воспользоваться аналогичным подходом для вывода линейных графиков или, скажем, секторных диаграмм.

Кроме графических функций, рассмотренных нами, существуют и многие другие.

Немало полезных ресурсов доступно в Интернете. Документацию по GD можно найти по адресу:

http://www.boutell.com/gd/

Не забывайте, что версия GD2 встроена в главную библиотеку PHP, поэтому некоторые детали могут отличаться.

Существуют также обучающие курсы по отдельным видам графических приложений. Они доступны по адресу:

http://www.zend.com и http://www.devshed.com.

Идеи приложения, создающего гистограмму, основаны на сценарии Стива Маранды, лоступном на сайте Devshed.