Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 6314
Последний выпуск: 19.06.2015

Вывод круговой диаграммы

Автор: mike, www.codenet.ru
20 апреля 2005 года

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

В этом уроке мы рассмотрим пример построения универсальной круговой диаграммы. Ее размер и размер подписи будет зависеть от размера изображения. (см. рисунки).

Круговая диаграмма строится с помощью функции imagefilledarc. В качестве 6 и 7 параметра ей передаются начальный и конечный углы сектора. Наша основная задача - рассчитать углы секторов в зависимости от передаваемых данных. Сделать это можно с помощью следующей формулы:

angle=(val/total)*360;

где,

  • angle - угол поворота грани сектора;
  • val - входное значение ;
  • total - сумма всех входных значений.

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

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

Рассмотрим исходный текст программы:

<?php
function Diagramm($im,$VALUES,$LEGEND) {
    GLOBAL $COLORS,$SHADOWS;

    $black=ImageColorAllocate($im,0,0,0);
  • $im - идентификатор изображения;
  • $VALUES - массив со значениями;
  • $LEGEND - массив с подписями.

Получим размеры изображения:

    $W=ImageSX($im);
    $H=ImageSY($im);

Вывод легенды

Посчитаем количество пунктов, от этого зависит высота легенды

    $legend_count=count($LEGEND);

Посчитаем максимальную длину пункта, от этого зависит ширина легенды

    $max_length=0;
    foreach($LEGEND as $v) if ($max_length<strlen($v)) $max_length=strlen($v);

Номер шрифта, котором мы будем выводить легенду. Также получим высоту и ширину символов для шрифта.

    $FONT=2;
    $font_w=ImageFontWidth($FONT);
    $font_h=ImageFontHeight($FONT);

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

Ширина =

  • (ширина текста (ширина символа * максимальное количество символов)) +
  • (место для квадратика с цветом (размер квадратика равен высоте шрифта)) +
  • (отступ от левого края легенды до квадратика с цветом) +
  • (отступ от квадратика с цветом до текста) +
  • (отступ от текста для правого края легенды);
    $l_width=($font_w*$max_length)+$font_h+10+5+10;

Высота =

  • (высота текста) +
  • (отступ между текстом и верхним краем) +
  • (отступ между текстом и нижним краем)
    $l_height=$font_h*$legend_count+10+10;

Получим координаты верхнего левого угла прямоугольника - границы легенды

    $l_x1=$W-10-$l_width;
    $l_y1=($H-$l_height)/2;

Вывод прямоугольника - границы легенды

    ImageRectangle($im, $l_x1, $l_y1, $l_x1+$l_width, $l_y1+$l_height, $black);

Вывод текст легенды и цветных квадратиков

    $text_x=$l_x1+10+5+$font_h;
    $square_x=$l_x1+10;
    $y=$l_y1+10;

    $i=0;
    foreach($LEGEND as $v) {
        $dy=$y+($i*$font_h);
        ImageString($im, $FONT, $text_x, $dy, $v, $black);
        ImageFilledRectangle($im,
                             $square_x+1,$dy+1,$square_x+$font_h-1,$dy+$font_h-1,
                             $COLORS[$i]);
        ImageRectangle($im,
                       $square_x+1,$dy+1,$square_x+$font_h-1,$dy+$font_h-1,
                       $black);
        $i++;
        }

Вывод круговой диаграммы

Для начала посчитаем сумму всех значений в массиве $VALUES и инициализируем массивы. В массиве $angle будет хранится угловая ширина сектора, а в массиве $anglesum начальный угол каждого сектора. Последним элементов массива $anglesum станет его первый элемент.

    $total=array_sum($VALUES);
    $anglesum=$angle=Array(0);
    $i=1;

    // Расчет углов
    while ($i<count($VALUES)) {
        $part=$VALUES[$i-1]/$total;
        $angle[$i]=floor($part*360);
        $anglesum[$i]=array_sum($angle);
        $i++;
        }
    $anglesum[]=$anglesum[0];

Расчет диаметра

    $diametr=$l_x1-10-10;

Расчет координат центра эллипса

    $circle_x=($diametr/2)+10;
    $circle_y=$H/2-10;

Поправка диаметра, если эллипс не помещается по высоте

    if ($diametr>($H*2)-10-10) $diametr=($H*2)-20-20-40;

Вывод тени

    for ($j=20;$j>0;$j--)
        for ($i=0;$i<count($anglesum)-1;$i++)
            ImageFilledArc($im,$circle_x,$circle_y+$j,
                               $diametr,$diametr/2,
                               $anglesum[$i],$anglesum[$i+1],
                               $SHADOWS[$i],IMG_ARC_PIE);

Вывод круговой диаграммы

    for ($i=0;$i<count($anglesum)-1;$i++)
        ImageFilledArc($im,$circle_x,$circle_y,
                           $diametr,$diametr/2,
                           $anglesum[$i],$anglesum[$i+1],
                           $COLORS[$i],IMG_ARC_PIE);

    } /* Конец функции вывода круговой диаграммы */

Зададим значение и подписи

$VALUES=Array(100,200,300,400,500,400,300);
$LEGEND=Array("John","Bob","Alex","Mike","Andrew","Greg");

Создадим изображение

header("Content-Type: image/png");
$im=ImageCreate(500,500);

Зададим цвет фона. Немного желтоватый, для того, чтобы было видно границы изображения на белом фоне.

$bgcolor=ImageColorAllocate($im,255,255,200);

Зададим цвета секторов

$COLORS[0] = imagecolorallocate($im, 255, 203, 3);
$COLORS[1] = imagecolorallocate($im, 220, 101, 29);
$COLORS[2] = imagecolorallocate($im, 189, 24, 51);
$COLORS[3] = imagecolorallocate($im, 214, 0, 127);
$COLORS[4] = imagecolorallocate($im, 98, 1, 96);
$COLORS[5] = imagecolorallocate($im, 0, 62, 136);
$COLORS[6] = imagecolorallocate($im, 0, 102, 179);
$COLORS[7] = imagecolorallocate($im, 0, 145, 195);
$COLORS[8] = imagecolorallocate($im, 0, 115, 106);
$COLORS[9] = imagecolorallocate($im, 178, 210, 52);
$COLORS[10] = imagecolorallocate($im, 137, 91, 74);
$COLORS[11] = imagecolorallocate($im, 82, 56, 47);

Зададим цвета теней секторов

$SHADOWS[0] = imagecolorallocate($im, 205, 153, 0);
$SHADOWS[1] = imagecolorallocate($im, 170, 51, 0);
$SHADOWS[2] = imagecolorallocate($im, 139, 0, 1);
$SHADOWS[3] = imagecolorallocate($im, 164, 0, 77);
$SHADOWS[4] = imagecolorallocate($im, 48, 0, 46);
$SHADOWS[5] = imagecolorallocate($im, 0, 12, 86);
$SHADOWS[6] = imagecolorallocate($im, 0, 52, 129);
$SHADOWS[7] = imagecolorallocate($im, 0, 95, 145);
$SHADOWS[8] = imagecolorallocate($im, 0, 65, 56);
$SHADOWS[9] = imagecolorallocate($im, 128, 160, 2);
$SHADOWS[10] = imagecolorallocate($im, 87, 41, 24);
$SHADOWS[11] = imagecolorallocate($im, 32, 6, 0);

Вызов функции рисования диаграммы

Diagramm($im,$VALUES,$LEGEND);

Генерация изображения

ImagePNG($im)

?>

Результат работы этой программы выглядит следующим образом:


500x300


500x100


150x500


120x120


300x300

Результат работы программы для изображения 4096x2048 можно посмотреть здесь.

Пример 30: Вывод круговой диаграммы. Исходный текст с сокращенным количеством комментариев:

<?php

// $im - идентификатор изображения
// $VALUES - массив со значениями
// $LEGEND - массив с подписями
function Diagramm($im,$VALUES,$LEGEND) {
	GLOBAL $COLORS,$SHADOWS;

	$black=ImageColorAllocate($im,0,0,0);

	// Получим размеры изображения
	$W=ImageSX($im);                 
	$H=ImageSY($im);

	// Вывод легенды #####################################

	// Посчитаем количество пунктов, от этого зависит высота легенды
	$legend_count=count($LEGEND);

	// Посчитаем максимальную длину пункта, от этого зависит ширина легенды
	$max_length=0;
	foreach($LEGEND as $v) if ($max_length<strlen($v)) $max_length=strlen($v);

	// Номер шрифта, котором мы будем выводить легенду
	$FONT=2;
	$font_w=ImageFontWidth($FONT);
	$font_h=ImageFontHeight($FONT);

	// Вывод прямоугольника - границы легенды ----------------------------

	$l_width=($font_w*$max_length)+$font_h+10+5+10;
	$l_height=$font_h*$legend_count+10+10;

	
	// Получим координаты верхнего левого угла прямоугольника - границы легенды
	$l_x1=$W-10-$l_width;
	$l_y1=($H-$l_height)/2;

	// Выводя прямоугольника - границы легенды
	ImageRectangle($im, $l_x1, $l_y1, $l_x1+$l_width, $l_y1+$l_height, $black);

	// Вывод текст легенды и цветных квадратиков
	$text_x=$l_x1+10+5+$font_h;
	$square_x=$l_x1+10;
	$y=$l_y1+10;

	$i=0;
	foreach($LEGEND as $v) {
		$dy=$y+($i*$font_h);
		ImageString($im, $FONT, $text_x, $dy, $v, $black);
		ImageFilledRectangle($im,
                             $square_x+1,$dy+1,$square_x+$font_h-1,$dy+$font_h-1,
                             $COLORS[$i]);
		ImageRectangle($im,
                       $square_x+1,$dy+1,$square_x+$font_h-1,$dy+$font_h-1,
                       $black);
		$i++;
		}

	// Вывод круговой диаграммы ----------------------------------------

	$total=array_sum($VALUES);
	$anglesum=$angle=Array(0);
	$i=1;

	// Расчет углов
	while ($i<count($VALUES)) {
		$part=$VALUES[$i-1]/$total;
		$angle[$i]=floor($part*360);
		$anglesum[$i]=array_sum($angle);
		$i++;
		}
	$anglesum[]=$anglesum[0];

	// Расчет диаметра
	$diametr=$l_x1-10-10;

	// Расчет координат центра эллипса
	$circle_x=($diametr/2)+10;
	$circle_y=$H/2-10;

	// Поправка диаметра, если эллипс не помещается по высоте
	if ($diametr>($H*2)-10-10) $diametr=($H*2)-20-20-40;

	// Вывод тени
	for ($j=20;$j>0;$j--)
		for ($i=0;$i<count($anglesum)-1;$i++)
			ImageFilledArc($im,$circle_x,$circle_y+$j,
                               $diametr,$diametr/2,
                               $anglesum[$i],$anglesum[$i+1],
                               $SHADOWS[$i],IMG_ARC_PIE);

	// Вывод круговой диаграммы
	for ($i=0;$i<count($anglesum)-1;$i++)
		ImageFilledArc($im,$circle_x,$circle_y,
                           $diametr,$diametr/2,
                           $anglesum[$i],$anglesum[$i+1],
                           $COLORS[$i],IMG_ARC_PIE);
	}

// Зададим значение и подписи
$VALUES=Array(100,200,300,400,500,400,300);
$LEGEND=Array("John","Bob","Alex","Mike","Andrew","Greg");

// Создадим изображения
header("Content-Type: image/png");
$im=ImageCreate(500,500);

// Зададим цвет фона. Немного желтоватый, для того, чтобы было
// видно границы изображения на белом фоне.
$bgcolor=ImageColorAllocate($im,255,255,200);

// Зададим цвета элементов
$COLORS[0] = imagecolorallocate($im, 255, 203, 3);
$COLORS[1] = imagecolorallocate($im, 220, 101, 29);
$COLORS[2] = imagecolorallocate($im, 189, 24, 51);
$COLORS[3] = imagecolorallocate($im, 214, 0, 127);
$COLORS[4] = imagecolorallocate($im, 98, 1, 96);
$COLORS[5] = imagecolorallocate($im, 0, 62, 136);
$COLORS[6] = imagecolorallocate($im, 0, 102, 179);
$COLORS[7] = imagecolorallocate($im, 0, 145, 195);
$COLORS[8] = imagecolorallocate($im, 0, 115, 106);
$COLORS[9] = imagecolorallocate($im, 178, 210, 52);
$COLORS[10] = imagecolorallocate($im, 137, 91, 74);
$COLORS[11] = imagecolorallocate($im, 82, 56, 47);

// Зададим цвета теней элементов
$SHADOWS[0] = imagecolorallocate($im, 205, 153, 0);
$SHADOWS[1] = imagecolorallocate($im, 170, 51, 0);
$SHADOWS[2] = imagecolorallocate($im, 139, 0, 1);
$SHADOWS[3] = imagecolorallocate($im, 164, 0, 77);
$SHADOWS[4] = imagecolorallocate($im, 48, 0, 46);
$SHADOWS[5] = imagecolorallocate($im, 0, 12, 86);
$SHADOWS[6] = imagecolorallocate($im, 0, 52, 129);
$SHADOWS[7] = imagecolorallocate($im, 0, 95, 145);
$SHADOWS[8] = imagecolorallocate($im, 0, 65, 56);
$SHADOWS[9] = imagecolorallocate($im, 128, 160, 2);
$SHADOWS[10] = imagecolorallocate($im, 87, 41, 24);
$SHADOWS[11] = imagecolorallocate($im, 32, 6, 0);

// Вызов функции рисования диаграммы
Diagramm($im,$VALUES,$LEGEND);

// Генерация изображения
ImagePNG($im)
?>

Ссылки по теме


Назад | Оглавление | Далее

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
48K
20 марта 2009 года
7upers
0 / / 20.03.2009
Мне нравитсяМне не нравится
20 марта 2009, 01:03:33
еще один моментик если сумма всех элементов массива $VALUES очень большая по сравнению с отдельными элементами то она составляет угол близкий к нулю от всего пирога а так как мы округляем до целых, то может возникнуть ситуация когда угол элемента =0 и тогда рисуется полный круг затирая предидущие дольки! Решение следующее: если угол =0 то дольку просто не рисуем , для этого просто добавляем условие
// Вывод тени
for ($j=60;$j>0;$j--)
for ($i=0;$i<count($anglesum)-1;$i++)
<b>if ($anglesum[$i]!=$anglesum[$i+1])</b> ImageFilledArc($im,$circle_x,$circle_y+$j,
$diametr,$diametr/2,
$anglesum[$i],$anglesum[$i+1],
$SHADOWS[$i],IMG_ARC_PIE);

// Вывод круговой диаграммы
for ($i=0;$i<count($anglesum)-1;$i++)
<b>if ($anglesum[$i]!=$anglesum[$i+1])</b> ImageFilledArc($im,$circle_x,$circle_y,
$diametr,$diametr/2,
$anglesum[$i],$anglesum[$i+1],
$COLORS[$i],IMG_ARC_PIE);
}
2.
Аноним
Мне нравитсяМне не нравится
16 ноября 2005, 16:16:17
статья отличная, пригодилось но нашёл ошибочку маленькую в процессе пользования , в куске // Расчет углов
while ($i<count($VALUES)) {
$part=$VALUES[$i-1]/$total;
$angle[$i]=floor($part*360);
$anglesum[$i]=array_sum($angle);
$i++;
}
нужно do
{
$part=$VALUES[$i-1]/$total;
$angle[$i]=floor($part*360);
$anglesum[$i]=array_sum($angle);
$i++;
}
while ($i<count($VALUES));
потому как если count($VALUES)=1 т.е позиция одна и занимает 100%; ничего не нарисует, хотя автор сам наверное всё исправил
3.
Аноним
+1 / -0
Мне нравитсяМне не нравится
25 октября 2005, 22:54:00
Спасибо за урок! Автору респект. Все просто и гениально
4.
Аноним
Мне нравитсяМне не нравится
23 апреля 2005, 16:12:10
Нужно просто потерпеть до урока №13 :)
5.
Аноним
Мне нравитсяМне не нравится
23 апреля 2005, 00:12:55
статья действительно отличная, ещё хотелось бы узнать как можно сделать края более сглажеными?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог