Location: PHPKode > projects > HuMo-gen > fanchart.php
<?php
@set_time_limit(3000);

 /****************************************************************************
 * fanchart.php                                                              *
 * Original fan plotting code from PhpGedView (GNU/GPL licence)              *
 *                                                                           *
 * Rewritten and adapted for HuMo-gen by Yossi Beck  -  October 2009         *
 *                                                                           *
 * This program is free software; you can redistribute it and/or modify      *
 * it under the terms of the GNU General Public License as published by      *
 * the Free Software Foundation; either version 2 of the License, or         *
 * (at your option) any later version.                                       *
 *                                                                           *
 * This program is distributed in the hope that it will be useful,           *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 * GNU General Public License for more details.                              *
 ****************************************************************************/

$kop="fanchart";
include("header.php");

include ("include/language_date.php");
include("include/language_event.php");
include("include/calculate_age_cls.php");
include('include/person_cls.php');
 
require_once('fanchart/persian_log2vis.php');

include("menu.php");

$gezin_id=1; // *** 1e gezin weergeven als dit bestand rechtstreeks wordt aangeroepen. ***
if (isset($_GET["id"])){ $gezin_id=$_GET["id"]; }
if (isset($_POST["id"])){ $gezin_id=$_POST["id"]; }

$chosengen=5;
if (isset($_GET["chosengen"])){ $chosengen=$_GET["chosengen"]; }
if (isset($_POST["chosengen"])){ $chosengen=$_POST["chosengen"]; }

$fontsize=7;
if (isset($_GET["fontsize"])){ $fontsize=$_GET["fontsize"]; }
if (isset($_POST["fontsize"])){ $fontsize=$_POST["fontsize"]; }

$date_display=2;
if (isset($_GET["date_display"])){ $date_display=$_GET["date_display"]; }
if (isset($_POST["date_display"])){ $date_display=$_POST["date_display"]; }

$printing=1;
if (isset($_GET["printing"])){ $printing=$_GET["printing"]; }
if (isset($_POST["printing"])){ $printing=$_POST["printing"]; }

$treeid = array();

$maxperson = pow(2,$chosengen);
// initialize array
for ($i=0 ; $i < $maxperson; $i++) {
	for ($n=0; $n<6; $n++) {
		$treeid[$i][$n]="";
	}
}

function fillarray ($nr, $famid) {
	global $maxperson;
	global $treeid;
	global $db;
	if ($nr >= $maxperson) { return; }
	if ($famid) {
		$persoonmn=mysql_query("SELECT * FROM ".veilig($_SESSION['tree_prefix'])."person
		  WHERE pers_gedcomnumber='".$famid."'",$db);
		@$persoonmnDb=mysql_fetch_object($persoonmn);
		$man_cls = New persoon_cls;
		$man_cls->construct($persoonmnDb);
		$levendmn=$man_cls->privacy;
						  
		$treeid[$nr][0]=$man_cls->naam($persoonmnDb);
		$treeid[$nr][1]=$persoonmnDb->pers_birth_date;
		$treeid[$nr][4]=$persoonmnDb->pers_death_date;
		$pos=strpos($persoonmnDb->pers_fams,";");
		if($pos===false) { $treeid[$nr][2]=$persoonmnDb->pers_fams; }
		else {$treeid[$nr][2]=substr($persoonmnDb->pers_fams,0,$pos);}
		$treeid[$nr][3]=$famid;
		$treeid[$nr][5]=$persoonmnDb->pers_sexe;

		if ($persoonmnDb->pers_famc){
			$query_gezin= "SELECT * FROM ".veilig($_SESSION['tree_prefix'])."family
			 WHERE fam_gedcomnumber = '".$persoonmnDb->pers_famc."'";
			$result_gezin = mysql_query($query_gezin,$db);
			@$record_gezin = mysql_fetch_object($result_gezin);
			if ($record_gezin->fam_man){
				fillarray ($nr*2, $record_gezin->fam_man);
			}
			if ($record_gezin->fam_woman){
				fillarray ($nr*2+1, $record_gezin->fam_woman);
			}
		}
	}
} //END FUNCTION FILLARRAY

fillarray(1, $gezin_id);

/* split and center text by lines
 * @param string $data input string
 * @param int $maxlen max length of each line
 * @return string $text output string
 */
function split_align_text($data, $maxlen, $rtlflag, $nameflag, $gennr) {
	$lines = explode("\n", $data);
	// more than 1 line : recursive calls
	if (count($lines)>1) {
		$text = "";
		foreach ($lines as $indexval => $line) $text .= split_align_text($line, $maxlen, $rtlflag, $nameflag, $gennr )."\n";
		return $text;
	}

	// process current line word by word
	$split = explode(" ", $data);
	$text = "";
	$line = "";
	
	if($rtlflag==1 AND $nameflag==1) {	// rtl name has to be re-positioned	 		 
		global $fan_style;
		if($fan_style==2 AND ($gennr==1 OR $gennr==2)) { $maxlen *= 1.5; } // half-circle has different position for 2nd 3rd generation
		else { $maxlen *= 2; }
	}    
	
	$found = false;
	if ($found) $line=$data;
	else
	foreach ($split as $indexval => $word) {
		$len = strlen($line);
		$wlen = strlen($word);

		// line too long ?
		if (($len+$wlen)<$maxlen) {
			if (!empty($line)) $line .= " ";
			$line .= "$word";
		}
		else {
			$p = max(0,floor(($maxlen-$len)/2));
			if (!empty($line)) {
				if($rtlflag==1 AND $nameflag==1) {   // trl name
					$line = "$line".str_repeat(" ", $p); //
				}
				elseif ($rtlflag==1 AND $nameflag==0) {
					$line = str_repeat(" ", $p*1.5) . "$line"; // center alignment using spaces
				}
				else {
					$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,floor(($maxlen-$len)/2));
		if($rtlflag==1 AND $nameflag==1) {
			$line = "$line".str_repeat(" ", $p);
		}
		elseif ($rtlflag==1 AND $nameflag==0) {
			$line = str_repeat(" ", $p*1.5) . "$line"; // center alignment using spaces
		}
		else {
			$line = str_repeat(" ", $p) . "$line"; // center alignment using spaces
		}
		$text .= "$line";
	}
        // $text.=$wlen;
	return $text;
}

/**
 * print ancestors on a fan chart
 * @param array $treeid ancestry pid
 * @param int $fanw fan width in px (default=840)
 * @param int $fandeg fan size in deg (default=270)
 */
function print_fan_chart($treeid, $fanw=840, $fandeg=270) {
	global $fontsize, $date_display;
	global $fan_style, $gezin_id;
	global $printing, $language;

	// check for GD 2.x library
	if (!defined("IMG_ARC_PIE")) {
		print "ERROR: NO GD LIBRARY";
		return false;
	}
	if (!function_exists("ImageTtfBbox")) {
		print "ERROR: NO GD LIBRARY";
		return false;
	}

	$fontfile="./fanchart/dejavusans.ttf";

	if (intval($fontsize)<2) $fontsize = 7;

	$treesize=count($treeid);
	if ($treesize<1) return;

	// generations count
	$gen=log($treesize)/log(2)-1;
	$sosa=$treesize-1;

	// fan size
	if ($fandeg==0) $fandeg=360;
	$fandeg=min($fandeg, 360);
	$fandeg=max($fandeg, 90);
	$cx=$fanw/2-1; // center x
	$cy=$cx; // center y
	$rx=$fanw-1;
	$rw=$fanw/($gen+1);
	$fanh=$fanw; // fan height
	if ($fandeg==180) $fanh=round($fanh*($gen+1)/($gen*2));
	if ($fandeg==270) $fanh=round($fanh*.86);
	$scale=$fanw/840;

	// image init
	$image = ImageCreate($fanw, $fanh);
	$black = ImageColorAllocate($image, 0, 0, 0);
	$white = ImageColorAllocate($image, 0xFF, 0xFF, 0xFF);
	ImageFilledRectangle ($image, 0, 0, $fanw, $fanh, $white);
	if($printing==1) {
		ImageColorTransparent($image, $white);
	}

	// *** Border colour ***
	$rgb=""; if (empty($rgb)) $rgb = "#6E6E6E";
	$grey = ImageColorAllocate($image, hexdec(substr($rgb,1,2)), hexdec(substr($rgb,3,2)), hexdec(substr($rgb,5,2)));

	// *** Text colour ***
	$rgb=""; if (empty($rgb)) $rgb = "#000000";
	$color = ImageColorAllocate($image, hexdec(substr($rgb,1,2)), hexdec(substr($rgb,3,2)), hexdec(substr($rgb,5,2)));

	// *** Background colour ***
	$rgb=""; if (empty($rgb)) $rgb = "#EEEEEE";
	$bgcolor = ImageColorAllocate($image, hexdec(substr($rgb,1,2)), hexdec(substr($rgb,3,2)), hexdec(substr($rgb,5,2)));

	// *** Man colour ***
	$rgb=""; if (empty($rgb)) $rgb = "#B2DFEE";
	$bgcolorM = ImageColorAllocate($image, hexdec(substr($rgb,1,2)), hexdec(substr($rgb,3,2)), hexdec(substr($rgb,5,2)));

	// *** wife colour ***
	$rgb=""; if (empty($rgb)) $rgb = "#FFE4C4";
	$bgcolorF = ImageColorAllocate($image, hexdec(substr($rgb,1,2)), hexdec(substr($rgb,3,2)), hexdec(substr($rgb,5,2)));

	// imagemap
	$imagemap="<map id=\"fanmap\" name=\"fanmap\">";

	// loop to create fan cells
	while ($gen>=0) {
		// clean current generation area
		$deg2=360+($fandeg-180)/2;
		$deg1=$deg2-$fandeg;
		ImageFilledArc($image, $cx, $cy, $rx, $rx, $deg1, $deg2, $bgcolor, IMG_ARC_PIE);
		ImageFilledArc($image, $cx, $cy, $rx, $rx, $deg1, $deg2, $bgcolor, IMG_ARC_EDGED | IMG_ARC_NOFILL);
		$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;
		}

		// draw each cell
		while ($sosa >= $p2) {
			$pid=$treeid[$sosa][0];
			$birthyr=$treeid[$sosa][1];
			$deathyr=$treeid[$sosa][4];
			$fontpx=$fontsize;
			if($sosa>=16 AND $fandeg==180) { $fontpx=$fontsize-1; }
			if($sosa>=32 AND $fandeg!=180) { $fontpx=$fontsize-1; }
			if (!empty($pid)) {
				if ($sosa%2) $bg=$bgcolorF;
				else $bg=$bgcolorM; 
				if ($sosa==1) {
					if($treeid[$sosa][5]=="F") {
						$bg=$bgcolorF;
							}
						else if ($treeid[$sosa][5]=="M") {
							$bg=$bgcolorM;
						}
					else {
						$bg=$bgcolor; // sex unknown
	    			}
				}

				ImageFilledArc($image, $cx, $cy, $rx, $rx, $deg1, $deg2, $bg, IMG_ARC_PIE);
				if($gen!=0) {
					ImageFilledArc($image, $cx, $cy, $rx, $rx, $deg1, $deg2, $grey, IMG_ARC_EDGED | IMG_ARC_NOFILL);
				}
				else {
					ImageFilledArc($image, $cx, $cy, $rx, $rx, $deg1, $deg2, $grey, IMG_ARC_NOFILL);
		 			}

				$name=$pid; 
				
				// check if string is rtl by checking first or second char (second in case first is " or parentheses)
				$rtlstr=0;
				$tempname=htmlentities($name);

				if(substr($tempname,0,1)=="&" OR substr($tempname,1,1)=="&") {
					//  persian_log2vis($name);
					$rtlstr=1;
				}

				$text = $name; // names
				$text2=""; // dates
				if($date_display==1) {  // don't show dates
				}
				else if ($date_display==2) { //show years only
					// years only chosen but we also do this if no place in outer circles
					$text2 .= substr($birthyr,-4)." - ".substr($deathyr,-4);
		 		}
				else if ($date_display==3) {  //show full dates (but not in narrow outer circles!)
					if ($gen >5) {
						$text2 .= substr($birthyr,-4)." - ".substr($deathyr,-4);
					}
						else if ($gen >4 AND $fan_style != 4) {
						$text2 .= substr($birthyr,-4)." - ".substr($deathyr,-4);
					}
					else {  // full dates
						if($birthyr) { $text2 .= "b.".$birthyr."\n"; }
						if($deathyr) { $text2 .= "d.".$deathyr; }
					}
				}

				// split and center text by lines
				$wmax = floor($angle*7/$fontpx*$scale);
				$wmax = min($wmax,35*$scale);  //35
				//$wmax = floor((90*$wmax)/100);
				if ($gen==0) $wmax = min($wmax, 17*$scale);  //17
				$text = split_align_text($text, $wmax, $rtlstr, 1, $gen);
				$text2 = split_align_text($text2, $wmax, $rtlstr, 0, $gen);

				if($rtlstr==1) {
					persian_log2vis($text);
				}

				$text.="\n".$text2;

				// text angle
				$tangle = 270-($deg1+$angle/2);
				if ($gen==0) $tangle=0;

				// calculate text position
				$bbox=ImageTtfBbox((double)$fontpx, 0, $fontfile, $text);
				$textwidth = $bbox[4]; //4
 
				$deg = $deg1+.44;  
				if ($deg2-$deg1>40) $deg = $deg1+($deg2-$deg1)/11;   // 11
				if ($deg2-$deg1>80) $deg = $deg1+($deg2-$deg1)/7;   //  7
				if ($deg2-$deg1>140) $deg = $deg1+($deg2-$deg1)/4;  //  4


				if ($gen==0) $deg=180;

				$rad=deg2rad($deg);
				$mr=($rx-$rw/4)/2;
				if ($gen>0 and $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, (double)$fontpx, $tangle, $tx, $ty, $color, $fontfile, $text);

				$imagemap .= "<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));
					$imagemap .= "$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));
					$imagemap .= "$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));
				$imagemap .= "$tx, $ty";
					$imagemap .= "\" href=\"gezin.php?id=".$treeid[$sosa][2]."&amp;hoofdpersoon=".$treeid[$sosa][3]."\"";
	        $imagemap .= " alt=\"".$pid."\" title=\"".$pid."\">";
			}
			$deg1-=$angle;
			$deg2-=$angle;
			$sosa--;
		}
		$rx-=$rw;
		$gen--;
	}

	$imagemap .= "</map>";

	echo $imagemap;

	// here we cannot send image to browser ('header already sent')
	// and we dont want to use a tmp file

	// step 1. save image data in a session variable
	ob_start();
	ImagePng($image);
	$image_data = ob_get_contents();
	ob_end_clean();
	$image_data = serialize($image_data);
	unset ($_SESSION['image_data']);
	$_SESSION['image_data']=$image_data;

	// step 2. call fanimage.php to read this session variable and display image
	$image_title=preg_replace("~<.*>~", "", $name) ."   - RELOAD FANCHART WITH 'VIEW' BUTTON ON THE LEFT";
	echo "<p align=\"center\" >";
	echo "<img src=\"fanchart/fanimage.php\" width=\"$fanw\" height=\"$fanh\" border=\"0\" alt=\"$image_title\" title=\"$image_title\" usemap=\"#fanmap\">";
	echo "</p>\n";
	ImageDestroy($image);
}

$fan_style=3;
$maxgens=7;
$fan_width="auto";

if (isset($_GET["fan_style"])){ $fan_style=$_GET["fan_style"]; }
if (isset($_POST["fan_style"])){ $fan_style=$_POST["fan_style"]; }
if (isset($_GET["fan_width"])){ $fan_width=$_GET["fan_width"]; }
if (isset($_POST["fan_width"])){ $fan_width=$_POST["fan_width"]; }

if ($fan_width >50 AND $fan_width <301){ $tmp_width=$fan_width; }
	else { // "auto" or invalid entry - reset to 100%
		$tmp_width=100;
}
$realwidth=(840*$tmp_width)/100; // realwidth needed for next line (top text)

// Text on Top: Name of base person and print-help link
echo '<div style="z-index:80; position:absolute; top:25px; left:130px; width:'.$realwidth.'px; height:30px; text-align:center; color:#000000">';
 
echo '<div style="padding:5px">';  
print "<strong>FANCHART - ".$treeid[1][0]."</strong>\n";

//======== HELP POPUP ========================
//echo '<span class="sddm" style="position:absolute;left:500px;top:3px;">';
echo '<div class='.$rtlmarker.'sddm>';
	echo '<a href="#"';
	echo ' style="display:inline" ';
	//echo 'onmouseover="mopen(event,\'hulpmenu\')"';
	echo 'onmouseover="mopen(event,\'hulpmenu\',0,0)"';
	echo 'onmouseout="mclosetime()">';
	echo '<br><strong>'.$language["fan_help"].'</strong>';
	echo '</a>&nbsp;';

	//echo '<div style="z-index:40;padding:4px" id="hulpmenu" onmouseover="mcancelclosetime()" onmouseout="mclosetime()">';
	echo '<div class="sddm_fixed" style="z-index:40; text-align:'.$alignmarker.'; padding:4px; direction:'.$rtlmarker.'" id="hulpmenu" onmouseover="mcancelclosetime()" onmouseout="mclosetime()">';

		echo $language["fan_help1"].'<br>';
		echo $language["fan_help2"];
		
	echo '</div>';
echo "</div>\n";

//=================================


echo '</div></div>';

// Semi-transparant MENU BOX on the left
echo '<div class="weergave fanmenu1">';
echo '<div class="weergave fanmenu2">';
echo '<div class="weergave fanmenu3">';
echo '</div>';
echo '<div class=weergave style="position:absolute; left:0; top:0; color: #000000">';

//echo '<div style="border: 2px solid #000077; padding:10px">';
			 
print "<form name=\"people\" method=\"post\" action=\"fanchart.php?id=".$gezin_id."\" style=\"display:inline;\">";
	//print "<br>";
	print "<input type=\"submit\" value=\"" .$language["fanmenu_view"]. "\">";

	// Fan style
	print '<br><hr style="width:110px">';
	print $language["fanmenu_style"]."<br>";         
	print '<div style="text-align:'.$alignmarker.';margin-left:15%;margin-right:15%">'; 
        print "<input type=\"radio\" name=\"fan_style\" value=\"2\"";
	if ($fan_style==2) print " checked=\"checked\"";
	print ">".$language["fanmenu_half"];
         
	print "<br><input type=\"radio\" name=\"fan_style\" value=\"3\"";
	if ($fan_style==3) print " checked=\"checked\"";
	print "> 3/4";
	print "<br><input type=\"radio\" name=\"fan_style\" value=\"4\"";
	if ($fan_style==4) print " checked=\"checked\"";
	print ">".$language["fanmenu_full"]; 
        print '</div>';

	// Nr. of generations
	print '<hr style="width:110px">';
	print $language["fanmenu_generations"]."<br>";
	print "<select name=\"chosengen\">";
	for ($i=2; $i<=min(9,$maxgens); $i++) {
		print "<option value=\"".$i."\"" ;
		if ($i == $chosengen) print "selected=\"selected\" ";
		print ">".$i."</option>";
	}
	print "</select>";

	// Fontsize
	print '<br><hr style="width:110px">';
	print $language["fanmenu_fontsize"]."<br>";
	print "<select name=\"fontsize\">";
	for ($i=5; $i<=10; $i++) {
		print "<option value=\"".$i."\"" ;
		if ($i == $fontsize) print "selected=\"selected\" ";
	print ">".$i."</option>";
	}
	print "</select>";

	// Date display
	print '<br><hr style="width:110px">';
	print $language["fanmenu_datedisplay"]."<br>";

	print '<div style="text-align:'.$alignmarker.';margin-left:5%;margin-right:5%">';
 		print "<input type=\"radio\" name=\"date_display\" value=\"1\"";
		if ($date_display=="1") print " checked=\"checked\"";
		//print '>'.$language["fanmenu_nodates"].'</span>';
		print '>'.$language["fanmenu_nodates"];
   
		print "<br><input type=\"radio\" name=\"date_display\" value=\"2\"";
		if ($date_display=="2") print " checked=\"checked\"";
		print ">".$language["fanmenu_yearsonly"];
         
		print "<br><input type=\"radio\" name=\"date_display\" value=\"3\"";
		if ($date_display=="3") print " checked=\"checked\"";
		print ">".$language["fanmenu_fulldates"];
	print '</div>'; 

	// Fan width in percentages
	print '<hr style="width:110px">';
	print $language["fanmenu_fanwidth"]."<br>";
	print "<input type=\"text\" size=\"3\" name=\"fan_width\" value=\"$fan_width\"> <b>%</b> ";
	print '<div style="font-size:10px;">'.$language["fanmenu_auto"].'</div>';

	// Background (for printing with IE)
	print '<hr style="width:110px">';
	print $language["fanmenu_background"]."<br>";

	print '<div style="text-align:'.$alignmarker.';margin-left:5%;margin-right:5%">';
		print "<input type=\"radio\" name=\"printing\" value=\"1\"";
		if ($printing==1) print " checked=\"checked\"";
		print "> <span style=\"font-size:10px;\">".$language["fanmenu_transparent"]."</span>";
		print "<br><input type=\"radio\" name=\"printing\" value=\"2\"";
		if ($printing==2) print " checked=\"checked\"";
		print "> <span style=\"font-size:10px;\">".$language["fanmenu_white"]."</span>";
	print '</div>';

	print "</form>";
	print "</div></div></div>";

	//YB  Code to automatically make chart bigger when 7 generations are chosen
	//    and the boxes for generations in outer circle(s) become too small
	//    Same for 6 generations in half circle chart

if($fan_width=="auto") {
	if($chosengen==7) {
		if($fan_style==2){
			$fan_width=220;
		}
		else if($fan_style==3) {
			$fan_width=160;
		}
		else if($fan_style==4) {
			$fan_width=130;
		}
		else { //YB: you can never get here, but just for paranoia's sake...
			$fan_width=100;
		}
	}
	// or 6 generations with half circle...
	else if($chosengen==6 AND $fan_style==2){
		$fan_width=130;
	}
	else {
		$fan_width=100;
	}
}
else if($fan_width >50 AND $fan_width <301) {
}  // valid entry - leave it..
else { // invalid entry! reset to 100%
	$fan_width=100;
}

//  Container for fanchart
echo '<div style="position:absolute; top:60px; left:135px; width:'.$fan_width.'">';
echo '<div style="padding:10px">';

print_fan_chart($treeid, 840*$fan_width/100, $fan_style*90);

echo '</div></div>';
// end container for fanchart

include ("footer.php");
?>
Return current item: HuMo-gen