function Stroke($aStrokeFileName = '') { // Fist make a sanity check that user has specified a scale if (empty($this->yscale)) { JpGraphError::RaiseL(25031); //('You must specify what scale to use with a call to Graph::SetScale().'); } // Start by adjusting the margin so that potential titles will fit. $this->AdjustMarginsForTitles(); // Give the plot a chance to do any scale adjuments the individual plots // wants to do. Right now this is only used by the contour plot to set scale // limits for ($i = 0; $i < count($this->plots); ++$i) { $this->plots[$i]->PreScaleSetup($this); } // Init scale constants that are used to calculate the transformation from // world to pixel coordinates $this->InitScaleConstants(); // If the filename is the predefined value = '_csim_special_' // we assume that the call to stroke only needs to do enough // to correctly generate the CSIM maps. // We use this variable to skip things we don't strictly need // to do to generate the image map to improve performance // a best we can. Therefor you will see a lot of tests !$_csim in the // code below. $_csim = $aStrokeFileName === _CSIM_SPECIALFILE; // If we are called the second time (perhaps the user has called GetHTMLImageMap() // himself then the legends have alsready been populated once in order to get the // CSIM coordinats. Since we do not want the legends to be populated a second time // we clear the legends $this->legend->Clear(); // We need to know if we have stroked the plot in the // GetCSIMareas. Otherwise the CSIM hasn't been generated // and in the case of GetCSIM called before stroke to generate // CSIM without storing an image to disk GetCSIM must call Stroke. $this->iHasStroked = true; // Setup pre-stroked adjustments and Legends $this->doPrestrokeAdjustments(); if ($this->graph_theme) { $this->graph_theme->PreStrokeApply($this); } // Bail out if any of the Y-axis not been specified and // has no plots. (This means it is impossible to do autoscaling and // no other scale was given so we can't possible draw anything). If you use manual // scaling you also have to supply the tick steps as well. if (!$this->yscale->IsSpecified() && count($this->plots) == 0 || $this->y2scale != null && !$this->y2scale->IsSpecified() && count($this->y2plots) == 0) { //$e = "n=".count($this->y2plots)."\n"; // $e = "Can't draw unspecified Y-scale.<br>\nYou have either:<br>\n"; // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>\n"; // $e .= "2. Specified a scale manually but have forgot to specify the tick steps"; JpGraphError::RaiseL(25026); } // Bail out if no plots and no specified X-scale if (!$this->xscale->IsSpecified() && count($this->plots) == 0 && count($this->y2plots) == 0) { JpGraphError::RaiseL(25034); //("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>"); } // Autoscale the normal Y-axis $this->doAutoScaleYAxis(); // Autoscale all additiopnal y-axis $this->doAutoScaleYnAxis(); // Autoscale the regular x-axis and position the y-axis properly $this->doAutoScaleXAxis(); // If we have a negative values and x-axis position is at 0 // we need to supress the first and possible the last tick since // they will be drawn on top of the y-axis (and possible y2 axis) // The test below might seem strange the reasone being that if // the user hasn't specified a value for position this will not // be set until we do the stroke for the axis so as of now it // is undefined. // For X-text scale we ignore all this since the tick are usually // much further in and not close to the Y-axis. Hence the test // for 'text' if (($this->yaxis->pos == $this->xscale->GetMinVal() || is_string($this->yaxis->pos) && $this->yaxis->pos == 'min') && !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 && substr($this->axtype, 0, 4) != 'text' && $this->xaxis->pos != 'min') { //$this->yscale->ticks->SupressZeroLabel(false); $this->xscale->ticks->SupressFirst(); if ($this->y2axis != null) { $this->xscale->ticks->SupressLast(); } } elseif (!is_numeric($this->yaxis->pos) && $this->yaxis->pos == 'max') { $this->xscale->ticks->SupressLast(); } if (!$_csim) { $this->StrokePlotArea(); if ($this->iIconDepth == DEPTH_BACK) { $this->StrokeIcons(); } } $this->StrokeAxis(false); // Stroke colored bands $this->StrokeBands(DEPTH_BACK, $_csim); if ($this->grid_depth == DEPTH_BACK && !$_csim) { $this->ygrid->Stroke(); $this->xgrid->Stroke(); } // Stroke Y2-axis if ($this->y2axis != null && !$_csim) { $this->y2axis->Stroke($this->xscale); $this->y2grid->Stroke(); } // Stroke yn-axis $n = count($this->ynaxis); for ($i = 0; $i < $n; ++$i) { $this->ynaxis[$i]->Stroke($this->xscale); } $oldoff = $this->xscale->off; if (substr($this->axtype, 0, 4) == 'text') { if ($this->text_scale_abscenteroff > -1) { // For a text scale the scale factor is the number of pixel per step. // Hence we can use the scale factor as a substitute for number of pixels // per major scale step and use that in order to adjust the offset so that // an object of width "abscenteroff" becomes centered. $this->xscale->off += round($this->xscale->scale_factor / 2) - round($this->text_scale_abscenteroff / 2); } else { $this->xscale->off += ceil($this->xscale->scale_factor * $this->text_scale_off * $this->xscale->ticks->minor_step); } } if ($this->iDoClipping) { $oldimage = $this->img->CloneCanvasH(); } if (!$this->y2orderback) { // Stroke all plots for Y1 axis for ($i = 0; $i < count($this->plots); ++$i) { $this->plots[$i]->Stroke($this->img, $this->xscale, $this->yscale); $this->plots[$i]->StrokeMargin($this->img); } } // Stroke all plots for Y2 axis if ($this->y2scale != null) { for ($i = 0; $i < count($this->y2plots); ++$i) { $this->y2plots[$i]->Stroke($this->img, $this->xscale, $this->y2scale); } } if ($this->y2orderback) { // Stroke all plots for Y1 axis for ($i = 0; $i < count($this->plots); ++$i) { $this->plots[$i]->Stroke($this->img, $this->xscale, $this->yscale); $this->plots[$i]->StrokeMargin($this->img); } } $n = count($this->ynaxis); for ($i = 0; $i < $n; ++$i) { $m = count($this->ynplots[$i]); for ($j = 0; $j < $m; ++$j) { $this->ynplots[$i][$j]->Stroke($this->img, $this->xscale, $this->ynscale[$i]); $this->ynplots[$i][$j]->StrokeMargin($this->img); } } if ($this->iIconDepth == DEPTH_FRONT) { $this->StrokeIcons(); } if ($this->iDoClipping) { // Clipping only supports graphs at 0 and 90 degrees if ($this->img->a == 0) { $this->img->CopyCanvasH($oldimage, $this->img->img, $this->img->left_margin, $this->img->top_margin, $this->img->left_margin, $this->img->top_margin, $this->img->plotwidth + 1, $this->img->plotheight); } elseif ($this->img->a == 90) { $adj = ($this->img->height - $this->img->width) / 2; $this->img->CopyCanvasH($oldimage, $this->img->img, $this->img->bottom_margin - $adj, $this->img->left_margin + $adj, $this->img->bottom_margin - $adj, $this->img->left_margin + $adj, $this->img->plotheight + 1, $this->img->plotwidth); } else { JpGraphError::RaiseL(25035, $this->img->a); //('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.'); } $this->img->Destroy(); $this->img->SetCanvasH($oldimage); } $this->xscale->off = $oldoff; if ($this->grid_depth == DEPTH_FRONT && !$_csim) { $this->ygrid->Stroke(); $this->xgrid->Stroke(); } // Stroke colored bands $this->StrokeBands(DEPTH_FRONT, $_csim); // Finally draw the axis again since some plots may have nagged // the axis in the edges. if (!$_csim) { $this->StrokeAxis(); } if ($this->y2scale != null && !$_csim) { $this->y2axis->Stroke($this->xscale, false); } if (!$_csim) { $this->StrokePlotBox(); } // The titles and legends never gets rotated so make sure // that the angle is 0 before stroking them $aa = $this->img->SetAngle(0); $this->StrokeTitles(); $this->footer->Stroke($this->img); $this->legend->Stroke($this->img); $this->img->SetAngle($aa); $this->StrokeTexts(); $this->StrokeTables(); if (!$_csim) { $this->img->SetAngle($aa); // Draw an outline around the image map if (_JPG_DEBUG) { $this->DisplayClientSideaImageMapAreas(); } // Should we do any final image transformation if ($this->iImgTrans) { if (!class_exists('ImgTrans', false)) { require_once 'jpgraph_imgtrans.php'; //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); } $tform = new ImgTrans($this->img->img); $this->img->img = $tform->Skew3D($this->iImgTransHorizon, $this->iImgTransSkewDist, $this->iImgTransDirection, $this->iImgTransHighQ, $this->iImgTransMinSize, $this->iImgTransFillColor, $this->iImgTransBorder); } // If the filename is given as the special "__handle" // then the image handler is returned and the image is NOT // streamed back if ($aStrokeFileName == _IMG_HANDLER) { return $this->img->img; } else { // Finally stream the generated picture $this->cache->PutAndStream($this->img, $this->cache_name, $this->inline, $aStrokeFileName); } } }