fan_style = WT_Filter::getInteger('fan_style', 2, 4, 3); $this->fan_width = WT_Filter::getInteger('fan_width', 50, 300, 100); $this->generations = WT_Filter::getInteger('generations', 2, 9, $default_generations); if ($this->root && $this->root->canShowName()) { $this->setPageTitle( /* I18N: http://en.wikipedia.org/wiki/Family_tree#Fan_chart - %s is an individual’s name */ WT_I18N::translate('Fan chart of %s', $this->root->getFullName()) ); } else { $this->setPageTitle(WT_I18N::translate('Fan chart')); } } public function getFanStyles() { return array( 2=>/* I18N: layout option for the fan chart */ WT_I18N::translate('half circle'), 3=>/* I18N: layout option for the fan chart */ WT_I18N::translate('three-quarter circle'), 4=>/* I18N: layout option for the fan chart */ WT_I18N::translate('full circle'), ); } /** * split and center text by lines * * @param string $data input string * @param int $maxlen max length of each line * @return string $text output string */ public function split_align_text($data, $maxlen) { $RTLOrd = array(215,216,217,218,219); $lines = explode("\n", $data); // more than 1 line : recursive calls if (count($lines)>1) { $text = ""; foreach ($lines as $indexval => $line) $text .= $this->split_align_text($line, $maxlen)."\n"; return $text; } // process current line word by word $split = explode(" ", $data); $text = ""; $line = ""; // do not split hebrew line $found = false; foreach ($RTLOrd as $indexval => $ord) { if (strpos($data, chr($ord)) !== false) $found=true; } if ($found) $line=$data; else foreach ($split as $indexval => $word) { $len = strlen($line); //if (!empty($line) and ord($line{0})==215) $len/=2; // hebrew text $wlen = strlen($word); // line too long ? 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; } // Generate either the HTML or PNG components of the chart - we send them separately public function generate_fan_chart($what) { global $fanChart; $treeid=ancestry_array($this->root->getXref(), $this->generations); $fanw =640*$this->fan_width/100; $fandeg=90*$this->fan_style; $html =''; // check for GD 2.x library if (!defined("IMG_ARC_PIE")) { return false; } if (!function_exists("ImageTtfBbox")) { return false; } // Validate if (!file_exists($fanChart['font'])) { $html.= '

'.WT_I18N::translate('The file “%s” does not exist.', $fanChart['font']).'

'; return false; } $fanChart['size'] = intval($fanChart['size']); if ($fanChart['size']<2) $fanChart['size'] = 7; if (empty($fanChart['color']) || $fanChart['color']{0}!='#') $fanChart['color'] = '#000000'; if (empty($fanChart['bgColor']) || $fanChart['bgColor']{0}!='#') $fanChart['bgColor'] = '#EEEEEE'; if (empty($fanChart['bgMColor']) || $fanChart['bgMColor']{0}!='#') $fanChart['bgMColor'] = '#D0D0AC'; if (empty($fanChart['bgFColor']) || $fanChart['bgFColor']{0}!='#') $fanChart['bgFColor'] = '#D0ACD0'; $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/640; // 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); ImageColorTransparent($image, $white); $color = ImageColorAllocate($image, hexdec(substr($fanChart['color'],1,2)), hexdec(substr($fanChart['color'],3,2)), hexdec(substr($fanChart['color'],5,2))); $bgcolor = ImageColorAllocate($image, hexdec(substr($fanChart['bgColor'],1,2)), hexdec(substr($fanChart['bgColor'],3,2)), hexdec(substr($fanChart['bgColor'],5,2))); $bgcolorM = ImageColorAllocate($image, hexdec(substr($fanChart['bgMColor'],1,2)), hexdec(substr($fanChart['bgMColor'],3,2)), hexdec(substr($fanChart['bgMColor'],5,2))); $bgcolorF = ImageColorAllocate($image, hexdec(substr($fanChart['bgFColor'],1,2)), hexdec(substr($fanChart['bgFColor'],3,2)), hexdec(substr($fanChart['bgFColor'],5,2))); // imagemap $imagemap=""; // 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); $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]; $person = WT_Individual::getInstance($pid); if ($person) { $name = WT_Filter::unescapeHtml($person->getFullName()); $addname = WT_Filter::unescapeHtml($person->getAddName()); $text = reverseText($name); if ($addname) { $text .= "\n" . reverseText($addname); } $text .= "\n" . WT_Filter::unescapeHtml($person->getLifeSpan()); switch($person->getSex()) { case 'M': $bg=$bgcolorM; break; case 'F': $bg=$bgcolorF; break; case 'U': $bg=$bgcolor; break; } ImageFilledArc($image, $cx, $cy, $rx, $rx, $deg1, $deg2, $bg, IMG_ARC_PIE); // split and center text by lines $wmax = (int)($angle*7/$fanChart['size']*$scale); $wmax = min($wmax, 35*$scale); if ($gen==0) $wmax = min($wmax, 17*$scale); $text = $this->split_align_text($text, $wmax); // text angle $tangle = 270-($deg1+$angle/2); if ($gen==0) $tangle=0; // calculate text position $bbox=ImageTtfBbox((double)$fanChart['size'], 0, $fanChart['font'], $text); $textwidth = $bbox[4]; $deg = $deg1+.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 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)$fanChart['size'], $tangle, $tx, $ty, $color, $fanChart['font'], $text); $imagemap .= '=$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"; // add action url $imagemap .= '" href="'.$person->getHtmlUrl().'"'; $tempURL = 'fanchart.php?rootid='.$pid.'&generations='.$this->generations.'&fan_width='.$this->fan_width.'&fan_style='.$this->fan_style.'&ged='.WT_GEDURL; $count=0; $html.= "
"; $html.= "
"; $html.= "getHtmlUrl()."\" class=\"name1\">" . $name; if (!empty($addname)) $html.= "
" . $addname; $html.= "
"; $html.= "
".WT_I18N::translate('Pedigree').""; if (array_key_exists('googlemap', WT_Module::getActiveModules())) { $html.= "
".WT_I18N::translate('Pedigree map').""; } if (WT_USER_GEDCOM_ID && WT_USER_GEDCOM_ID!=$pid) { $html.= "
".WT_I18N::translate('Relationship to me').""; } $html.= "
".WT_I18N::translate('Descendants').""; $html.= "
".WT_I18N::translate('Ancestors').""; $html.= "
".WT_I18N::translate('Compact tree').""; $html.= "
".WT_I18N::translate('Fan chart').""; $html.= "
".WT_I18N::translate('Hourglass chart').""; if (array_key_exists('tree', WT_Module::getActiveModules())) { $html.= '
".WT_I18N::translate('Interactive tree').""; } // spouse(s) and children foreach ($person->getSpouseFamilies() as $family) { $spouse=$family->getSpouse($person); if ($spouse) { $html.= '
'.$spouse->getFullName().''; foreach ($family->getChildren() as $child) { $html.= '
  < '.$child->getFullName().''; } } } // siblings foreach ($person->getChildFamilies() as $family) { $children=$family->getChildren(); if (count($children)>2) { $html.= '
'.WT_I18N::translate('Siblings').''; } elseif (count($children)==2) { $html.= '
'.WT_I18N::translate('Sibling').''; } foreach ($children as $sibling) { if ($sibling === $person) { $html.= '
   '.$sibling->getFullName().''; } } } $html.= '
'; $html.= '
'; $imagemap .= " onclick=\"show_family_box('".$pid.".".$count."', 'relatives'); return false;\""; $imagemap .= " onmouseout=\"family_box_timeout('".$pid.".".$count."'); return false;\""; $imagemap .= " alt=\"".WT_Filter::escapeHtml(strip_tags($name))."\" title=\"".WT_Filter::escapeHtml(strip_tags($name))."\">"; } $deg1-=$angle; $deg2-=$angle; $sosa--; } $rx-=$rw; $gen--; } $imagemap .= '
'; switch ($what) { case 'html': $image_title=WT_I18N::translate('Fan chart of %s', strip_tags($name)); return $html.$imagemap.'

'.$image_title.'

'; case 'png': ImageStringUp($image, 1, $fanw-10, $fanh/3, WT_SERVER_NAME.WT_SCRIPT_PATH, $color); ImagePng($image); ImageDestroy($image); } } }