You are here

function pPie::draw3DPie in Visitors 7

Same name and namespace in other branches
  1. 7.2 pChart/class/pPie.class.php \pPie::draw3DPie()

File

pChart/class/pPie.class.php, line 299

Class

pPie

Code

function draw3DPie($X, $Y, $Format = "") {

  /* Rendering layout */
  $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 80;
  $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
  $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : 0.5;
  $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 20;
  $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
  $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
  $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE;
  $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;
  $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL;

  //PIE_VALUE_PERCENTAGE
  $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_INSIDE;
  $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;

  /* Error correction for overlaying rounded corners */
  if ($SkewFactor < 0.5) {
    $SkewFactor = 0.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 pie elements */
  $Step = 360 / (2 * PI * $Radius);
  $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;
    }
    if ($DataGapAngle == 0) {
      $X0 = $X;
      $Y0 = $Y;
    }
    else {
      $Angle = ($EndAngle - $Offset) / 2 + $Offset;
      $X0 = cos(($Angle - 90) * PI / 180) * $DataGapRadius + $X;
      $Y0 = sin(($Angle - 90) * PI / 180) * $DataGapRadius * $SkewFactor + $Y;
    }
    $Slices[$Slice][] = $X0;
    $Slices[$Slice][] = $Y0;
    $SliceAngle[$Slice][] = 0;
    for ($i = $Offset; $i >= $EndAngle; $i = $i - $Step) {
      $Xc = cos(($i - 90) * PI / 180) * $Radius + $X;
      $Yc = sin(($i - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
      if (($SecondPass || $RestoreShadow) && $i < 90) {
        $Yc++;
      }
      if (($SecondPass || $RestoreShadow) && ($i > 90 && $i < 180)) {
        $Xc++;
      }
      if (($SecondPass || $RestoreShadow) && ($i > 180 && $i < 270)) {
        $Xc++;
      }
      if (($SecondPass || $RestoreShadow) && $i >= 270) {
        $Xc++;
        $Yc++;
      }
      $Slices[$Slice][] = $Xc;
      $Slices[$Slice][] = $Yc;
      $SliceAngle[$Slice][] = $i;
    }
    $Offset = $i - $DataGapAngle;
    $ID--;
    $Slice++;
  }

  /* Draw the bottom shadow if needed */
  if ($RestoreShadow && ($this->pChartObject->ShadowX != 0 || $this->pChartObject->ShadowY != 0)) {
    foreach ($Slices as $SliceID => $Plots) {
      $ShadowPie = "";
      for ($i = 0; $i < count($Plots); $i = $i + 2) {
        $ShadowPie[] = $Plots[$i] + $this->pChartObject->ShadowX;
        $ShadowPie[] = $Plots[$i + 1] + $this->pChartObject->ShadowY;
      }
      $Settings = array(
        "R" => $this->pChartObject->ShadowR,
        "G" => $this->pChartObject->ShadowG,
        "B" => $this->pChartObject->ShadowB,
        "Alpha" => $this->pChartObject->Shadowa,
        "NoBorder" => TRUE,
      );
      $this->pChartObject
        ->drawPolygon($ShadowPie, $Settings);
    }
    $Step = 360 / (2 * PI * $Radius);
    $Offset = 360;
    foreach ($Values as $Key => $Value) {
      $EndAngle = $Offset - $Value * $ScaleFactor;
      if ($EndAngle < 0) {
        $EndAngle = 0;
      }
      for ($i = $Offset; $i >= $EndAngle; $i = $i - $Step) {
        $Xc = cos(($i - 90) * PI / 180) * $Radius + $X + $this->pChartObject->ShadowX;
        $Yc = sin(($i - 90) * PI / 180) * $Radius * $SkewFactor + $Y + $this->pChartObject->ShadowY;
        $this->pChartObject
          ->drawAntialiasPixel($Xc, $Yc, $Settings);
      }
      $Offset = $i - $DataGapAngle;
      $ID--;
    }
  }

  /* Draw the bottom pie splice */
  foreach ($Slices as $SliceID => $Plots) {
    $Settings = $SliceColors[$SliceID];
    $Settings["NoBorder"] = TRUE;
    $this->pChartObject
      ->drawPolygon($Plots, $Settings);
    if ($SecondPass) {
      $Settings = $SliceColors[$SliceID];
      if ($Border) {
        $Settings["R"] += 30;
        $Settings["G"] += 30;
        $Settings["B"] += 30;
      }
      if (isset($SliceAngle[$SliceID][1])) {

        /* Empty error handling */
        $Angle = $SliceAngle[$SliceID][1];
        $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
        $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
        $this->pChartObject
          ->drawLine($Plots[0], $Plots[1], $Xc, $Yc, $Settings);
        $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID]) - 1];
        $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
        $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
        $this->pChartObject
          ->drawLine($Plots[0], $Plots[1], $Xc, $Yc, $Settings);
      }
    }
  }

  /* Draw the two vertical edges */
  $Slices = array_reverse($Slices);
  $SliceColors = array_reverse($SliceColors);
  foreach ($Slices as $SliceID => $Plots) {
    $Settings = $SliceColors[$SliceID];
    $Settings["R"] += 10;
    $Settings["G"] += 10;
    $Settings["B"] += 10;
    $Settings["NoBorder"] = TRUE;
    if ($Visible[$SliceID]["Start"] && isset($Plots[2])) {

      /* Empty error handling */
      $this->pChartObject
        ->drawLine($Plots[2], $Plots[3], $Plots[2], $Plots[3] - $SliceHeight, array(
        "R" => $Settings["R"],
        "G" => $Settings["G"],
        "B" => $Settings["B"],
      ));
      $Border = "";
      $Border[] = $Plots[0];
      $Border[] = $Plots[1];
      $Border[] = $Plots[0];
      $Border[] = $Plots[1] - $SliceHeight;
      $Border[] = $Plots[2];
      $Border[] = $Plots[3] - $SliceHeight;
      $Border[] = $Plots[2];
      $Border[] = $Plots[3];
      $this->pChartObject
        ->drawPolygon($Border, $Settings);
    }
  }
  $Slices = array_reverse($Slices);
  $SliceColors = array_reverse($SliceColors);
  foreach ($Slices as $SliceID => $Plots) {
    $Settings = $SliceColors[$SliceID];
    $Settings["R"] += 10;
    $Settings["G"] += 10;
    $Settings["B"] += 10;
    $Settings["NoBorder"] = TRUE;
    if ($Visible[$SliceID]["End"]) {
      $this->pChartObject
        ->drawLine($Plots[count($Plots) - 2], $Plots[count($Plots) - 1], $Plots[count($Plots) - 2], $Plots[count($Plots) - 1] - $SliceHeight, array(
        "R" => $Settings["R"],
        "G" => $Settings["G"],
        "B" => $Settings["B"],
      ));
      $Border = "";
      $Border[] = $Plots[0];
      $Border[] = $Plots[1];
      $Border[] = $Plots[0];
      $Border[] = $Plots[1] - $SliceHeight;
      $Border[] = $Plots[count($Plots) - 2];
      $Border[] = $Plots[count($Plots) - 1] - $SliceHeight;
      $Border[] = $Plots[count($Plots) - 2];
      $Border[] = $Plots[count($Plots) - 1];
      $this->pChartObject
        ->drawPolygon($Border, $Settings);
    }
  }

  /* Draw the rounded edges */
  foreach ($Slices as $SliceID => $Plots) {
    $Settings = $SliceColors[$SliceID];
    $Settings["R"] += 10;
    $Settings["G"] += 10;
    $Settings["B"] += 10;
    $Settings["NoBorder"] = TRUE;
    for ($j = 2; $j < count($Plots) - 2; $j = $j + 2) {
      $Angle = $SliceAngle[$SliceID][$j / 2];
      if ($Angle < 270 && $Angle > 90) {
        $Border = "";
        $Border[] = $Plots[$j];
        $Border[] = $Plots[$j + 1];
        $Border[] = $Plots[$j + 2];
        $Border[] = $Plots[$j + 3];
        $Border[] = $Plots[$j + 2];
        $Border[] = $Plots[$j + 3] - $SliceHeight;
        $Border[] = $Plots[$j];
        $Border[] = $Plots[$j + 1] - $SliceHeight;
        $this->pChartObject
          ->drawPolygon($Border, $Settings);
      }
    }
    if ($SecondPass) {
      $Settings = $SliceColors[$SliceID];
      if ($Border) {
        $Settings["R"] += 30;
        $Settings["G"] += 30;
        $Settings["B"] += 30;
      }
      if (isset($SliceAngle[$SliceID][1])) {

        /* Empty error handling */
        $Angle = $SliceAngle[$SliceID][1];
        if ($Angle < 270 && $Angle > 90) {
          $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
          $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
          $this->pChartObject
            ->drawLine($Xc, $Yc, $Xc, $Yc - $SliceHeight, $Settings);
        }
      }
      $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID]) - 1];
      if ($Angle < 270 && $Angle > 90) {
        $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
        $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
        $this->pChartObject
          ->drawLine($Xc, $Yc, $Xc, $Yc - $SliceHeight, $Settings);
      }
      if (isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 270 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID]) - 1] < 270) {
        $Xc = cos((270 - 90) * PI / 180) * $Radius + $X;
        $Yc = sin((270 - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
        $this->pChartObject
          ->drawLine($Xc, $Yc, $Xc, $Yc - $SliceHeight, $Settings);
      }
      if (isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 90 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID]) - 1] < 90) {
        $Xc = cos(0 * PI / 180) * $Radius + $X;
        $Yc = sin(0 * PI / 180) * $Radius * $SkewFactor + $Y;
        $this->pChartObject
          ->drawLine($Xc, $Yc, $Xc, $Yc - $SliceHeight, $Settings);
      }
    }
  }

  /* Draw the top splice */
  foreach ($Slices as $SliceID => $Plots) {
    $Settings = $SliceColors[$SliceID];
    $Settings["R"] += 20;
    $Settings["G"] += 20;
    $Settings["B"] += 20;
    $Top = "";
    for ($j = 0; $j < count($Plots); $j = $j + 2) {
      $Top[] = $Plots[$j];
      $Top[] = $Plots[$j + 1] - $SliceHeight;
    }
    $this->pChartObject
      ->drawPolygon($Top, $Settings);
    if ($RecordImageMap && !$Shadow) {
      $this->pChartObject
        ->addToImageMap("POLY", $this
        ->arraySerialize($Top), $this->pChartObject
        ->toHTMLColor($Settings["R"], $Settings["G"], $Settings["B"]), $Data["Series"][$Data["Abscissa"]]["Data"][count($Slices) - $SliceID - 1], $Values[$SliceID]);
    }
  }

  /* Second pass to smooth the angles */
  if ($SecondPass) {
    $Step = 360 / (2 * PI * $Radius);
    $Offset = 360;
    $ID = count($Values) - 1;
    foreach ($Values as $Key => $Value) {
      $FirstPoint = TRUE;
      if ($Shadow) {
        $Settings = array(
          "R" => $this->pChartObject->ShadowR,
          "G" => $this->pChartObject->ShadowG,
          "B" => $this->pChartObject->ShadowB,
          "Alpha" => $this->pChartObject->Shadowa,
        );
      }
      else {
        if ($Border) {
          $Settings = array(
            "R" => $Palette[$ID]["R"] + 30,
            "G" => $Palette[$ID]["G"] + 30,
            "B" => $Palette[$ID]["B"] + 30,
            "Alpha" => $Palette[$ID]["Alpha"],
          );
        }
        else {
          $Settings = array(
            "R" => $Palette[$ID]["R"],
            "G" => $Palette[$ID]["G"],
            "B" => $Palette[$ID]["B"],
            "Alpha" => $Palette[$ID]["Alpha"],
          );
        }
      }
      $EndAngle = $Offset - $Value * $ScaleFactor;
      if ($EndAngle < 0) {
        $EndAngle = 0;
      }
      if ($DataGapAngle == 0) {
        $X0 = $X;
        $Y0 = $Y - $SliceHeight;
      }
      else {
        $Angle = ($EndAngle - $Offset) / 2 + $Offset;
        $X0 = cos(($Angle - 90) * PI / 180) * $DataGapRadius + $X;
        $Y0 = sin(($Angle - 90) * PI / 180) * $DataGapRadius * $SkewFactor + $Y - $SliceHeight;
      }
      $Plots[] = $X0;
      $Plots[] = $Y0;
      for ($i = $Offset; $i >= $EndAngle; $i = $i - $Step) {
        $Xc = cos(($i - 90) * PI / 180) * $Radius + $X;
        $Yc = sin(($i - 90) * PI / 180) * $Radius * $SkewFactor + $Y - $SliceHeight;
        if ($FirstPoint) {
          $this->pChartObject
            ->drawLine($Xc, $Yc, $X0, $Y0, $Settings);
        }
        $FirstPoint = FALSE;
        $this->pChartObject
          ->drawAntialiasPixel($Xc, $Yc, $Settings);
        if ($i < 270 && $i > 90) {
          $this->pChartObject
            ->drawAntialiasPixel($Xc, $Yc + $SliceHeight, $Settings);
        }
      }
      $this->pChartObject
        ->drawLine($Xc, $Yc, $X0, $Y0, $Settings);
      $Offset = $i - $DataGapAngle;
      $ID--;
    }
  }
  if ($WriteValues != NULL) {
    $Step = 360 / (2 * PI * $Radius);
    $Offset = 360;
    $ID = count($Values) - 1;
    $Settings = array(
      "Align" => TEXT_ALIGN_MIDDLEMIDDLE,
      "R" => $ValueR,
      "G" => $ValueG,
      "B" => $ValueB,
      "Alpha" => $ValueAlpha,
    );
    foreach ($Values as $Key => $Value) {
      $EndAngle = $Offset - $Value * $ScaleFactor;
      if ($EndAngle < 0) {
        $EndAngle = 0;
      }
      $Angle = ($EndAngle - $Offset) / 2 + $Offset;
      if ($ValuePosition == PIE_VALUE_OUTSIDE) {
        $Xc = cos(($Angle - 90) * PI / 180) * ($Radius + $ValuePadding) + $X;
        $Yc = sin(($Angle - 90) * PI / 180) * ($Radius * $SkewFactor + $ValuePadding) + $Y - $SliceHeight;
      }
      else {
        $Xc = cos(($Angle - 90) * PI / 180) * $Radius / 2 + $X;
        $Yc = sin(($Angle - 90) * PI / 180) * ($Radius * $SkewFactor) / 2 + $Y - $SliceHeight;
      }
      if ($WriteValues == PIE_VALUE_PERCENTAGE) {
        $Display = round(100 / $SerieSum * $Value, $Precision) . "%";
      }
      elseif ($WriteValues == PIE_VALUE_NATURAL) {
        $Display = $Value . $ValueSuffix;
      }
      $this->pChartObject
        ->drawText($Xc, $Yc, $Display, $Settings);
      $Offset = $EndAngle - $DataGapAngle;
      $ID--;
    }
  }
  if ($DrawLabels) {
    $Step = 360 / (2 * PI * $Radius);
    $Offset = 360;
    $ID = count($Values) - 1;
    foreach ($Values as $Key => $Value) {
      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,
        );
      }
      $EndAngle = $Offset - $Value * $ScaleFactor;
      if ($EndAngle < 0) {
        $EndAngle = 0;
      }
      $Angle = ($EndAngle - $Offset) / 2 + $Offset;
      $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
      $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y - $SliceHeight;
      if (isset($Data["Series"][$Data["Abscissa"]]["Data"][$ID])) {
        $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$ID];
        if ($LabelStacked) {
          $this
            ->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, TRUE, $X, $Y, $Radius, TRUE);
        }
        else {
          $this
            ->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, FALSE);
        }
      }
      $Offset = $EndAngle - $DataGapAngle;
      $ID--;
    }
  }
  if ($DrawLabels && $LabelStacked) {
    $this
      ->writeShiftedLabels();
  }
  $this->pChartObject->Shadow = $RestoreShadow;
  return PIE_RENDERED;
}