+ function draw_pie()
+ {
+ $n = count(self::$palette);
+ if ($this->stream == 'svg')
+ {
+ $cx = ($this->graphic_area_x1 + $this->graphic_area_x2) / 2;
+ $cy = ($this->graphic_area_y1 + $this->graphic_area_y2) / 2;
+ $width = $this->graphic_area_width;
+ $height = $this->graphic_area_height;
+ if ($this->sum_total[0] == 0)
+ $this->sum_total[0] = 1;
+ $r = $cx * 0.7;
+ $rc = $this->type == 5 ? 0.01 : $r - 25;
+ $d = $this->type == 7 ? 180 : 360; // half donut or all
+ $area = $d / $this->sum_total[0];
+ $start = $this->type == 7 ? 180 : 90;
+ $rad = pi() / 180.;
+ $out='';
+ $gap=0.01;
+ $ang1=0; // start angle
+ foreach ($this->labels as $i => $num)
+ {
+ $n = count(self::$palette);
+ $pct[$i] = round($this->series[0]['data'][$i] / $this->sum_total[0] * 100, 1);
+ $dang = $this->series[0]['data'][$i] * $area; // delta angle
+ $laf = $dang > 180 ? 1 : 0; // Large Arc Flag
+ $ang2 = $ang1 + $dang; // second angle
+ $a = ($ang1 - $start) * $rad + asin($gap / $rc);
+ $p1 = sprintf('%0.2f,%0.2f', $cx + $rc * cos($a), $cy + $rc * sin($a));
+ $a = ($ang1 - $start) * $rad + asin($gap / $r);
+ $p2 = sprintf('%0.2f,%0.2f', $cx + $r * cos($a), $cy + $r * sin($a));
+ $a = ($ang2 - $start) * $rad - asin($gap / $r);
+ $p3 = sprintf('%0.2f,%0.2f', $cx + $r * cos($a), $cy + $r * sin($a));
+ $a = ($ang2 - $start) * $rad - asin($gap / $rc);
+ $p4 = sprintf('%0.2f,%0.2f', $cx + $rc * cos($a), $cy + $rc * sin($a));
+ $a = ($ang1 - $start) * $rad + asin($gap / $rc);
+ $p5 = sprintf('%0.2f,%0.2f', $cx + $rc * cos($a), $cy + $rc * sin($a));
+ $this->svg->path("M$p1 L$p2 A$r,$r 0 $laf,1 $p3 L$p4 A$rc,$rc 0 $laf,0 $p5", $this->color[$i % $n], 0, $this->color[$i % $n], "class=\"tips\"", "$num: ".number_format($pct[$i], 1)."%");
+ $ang1=$ang2;
+ }
+ if (!empty($this->donut_title) && $this->type != 5)
+ {
+ // Display center text
+ if ($this->type == 6)
+ $cy += 5;
+ $this->svg->text($cx, $cy, $this->donut_title, $this->size, $this->color[0], "style=\"font-size:18px;font-weight:bold;\"", "middle");
+ }
+ }
+ else
+ {
+ $start = 0;
+ $sizes = array();
+ $degrees = $this->type == 7 ? 180 : 360; // half donut or all
+ foreach ($this->labels as $i => $parameter)
+ {
+ if ($this->sum_total[0] == 0)
+ $this->sum_total[0] = 1;
+ if ($this->series[0]['data'][$i] < 0)
+ $this->series[0]['data'][$i] = 0;
+ $size = $this->series[0]['data'][$i] * $degrees / $this->sum_total[0];
+ $size = round($size, 0);
+ $sizes[] = $size;
+ $start += $size;
+ }
+ $center_x = ($this->graphic_area_x1 + $this->graphic_area_x2) / 2;
+ $center_y = ($this->graphic_area_y1 + $this->graphic_area_y2) / 2;
+ $width = $this->graphic_area_width;
+ $height = $this->graphic_area_height;
+ $start = $this->type == 7 ? 180 : 270;
+ // Draw pieces
+ foreach ($sizes as $i => $size)
+ {
+ $j = $i % $n;
+ $color = 'arc_' . $j;
+ if ($size >= 1)
+ imagefilledarc($this->img, $center_x, $center_y, $width, $height, $start, ($start+$size), $this->color[$color], IMG_ARC_PIE);
+ $start += $size;
+ }
+ if ($this->type != 5) // DONUTS
+ {
+ // 85 pixels width hole
+ $start = $this->type == 7 ? 180 : 0;
+ imagefilledarc($this->img, $center_x, $center_y, 85, 85, $start, 360, $this->color['background'], IMG_ARC_PIE);
+ imagearc($this->img, $center_x, $center_y, 85, 85, $start, 360, $this->color['bg_legend']);
+ imagearc($this->img, $center_x, $center_y, ($width+1), ($height+1), $start, 360, $this->color['bg_legend']);
+ if (!empty($this->donut_title))
+ {
+ $plen = $this->string_width($this->donut_title, $this->size);
+ $x1 = $center_x - $plen / 2 - 6;
+ $co = $this->type == 7 ? 20 : 10; // HALF or ALL
+ $this->_imagestring($this->img, $this->size + 4, $x1, $center_y - $co, $this->donut_title, $this->color['arc_0'], 2, 0);
+ $this->_imagestring($this->img, $this->size + 4, $x1+1, $center_y - $co, $this->donut_title, $this->color['arc_0'], 2, 0);
+ }
+ }
+ }
+ }
+
+ function draw_table()
+ {
+ $cs = $this->num_labels + 1;
+ $html = "<table cellspacing='0' //style='width:{$this->width}px;font-family:{$this->font};font-size:12px;background:inherit;'>\n";
+ if (!empty($this->title))
+ $html .= "<tr><th colspan=$cs style='text-align:center;'><h3>$this->title</th><tr>\n";
+ $html .= "<tr><th style='border-bottom:1px solid #444'>#</th>";
+ for ($i = 0; $i < $this->num_labels; $i++)
+ $html .= "<th style='text-align:right;border-bottom:1px solid #444'>{$this->labels[$i]}</th>";
+ $html .= "</tr>\n";
+ for ($j = 0; $j < $this->num_series; $j++)
+ {
+ $html .= "<tr><td style=''>{$this->series[$j]['label']}</td>";
+ for ($i = 0; $i < $this->num_labels; $i++)
+ $html .= "<td style='text-align:right;'>".number_format($this->series[$j]['data'][$i], 0)."</td>";
+ $html .= "</tr>\n";
+ }
+ $html .= "</table>\n";
+ echo $html;
+ }
+
+ function calculate_width()
+ {
+ $this->legend_box_width = ($this->legend_exists == true) ? ($this->string_width($this->max_legend_str, $this->size) + 70) : 0;
+ switch ($this->type)
+ {
+ // Vertical bars or Table
+ case 1:
+ case 9:
+ $this->graphic_area_x1 += $this->string_width($this->higher_value_str, $this->size);
+ if (!empty($this->width))
+ $this->graphic_area_width = $this->width - $this->graphic_area_x1 - 30 - $this->legend_box_width;
+ else
+ {
+ $gap_series = 10;
+ $gap_labels = 5;
+ $serie_width = 0;
+ for ($j = 0; $j < $this->num_series; $j++)
+ {
+ if ($this->series[$j]['type'] != 4 && $this->series[$j]['type'] != 8)
+ $serie_width += $this->bar_width;
+ $serie_width += $gap_labels;
+ }
+ $serie_width += $gap_series;
+ $this->graphic_area_width = $serie_width * $this->num_labels;
+ $this->width += $this->graphic_area_width;
+ $this->width += $this->graphic_area_x1;
+ $this->width += $this->legend_box_width;
+ }
+ break;
+ // Horizontal bars
+ case 2:
+ $this->graphic_area_x1 += $this->string_width($this->max_label, $this->size);
+ if (!empty($this->width))
+ $this->graphic_area_width = $this->width - $this->graphic_area_x1 - 30 - $this->legend_box_width;
+ else
+ {
+ $this->graphic_area_width = ($this->string_width($this->higher_value_str, $this->size) > 50) ? (5 * ($this->string_width($this->higher_value_str, $this->size)) * 0.85) : 200;
+ $this->width += $this->graphic_area_x1;
+ $this->width += $this->graphic_area_width;
+ $this->width += $this->legend_box_width;
+ }
+ break;
+ // Dots
+ case 3:
+ // Lines
+ case 4:
+ // Splines
+ case 8:
+ $this->graphic_area_x1 += $this->string_width(($this->higher_value_str), $this->size);
+ if (!empty($this->width))
+ $this->graphic_area_width = $this->width - $this->graphic_area_x1 - 30 - $this->legend_box_width;
+ else
+ {
+ $this->graphic_area_width = $this->space_between_dots * ($this->num_labels - 1) + 5;
+ $this->width += $this->graphic_area_width;
+ $this->width += $this->graphic_area_x1 + 30;
+ $this->width += $this->legend_box_width;
+ }
+ break;
+ // Pie
+ case 5:
+ // Donut
+ case 6:
+ // Half Donut
+ case 7:
+ $this->legend_box_width += 60;
+ if (!empty($this->width))
+ $this->graphic_area_width = $this->width - $this->graphic_area_x1 - 30 - $this->legend_box_width;
+ else
+ {
+ $this->graphic_area_width = 150;
+ $this->width += $this->graphic_area_x1 +20;
+ $this->width += $this->legend_box_width;
+ $this->width += $this->graphic_area_width;
+ $this->width += 90;
+ }
+ break;
+ }
+ $this->graphic_area_width = max($this->graphic_area_width, $this->string_width($this->title, $this->size));
+ $this->graphic_area_x2 = $this->graphic_area_x1 + $this->graphic_area_width;
+ $this->legend_box_x1 = $this->graphic_area_x2 + 20;
+ $this->legend_box_x2 = $this->legend_box_x1 + $this->legend_box_width;
+ }
+
+ function calculate_height()
+ {
+ switch ($this->type)
+ {
+ // Vertical bars
+ case 1:
+ if (!empty($this->height))
+ $this->graphic_area_height = $this->height - $this->title_height;
+ else
+ {
+ $this->graphic_area_height = 150;
+ $this->height += 65;
+ }
+ break;
+ // Horizontal bars
+ case 2:
+ if (!empty($this->height))
+ $this->graphic_area_height = $this->height - $this->title_height;
+ else
+ {
+ $gap_labels = 12;
+ if ($this->stream != 'svg')
+ $gap_labels += 6;
+ $this->graphic_area_height = $this->num_series * $this->bar_width * $this->num_labels + $this->num_labels * $gap_labels;
+ $this->height += 65;
+ }
+ break;
+ // Dots
+ case 3:
+ // Lines
+ case 4:
+ // Spines
+ case 8:
+ if (!empty($this->height))
+ $this->graphic_area_height = $this->height - $this->title_height;
+ else
+ {
+ $this->graphic_area_height = 150;
+ $this->height += 65;
+ }
+ break;
+ // Pie
+ case 5:
+ // Donut
+ case 6:
+ // Half Donut
+ case 7:
+ if (!empty($this->height))
+ $this->graphic_area_height = $this->height - $this->title_height;
+ else
+ {
+ $this->graphic_area_height = 150;
+ $this->height += 65;
+ }
+ break;
+ }
+ //if ($this->type == 7) // Half Donut;
+ $this->graphic_area_y1 -= 10;
+ $this->legend_box_y1 = $this->graphic_area_y1;
+ $this->height += $this->graphic_area_height + 40;
+ $this->graphic_area_y2 = $this->graphic_area_y1 + $this->graphic_area_height;
+ $this->legend_box_y2 = $this->legend_box_y1 + $this->legend_box_height;
+ }
+
+ function draw_legend()
+ {
+ $x1 = $this->legend_box_x1;
+ $y1 = $this->legend_box_y1;
+ $x2 = $this->legend_box_x2;
+ $y2 = $this->legend_box_y2;
+ if ($this->stream == 'svg')
+ $this->svg->rect($x1, $y1, $x2, $y2, $this->color['bg_legend']);
+ else
+ imagefilledrectangle($this->img, $x1, $y1, $x2, $y2, $this->color['bg_legend']);
+ $x = $x1 + 10;
+ $y = $y1;
+ // Draw legend values for VERTICAL BARS, HORIZONTAL BARS, DOTS, LINES AND SPLINES
+ if (preg_match("/^(1|2|3|4|8)$/", $this->type))
+ {
+ for ($j = 0; $j < $this->num_series; $j++)
+ {
+ $color = (preg_match("/^(1|2)$/", $this->type)) ? $this->color['bars'][$j] : $this->color['line'][$j];
+ $len = $this->string_width($this->max_legend_str, $this->size)-20;
+ if ($this->stream == 'svg')
+ {
+ $lex = $this->dir == 'rtl' ? $x1+$len : $x1-5;
+ $this->svg->circle($lex, $y-5, 6, "#fff", 1, $color);
+ //$this->svg->rect($lex, $y-10, 10, 10, "#fff", 1, $color);
+ $lex = $this->dir == 'rtl' ? $x1+$len-15 : $x-5;
+ $this->svg->text($lex, ($y-2), $this->series[$j]['label'], $this->size, $this->color['axis_values'], false, "start");
+ }
+ else
+ {
+ $lex = $this->dir == 'rtl' ? $x1+$len+20 : $x-10;
+ imagefilledrectangle($this->img, $lex, $y, ($lex+10), ($y+10), $color);
+ imagerectangle($this->img, $lex, $y, ($lex+10), ($y+10), $this->color['title']);
+ $lex = $this->dir == 'rtl' ? $x1+$len+20 : $x+10;
+ $this->_imagestring($this->img, $this->size, $lex, ($y-2), $this->series[$j]['label'], $this->color['axis_values'], 0, 0, $this->align);
+ }
+ $y += 20;
+ }
+ }
+ // Draw legend values for PIE, DONUT or HALF DONUT
+ else if (preg_match("/^(5|6|7)$/", $this->type))
+ {
+ $n = count(self::$palette);
+ if ($this->sum_total[0] == 0)
+ return;
+ $label_len = $this->string_width($this->max_label, $this->size);
+ //$value_len = $this->string_width($this->max_value, $this->size);
+ $value_len = $this->string_width(number_format($this->max_value), $this->size);
+ $total_len = $label_len + $value_len;
+ $total_len = max($total_len, $x2-$x1);
+ if (!empty($this->axis_x)) // Only first serie [0]
+ {
+ if ($this->stream == 'svg')
+ $this->svg->text(((($x1+$x1+$total_len)/2) - (strlen($this->axis_x)*7/2)), $y, $this->axis_x." (".$this->series[0]['label'].")", $this->size, $this->color['title'], false, $this->align);
+ else
+ $this->_imagestring($this->img, $this->size, (($x1+$x1+$total_len)/2 - strlen($this->axis_x)*7/2)+30, $y,
+ $this->axis_x."-".$this->series[0]['label'], $this->color['title']);
+ $y += 25;
+ }
+ foreach ($this->labels as $i => $parameter)
+ {
+ if ($this->set_values)
+ $text = number_format($this->series[0]['data'][$i]);
+ else
+ $text = number_format($this->series[0]['data'][$i] * 100 / $this->sum_total[0], 2) . ' %';
+ if ($this->stream == 'svg')
+ {
+ $j = $i % $n;
+ $lex = $this->dir == 'rtl' ? $x1+$total_len-25 : $x1;
+ $this->svg->circle($lex, $y-5, 6, "#fff", 1, $this->color[$j]);
+ // $this->svg->rect($lex-5, $y-10, 10, 10, "#fff", 1, $this->color[$j]);
+ // Display label text
+ $lex = $this->dir == 'rtl' ? $x1+$total_len-40 : $x1+15;
+ $this->svg->text($lex, ($y-2), $parameter, $this->size, $this->color['axis_values'], false, "start");
+ $lex = $this->dir == 'rtl' ? $x1+$value_len-25 : $x1+$total_len;
+ $al = $this->dir == 'rtl' ? "start" : "end";
+ $this->svg->text($lex, ($y-2), $text, $this->size, $this->color['axis_values'], false, $al);
+ $lex2 = $this->dir == 'rtl' ? $x1+$total_len-25 : $x1+$total_len;
+ $this->svg->line($x1, $y+1, $lex2, $y+1, $this->color['bg_lines']);
+ }
+ else
+ {
+ $j = $i % $n;
+ $color = 'arc_' . $j;
+ $width = $this->string_width($text, $this->size);
+ imageline($this->img, $x1+15, ($y+11), $x2+20, ($y+11), $this->color['bg_lines']);
+ $lex = $this->dir == 'rtl' ? $x2+20 : $x;
+ imagefilledrectangle($this->img, $lex, $y, ($lex+10), ($y+10), $this->color[$color]);
+ imagerectangle($this->img, $lex, $y, ($lex+10), ($y+10), $this->color['title']);
+ $lex = $this->dir == 'rtl' ? $x2+5 : $x+15;
+ $this->_imagestring($this->img, $this->size, $lex, ($y-2), $parameter, $this->color['axis_values'], 0, 0, $this->align);
+ //$lex = $this->dir == 'rtl' ? $x+10 : $x2-$width;
+ $lex = $this->dir == 'rtl' ? $x1+$value_len : $x2-$width;
+ $al = $this->dir == 'rtl' ? "end" : $this->align;
+ $this->_imagestring($this->img, $this->size, $lex, ($y-2), $text, $this->color['axis_values'], 0, 0, $al);
+ }
+ $y += 18;
+ }
+ }
+ }
+
+ function string_width($string, $size)
+ {
+ if ($string == NULL)
+ return $size;
+ $p = imageftbbox($size, 0, $this->fontfile, $string);
+ return $p[4] - $p[0];
+ }
+
+ function calculate_higher_value()
+ {
+ $digits = strlen(round($this->max_value));
+ $interval = pow(10, ($digits-1));
+ $this->higher_value = round(($this->max_value - ((int)$this->max_value % $interval) + $interval), 1);
+ $this->higher_value_str = $this->number_formated($this->higher_value, $this->dec1);
+ }
+
+ function number_formated($number, $dec_size = 1)
+ {
+ if ($this->latin_notation == true)
+ return number_format(round($number, $dec_size), $dec_size, ",", ".");
+ return number_format(round($number, $dec_size), $dec_size, ".", ",");
+ }
+
+ function load_color_palette($type)
+ {
+ // The usual color palette. Change if you like. Must be 6 colors.
+ $color = self::$palette;
+ if ($this->stream == 'svg')
+ {
+ $this->color['title'] = sprintf("#%02x%02x%02x", 40, 70, 130);
+ $this->color['background'] = sprintf("#%02x%02x%02x", 255, 255, 255);
+ $this->color['axis_values'] = sprintf("#%02x%02x%02x", 50, 50, 50);
+ $this->color['axis_line'] = sprintf("#%02x%02x%02x", 100, 100, 100);
+ $this->color['bg_lines'] = sprintf("#%02x%02x%02x", 220, 220, 220);
+ $this->color['bg_legend'] = sprintf("#%02x%02x%02x", 255, 255, 255);
+ $this->color['shadow'] = sprintf("#%02x%02x%02x", 255, 255, 255);
+
+ if (preg_match("/^(1|2)$/", $type)) // Vertical Bar or Horizontal bar
+ {
+ for ($j = 0; $j < $this->num_series; $j++)
+ {
+ $this->color['bars'][$j] = $color[$j];
+ }
+ }
+ elseif (preg_match("/^(3|4|8)$/", $type)) // Dots, Lines or Splines
+ {
+ for ($j = 0; $j < $this->num_series; $j++)
+ {
+ $this->color['line'][$j] = $color[$j];
+ $this->color['line_light'][$j] = $this->colorLuminate($color[$j], 0.8);
+ }
+ }
+ elseif (preg_match("/^(5|6|7)$/", $type)) // Pie, Donut or Half Donut
+ {
+ $n = count($color);
+ for ($j = 0; $j < $n; $j++)
+ $this->color[$j] = $color[$j];
+ }
+ }
+ else
+ {
+ $this->color['title'] = imagecolorallocate($this->img, 40, 70, 130);
+ $this->color['background'] = imagecolorallocate($this->img, 255, 255, 255);
+ $this->color['axis_values'] = imagecolorallocate($this->img, 50, 50, 50);
+ $this->color['axis_line'] = imagecolorallocate($this->img, 100, 100, 100);
+ $this->color['bg_lines'] = imagecolorallocate($this->img, 220, 220, 220);
+ $this->color['bg_legend'] = imagecolorallocate($this->img, 255, 255, 255);
+ $this->color['shadow'] = imagecolorallocate($this->img, 255, 255, 255);
+
+ if (preg_match("/^(1|2)$/", $type)) // Vertical Bar or Horizontal bar
+ {
+ for ($j = 0; $j < $this->num_series; $j++)
+ {
+ $c = $this->hex2rgb($color[$j]);
+ $this->color['bars'][$j] = imagecolorallocate($this->img, $c[0], $c[1], $c[2]);
+ }
+ }
+ else if (preg_match("/^(3|4|8)$/", $type)) // Dots, Lines or Splines
+ {
+ for ($j = 0; $j < $this->num_series; $j++)
+ {
+ $c = $this->hex2rgb($color[$j]);
+ $this->color['line'][$j] = imagecolorallocate($this->img, $c[0], $c[1], $c[2]);
+ $c = $this->hex2rgb($this->colorLuminate($color[$j], 0.8)); // lighten for Areas
+ $this->color['line_light'][$j] = imagecolorallocate($this->img, $c[0], $c[1], $c[2]);
+ }
+ }
+ else if (preg_match("/^(5|6|7)$/", $type)) // Pie, Donut or Half Donut
+ {
+ $n = count($color);
+ for ($j = 0; $j < $n; $j++)
+ {
+ $c = $this->hex2rgb($color[$j]);
+ $this->color["arc_{$j}"] = imagecolorallocate($this->img, $c[0], $c[1], $c[2]);
+ }
+ }
+ }
+ }