From 8aac162cd417b18a0f3919cb2496ce4c15039277 Mon Sep 17 00:00:00 2001 From: m-lopez-f Date: Fri, 10 Jun 2016 11:11:11 +0200 Subject: [PATCH] Fixed problems when selected no interactive charts or print pdfs. Tiquet: #3742 (cherry picked from commit d058d096d7b641f595c6801f792b11079a724d33) --- .../include/functions_custom_graphs.php | 6 +- pandora_console/include/functions_graph.php | 62 +- .../include/functions_reporting.php | 2 +- pandora_console/include/graphs/fgraph.php | 128 +++- .../include/graphs/functions_pchart.php | 162 +++- .../include/graphs/pChart/pData.class.php | 64 ++ .../include/graphs/pChart/pPie.class.php | 721 ++++++++++++++++++ 7 files changed, 1106 insertions(+), 39 deletions(-) diff --git a/pandora_console/include/functions_custom_graphs.php b/pandora_console/include/functions_custom_graphs.php index 55dfee8146..a4ac261cb0 100644 --- a/pandora_console/include/functions_custom_graphs.php +++ b/pandora_console/include/functions_custom_graphs.php @@ -198,11 +198,11 @@ function custom_graphs_print($id_graph, $height, $width, $period, foreach ($sources as $source) { array_push ($modules, $source['id_agent_module']); array_push ($weights, $source['weight']); - $labels[$source['id_agent_module']] = $source['label']; + if ($source['label'] != '') + $labels[$source['id_agent_module']] = $source['label']; } } - - + if ($sources === false) { if ($return){ diff --git a/pandora_console/include/functions_graph.php b/pandora_console/include/functions_graph.php index 15088eb3ea..9c860c79d3 100644 --- a/pandora_console/include/functions_graph.php +++ b/pandora_console/include/functions_graph.php @@ -976,7 +976,7 @@ function graphic_combined_module ($module_list, $weight_list, $period, $only_image = false, $homeurl = '', $ttl = 1, $projection = false, $prediction_period = false, $background_color = 'white', $name_list = array(), $unit_list = array(), $show_last = true, $show_max = true, - $show_min = true, $show_avg = true, $labels = false, $dashboard = false, $vconsole = false) { + $show_min = true, $show_avg = true, $labels = array(), $dashboard = false, $vconsole = false) { global $config; global $graphic_type; @@ -1414,6 +1414,22 @@ function graphic_combined_module ($module_list, $weight_list, $period, } $temp = array(); + $user = users_get_user_by_id($config['id_user']); + $user_flash_charts = $user['flash_chart']; + + if ($user_flash_charts == 1) + $flash_charts = true; + elseif($user_flash_charts == -1) + $flash_charts = $config['flash_charts']; + elseif($user_flash_charts == 0) + $flash_charts = false; + + if ($only_image) { + $flash_charts = false; + } + + if ($flash_charts === false && $stacked == CUSTOM_GRAPH_GAUGE) + $stacked = CUSTOM_GRAPH_BULLET_CHART; switch ($stacked) { case CUSTOM_GRAPH_BULLET_CHART: @@ -1456,8 +1472,13 @@ function graphic_combined_module ($module_list, $weight_list, $period, $value = false; } - if ($labels[$module] != '') - $temp[$module]['label'] = $labels[$module]; + + if ( !empty($labels) && isset($labels[$module]) ) + $label = io_safe_input($labels[$module]); + else + $label = agents_get_name($temp[$module]['id_agente']) . ': ' . $temp[$module]['nombre']; + + $temp[$module]['label'] = $label; $temp[$module]['value'] = $value; $temp[$module]['max'] = reporting_get_agentmodule_data_max($module,$period,$date); $temp[$module]['min'] = reporting_get_agentmodule_data_min($module,$period,$date); @@ -1507,7 +1528,7 @@ function graphic_combined_module ($module_list, $weight_list, $period, $agent_name = io_safe_output( modules_get_agentmodule_agent_name ($module)); - if ($labels[$module] != '') + if (!empty($labels) && isset($labels[$module]) ) $label = $labels[$module]; else $label = $agent_name . " - " .$module_data['nombre']; @@ -1547,10 +1568,12 @@ function graphic_combined_module ($module_list, $weight_list, $period, SELECT datos FROM tagente_datos WHERE id_agente_modulo = %d + AND utimestamp > %d AND utimestamp < %d ORDER BY utimestamp DESC', - $module, $date); + $module, $datelimit, $date); $temp_data = db_get_value_sql($query_last_value); + if ( $temp_data ){ if (is_numeric($temp_data)) $value = $temp_data; @@ -1562,17 +1585,15 @@ function graphic_combined_module ($module_list, $weight_list, $period, } $total_modules += $value; - if ( !isset($labels[$module]) ) - $label = $labels[$module]; - else - $label = $data_module['nombre']; - - $label = io_safe_output($label); - $temp[$label] = array( - 'value'=>$value, - 'unit'=>$data_module['unit']); - + if ( !empty($labels) && isset($labels[$module]) ) + $label = io_safe_input($labels[$module]); + else { + $agent_name = agents_get_name($data_module['id_agente']); + $label = $agent_name . ": " . $data_module['nombre']; + } + $temp[$label] = array('value'=>$value, + 'unit'=>$data_module['unit']); if ($config['metaconsole']) { // Automatic custom graph from the report template in metaconsole if (is_array($module_list[0])) { @@ -1581,6 +1602,7 @@ function graphic_combined_module ($module_list, $weight_list, $period, } } $temp['total_modules'] = $total_modules; + break; case CUSTOM_GRAPH_GAUGE: $datelimit = $date - $period; @@ -1767,7 +1789,7 @@ function graphic_combined_module ($module_list, $weight_list, $period, return stacked_bullet_chart($flash_charts, $graph_values, $width, $height, $color, $module_name_list, $long_index, ui_get_full_url("images/image_problem.opaque.png", false, false, false), - "", "", $water_mark, $config['fontpath'], $fixed_font_size, + "", "", $water_mark, $config['fontpath'], ($config['font_size']+1), "", $ttl, $homeurl, $background_color); break; case CUSTOM_GRAPH_GAUGE: @@ -1792,11 +1814,9 @@ function graphic_combined_module ($module_list, $weight_list, $period, "", $ttl, $homeurl, $background_color); break; case CUSTOM_GRAPH_PIE: - return flot_custom_pie_chart($flash_charts, $graph_values, - $width, $height, $color, $module_name_list, $long_index, - ui_get_full_url("images/image_problem.opaque.png", false, false, false), - "", "", $water_mark, $config['fontpath'], ($config['font_size']+1), - "", $ttl, $homeurl, $background_color,'other'); + return ring_graph($flash_charts, $graph_values, $width, $height, + $others_str, $homeurl, $water_mark, $config['fontpath'], + ($config['font_size']+1), 1, false, $color, false); break; } } diff --git a/pandora_console/include/functions_reporting.php b/pandora_console/include/functions_reporting.php index 0090135b7d..d6c0498311 100644 --- a/pandora_console/include/functions_reporting.php +++ b/pandora_console/include/functions_reporting.php @@ -4351,7 +4351,7 @@ function reporting_custom_graph($report, $content, $type = 'dinamic', $weights, $content['period'], $width, $height, - 'Combined%20Sample%20Graph', + __('Combined%20Sample%20Graph'), '', 0, 0, diff --git a/pandora_console/include/graphs/fgraph.php b/pandora_console/include/graphs/fgraph.php index e8f4b3d1cf..ae6800aca9 100644 --- a/pandora_console/include/graphs/fgraph.php +++ b/pandora_console/include/graphs/fgraph.php @@ -427,18 +427,49 @@ function stacked_bullet_chart($flash_chart, $chart_data, $width, $height, if (empty($chart_data)) { return ''; } + if ($flash_chart) { + return d3_bullet_chart( + $chart_data, + $width, + $height, + $color, + $legend, + $homeurl, + $unit, + $font, + $font_size + ); + } + else { + $legend = array(); + $new_data = array(); + foreach($chart_data as $key => $data) { + $temp[] = ($data['min'] != false) ? $data['min'] : 0; + $temp[] = ($data['value'] != false) ? $data['value'] : 0; + $temp[] = ($data['max'] != false) ? $data['max'] : 0; + + $legend[] = $data['label']; + array_push($new_data, $temp); + $temp = array(); + } + $graph = array(); + $graph['data'] = $new_data; + $graph['width'] = $width; + $graph['height'] = $height; + $graph['color'] = $color; + $graph['legend'] = $legend; + $graph['xaxisname'] = $xaxisname; + $graph['yaxisname'] = $yaxisname; + $graph['water_mark'] = $water_mark_file; + $graph['font'] = $font; + $graph['font_size'] = $font_size; + $graph['backgroundColor'] = $backgroundColor; + + $id_graph = serialize_in_temp($graph, null, $ttl); + + return ""; + } - return d3_bullet_chart( - $chart_data, - $width, - $height, - $color, - $legend, - $homeurl, - $unit, - $font, - $font_size - ); } function stacked_gauge($flash_chart, $chart_data, $width, $height, @@ -685,4 +716,79 @@ function pie_graph($graph_type, $flash_chart, $chart_data, $width, } } +function ring_graph($flash_chart, $chart_data, $width, + $height, $others_str = "other", $homedir="", $water_mark = "", + $font = '', $font_size = '', $ttl = 1, $legend_position = false, + $colors = '', $hide_labels = false) { + + if (empty($chart_data)) { + return graph_nodata_image($width, $height, 'pie'); + } + + setup_watermark($water_mark, $water_mark_file, $water_mark_url); + + // This library allows only 8 colors + $max_values = 18; + + + if ($flash_chart) { + return flot_custom_pie_chart ($flash_chart, $chart_data, + $width, $height, $colors, $module_name_list, $long_index, + $no_data, false, '', $water_mark, $font, $font_size, + $unit, $ttl, $homeurl, $background_color, $legend_position); + } + else { + $total_modules = $chart_data['total_modules']; + unset($chart_data['total_modules']); + + + //Remove the html_entities + $n = 0; + $temp = array(); + $coloretes = array(); + foreach ($chart_data as $key => $value) { + $temp[io_safe_output($key)] = $value['value']; + $legend[] = io_safe_output($key) .": " . $value['value'] . " " .$value['unit']; + //~ $coloretes[$n] = $colors[$n]['color']; + //~ $n++; + } + $chart_data = $temp; + + $chart_data_trunc = array(); + $coloretes = array(); + $n = 1; + foreach ($chart_data as $key => $value) { + if ($n < $max_values) { + + $chart_data_trunc[$key] = $value; + } + //~ else { + //~ if (!isset($chart_data_trunc[$others_str])) { + //~ $chart_data_trunc[$others_str] = 0; + //~ } + //~ $chart_data_trunc[$others_str] += $value; + //~ } + $n++; + } + $chart_data = $chart_data_trunc; + + //TODO SET THE LEGEND POSITION + + $graph = array(); + $graph['data'] = $chart_data; + $graph['width'] = $width; + $graph['height'] = $height; + $graph['water_mark'] = $water_mark_file; + $graph['font'] = $font; + $graph['font_size'] = $font_size; + $graph['legend_position'] = $legend_position; + $graph['legend'] = $legend; + + $id_graph = serialize_in_temp($graph, null, $ttl); + + return ""; + + } +} + ?> diff --git a/pandora_console/include/graphs/functions_pchart.php b/pandora_console/include/graphs/functions_pchart.php index f8568f30c5..13e933bb0a 100644 --- a/pandora_console/include/graphs/functions_pchart.php +++ b/pandora_console/include/graphs/functions_pchart.php @@ -79,7 +79,7 @@ if (isset($graph['color'])) { if (isset($graph['legend'])) { $legend = $graph['legend']; } -if (isset($graph['xaxisname'])) { +if (isset($graph['xaxisname'])) { $xaxisname = $graph['xaxisname']; } if (isset($graph['yaxisname'])) { @@ -188,6 +188,29 @@ switch ($graph_type) { } $colors = $fine_colors; + break; + case 'bullet_chart': + $anterior = 0; + foreach ($data as $i => $values) { + foreach ($values as $key => $val) { + switch ($key) { + case 0: + $name = __("Max"); + break; + case 1: + $name = __("Actual"); + break; + case 2: + $name = __("Min"); + break; + } + $data_values[$name][] = ($val - $anterior); + $anterior += (($val - $anterior)<0) ? 0 : ($val - $anterior); + } + $anterior = 0; + $data_keys[] = $i; + + } break; case 'progress': case 'area': @@ -216,6 +239,8 @@ switch ($graph_type) { case 'radar': case 'pie3d': case 'pie2d': + case 'ring3d': + break; } @@ -225,6 +250,8 @@ switch($graph_type) { case 'radar': case 'pie3d': case 'pie2d': + case 'ring3d': + case 'bullet_chart': break; default: if (!is_array(reset($data_values))) { @@ -282,6 +309,14 @@ foreach ($colors as $i => $color) { ob_get_clean(); //HACK TO EAT ANYTHING THAT CORRUPS THE IMAGE FILE switch ($graph_type) { + case 'ring3d': + pch_ring_graph($graph_type, array_values($data), $legend, + $width, $height, $font, $water_mark, $font_size, $legend_position, $colors); + break; + case 'bullet_chart': + pch_bullet_chart($graph_type, $data_values, $legend, + $width, $height, $font, $water_mark, $font_size, $legend_position, $colors); + break; case 'pie3d': case 'pie2d': pch_pie_graph($graph_type, array_values($data), array_keys($data), @@ -454,6 +489,74 @@ function pch_pie_graph ($graph_type, $data_values, $legend_values, $width, $myPicture->stroke(); } +function pch_ring_graph ($graph_type, $data_values, $legend_values, $width, + $height, $font, $water_mark, $font_size, $legend_position, $colors) { + /* CAT:Ring charts */ + + /* Create and populate the pData object */ + $MyData = new pData(); + $MyData->addPoints($data_values,"ScoreA"); + $MyData->setSerieDescription("ScoreA","Application A"); + + /* Define the absissa serie */ + $MyData->addPoints($legend_values,"Labels"); + $MyData->setAbscissa("Labels"); + + /* Create the pChart object */ + $myPicture = new pImage($width,$height,$MyData,TRUE); + + /* Set the default font properties */ + $myPicture->setFontProperties(array("FontName"=>$font,"FontSize"=>$font_size,"R"=>80,"G"=>80,"B"=>80)); + + $water_mark_height = 0; + $water_mark_width = 0; + if (!empty($water_mark)) { + if (is_array($water_mark)) { + if (!empty($water_mark['file'])) { + $water_mark = $water_mark['file']; + } + } + + $size_water_mark = getimagesize($water_mark); + $water_mark_height = $size_water_mark[1]; + $water_mark_width = $size_water_mark[0]; + + $myPicture->drawFromPNG(($width - $water_mark_width), + ($height - $water_mark_height) - 50, $water_mark); + } + + + /* Create the pPie object */ + $PieChart = new pPie($myPicture,$MyData); + foreach ($legend_values as $key => $value) { + if (isset($colors[$value])) { + $PieChart->setSliceColor($key, hex_2_rgb($colors[$value])); + } + } + + /* Draw an AA pie chart */ + $PieChart->draw3DRing($width/3, $height/2,array("InnerRadius"=>100, "InnerRadius"=>10,"DrawLabels"=>TRUE,"LabelStacked"=>FALSE,"Precision"=>2,"Border"=>FALSE,"WriteValues"=>TRUE,"ValueR"=>0,"ValueG"=>0,"ValueB"=>0,"ValuePadding" => 15)); + + + /* Write down the legend next to the 2nd chart*/ + //Calculate the bottom margin from the size of string in each index + $max_chars = graph_get_max_index($legend_values); + + if ($legend_position != 'hidden') { + // This is a hardcore adjustment to match most of the graphs, please don't alter + $legend_with_aprox = 150 + (4.5 * $max_chars); + + $PieChart->drawPieLegend($width - $legend_with_aprox, 10, array("R"=>255,"G"=>255,"B"=>255, "BoxSize"=>10)); + } + + /* Enable shadow computing */ + $myPicture->setShadow(TRUE, + array("X" => 3, "Y" => 3, "R" => 0, "G" => 0, "B" => 0, "Alpha" => 10)); + + /* Render the picture */ + $myPicture->stroke(); +} + function pch_kiviat_graph ($graph_type, $data_values, $legend_values, $width, $height, $font, $font_size) { /* CAT:Radar/Polar charts */ @@ -684,7 +787,7 @@ function pch_vertical_graph ($graph_type, $index, $data, $width, $height, "BorderG" => $rgb_color[$i]['border']["G"], "BorderB" => $rgb_color[$i]['border']["B"], "Alpha" => $rgb_color[$i]['alpha'])); - + /*$palette_color = array(); if (isset($rgb_color[$i]['color'])) { $palette_color["R"] = $rgb_color[$i]['color']["R"]; @@ -997,7 +1100,60 @@ function pch_threshold_graph ($graph_type, $index, $data, $width, $height, $font $myPicture->drawLegend(643,210,array("Style"=>LEGEND_NOBORDER,"Mode"=>LEGEND_HORIZONTAL)); } + /* Render the picture */ + $myPicture->stroke(); +} + +function pch_bullet_chart($graph_type, $data, $legend, + $width, $height, $font, $water_mark, $font_size, $legend_position, $colors) { + + + /* Create and populate the pData object */ + $MyData = new pData(); + + html_debug($data,true); + foreach ($data as $key => $dat) { + $MyData->addPoints($dat, $key); + } + $MyData->setPalette(__("Min"),array("R"=>55,"G"=>91,"B"=>127)); + $MyData->setPalette(__("Actual"),array("R"=>70,"G"=>130,"B"=>180)); + $MyData->setPalette(__("Max"),array("R"=>221,"G"=>221,"B"=>221)); + + $MyData->addPoints($legend,"Labels"); + + + $MyData->setAbscissa("Labels"); + $MyData->setSerieDescription("Labels", __("Agents/Modules")); + + $height_t = ($height * count($data) ) + 40; + $width_t = ($width + ( 200 + $max_chars)); + $max_chars = graph_get_max_index($legend_values); + + /* Create the pChart object */ + $myPicture = new pImage($width_t, $height_t,$MyData); + + /* Write the picture title */ + $myPicture->setFontProperties(array("FontName"=>$font,"FontSize"=>$font_size)); + + /* Write the chart title */ + $myPicture->setFontProperties(array("FontName"=>$font,"FontSize"=>$font_size)); + + $height_t - 10; + /* Draw the scale and chart */ + $myPicture->setGraphArea(220,20,($width + 80), $height_t); + $myPicture->drawScale(array("Pos"=>SCALE_POS_TOPBOTTOM, "Mode"=>SCALE_MODE_ADDALL_START0, + "LabelingMethod"=>LABELING_DIFFERENT, "GridR"=>255, "GridG"=>255, + "GridB"=>255, "GridAlpha"=>50, "TickR"=>0,"TickG"=>0, "TickB"=>0, + "TickAlpha"=>50, "LabelRotation"=>0, "CycleBackground"=>1, + "DrawXLines"=>1, "DrawSubTicks"=>1, "SubTickR"=>255, + "SubTickG"=>0, "SubTickB"=>0, "SubTickAlpha"=>50, + "DrawYLines"=>ALL)); + $myPicture->drawStackedBarChart(array("MODE"=>SCALE_MODE_START0)); + + /* Write the chart legend */ + //$myPicture->drawLegend(0,205,array("Style"=>LEGEND_NOBORDER,"Mode"=>LEGEND_HORIZONTAL)); + /* Render the picture */ $myPicture->stroke(); } -?> +?> \ No newline at end of file diff --git a/pandora_console/include/graphs/pChart/pData.class.php b/pandora_console/include/graphs/pChart/pData.class.php index 25064267f5..6fcf4557b1 100755 --- a/pandora_console/include/graphs/pChart/pData.class.php +++ b/pandora_console/include/graphs/pChart/pData.class.php @@ -151,10 +151,21 @@ function setAbscissa($Serie) { if (isset($this->Data["Series"][$Serie])) { $this->Data["Abscissa"] = $Serie; } } + function setAbsicssaPosition($Position = AXIS_POSITION_BOTTOM) + { $this->Data["AbsicssaPosition"] = $Position; } + + /* Set the name of the abscissa axis */ + function setAbscissaName($Name) + { $this->Data["AbscissaName"] = $Name; } + /* Create a scatter group specifyin X and Y data series */ function setScatterSerie($SerieX,$SerieY,$ID=0) { if (isset($this->Data["Series"][$SerieX]) && isset($this->Data["Series"][$SerieY]) ) { $this->initScatterSerie($ID); $this->Data["ScatterSeries"][$ID]["X"] = $SerieX; $this->Data["ScatterSeries"][$ID]["Y"] = $SerieY; } } + /* Set the shape of a given sctatter serie */ + function setScatterSerieShape($ID,$Shape=SERIE_SHAPE_FILLEDCIRCLE) + { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Shape"] = $Shape; } } + /* Set the description of a given scatter serie */ function setScatterSerieDescription($ID,$Description="My serie") { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Description"] = $Description; } } @@ -551,10 +562,63 @@ } } + /* Create a dataset based on a formula */ + function createFunctionSerie($SerieName,$Formula="",$Options="") + { + $MinX = isset($Options["MinX"]) ? $Options["MinX"] : -10; + $MaxX = isset($Options["MaxX"]) ? $Options["MaxX"] : 10; + $XStep = isset($Options["XStep"]) ? $Options["XStep"] : 1; + $AutoDescription = isset($Options["AutoDescription"]) ? $Options["AutoDescription"] : FALSE; + $RecordAbscissa = isset($Options["RecordAbscissa"]) ? $Options["RecordAbscissa"] : FALSE; + $AbscissaSerie = isset($Options["AbscissaSerie"]) ? $Options["AbscissaSerie"] : "Abscissa"; + + if ( $Formula == "" ) { return(0); } + + $Result = ""; $Abscissa = ""; + for($i=$MinX; $i<=$MaxX; $i=$i+$XStep) + { + $Expression = "\$return = '!'.(".str_replace("z",$i,$Formula).");"; + if ( @eval($Expression) === FALSE ) { $return = VOID; } + if ( $return == "!" ) { $return = VOID; } else { $return = $this->right($return,strlen($return)-1); } + if ( $return == "NAN" ) { $return = VOID; } + if ( $return == "INF" ) { $return = VOID; } + if ( $return == "-INF" ) { $return = VOID; } + + $Abscissa[] = $i; + $Result[] = $return; + } + + $this->addPoints($Result,$SerieName); + if ( $AutoDescription ) { $this->setSerieDescription($SerieName,$Formula); } + if ( $RecordAbscissa ) { $this->addPoints($Abscissa,$AbscissaSerie); } + } + + function negateValues($Series) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $SerieName) + { + if (isset($this->Data["Series"][$SerieName])) + { + $Data = ""; + foreach($this->Data["Series"][$SerieName]["Data"] as $Key => $Value) + { if ( $Value == VOID ) { $Data[] = VOID; } else { $Data[] = -$Value; } } + $this->Data["Series"][$SerieName]["Data"] = $Data; + + $this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"])); + $this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"])); + } + } + } + /* Return the data & configuration of the series */ function getData() { return($this->Data); } + /* Save a palette element */ + function savePalette($ID,$Color) + { $this->Palette[$ID] = $Color; } + /* Return the palette of the series */ function getPalette() { return($this->Palette); } diff --git a/pandora_console/include/graphs/pChart/pPie.class.php b/pandora_console/include/graphs/pChart/pPie.class.php index 661993ad5d..b84ab82328 100755 --- a/pandora_console/include/graphs/pChart/pPie.class.php +++ b/pandora_console/include/graphs/pChart/pPie.class.php @@ -25,11 +25,15 @@ define("PIE_VALUE_NATURAL" , 140020); define("PIE_VALUE_PERCENTAGE" , 140021); + define("PIE_VALUE_INSIDE" , 140030); + define("PIE_VALUE_OUTSIDE" , 140031); + /* pPie class definition */ class pPie { var $pChartObject; var $pDataObject; + var $LabelPos = "" ; /* Class creator */ function pPie($Object,$pDataObject) @@ -46,6 +50,7 @@ { /* Rendering layout */ $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 60; + $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0; $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0; $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE; @@ -55,11 +60,21 @@ $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; + $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; + $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15; + $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; + $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; + $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; + $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; + $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; /* Data Processing */ $Data = $this->pDataObject->getData(); @@ -76,6 +91,9 @@ /* Do we have data to compute? */ if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } + /* Remove unused data */ + list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); + /* Compute the pie sum */ $SerieSum = $this->pDataObject->getSum($DataSerie); @@ -151,6 +169,7 @@ } $this->pChartObject->drawPolygon($Plots,$Settings); + if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); } if ( $DrawLabels && !$Shadow && !$SecondPass ) { @@ -732,5 +751,707 @@ $this->pDataObject->Palette[$SliceID]["B"] = $B; $this->pDataObject->Palette[$SliceID]["Alpha"] = $Alpha; } + + /* Internally used compute the label positions */ + function writePieLabel($X,$Y,$Label,$Angle,$Settings,$Stacked,$Xc=0,$Yc=0,$Radius=0,$Reversed=FALSE) + { + $LabelOffset = 30; + $FontName = $this->pChartObject->FontName; + $FontSize = $this->pChartObject->FontSize; + + if ( !$Stacked ) + { + $Settings["Angle"] = 360-$Angle; + $Settings["Length"] = 25; + $Settings["Size"] = 8; + + $this->pChartObject->drawArrowLabel($X,$Y," ".$Label." ",$Settings); + } + else + { + $X2 = cos(deg2rad($Angle-90))*20+$X; + $Y2 = sin(deg2rad($Angle-90))*20+$Y; + + $TxtPos = $this->pChartObject->getTextBox($X,$Y,$FontName,$FontSize,0,$Label); + $Height = $TxtPos[0]["Y"] - $TxtPos[2]["Y"]; + $YTop = $Y2 - $Height/2 - 2; + $YBottom = $Y2 + $Height/2 + 2; + + if ( $this->LabelPos != "" ) + { + $Done = FALSE; + foreach($this->LabelPos as $Key => $Settings) + { + if ( !$Done ) + { + if ( $Angle <= 90 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) + { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; } + if ( $Angle > 90 && $Angle <= 180 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) + { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; } + if ( $Angle > 180 && $Angle <= 270 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) + { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; } + if ( $Angle > 270 && $Angle <= 360 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) + { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; } + } + } + } + + $LabelSettings = array("YTop"=>$YTop,"YBottom"=>$YBottom,"Label"=>$Label,"Angle"=>$Angle,"X1"=>$X,"Y1"=>$Y,"X2"=>$X2,"Y2"=>$Y2); + if ( $Angle <= 180 ) { $LabelSettings["X3"] = $Xc+$Radius+$LabelOffset; } + if ( $Angle > 180 ) { $LabelSettings["X3"] = $Xc-$Radius-$LabelOffset; } + $this->LabelPos[] = $LabelSettings; + } + } + + /* Internally used to shift label positions */ + function shift($StartAngle,$EndAngle,$Offset,$Reversed) + { + if ( $Reversed ) { $Offset = -$Offset; } + foreach($this->LabelPos as $Key => $Settings) + { + if ( $Settings["Angle"] > $StartAngle && $Settings["Angle"] <= $EndAngle ) { $this->LabelPos[$Key]["YTop"] = $Settings["YTop"] + $Offset; $this->LabelPos[$Key]["YBottom"] = $Settings["YBottom"] + $Offset; $this->LabelPos[$Key]["Y2"] = $Settings["Y2"] + $Offset; } + } + } + + /* Internally used to write the re-computed labels */ + function writeShiftedLabels() + { + if ( $this->LabelPos == "" ) { return(0); } + foreach($this->LabelPos as $Key => $Settings) + { + $X1 = $Settings["X1"]; $Y1 = $Settings["Y1"]; + $X2 = $Settings["X2"]; $Y2 = $Settings["Y2"]; + $X3 = $Settings["X3"]; + $Angle = $Settings["Angle"]; + $Label = $Settings["Label"]; + + $this->pChartObject->drawArrow($X2,$Y2,$X1,$Y1,array("Size"=>8)); + if ( $Angle <= 180 ) + { + $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2); + $this->pChartObject->drawText($X3+2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + } + else + { + $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2); + $this->pChartObject->drawText($X3-2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + } + } + } + + /* Draw a ring chart */ + function draw2DRing($X,$Y,$Format="") + { + $OuterRadius = isset($Format["Radius"]) ? $Format["Radius"] : 60; + $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; + $InnerRadius = isset($Format["Radius"]) ? $Format["Radius"] : 30; + $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100; + $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; + $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; + $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; + $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; + $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; + $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; + $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; + $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 5; + $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; + $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; + $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; + $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; + $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; + $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + /* Do we have an abscissa serie defined? */ + if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } + + /* Try to find the data serie */ + $DataSerie = ""; + foreach ($Data["Series"] as $SerieName => $SerieData) + { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } + + /* Do we have data to compute? */ + if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } + + /* Remove unused data */ + list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); + + /* Compute the pie sum */ + $SerieSum = $this->pDataObject->getSum($DataSerie); + + /* Do we have data to draw? */ + if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } + + /* Dump the real number of data to draw */ + $Values = ""; + foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { if ($Value != 0) { $Values[] = $Value; } } + + /* Compute the wasted angular space between series */ + if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = 0; } // count($Values) + + /* Compute the scale */ + $ScaleFactor = (360 - $WastedAngular) / $SerieSum; + + $RestoreShadow = $this->pChartObject->Shadow; + if ( $this->pChartObject->Shadow ) + { + $this->pChartObject->Shadow = FALSE; + + $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE; + $this->draw2DRing($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat); + } + + /* Draw the polygon pie elements */ + $Step = 360 / (2 * PI * $OuterRadius); + $Offset = 0; $ID = 0; + foreach($Values as $Key => $Value) + { + if ( $Shadow ) + { + $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); + $BorderColor = $Settings; + } + else + { + if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } + $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); + + if ( $Border ) + $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); + else + $BorderColor = $Settings; + } + + $Plots = ""; $Boundaries = ""; $AAPixels = ""; + $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; } + for($i=$Offset;$i<=$EndAngle;$i=$i+$Step) + { + $Xc = cos(($i-90)*PI/180) * $OuterRadius + $X; + $Yc = sin(($i-90)*PI/180) * $OuterRadius + $Y; + + if ( !isset($Boundaries[0]["X1"]) ) { $Boundaries[0]["X1"] = $Xc; $Boundaries[0]["Y1"] = $Yc; } + $AAPixels[] = array($Xc,$Yc); + + if ( $i<90 ) { $Yc++; } + if ( $i>180 && $i<270 ) { $Xc++; } + if ( $i>=270 ) { $Xc++; $Yc++; } + + $Plots[] = $Xc; $Plots[] = $Yc; + } + $Boundaries[1]["X1"] = $Xc; $Boundaries[1]["Y1"] = $Yc; + $Lasti = $EndAngle; + + for($i=$EndAngle;$i>=$Offset;$i=$i-$Step) + { + $Xc = cos(($i-90)*PI/180) * ($InnerRadius-1) + $X; + $Yc = sin(($i-90)*PI/180) * ($InnerRadius-1) + $Y; + + if ( !isset($Boundaries[1]["X2"]) ) { $Boundaries[1]["X2"] = $Xc; $Boundaries[1]["Y2"] = $Yc; } + $AAPixels[] = array($Xc,$Yc); + + $Xc = cos(($i-90)*PI/180) * $InnerRadius + $X; + $Yc = sin(($i-90)*PI/180) * $InnerRadius + $Y; + + if ( $i<90 ) { $Yc++; } + if ( $i>180 && $i<270 ) { $Xc++; } + if ( $i>=270 ) { $Xc++; $Yc++; } + + $Plots[] = $Xc; $Plots[] = $Yc; + } + $Boundaries[0]["X2"] = $Xc; $Boundaries[0]["Y2"] = $Yc; + + /* Draw the polygon */ + $this->pChartObject->drawPolygon($Plots,$Settings); + if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); } + + /* Smooth the edges using AA */ + foreach($AAPixels as $iKey => $Pos ) { $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$BorderColor); } + $this->pChartObject->drawLine($Boundaries[0]["X1"],$Boundaries[0]["Y1"],$Boundaries[0]["X2"],$Boundaries[0]["Y2"],$BorderColor); + $this->pChartObject->drawLine($Boundaries[1]["X1"],$Boundaries[1]["Y1"],$Boundaries[1]["X2"],$Boundaries[1]["Y2"],$BorderColor); + + if ( $DrawLabels && !$Shadow ) + { + if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) + { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} + else + { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $Xc = cos(($Angle-90)*PI/180) * $OuterRadius + $X; + $Yc = sin(($Angle-90)*PI/180) * $OuterRadius + $Y; + + $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; + + if ( $LabelStacked ) + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius); + else + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); + } + + $Offset = $Lasti; $ID++; + } + + if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } + + if ( $WriteValues && !$Shadow ) + { + $Step = 360 / (2 * PI * $OuterRadius); + $Offset = 0; + foreach($Values as $Key => $Value) + { + $EndAngle = $Offset+($Value*$ScaleFactor); + if ( $EndAngle > 360 ) { $EndAngle = 360; } + + $Angle = $Offset+($Value*$ScaleFactor)/2; + if ( $ValuePosition == PIE_VALUE_OUTSIDE ) + { + $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $X; + $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $Y; + if ( $Angle >=0 && $Angle <= 90 ) { $Align = TEXT_ALIGN_BOTTOMLEFT; } + if ( $Angle > 90 && $Angle <= 180 ) { $Align = TEXT_ALIGN_TOPLEFT; } + if ( $Angle > 180 && $Angle <= 270 ) { $Align = TEXT_ALIGN_TOPRIGHT; } + if ( $Angle > 270 ) { $Align = TEXT_ALIGN_BOTTOMRIGHT; } + } + else + { + $Xc = cos(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $X; + $Yc = sin(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $Y; + $Align = TEXT_ALIGN_MIDDLEMIDDLE; + } + + if ( $WriteValues == PIE_VALUE_PERCENTAGE ) + $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; + elseif ( $WriteValues == PIE_VALUE_NATURAL ) + $Display = $Value.$ValueSuffix; + else + $Label = ""; + + $this->pChartObject->drawText($Xc,$Yc,$Display,array("Align"=>$Align,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB)); + $Offset = $EndAngle; + } + } + + $this->pChartObject->Shadow = $RestoreShadow; + + return(PIE_RENDERED); + } + + /* Draw a 3D ring chart */ + function draw3DRing($X,$Y,$Format="") + { + $OuterRadius = isset($Format["OuterRadius"]) ? $Format["OuterRadius"] : 100; + $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; + $InnerRadius = isset($Format["InnerRadius"]) ? $Format["InnerRadius"] : 30; + $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .6; + $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 10; + $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 10; + $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 10; + $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; + $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; + $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; + $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; + $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; + $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; + $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; + $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; + $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; + $Cf = isset($Format["Cf"]) ? $Format["Cf"] : 20; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : PIE_VALUE_NATURAL; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : $SliceHeight + 15; + $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; + $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; + $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; + $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; + $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; + $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + /* Error correction for overlaying rounded corners */ + if ( $SkewFactor < .5 ) { $SkewFactor = .5; } + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + /* Do we have an abscissa serie defined? */ + if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } + + /* Try to find the data serie */ + $DataSerie = ""; + foreach ($Data["Series"] as $SerieName => $SerieData) + { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } + + /* Do we have data to compute? */ + if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } + + /* Remove unused data */ + list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); + + /* Compute the pie sum */ + $SerieSum = $this->pDataObject->getSum($DataSerie); + + /* Do we have data to draw? */ + if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } + + /* Dump the real number of data to draw */ + $Values = ""; + foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { if ($Value != 0) { $Values[] = $Value; } } + + /* Compute the wasted angular space between series */ + if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; } + + /* Compute the scale */ + $ScaleFactor = (360 - $WastedAngular) / $SerieSum; + + $RestoreShadow = $this->pChartObject->Shadow; + if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; } + + /* Draw the polygon ring elements */ + $Offset = 360; $ID = count($Values)-1; + $Values = array_reverse($Values); + $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = ""; + foreach($Values as $Key => $Value) + { + if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } + $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); + + $SliceColors[$Slice] = $Settings; + + $StartAngle = $Offset; + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; } + if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; } + + $Step = (360 / (2 * PI * $OuterRadius))/2; + $OutX1 = VOID; $OutY1 = VOID; + for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) + { + $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2) + $X; + $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2)*$SkewFactor + $Y; + $Slices[$Slice]["AA"][] = array($Xc,$Yc); + + $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1) + $X; + $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1)*$SkewFactor + $Y; + $Slices[$Slice]["AA"][] = array($Xc,$Yc); + + $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X; + $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y; + $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); + + if ( $OutX1 == VOID ) { $OutX1 = $Xc; $OutY1 = $Yc; } + + if ( $i<90 ) { $Yc++; } + if ( $i>90 && $i<180 ) { $Xc++; } + if ( $i>180 && $i<270 ) { $Xc++; } + if ( $i>=270 ) { $Xc++; $Yc++; } + + $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc); + $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight; + $Slices[$Slice]["Angle"][] = $i; + } + $OutX2 = $Xc; $OutY2 = $Yc; + + $Slices[$Slice]["Angle"][] = VOID; + $Lasti = $i; + + $Step = (360 / (2 * PI * $InnerRadius))/2; + $InX1 = VOID; $InY1 = VOID; + for($i=$EndAngle;$i<=$Offset;$i=$i+$Step) + { + $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1) + $X; + $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1)*$SkewFactor + $Y; + $Slices[$Slice]["AA"][] = array($Xc,$Yc); + + $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius) + $X; + $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius)*$SkewFactor + $Y; + $Slices[$Slice]["AA"][] = array($Xc,$Yc); + + if ( $InX1 == VOID ) { $InX1 = $Xc; $InY1 = $Yc; } + + if ( $i<90 ) { $Yc++; } + if ( $i>90 && $i<180 ) { $Xc++; } + if ( $i>180 && $i<270 ) { $Xc++; } + if ( $i>=270 ) { $Xc++; $Yc++; } + + $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc); + $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight; + $Slices[$Slice]["Angle"][] = $i; + } + $InX2 = $Xc; $InY2 = $Yc; + + $Slices[$Slice]["InX1"] = $InX1; $Slices[$Slice]["InY1"] = $InY1; + $Slices[$Slice]["InX2"] = $InX2; $Slices[$Slice]["InY2"] = $InY2; + $Slices[$Slice]["OutX1"] = $OutX1; $Slices[$Slice]["OutY1"] = $OutY1; + $Slices[$Slice]["OutX2"] = $OutX2; $Slices[$Slice]["OutY2"] = $OutY2; + + $Offset = $Lasti - $DataGapAngle; $ID--; $Slice++; + } + + /* Draw the bottom pie splice */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $this->pChartObject->drawPolygon($Plots["BottomPoly"],$Settings); + + foreach($Plots["AA"] as $Key => $Pos) + $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$Settings); + + $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["OutX2"],$Plots["OutY2"],$Settings); + $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["OutX1"],$Plots["OutY1"],$Settings); + } + + $Slices = array_reverse($Slices); + $SliceColors = array_reverse($SliceColors); + + /* Draw the vertical edges (semi-visible) */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; + + $StartAngle = $Plots["Angle"][0]; + foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } + + if ( $StartAngle >= 270 || $StartAngle <= 90 ) + $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); + if ( $StartAngle >= 270 || $StartAngle <= 90 ) + $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); + + $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Settings); + $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Settings); + } + + /* Draw the inner vertical slices */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; + + $Outer = TRUE; $Inner = FALSE; + $InnerPlotsA = ""; $InnerPlotsB = ""; + foreach($Plots["Angle"] as $ID => $Angle) + { + if ( $Angle == VOID ) + { $Outer = FALSE; $Inner = TRUE; } + elseif( $Inner ) + { + if (( $Angle < 90 || $Angle > 270 ) && isset($Plots["BottomPoly"][$ID*2]) ) + { + $Xo = $Plots["BottomPoly"][$ID*2]; + $Yo = $Plots["BottomPoly"][$ID*2+1]; + + $InnerPlotsA[] = $Xo; $InnerPlotsA[] = $Yo; + $InnerPlotsB[] = $Xo; $InnerPlotsB[] = $Yo-$SliceHeight; + } + } + } + + if ( $InnerPlotsA != "" ) + { $InnerPlots = array_merge($InnerPlotsA,$this->arrayReverse($InnerPlotsB)); $this->pChartObject->drawPolygon($InnerPlots,$Settings); } + } + + /* Draw the splice top and left poly */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf*1.5; $Settings["G"] = $Settings["G"]+$Cf*1.5; $Settings["B"] = $Settings["B"]+$Cf*1.5; + + $StartAngle = $Plots["Angle"][0]; + foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } + + if ( $StartAngle < 180 ) + { + $Points = ""; + $Points[] = $Plots["InX2"]; + $Points[] = $Plots["InY2"]; + $Points[] = $Plots["InX2"]; + $Points[] = $Plots["InY2"]-$SliceHeight; + $Points[] = $Plots["OutX1"]; + $Points[] = $Plots["OutY1"]-$SliceHeight; + $Points[] = $Plots["OutX1"]; + $Points[] = $Plots["OutY1"]; + + $this->pChartObject->drawPolygon($Points,$Settings); + } + + if ( $EndAngle > 180 ) + { + $Points = ""; + $Points[] = $Plots["InX1"]; + $Points[] = $Plots["InY1"]; + $Points[] = $Plots["InX1"]; + $Points[] = $Plots["InY1"]-$SliceHeight; + $Points[] = $Plots["OutX2"]; + $Points[] = $Plots["OutY2"]-$SliceHeight; + $Points[] = $Plots["OutX2"]; + $Points[] = $Plots["OutY2"]; + + $this->pChartObject->drawPolygon($Points,$Settings); + } + } + + + /* Draw the vertical edges (visible) */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; + + $StartAngle = $Plots["Angle"][0]; + foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } + + if ( $StartAngle <= 270 && $StartAngle >= 90 ) + $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); + if ( $EndAngle <= 270 && $EndAngle >= 90 ) + $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); + } + + + /* Draw the outer vertical slices */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; + + $Outer = TRUE; $Inner = FALSE; + $OuterPlotsA = ""; $OuterPlotsB = ""; $InnerPlotsA = ""; $InnerPlotsB = ""; + foreach($Plots["Angle"] as $ID => $Angle) + { + if ( $Angle == VOID ) + { $Outer = FALSE; $Inner = TRUE; } + elseif( $Outer ) + { + if ( ( $Angle > 90 && $Angle < 270 ) && isset($Plots["BottomPoly"][$ID*2]) ) + { + $Xo = $Plots["BottomPoly"][$ID*2]; + $Yo = $Plots["BottomPoly"][$ID*2+1]; + + $OuterPlotsA[] = $Xo; $OuterPlotsA[] = $Yo; + $OuterPlotsB[] = $Xo; $OuterPlotsB[] = $Yo-$SliceHeight; + } + } + } + if ( $OuterPlotsA != "" ) + { $OuterPlots = array_merge($OuterPlotsA,$this->arrayReverse($OuterPlotsB)); $this->pChartObject->drawPolygon($OuterPlots,$Settings); } + } + + $Slices = array_reverse($Slices); + $SliceColors = array_reverse($SliceColors); + + + /* Draw the top pie splice */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf*2; $Settings["G"] = $Settings["G"]+$Cf*2; $Settings["B"] = $Settings["B"]+$Cf*2; + + $this->pChartObject->drawPolygon($Plots["TopPoly"],$Settings); + + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots["TopPoly"]),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$SliceID],$Data["Series"][$DataSerie]["Data"][count($Slices)-$SliceID-1]); } + + foreach($Plots["AA"] as $Key => $Pos) + $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1]-$SliceHeight,$Settings); + + $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); + $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); + } + + if ( $DrawLabels ) + { + $Offset = 360; + foreach($Values as $Key => $Value) + { + $StartAngle = $Offset; + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) + { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} + else + { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X; + $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y; + + if ( $WriteValues == PIE_VALUE_PERCENTAGE ) + $Label = $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; + elseif ( $WriteValues == PIE_VALUE_NATURAL ) + $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; + else + $Label = ""; + + if ( $LabelStacked ) + $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius); + else + $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,FALSE); + + $Offset = $EndAngle - $DataGapAngle; $ID--; $Slice++; + } + } + if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } + + $this->pChartObject->Shadow = $RestoreShadow; + + return(PIE_RENDERED); + } + + /* Serialize an array */ + function arraySerialize($Data) + { + $Result = ""; + foreach($Data as $Key => $Value) + { if ($Result == "") { $Result = floor($Value); } else { $Result = $Result.",".floor($Value); } } + + return($Result); + } + + /* Reverse an array */ + function arrayReverse($Plots) + { + $Result = ""; + + for($i=count($Plots)-1;$i>=0;$i=$i-2) + { $Result[] = $Plots[$i-1]; $Result[] = $Plots[$i]; } + + return($Result); + } + + /* Remove unused series & values */ + function clean0Values($Data,$Palette,$DataSerie,$AbscissaSerie) + { + $NewPalette = ""; $NewData = ""; $NewAbscissa = ""; + + /* Remove unused series */ + foreach($Data["Series"] as $SerieName => $SerieSettings) + { if ( $SerieName != $DataSerie && $SerieName != $AbscissaSerie ) { unset($Data["Series"][$SerieName]); } } + + /* Remove NULL values */ + foreach($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { + if ($Value != 0 ) + { + $NewData[] = $Value; + $NewAbscissa[] = $Data["Series"][$AbscissaSerie]["Data"][$Key]; + if ( isset($Palette[$Key]) ) { $NewPalette[] = $Palette[$Key]; } + } + } + $Data["Series"][$DataSerie]["Data"] = $NewData; + $Data["Series"][$AbscissaSerie]["Data"] = $NewAbscissa; + + return(array($Data,$NewPalette)); + } } ?>