summaryrefslogtreecommitdiff
path: root/app/Http/Controllers/FanChartController.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/Http/Controllers/FanChartController.php')
-rw-r--r--app/Http/Controllers/FanChartController.php693
1 files changed, 355 insertions, 338 deletions
diff --git a/app/Http/Controllers/FanChartController.php b/app/Http/Controllers/FanChartController.php
index 3c96046338..78e87f4816 100644
--- a/app/Http/Controllers/FanChartController.php
+++ b/app/Http/Controllers/FanChartController.php
@@ -27,395 +27,412 @@ use Symfony\Component\HttpFoundation\Response;
/**
* A chart of direct-line ancestors in a circular layour.
*/
-class FanChartController extends AbstractChartController {
- // Chart styles
- const STYLE_HALF_CIRCLE = 2;
- const STYLE_THREE_QUARTER_CIRCLE = 3;
- const STYLE_FULL_CIRCLE = 4;
+class FanChartController extends AbstractChartController
+{
+ // Chart styles
+ const STYLE_HALF_CIRCLE = 2;
+ const STYLE_THREE_QUARTER_CIRCLE = 3;
+ const STYLE_FULL_CIRCLE = 4;
- // Limits
- const MINIMUM_GENERATIONS = 2;
- const MAXIMUM_GENERATIONS = 9;
- const MINIMUM_WIDTH = 50;
- const MAXIMUM_WIDTH = 500;
+ // Limits
+ const MINIMUM_GENERATIONS = 2;
+ const MAXIMUM_GENERATIONS = 9;
+ const MINIMUM_WIDTH = 50;
+ const MAXIMUM_WIDTH = 500;
- // Defaults
- const DEFAULT_STYLE = self::STYLE_THREE_QUARTER_CIRCLE;
- const DEFAULT_GENERATIONS = 4;
- const DEFAULT_WIDTH = 100;
+ // Defaults
+ const DEFAULT_STYLE = self::STYLE_THREE_QUARTER_CIRCLE;
+ const DEFAULT_GENERATIONS = 4;
+ const DEFAULT_WIDTH = 100;
- /**
- * A form to request the chart parameters.
- *
- * @param Request $request
- *
- * @return Response
- */
- public function page(Request $request): Response {
- /** @var Tree $tree */
- $tree = $request->attributes->get('tree');
+ /**
+ * A form to request the chart parameters.
+ *
+ * @param Request $request
+ *
+ * @return Response
+ */
+ public function page(Request $request): Response
+ {
+ /** @var Tree $tree */
+ $tree = $request->attributes->get('tree');
- $this->checkModuleIsActive($tree, 'fan_chart');
+ $this->checkModuleIsActive($tree, 'fan_chart');
- $xref = $request->get('xref');
- $individual = Individual::getInstance($xref, $tree);
+ $xref = $request->get('xref');
+ $individual = Individual::getInstance($xref, $tree);
- $this->checkIndividualAccess($individual);
+ $this->checkIndividualAccess($individual);
- $chart_style = (int) $request->get('chart_style', self::DEFAULT_STYLE);
- $fan_width = (int) $request->get('fan_width', self::DEFAULT_WIDTH);
- $generations = (int) $request->get('generations', self::DEFAULT_GENERATIONS);
+ $chart_style = (int)$request->get('chart_style', self::DEFAULT_STYLE);
+ $fan_width = (int)$request->get('fan_width', self::DEFAULT_WIDTH);
+ $generations = (int)$request->get('generations', self::DEFAULT_GENERATIONS);
- $fan_width = min($fan_width, self::MAXIMUM_WIDTH);
- $fan_width = max($fan_width, self::MINIMUM_WIDTH);
+ $fan_width = min($fan_width, self::MAXIMUM_WIDTH);
+ $fan_width = max($fan_width, self::MINIMUM_WIDTH);
- $generations = min($generations, self::MAXIMUM_GENERATIONS);
- $generations = max($generations, self::MINIMUM_GENERATIONS);
+ $generations = min($generations, self::MAXIMUM_GENERATIONS);
+ $generations = max($generations, self::MINIMUM_GENERATIONS);
- $title = /* I18N: http://en.wikipedia.org/wiki/Family_tree#Fan_chart - %s is an individual’s name */ I18N::translate('Fan chart of %s', $individual->getFullName());
+ $title = /* I18N: http://en.wikipedia.org/wiki/Family_tree#Fan_chart - %s is an individual’s name */
+ I18N::translate('Fan chart of %s', $individual->getFullName());
- return $this->viewResponse('fan-page', [
- 'chart_style' => $chart_style,
- 'chart_styles' => $this->chartStyles(),
- 'fan_width' => $fan_width,
- 'generations' => $generations,
- 'individual' => $individual,
- 'maximum_generations' => self::MAXIMUM_GENERATIONS,
- 'minimum_generations' => self::MINIMUM_GENERATIONS,
- 'maximum_width' => self::MAXIMUM_WIDTH,
- 'minimum_width' => self::MINIMUM_WIDTH,
- 'title' => $title,
- ]);
- }
+ return $this->viewResponse('fan-page', [
+ 'chart_style' => $chart_style,
+ 'chart_styles' => $this->chartStyles(),
+ 'fan_width' => $fan_width,
+ 'generations' => $generations,
+ 'individual' => $individual,
+ 'maximum_generations' => self::MAXIMUM_GENERATIONS,
+ 'minimum_generations' => self::MINIMUM_GENERATIONS,
+ 'maximum_width' => self::MAXIMUM_WIDTH,
+ 'minimum_width' => self::MINIMUM_WIDTH,
+ 'title' => $title,
+ ]);
+ }
- /**
- * Generate both the HTML and PNG components of the fan chart
- *
- * @param Request $request
- *
- * @return Response
- */
- public function chart(Request $request): Response {
- /** @var Tree $tree */
- $tree = $request->attributes->get('tree');
+ /**
+ * Generate both the HTML and PNG components of the fan chart
+ *
+ * @param Request $request
+ *
+ * @return Response
+ */
+ public function chart(Request $request): Response
+ {
+ /** @var Tree $tree */
+ $tree = $request->attributes->get('tree');
- $this->checkModuleIsActive($tree, 'fan_chart');
+ $this->checkModuleIsActive($tree, 'fan_chart');
- $xref = $request->get('xref');
- $individual = Individual::getInstance($xref, $tree);
+ $xref = $request->get('xref');
+ $individual = Individual::getInstance($xref, $tree);
- $this->checkIndividualAccess($individual);
+ $this->checkIndividualAccess($individual);
- $chart_style = (int) $request->get('chart_style', self::DEFAULT_STYLE);
- $fan_width = (int) $request->get('fan_width', self::DEFAULT_WIDTH);
- $generations = (int) $request->get('generations', self::DEFAULT_GENERATIONS);
+ $chart_style = (int)$request->get('chart_style', self::DEFAULT_STYLE);
+ $fan_width = (int)$request->get('fan_width', self::DEFAULT_WIDTH);
+ $generations = (int)$request->get('generations', self::DEFAULT_GENERATIONS);
- $fan_width = min($fan_width, self::MAXIMUM_WIDTH);
- $fan_width = max($fan_width, self::MINIMUM_WIDTH);
+ $fan_width = min($fan_width, self::MAXIMUM_WIDTH);
+ $fan_width = max($fan_width, self::MINIMUM_WIDTH);
- $generations = min($generations, self::MAXIMUM_GENERATIONS);
- $generations = max($generations, self::MINIMUM_GENERATIONS);
+ $generations = min($generations, self::MAXIMUM_GENERATIONS);
+ $generations = max($generations, self::MINIMUM_GENERATIONS);
- $ancestors = $this->sosaStradonitzAncestors($individual, $generations);
+ $ancestors = $this->sosaStradonitzAncestors($individual, $generations);
- $gen = $generations - 1;
- $sosa = count($ancestors);
+ $gen = $generations - 1;
+ $sosa = count($ancestors);
- // fan size
- $fanw = 640 * $fan_width / 100;
- $cx = $fanw / 2 - 1; // center x
- $cy = $cx; // center y
- $rx = $fanw - 1;
- $rw = $fanw / ($gen + 1);
- $fanh = $fanw; // fan height
- if ($chart_style === self::STYLE_HALF_CIRCLE) {
- $fanh = $fanh * ($gen + 1) / ($gen * 2);
- }
- if ($chart_style === self::STYLE_THREE_QUARTER_CIRCLE) {
- $fanh = $fanh * 0.86;
- }
- $scale = $fanw / 640;
+ // fan size
+ $fanw = 640 * $fan_width / 100;
+ $cx = $fanw / 2 - 1; // center x
+ $cy = $cx; // center y
+ $rx = $fanw - 1;
+ $rw = $fanw / ($gen + 1);
+ $fanh = $fanw; // fan height
+ if ($chart_style === self::STYLE_HALF_CIRCLE) {
+ $fanh = $fanh * ($gen + 1) / ($gen * 2);
+ }
+ if ($chart_style === self::STYLE_THREE_QUARTER_CIRCLE) {
+ $fanh = $fanh * 0.86;
+ }
+ $scale = $fanw / 640;
- // Create the image
- $image = imagecreate((int) $fanw, (int) $fanh);
+ // Create the image
+ $image = imagecreate((int)$fanw, (int)$fanh);
- // Create colors
- $transparent = imagecolorallocate($image, 0, 0, 0);
- imagecolortransparent($image, $transparent);
+ // Create colors
+ $transparent = imagecolorallocate($image, 0, 0, 0);
+ imagecolortransparent($image, $transparent);
- $theme = Theme::theme();
+ $theme = Theme::theme();
- $foreground = $this->imageColor($image, $theme->parameter('chart-font-color'));
+ $foreground = $this->imageColor($image, $theme->parameter('chart-font-color'));
- $backgrounds = [
- 'M' => $this->imageColor($image, $theme->parameter('chart-background-m')),
- 'F' => $this->imageColor($image, $theme->parameter('chart-background-f')),
- 'U' => $this->imageColor($image, $theme->parameter('chart-background-u')),
- ];
+ $backgrounds = [
+ 'M' => $this->imageColor($image, $theme->parameter('chart-background-m')),
+ 'F' => $this->imageColor($image, $theme->parameter('chart-background-f')),
+ 'U' => $this->imageColor($image, $theme->parameter('chart-background-u')),
+ ];
- imagefilledrectangle($image, 0, 0, (int) $fanw, (int) $fanh, $transparent);
+ imagefilledrectangle($image, 0, 0, (int)$fanw, (int)$fanh, $transparent);
- $fandeg = 90 * $chart_style;
+ $fandeg = 90 * $chart_style;
- // Popup menus for each ancestor
- $html = '';
+ // Popup menus for each ancestor
+ $html = '';
- // Areas for the imagemap
- $areas = '';
+ // Areas for the imagemap
+ $areas = '';
- // loop to create fan cells
- while ($gen >= 0) {
- // clean current generation area
- $deg2 = 360 + ($fandeg - 180) / 2;
- $deg1 = $deg2 - $fandeg;
- imagefilledarc($image, (int) $cx, (int) $cy, (int) $rx, (int) $rx, (int) $deg1, (int) $deg2, $backgrounds['U'], IMG_ARC_PIE);
- $rx -= 3;
+ // loop to create fan cells
+ while ($gen >= 0) {
+ // clean current generation area
+ $deg2 = 360 + ($fandeg - 180) / 2;
+ $deg1 = $deg2 - $fandeg;
+ imagefilledarc($image, (int)$cx, (int)$cy, (int)$rx, (int)$rx, (int)$deg1, (int)$deg2, $backgrounds['U'], IMG_ARC_PIE);
+ $rx -= 3;
- // calculate new angle
- $p2 = pow(2, $gen);
- $angle = $fandeg / $p2;
- $deg2 = 360 + ($fandeg - 180) / 2;
- $deg1 = $deg2 - $angle;
- // special case for rootid cell
- if ($gen == 0) {
- $deg1 = 90;
- $deg2 = 360 + $deg1;
- }
+ // calculate new angle
+ $p2 = pow(2, $gen);
+ $angle = $fandeg / $p2;
+ $deg2 = 360 + ($fandeg - 180) / 2;
+ $deg1 = $deg2 - $angle;
+ // special case for rootid cell
+ if ($gen == 0) {
+ $deg1 = 90;
+ $deg2 = 360 + $deg1;
+ }
- // draw each cell
- while ($sosa >= $p2) {
- $person = $ancestors[$sosa];
- if ($person) {
- $name = $person->getFullName();
- $addname = $person->getAddName();
+ // draw each cell
+ while ($sosa >= $p2) {
+ $person = $ancestors[$sosa];
+ if ($person) {
+ $name = $person->getFullName();
+ $addname = $person->getAddName();
- $text = I18N::reverseText($name);
- if ($addname) {
- $text .= "\n" . I18N::reverseText($addname);
- }
+ $text = I18N::reverseText($name);
+ if ($addname) {
+ $text .= "\n" . I18N::reverseText($addname);
+ }
- $text .= "\n" . I18N::reverseText($person->getLifeSpan());
+ $text .= "\n" . I18N::reverseText($person->getLifeSpan());
- $background = $backgrounds[$person->getSex()];
+ $background = $backgrounds[$person->getSex()];
- imagefilledarc($image, (int) $cx, (int) $cy, (int) $rx, (int) $rx, (int) $deg1, (int) $deg2, $background, IMG_ARC_PIE);
+ imagefilledarc($image, (int)$cx, (int)$cy, (int)$rx, (int)$rx, (int)$deg1, (int)$deg2, $background, IMG_ARC_PIE);
- // split and center text by lines
- $wmax = (int) ($angle * 7 / 7 * $scale);
- $wmax = min($wmax, 35 * $scale);
- if ($gen == 0) {
- $wmax = min($wmax, 17 * $scale);
- }
- $text = $this->splitAlignText($text, (int) $wmax);
+ // split and center text by lines
+ $wmax = (int)($angle * 7 / 7 * $scale);
+ $wmax = min($wmax, 35 * $scale);
+ if ($gen == 0) {
+ $wmax = min($wmax, 17 * $scale);
+ }
+ $text = $this->splitAlignText($text, (int)$wmax);
- // text angle
- $tangle = 270 - ($deg1 + $angle / 2);
- if ($gen == 0) {
- $tangle = 0;
- }
+ // text angle
+ $tangle = 270 - ($deg1 + $angle / 2);
+ if ($gen == 0) {
+ $tangle = 0;
+ }
- // calculate text position
- $deg = $deg1 + 0.44;
- if ($deg2 - $deg1 > 40) {
- $deg = $deg1 + ($deg2 - $deg1) / 11;
- }
- if ($deg2 - $deg1 > 80) {
- $deg = $deg1 + ($deg2 - $deg1) / 7;
- }
- if ($deg2 - $deg1 > 140) {
- $deg = $deg1 + ($deg2 - $deg1) / 4;
- }
- if ($gen == 0) {
- $deg = 180;
- }
- $rad = deg2rad($deg);
- $mr = ($rx - $rw / 4) / 2;
- if ($gen > 0 && $deg2 - $deg1 > 80) {
- $mr = $rx / 2;
- }
- $tx = $cx + $mr * cos($rad);
- $ty = $cy + $mr * sin($rad);
- if ($sosa == 1) {
- $ty -= $mr / 2;
- }
+ // calculate text position
+ $deg = $deg1 + 0.44;
+ if ($deg2 - $deg1 > 40) {
+ $deg = $deg1 + ($deg2 - $deg1) / 11;
+ }
+ if ($deg2 - $deg1 > 80) {
+ $deg = $deg1 + ($deg2 - $deg1) / 7;
+ }
+ if ($deg2 - $deg1 > 140) {
+ $deg = $deg1 + ($deg2 - $deg1) / 4;
+ }
+ if ($gen == 0) {
+ $deg = 180;
+ }
+ $rad = deg2rad($deg);
+ $mr = ($rx - $rw / 4) / 2;
+ if ($gen > 0 && $deg2 - $deg1 > 80) {
+ $mr = $rx / 2;
+ }
+ $tx = $cx + $mr * cos($rad);
+ $ty = $cy + $mr * sin($rad);
+ if ($sosa == 1) {
+ $ty -= $mr / 2;
+ }
- // print text
- imagettftext(
- $image,
- 7,
- $tangle, (int) $tx, (int) $ty,
- $foreground,
- WT_ROOT . 'resources/fonts/DejaVuSans.ttf',
- $text
- );
+ // print text
+ imagettftext(
+ $image,
+ 7,
+ $tangle, (int)$tx, (int)$ty,
+ $foreground,
+ WT_ROOT . 'resources/fonts/DejaVuSans.ttf',
+ $text
+ );
- $areas .= '<area shape="poly" coords="';
- // plot upper points
- $mr = $rx / 2;
- $deg = $deg1;
- while ($deg <= $deg2) {
- $rad = deg2rad($deg);
- $tx = round($cx + $mr * cos($rad));
- $ty = round($cy + $mr * sin($rad));
- $areas .= "$tx,$ty,";
- $deg += ($deg2 - $deg1) / 6;
- }
- // plot lower points
- $mr = ($rx - $rw) / 2;
- $deg = $deg2;
- while ($deg >= $deg1) {
- $rad = deg2rad($deg);
- $tx = round($cx + $mr * cos($rad));
- $ty = round($cy + $mr * sin($rad));
- $areas .= "$tx,$ty,";
- $deg -= ($deg2 - $deg1) / 6;
- }
- // join first point
- $mr = $rx / 2;
- $deg = $deg1;
- $rad = deg2rad($deg);
- $tx = round($cx + $mr * cos($rad));
- $ty = round($cy + $mr * sin($rad));
- $areas .= "$tx,$ty";
- // add action url
- $areas .= '" href="#' . $person->getXref() . '"';
- $html .= '<div id="' . $person->getXref() . '" class="fan_chart_menu">';
- $html .= '<div class="person_box"><div class="details1">';
- $html .= '<a href="' . e($person->url()) . '" class="name1">' . $name;
- if ($addname) {
- $html .= $addname;
- }
- $html .= '</a>';
- $html .= '<ul class="charts">';
- foreach ($theme->individualBoxMenu($person) as $menu) {
- $html .= $menu->getMenuAsList();
- }
- $html .= '</ul>';
- $html .= '</div></div>';
- $html .= '</div>';
- $areas .= ' alt="' . strip_tags($person->getFullName()) . '" title="' . strip_tags($person->getFullName()) . '">';
- }
- $deg1 -= $angle;
- $deg2 -= $angle;
- $sosa--;
- }
- $rx -= $rw;
- $gen--;
- }
+ $areas .= '<area shape="poly" coords="';
+ // plot upper points
+ $mr = $rx / 2;
+ $deg = $deg1;
+ while ($deg <= $deg2) {
+ $rad = deg2rad($deg);
+ $tx = round($cx + $mr * cos($rad));
+ $ty = round($cy + $mr * sin($rad));
+ $areas .= "$tx,$ty,";
+ $deg += ($deg2 - $deg1) / 6;
+ }
+ // plot lower points
+ $mr = ($rx - $rw) / 2;
+ $deg = $deg2;
+ while ($deg >= $deg1) {
+ $rad = deg2rad($deg);
+ $tx = round($cx + $mr * cos($rad));
+ $ty = round($cy + $mr * sin($rad));
+ $areas .= "$tx,$ty,";
+ $deg -= ($deg2 - $deg1) / 6;
+ }
+ // join first point
+ $mr = $rx / 2;
+ $deg = $deg1;
+ $rad = deg2rad($deg);
+ $tx = round($cx + $mr * cos($rad));
+ $ty = round($cy + $mr * sin($rad));
+ $areas .= "$tx,$ty";
+ // add action url
+ $areas .= '" href="#' . $person->getXref() . '"';
+ $html .= '<div id="' . $person->getXref() . '" class="fan_chart_menu">';
+ $html .= '<div class="person_box"><div class="details1">';
+ $html .= '<a href="' . e($person->url()) . '" class="name1">' . $name;
+ if ($addname) {
+ $html .= $addname;
+ }
+ $html .= '</a>';
+ $html .= '<ul class="charts">';
+ foreach ($theme->individualBoxMenu($person) as $menu) {
+ $html .= $menu->getMenuAsList();
+ }
+ $html .= '</ul>';
+ $html .= '</div></div>';
+ $html .= '</div>';
+ $areas .= ' alt="' . strip_tags($person->getFullName()) . '" title="' . strip_tags($person->getFullName()) . '">';
+ }
+ $deg1 -= $angle;
+ $deg2 -= $angle;
+ $sosa--;
+ }
+ $rx -= $rw;
+ $gen--;
+ }
- ob_start();
- imagepng($image);
- imagedestroy($image);
- $png = ob_get_clean();
+ ob_start();
+ imagepng($image);
+ imagedestroy($image);
+ $png = ob_get_clean();
- $title = /* I18N: http://en.wikipedia.org/wiki/Family_tree#Fan_chart - %s is an individual’s name */ I18N::translate('Fan chart of %s', $individual->getFullName());
+ $title = /* I18N: http://en.wikipedia.org/wiki/Family_tree#Fan_chart - %s is an individual’s name */
+ I18N::translate('Fan chart of %s', $individual->getFullName());
- return new Response(view('fan-chart', [
- 'fanh' => $fanh,
- 'fanw' => $fanw,
- 'html' => $html,
- 'areas' => $areas,
- 'png' => $png,
- 'title' => $title,
- ]));
- }
+ return new Response(view('fan-chart', [
+ 'fanh' => $fanh,
+ 'fanw' => $fanw,
+ 'html' => $html,
+ 'areas' => $areas,
+ 'png' => $png,
+ 'title' => $title,
+ ]));
+ }
- /**
- * split and center text by lines
- *
- * @param string $data input string
- * @param int $maxlen max length of each line
- *
- * @return string $text output string
- */
- private function splitAlignText(string $data, int $maxlen): string {
- $RTLOrd = [215, 216, 217, 218, 219];
+ /**
+ * split and center text by lines
+ *
+ * @param string $data input string
+ * @param int $maxlen max length of each line
+ *
+ * @return string $text output string
+ */
+ private function splitAlignText(string $data, int $maxlen): string
+ {
+ $RTLOrd = [
+ 215,
+ 216,
+ 217,
+ 218,
+ 219,
+ ];
- $lines = explode("\n", $data);
- // more than 1 line : recursive calls
- if (count($lines) > 1) {
- $text = '';
- foreach ($lines as $line) {
- $text .= $this->splitAlignText($line, $maxlen) . "\n";
- }
+ $lines = explode("\n", $data);
+ // more than 1 line : recursive calls
+ if (count($lines) > 1) {
+ $text = '';
+ foreach ($lines as $line) {
+ $text .= $this->splitAlignText($line, $maxlen) . "\n";
+ }
- return $text;
- }
- // process current line word by word
- $split = explode(' ', $data);
- $text = '';
- $line = '';
+ return $text;
+ }
+ // process current line word by word
+ $split = explode(' ', $data);
+ $text = '';
+ $line = '';
- // do not split hebrew line
- $found = false;
- foreach ($RTLOrd as $ord) {
- if (strpos($data, chr($ord)) !== false) {
- $found = true;
- }
- }
- if ($found) {
- $line = $data;
- } else {
- foreach ($split as $word) {
- $len = strlen($line);
- $wlen = strlen($word);
- if (($len + $wlen) < $maxlen) {
- if (!empty($line)) {
- $line .= ' ';
- }
- $line .= "$word";
- } else {
- $p = max(0, (int) (($maxlen - $len) / 2));
- if (!empty($line)) {
- $line = str_repeat(' ', $p) . $line; // center alignment using spaces
- $text .= $line . "\n";
- }
- $line = $word;
- }
- }
- }
- // last line
- if (!empty($line)) {
- $len = strlen($line);
- if (in_array(ord($line{0}), $RTLOrd)) {
- $len /= 2;
- }
- $p = max(0, (int) (($maxlen - $len) / 2));
- $line = str_repeat(' ', $p) . $line; // center alignment using spaces
- $text .= $line;
- }
+ // do not split hebrew line
+ $found = false;
+ foreach ($RTLOrd as $ord) {
+ if (strpos($data, chr($ord)) !== false) {
+ $found = true;
+ }
+ }
+ if ($found) {
+ $line = $data;
+ } else {
+ foreach ($split as $word) {
+ $len = strlen($line);
+ $wlen = strlen($word);
+ if (($len + $wlen) < $maxlen) {
+ if (!empty($line)) {
+ $line .= ' ';
+ }
+ $line .= "$word";
+ } else {
+ $p = max(0, (int)(($maxlen - $len) / 2));
+ if (!empty($line)) {
+ $line = str_repeat(' ', $p) . $line; // center alignment using spaces
+ $text .= $line . "\n";
+ }
+ $line = $word;
+ }
+ }
+ }
+ // last line
+ if (!empty($line)) {
+ $len = strlen($line);
+ if (in_array(ord($line{0}), $RTLOrd)) {
+ $len /= 2;
+ }
+ $p = max(0, (int)(($maxlen - $len) / 2));
+ $line = str_repeat(' ', $p) . $line; // center alignment using spaces
+ $text .= $line;
+ }
- return $text;
- }
+ return $text;
+ }
- /**
- * Convert a CSS color into a GD color.
- *
- * @param resource $image
- * @param string $css_color
- *
- * @return int
- */
- private function imageColor($image, string $css_color): int {
- return imagecolorallocate(
- $image,
- (int) hexdec(substr($css_color, 0, 2)),
- (int) hexdec(substr($css_color, 2, 2)),
- (int) hexdec(substr($css_color, 4, 2))
- );
- }
+ /**
+ * Convert a CSS color into a GD color.
+ *
+ * @param resource $image
+ * @param string $css_color
+ *
+ * @return int
+ */
+ private function imageColor($image, string $css_color): int
+ {
+ return imagecolorallocate(
+ $image,
+ (int)hexdec(substr($css_color, 0, 2)),
+ (int)hexdec(substr($css_color, 2, 2)),
+ (int)hexdec(substr($css_color, 4, 2))
+ );
+ }
- /**
- * This chart can display its output in a number of styles
- *
- * @return array
- */
- private function chartStyles(): array {
- return [
- self::STYLE_HALF_CIRCLE => /* I18N: layout option for the fan chart */ I18N::translate('half circle'),
- self::STYLE_THREE_QUARTER_CIRCLE => /* I18N: layout option for the fan chart */ I18N::translate('three-quarter circle'),
- self::STYLE_FULL_CIRCLE => /* I18N: layout option for the fan chart */ I18N::translate('full circle'),
- ];
- }
+ /**
+ * This chart can display its output in a number of styles
+ *
+ * @return array
+ */
+ private function chartStyles(): array
+ {
+ return [
+ self::STYLE_HALF_CIRCLE => /* I18N: layout option for the fan chart */
+ I18N::translate('half circle'),
+ self::STYLE_THREE_QUARTER_CIRCLE => /* I18N: layout option for the fan chart */
+ I18N::translate('three-quarter circle'),
+ self::STYLE_FULL_CIRCLE => /* I18N: layout option for the fan chart */
+ I18N::translate('full circle'),
+ ];
+ }
}