public function Stroke($img, $xscale, $yscale) { $numpoints = count($this->coords[0]); if (isset($this->coords[1])) { if (count($this->coords[1]) != $numpoints) { Util\JpGraphError::RaiseL(2003, count($this->coords[1]), $numpoints); //"Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])."Number of Y-points:$numpoints"); } else { $exist_x = true; } } else { $exist_x = false; } $numbars = count($this->coords[0]); // Use GetMinVal() instead of scale[0] directly since in the case // of log scale we get a correct value. Log scales will have negative // values for values < 1 while still not representing negative numbers. if ($yscale->GetMinVal() >= 0) { $zp = $yscale->scale_abs[0]; } else { $zp = $yscale->Translate(0); } if ($this->abswidth > -1) { $abswidth = $this->abswidth; } else { $abswidth = round($this->width * $xscale->scale_factor, 0); } // Count pontetial pattern array to avoid doing the count for each iteration if (is_array($this->iPattern)) { $np = count($this->iPattern); } $grad = null; for ($i = 0; $i < $numbars; ++$i) { // If value is NULL, or 0 then don't draw a bar at all if ($this->coords[0][$i] === null || $this->coords[0][$i] === '') { continue; } if ($exist_x) { $x = $this->coords[1][$i]; } else { $x = $i; } $x = $xscale->Translate($x); // Comment Note: This confuses the positioning when using acc together with // grouped bars. Workaround for fixing #191 /* if( !$xscale->textscale ) { if($this->align=="center") $x -= $abswidth/2; elseif($this->align=="right") $x -= $abswidth; } */ // Stroke fill color and fill gradient $pts = array($x, $zp, $x, $yscale->Translate($this->coords[0][$i]), $x + $abswidth, $yscale->Translate($this->coords[0][$i]), $x + $abswidth, $zp); if ($this->grad) { if ($grad === null) { $grad = new Gradient($img); } if (is_array($this->grad_fromcolor)) { // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be // an array to specify both (from, to style) for each individual bar. The way to know the difference is // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB // triple. $ng = count($this->grad_fromcolor); if ($ng === 3) { if (is_numeric($this->grad_fromcolor[0]) && $this->grad_fromcolor[0] > 0 && $this->grad_fromcolor[0] < 256) { // RGB Triple $fromcolor = $this->grad_fromcolor; $tocolor = $this->grad_tocolor; $style = $this->grad_style; } else { $fromcolor = $this->grad_fromcolor[$i % $ng][0]; $tocolor = $this->grad_fromcolor[$i % $ng][1]; $style = $this->grad_fromcolor[$i % $ng][2]; } } else { $fromcolor = $this->grad_fromcolor[$i % $ng][0]; $tocolor = $this->grad_fromcolor[$i % $ng][1]; $style = $this->grad_fromcolor[$i % $ng][2]; } $grad->FilledRectangle($pts[2], $pts[3], $pts[6], $pts[7], $fromcolor, $tocolor, $style); } else { $grad->FilledRectangle($pts[2], $pts[3], $pts[6], $pts[7], $this->grad_fromcolor, $this->grad_tocolor, $this->grad_style); } } elseif (!empty($this->fill_color)) { if (is_array($this->fill_color)) { $img->PushColor($this->fill_color[$i % count($this->fill_color)]); } else { $img->PushColor($this->fill_color); } $img->FilledPolygon($pts); $img->PopColor(); } /////////////////////////kokorahen rectangle polygon////////////////////// // Remember value of this bar $val = $this->coords[0][$i]; if (!empty($val) && !is_numeric($val)) { Util\JpGraphError::RaiseL(2004, $i, $val); //'All values for a barplot must be numeric. You have specified value['.$i.'] == \''.$val.'\''); } // Determine the shadow if ($this->bar_shadow && $val != 0) { $ssh = $this->bar_shadow_hsize; $ssv = $this->bar_shadow_vsize; // Create points to create a "upper-right" shadow if ($val > 0) { $sp[0] = $pts[6]; $sp[1] = $pts[7]; $sp[2] = $pts[4]; $sp[3] = $pts[5]; $sp[4] = $pts[2]; $sp[5] = $pts[3]; $sp[6] = $pts[2] + $ssh; $sp[7] = $pts[3] - $ssv; $sp[8] = $pts[4] + $ssh; $sp[9] = $pts[5] - $ssv; $sp[10] = $pts[6] + $ssh; $sp[11] = $pts[7] - $ssv; } elseif ($val < 0) { $sp[0] = $pts[4]; $sp[1] = $pts[5]; $sp[2] = $pts[6]; $sp[3] = $pts[7]; $sp[4] = $pts[0]; $sp[5] = $pts[1]; $sp[6] = $pts[0] + $ssh; $sp[7] = $pts[1] - $ssv; $sp[8] = $pts[6] + $ssh; $sp[9] = $pts[7] - $ssv; $sp[10] = $pts[4] + $ssh; $sp[11] = $pts[5] - $ssv; } if (is_array($this->bar_shadow_color)) { $numcolors = count($this->bar_shadow_color); if ($numcolors == 0) { Util\JpGraphError::RaiseL(2005); //('You have specified an empty array for shadow colors in the bar plot.'); } $img->PushColor($this->bar_shadow_color[$i % $numcolors]); } else { $img->PushColor($this->bar_shadow_color); } $img->FilledPolygon($sp); $img->PopColor(); } elseif ($this->bar_3d && $val != 0) { // Determine the 3D $ssh = $this->bar_3d_hsize; $ssv = $this->bar_3d_vsize; // Create points to create a "upper-right" shadow if ($val > 0) { $sp1[0] = $pts[6]; $sp1[1] = $pts[7]; $sp1[2] = $pts[4]; $sp1[3] = $pts[5]; $sp1[4] = $pts[4] + $ssh; $sp1[5] = $pts[5] - $ssv; $sp1[6] = $pts[6] + $ssh; $sp1[7] = $pts[7] - $ssv; $sp2[0] = $pts[4]; $sp2[1] = $pts[5]; $sp2[2] = $pts[2]; $sp2[3] = $pts[3]; $sp2[4] = $pts[2] + $ssh; $sp2[5] = $pts[3] - $ssv; $sp2[6] = $pts[4] + $ssh; $sp2[7] = $pts[5] - $ssv; } elseif ($val < 0) { $sp1[0] = $pts[4]; $sp1[1] = $pts[5]; $sp1[2] = $pts[6]; $sp1[3] = $pts[7]; $sp1[4] = $pts[6] + $ssh; $sp1[5] = $pts[7] - $ssv; $sp1[6] = $pts[4] + $ssh; $sp1[7] = $pts[5] - $ssv; $sp2[0] = $pts[6]; $sp2[1] = $pts[7]; $sp2[2] = $pts[0]; $sp2[3] = $pts[1]; $sp2[4] = $pts[0] + $ssh; $sp2[5] = $pts[1] - $ssv; $sp2[6] = $pts[6] + $ssh; $sp2[7] = $pts[7] - $ssv; } $base_color = $this->fill_color; $img->PushColor($base_color . ':0.7'); $img->FilledPolygon($sp1); $img->PopColor(); $img->PushColor($base_color . ':1.1'); $img->FilledPolygon($sp2); $img->PopColor(); } // Stroke the pattern if (is_array($this->iPattern)) { $f = new RectPatternFactory(); if (is_array($this->iPatternColor)) { $pcolor = $this->iPatternColor[$i % $np]; } else { $pcolor = $this->iPatternColor; } $prect = $f->Create($this->iPattern[$i % $np], $pcolor, 1); $prect->SetDensity($this->iPatternDensity[$i % $np]); if ($val < 0) { $rx = $pts[0]; $ry = $pts[1]; } else { $rx = $pts[2]; $ry = $pts[3]; } $width = abs($pts[4] - $pts[0]) + 1; $height = abs($pts[1] - $pts[3]) + 1; $prect->SetPos(new Rectangle($rx, $ry, $width, $height)); $prect->Stroke($img); } else { if ($this->iPattern > -1) { $f = new RectPatternFactory(); $prect = $f->Create($this->iPattern, $this->iPatternColor, 1); $prect->SetDensity($this->iPatternDensity); if ($val < 0) { $rx = $pts[0]; $ry = $pts[1]; } else { $rx = $pts[2]; $ry = $pts[3]; } $width = abs($pts[4] - $pts[0]) + 1; $height = abs($pts[1] - $pts[3]) + 1; $prect->SetPos(new Rectangle($rx, $ry, $width, $height)); $prect->Stroke($img); } } // Stroke the outline of the bar if (is_array($this->color)) { $img->SetColor($this->color[$i % count($this->color)]); } else { $img->SetColor($this->color); } $pts[] = $pts[0]; $pts[] = $pts[1]; if ($this->weight > 0) { $img->SetLineWeight($this->weight); $img->Polygon($pts); } // Determine how to best position the values of the individual bars $x = $pts[2] + ($pts[4] - $pts[2]) / 2; $this->value->SetMargin(5); if ($this->valuepos == 'top') { $y = $pts[3]; if ($img->a === 90) { if ($val < 0) { $this->value->SetAlign('right', 'center'); } else { $this->value->SetAlign('left', 'center'); } } else { if ($val < 0) { $this->value->SetMargin(-5); $y = $pts[1]; $this->value->SetAlign('center', 'bottom'); } else { $this->value->SetAlign('center', 'bottom'); } } $this->value->Stroke($img, $val, $x, $y); } elseif ($this->valuepos == 'max') { $y = $pts[3]; if ($img->a === 90) { if ($val < 0) { $this->value->SetAlign('left', 'center'); } else { $this->value->SetAlign('right', 'center'); } } else { if ($val < 0) { $this->value->SetAlign('center', 'bottom'); } else { $this->value->SetAlign('center', 'top'); } } $this->value->SetMargin(-5); $this->value->Stroke($img, $val, $x, $y); } elseif ($this->valuepos == 'center') { $y = ($pts[3] + $pts[1]) / 2; $this->value->SetAlign('center', 'center'); $this->value->SetMargin(0); $this->value->Stroke($img, $val, $x, $y); } elseif ($this->valuepos == 'bottom' || $this->valuepos == 'min') { $y = $pts[1]; if ($img->a === 90) { if ($val < 0) { $this->value->SetAlign('right', 'center'); } else { $this->value->SetAlign('left', 'center'); } } $this->value->SetMargin(3); $this->value->Stroke($img, $val, $x, $y); } else { Util\JpGraphError::RaiseL(2006, $this->valuepos); //'Unknown position for values on bars :'.$this->valuepos); } // Create the client side image map $rpts = $img->ArrRotate($pts); $csimcoord = round($rpts[0]) . ", " . round($rpts[1]); for ($j = 1; $j < 4; ++$j) { $csimcoord .= ", " . round($rpts[2 * $j]) . ", " . round($rpts[2 * $j + 1]); } if (!empty($this->csimtargets[$i])) { $this->csimareas .= '<area shape="poly" coords="' . $csimcoord . '" '; $this->csimareas .= " href=\"" . htmlentities($this->csimtargets[$i]) . "\""; if (!empty($this->csimwintargets[$i])) { $this->csimareas .= " target=\"" . $this->csimwintargets[$i] . "\" "; } $sval = ''; if (!empty($this->csimalts[$i])) { $sval = sprintf($this->csimalts[$i], $this->coords[0][$i]); $this->csimareas .= " title=\"{$sval}\" alt=\"{$sval}\" "; } $this->csimareas .= " />\n"; } } return true; }
public function StrokeBackgroundGrad() { if ($this->bkg_gradtype < 0) { return; } $grad = new Plot\Gradient($this->img); if ($this->bkg_gradstyle == BGRAD_PLOT) { $xl = $this->img->left_margin; $yt = $this->img->top_margin; $xr = $xl + $this->img->plotwidth + 1; $yb = $yt + $this->img->plotheight; $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->bkg_gradfrom, $this->bkg_gradto, $this->bkg_gradtype); } else { $xl = 0; $yt = 0; $xr = $xl + $this->img->width - 1; $yb = $yt + $this->img->height - 1; if ($this->doshadow) { $xr -= $this->shadow_width; $yb -= $this->shadow_width; } if ($this->doframe) { $yt += $this->frame_weight; $yb -= $this->frame_weight; $xl += $this->frame_weight; $xr -= $this->frame_weight; } $aa = $this->img->SetAngle(0); $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->bkg_gradfrom, $this->bkg_gradto, $this->bkg_gradtype); $aa = $this->img->SetAngle($aa); } }
public function Stroke($img, $xscale, $yscale) { $idx = 0; $numpoints = count($this->coords[0]); if (isset($this->coords[1])) { if (count($this->coords[1]) != $numpoints) { Util\JpGraphError::RaiseL(2003, count($this->coords[1]), $numpoints); //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); } else { $exist_x = true; } } else { $exist_x = false; } if ($this->barcenter) { $textadj = 0.5 - $xscale->text_scale_off; } else { $textadj = 0; } // Find the first numeric data point $startpoint = 0; while ($startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint])) { ++$startpoint; } // Bail out if no data points if ($startpoint == $numpoints) { return; } if ($this->iFastStroke) { $this->FastStroke($img, $xscale, $yscale, $startpoint, $exist_x); return; } if ($exist_x) { $xs = $this->coords[1][$startpoint]; } else { $xs = $textadj + $startpoint; } $img->SetStartPoint($xscale->Translate($xs), $yscale->Translate($this->coords[0][$startpoint])); if ($this->filled) { if ($this->fillFromMax) { //$max = $yscale->GetMaxVal(); $cord[$idx++] = $xscale->Translate($xs); $cord[$idx++] = $yscale->scale_abs[1]; } else { $min = $yscale->GetMinVal(); if ($min > 0 || $this->fillFromMin) { $fillmin = $yscale->scale_abs[0]; //Translate($min); } else { $fillmin = $yscale->Translate(0); } $cord[$idx++] = $xscale->Translate($xs); $cord[$idx++] = $fillmin; } } $xt = $xscale->Translate($xs); $yt = $yscale->Translate($this->coords[0][$startpoint]); $cord[$idx++] = $xt; $cord[$idx++] = $yt; $yt_old = $yt; $xt_old = $xt; $y_old = $this->coords[0][$startpoint]; $this->value->Stroke($img, $this->coords[0][$startpoint], $xt, $yt); $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->SetLineStyle($this->line_style); $pnts = $startpoint + 1; $firstnonumeric = false; while ($pnts < $numpoints) { if ($exist_x) { $x = $this->coords[1][$pnts]; } else { $x = $pnts + $textadj; } $xt = $xscale->Translate($x); $yt = $yscale->Translate($this->coords[0][$pnts]); $y = $this->coords[0][$pnts]; if ($this->step_style) { // To handle null values within step style we need to record the // first non numeric value so we know from where to start if the // non value is '-'. if (is_numeric($y)) { $firstnonumeric = false; if (is_numeric($y_old)) { $img->StyleLine($xt_old, $yt_old, $xt, $yt_old); $img->StyleLine($xt, $yt_old, $xt, $yt); } elseif ($y_old == '-') { $img->StyleLine($xt_first, $yt_first, $xt, $yt_first); $img->StyleLine($xt, $yt_first, $xt, $yt); } else { $yt_old = $yt; $xt_old = $xt; } $cord[$idx++] = $xt; $cord[$idx++] = $yt_old; $cord[$idx++] = $xt; $cord[$idx++] = $yt; } elseif ($firstnonumeric == false) { $firstnonumeric = true; $yt_first = $yt_old; $xt_first = $xt_old; } } else { $tmp1 = $y; $prev = $this->coords[0][$pnts - 1]; if ($tmp1 === '' || $tmp1 === null || $tmp1 === 'X') { $tmp1 = 'x'; } if ($prev === '' || $prev === null || $prev === 'X') { $prev = 'x'; } if (is_numeric($y) || is_string($y) && $y != '-') { if (is_numeric($y) && (is_numeric($prev) || $prev === '-')) { $img->StyleLineTo($xt, $yt); } else { $img->SetStartPoint($xt, $yt); } } if ($this->filled && $tmp1 !== '-') { if ($tmp1 === 'x') { $cord[$idx++] = $cord[$idx - 3]; $cord[$idx++] = $fillmin; } elseif ($prev === 'x') { $cord[$idx++] = $xt; $cord[$idx++] = $fillmin; $cord[$idx++] = $xt; $cord[$idx++] = $yt; } else { $cord[$idx++] = $xt; $cord[$idx++] = $yt; } } else { if (is_numeric($tmp1) && (is_numeric($prev) || $prev === '-')) { $cord[$idx++] = $xt; $cord[$idx++] = $yt; } } } $yt_old = $yt; $xt_old = $xt; $y_old = $y; $this->StrokeDataValue($img, $this->coords[0][$pnts], $xt, $yt); ++$pnts; } if ($this->filled) { $cord[$idx++] = $xt; if ($this->fillFromMax) { $cord[$idx++] = $yscale->scale_abs[1]; } else { if ($min > 0 || $this->fillFromMin) { $cord[$idx++] = $yscale->Translate($min); } else { $cord[$idx++] = $yscale->Translate(0); } } if ($this->fillgrad) { $img->SetLineWeight(1); $grad = new Gradient($img); $grad->SetNumColors($this->fillgrad_numcolors); $grad->FilledFlatPolygon($cord, $this->fillgrad_fromcolor, $this->fillgrad_tocolor); $img->SetLineWeight($this->weight); } else { $img->SetColor($this->fill_color); $img->FilledPolygon($cord); } if ($this->weight > 0) { $img->SetLineWeight($this->weight); $img->SetColor($this->color); // Remove first and last coordinate before drawing the line // sine we otherwise get the vertical start and end lines which // doesn't look appropriate $img->Polygon(array_slice($cord, 2, count($cord) - 4)); } } if (!empty($this->filledAreas)) { $minY = $yscale->Translate($yscale->GetMinVal()); $factor = $this->step_style ? 4 : 2; for ($i = 0; $i < sizeof($this->filledAreas); ++$i) { // go through all filled area elements ordered by insertion // fill polygon array $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor]; $areaCoords[] = $minY; $areaCoords = array_merge($areaCoords, array_slice($cord, $this->filledAreas[$i][0] * $factor, ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1)) * $factor)); $areaCoords[] = $areaCoords[sizeof($areaCoords) - 2]; // last x $areaCoords[] = $minY; // last y if ($this->filledAreas[$i][3]) { $img->SetColor($this->filledAreas[$i][2]); $img->FilledPolygon($areaCoords); $img->SetColor($this->color); } // Check if we should draw the frame. // If not we still re-draw the line since it might have been // partially overwritten by the filled area and it doesn't look // very good. if ($this->filledAreas[$i][4]) { $img->Polygon($areaCoords); } else { $img->Polygon($cord); } $areaCoords = array(); } } if (!is_object($this->mark) || $this->mark->type == -1 || $this->mark->show == false) { return; } for ($pnts = 0; $pnts < $numpoints; ++$pnts) { if ($exist_x) { $x = $this->coords[1][$pnts]; } else { $x = $pnts + $textadj; } $xt = $xscale->Translate($x); $yt = $yscale->Translate($this->coords[0][$pnts]); if (is_numeric($this->coords[0][$pnts])) { if (!empty($this->csimtargets[$pnts])) { if (!empty($this->csimwintargets[$pnts])) { $this->mark->SetCSIMTarget($this->csimtargets[$pnts], $this->csimwintargets[$pnts]); } else { $this->mark->SetCSIMTarget($this->csimtargets[$pnts]); } $this->mark->SetCSIMAlt($this->csimalts[$pnts]); } if ($exist_x) { $x = $this->coords[1][$pnts]; } else { $x = $pnts; } $this->mark->SetCSIMAltVal($this->coords[0][$pnts], $x); $this->mark->Stroke($img, $xt, $yt); $this->csimareas .= $this->mark->GetCSIMAreas(); } } }
public function Stroke($aImg) { // Constant $fillBoxFrameWeight = 1; if ($this->hide) { return; } $aImg->SetFont($this->font_family, $this->font_style, $this->font_size); if ($this->reverse) { $this->txtcol = array_reverse($this->txtcol); } $n = count($this->txtcol); if ($n == 0) { return; } // Find out the max width and height of each column to be able // to size the legend box. $numcolumns = $n > $this->layout_n ? $this->layout_n : $n; for ($i = 0; $i < $numcolumns; ++$i) { $colwidth[$i] = $aImg->GetTextWidth($this->txtcol[$i][0]) + 2 * $this->xmargin + 2 * $this->mark_abs_hsize; $colheight[$i] = 0; } // Find our maximum height in each row $rows = 0; $rowheight[0] = 0; for ($i = 0; $i < $n; ++$i) { $h = max($this->mark_abs_vsize, $aImg->GetTextHeight($this->txtcol[$i][0])) + $this->ylinespacing; // Makes sure we always have a minimum of 1/4 (1/2 on each side) of the mark as space // between two vertical legend entries //$h = round(max($h,$this->mark_abs_vsize+$this->ymargin)); //echo "Textheight #$i: tetxheight=".$aImg->GetTextHeight($this->txtcol[$i][0]).', '; //echo "h=$h ({$this->mark_abs_vsize},{$this->ymargin})<br>"; if ($i % $numcolumns == 0) { $rows++; $rowheight[$rows - 1] = 0; } $rowheight[$rows - 1] = max($rowheight[$rows - 1], $h) + 1; } $abs_height = 0; for ($i = 0; $i < $rows; ++$i) { $abs_height += $rowheight[$i]; } // Make sure that the height is at least as high as mark size + ymargin $abs_height = max($abs_height, $this->mark_abs_vsize); $abs_height += $this->ybottom_margin; // Find out the maximum width in each column for ($i = $numcolumns; $i < $n; ++$i) { $colwidth[$i % $numcolumns] = max($aImg->GetTextWidth($this->txtcol[$i][0]) + 2 * $this->xmargin + 2 * $this->mark_abs_hsize, $colwidth[$i % $numcolumns]); } // Get the total width $mtw = 0; for ($i = 0; $i < $numcolumns; ++$i) { $mtw += $colwidth[$i]; } // remove the last rows interpace margin (since there is no next row) $abs_height -= $this->ylinespacing; // Find out maximum width we need for legend box $abs_width = $mtw + $this->xlmargin + ($numcolumns - 1) * $this->mark_abs_hsize; if ($this->xabspos === -1 && $this->yabspos === -1) { $this->xabspos = $this->xpos * $aImg->width; $this->yabspos = $this->ypos * $aImg->height; } // Positioning of the legend box if ($this->halign == 'left') { $xp = $this->xabspos; } elseif ($this->halign == 'center') { $xp = $this->xabspos - $abs_width / 2; } else { $xp = $aImg->width - $this->xabspos - $abs_width; } $yp = $this->yabspos; if ($this->valign == 'center') { $yp -= $abs_height / 2; } elseif ($this->valign == 'bottom') { $yp -= $abs_height; } // Stroke legend box $aImg->SetColor($this->color); $aImg->SetLineWeight($this->frameweight); $aImg->SetLineStyle('solid'); if ($this->shadow) { $aImg->ShadowRectangle($xp, $yp, $xp + $abs_width + $this->shadow_width + 2, $yp + $abs_height + $this->shadow_width + 2, $this->fill_color, $this->shadow_width + 2, $this->shadow_color); } else { $aImg->SetColor($this->fill_color); $aImg->FilledRectangle($xp, $yp, $xp + $abs_width, $yp + $abs_height); $aImg->SetColor($this->color); $aImg->Rectangle($xp, $yp, $xp + $abs_width, $yp + $abs_height); } if ($this->bkg_gradtype >= 0) { $grad = new Plot\Gradient($aImg); $grad->FilledRectangle($xp + 1, $yp + 1, $xp + $abs_width - 3, $yp + $abs_height - 3, $this->bkg_gradfrom, $this->bkg_gradto, $this->bkg_gradtype); } // x1,y1 is the position for the legend marker + text // The vertical position is the baseline position for the text // and every marker is adjusted acording to that. // For multiline texts this get more complicated. $x1 = $xp + $this->xlmargin; $y1 = $yp + $rowheight[0] - $this->ylinespacing + 2; // The ymargin is included in rowheight // Now, y1 is the bottom vertical position of the first legend, i.e if // the legend has multiple lines it is the bottom line. $grad = new Plot\Gradient($aImg); $patternFactory = null; // Now stroke each legend in turn // Each plot has added the following information to the legend // p[0] = Legend text // p[1] = Color, // p[2] = For markers a reference to the PlotMark object // p[3] = For lines the line style, for gradient the negative gradient style // p[4] = CSIM target // p[5] = CSIM Alt text $i = 1; $row = 0; foreach ($this->txtcol as $p) { // STROKE DEBUG BOX if (_JPG_DEBUG) { $aImg->SetLineWeight(1); $aImg->SetColor('red'); $aImg->SetLineStyle('solid'); $aImg->Rectangle($x1, $y1, $xp + $abs_width - 1, $y1 - $rowheight[$row]); } $aImg->SetLineWeight($this->weight); $x1 = round($x1) + 1; // We add one to not collide with the border $y1 = round($y1); // This is the center offset up from the baseline which is // considered the "center" of the marks. This gets slightly complicated since // we need to consider if the text is a multiline paragraph or if it is only // a single line. The reason is that for single line the y1 corresponds to the baseline // and that is fine. However for a multiline paragraph there is no single baseline // and in that case the y1 corresponds to the lowest y for the bounding box. In that // case we center the mark in the middle of the paragraph if (!preg_match('/\\n/', $p[0])) { // Single line $marky = ceil($y1 - $this->mark_abs_vsize / 2) - 1; } else { // Paragraph $marky = $y1 - $aImg->GetTextHeight($p[0]) / 2; // echo "y1=$y1, p[o]={$p[0]}, marky=$marky<br>"; } //echo "<br>Mark #$i: marky=$marky<br>"; $x1 += $this->mark_abs_hsize; if (!empty($p[2]) && $p[2]->GetType() > -1) { // Make a plot mark legend. This is constructed with a mark which // is run through with a line // First construct a bit of the line that looks exactly like the // line in the plot $aImg->SetColor($p[1]); if (is_string($p[3]) || $p[3] > 0) { $aImg->SetLineStyle($p[3]); $aImg->StyleLine($x1 - $this->mark_abs_hsize, $marky, $x1 + $this->mark_abs_hsize, $marky); } // Stroke a mark using image if ($p[2]->GetType() == MARK_IMG) { $p[2]->Stroke($aImg, $x1, $marky); } // Stroke a mark with the standard size // (As long as it is not an image mark ) if ($p[2]->GetType() != MARK_IMG) { // Clear any user callbacks since we ont want them called for // the legend marks $p[2]->iFormatCallback = ''; $p[2]->iFormatCallback2 = ''; // Since size for circles is specified as the radius // this means that we must half the size to make the total // width behave as the other marks if ($p[2]->GetType() == MARK_FILLEDCIRCLE || $p[2]->GetType() == MARK_CIRCLE) { $p[2]->SetSize(min($this->mark_abs_vsize, $this->mark_abs_hsize) / 2); $p[2]->Stroke($aImg, $x1, $marky); } else { $p[2]->SetSize(min($this->mark_abs_vsize, $this->mark_abs_hsize)); $p[2]->Stroke($aImg, $x1, $marky); } } } elseif (!empty($p[2]) && (is_string($p[3]) || $p[3] > 0)) { // Draw a styled line $aImg->SetColor($p[1]); $aImg->SetLineStyle($p[3]); $aImg->StyleLine($x1 - $this->mark_abs_hsize, $marky, $x1 + $this->mark_abs_hsize, $marky); $aImg->StyleLine($x1 - $this->mark_abs_hsize, $marky + 1, $x1 + $this->mark_abs_hsize, $marky + 1); } else { // Draw a colored box $color = $p[1]; // We make boxes slightly larger to better show $boxsize = max($this->mark_abs_vsize, $this->mark_abs_hsize) + 2; $ym = $marky - ceil($boxsize / 2); // Marker y-coordinate // We either need to plot a gradient or a // pattern. To differentiate we use a kludge. // Patterns have a p[3] value of < -100 if ($p[3] < -100) { // p[1][0] == iPattern, p[1][1] == iPatternColor, p[1][2] == iPatternDensity if ($patternFactory == null) { $patternFactory = new RectPatternFactory(); } $prect = $patternFactory->Create($p[1][0], $p[1][1], 1); $prect->SetBackground($p[1][3]); $prect->SetDensity($p[1][2] + 1); $prect->SetPos(new Rectangle($x1, $ym, $boxsize, $boxsize)); $prect->Stroke($aImg); $prect = null; } else { if (is_array($color) && count($color) == 2) { // The client want a gradient color $grad->FilledRectangle($x1 - $boxsize / 2, $ym, $x1 + $boxsize / 2, $ym + $boxsize, $color[0], $color[1], -$p[3]); } else { $aImg->SetColor($p[1]); $aImg->FilledRectangle($x1 - $boxsize / 2, $ym, $x1 + $boxsize / 2, $ym + $boxsize); } // Draw a plot frame line $aImg->SetColor($this->color); $aImg->SetLineWeight($fillBoxFrameWeight); $aImg->Rectangle($x1 - $boxsize / 2, $ym, $x1 + $boxsize / 2, $ym + $boxsize); } } $aImg->SetColor($this->font_color); $aImg->SetFont($this->font_family, $this->font_style, $this->font_size); $aImg->SetTextAlign('left', 'baseline'); $debug = false; $aImg->StrokeText($x1 + $this->mark_abs_hsize + $this->xmargin, $y1, $p[0], 0, 'left', $debug); // Add CSIM for Legend if defined if (!empty($p[4])) { $xs = $x1 - $this->mark_abs_hsize; $ys = $y1 + 1; $xe = $x1 + $aImg->GetTextWidth($p[0]) + $this->mark_abs_hsize + $this->xmargin; $ye = $y1 - $rowheight[$row] + 1; $coords = "{$xs},{$ys},{$xe},{$y1},{$xe},{$ye},{$xs},{$ye}"; if (!empty($p[4])) { $this->csimareas .= "<area shape=\"poly\" coords=\"{$coords}\" href=\"" . htmlentities($p[4]) . "\""; if (!empty($p[6])) { $this->csimareas .= " target=\"" . $p[6] . "\""; } if (!empty($p[5])) { $tmp = sprintf($p[5], $p[0]); $this->csimareas .= " title=\"{$tmp}\" alt=\"{$tmp}\" "; } $this->csimareas .= " />\n"; } } if ($i >= $this->layout_n) { $x1 = $xp + $this->xlmargin; $row++; if (!empty($rowheight[$row])) { $y1 += $rowheight[$row]; } $i = 1; } else { $x1 += $colwidth[($i - 1) % $numcolumns]; ++$i; } } }