| <?php |
| /** |
| * File containing the ezcGraphFlashDriver class |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package Graph |
| * @version //autogentag// |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| */ |
| /** |
| * Driver to create Flash4 (SWF) files as graph output. The options of this |
| * class are defined in The options of this class are defined in the option |
| * class {@link ezcGraphFlashDriverOptions} extending the basic |
| * {@link ezcGraphDriverOptions}. |
| * |
| * <code> |
| * $graph = new ezcGraphPieChart(); |
| * $graph->title = 'Access statistics'; |
| * $graph->legend = false; |
| * |
| * $graph->driver = new ezcGraphFlashDriver(); |
| * $graph->options->font = 'tutorial_font.fdb'; |
| * |
| * $graph->driver->options->compression = 7; |
| * |
| * $graph->data['Access statistics'] = new ezcGraphArrayDataSet( array( |
| * 'Mozilla' => 19113, |
| * 'Explorer' => 10917, |
| * 'Opera' => 1464, |
| * 'Safari' => 652, |
| * 'Konqueror' => 474, |
| * ) ); |
| * |
| * $graph->render( 400, 200, 'tutorial_driver_flash.swf' ); |
| * </code> |
| * |
| * |
| * @version //autogentag// |
| * @package Graph |
| * @mainclass |
| */ |
| class ezcGraphFlashDriver extends ezcGraphDriver |
| { |
| /** |
| * Flash movie |
| * |
| * @var SWFMovie |
| */ |
| protected $movie; |
| |
| /** |
| * Unique element id |
| * |
| * @var int |
| */ |
| protected $id = 1; |
| |
| /** |
| * Array with strings to draw later |
| * |
| * @var array |
| */ |
| protected $strings = array(); |
| |
| /** |
| * Constructor |
| * |
| * @param array $options Default option array |
| * @return void |
| * @ignore |
| */ |
| public function __construct( array $options = array() ) |
| { |
| ezcBase::checkDependency( 'Graph', ezcBase::DEP_PHP_EXTENSION, 'ming' ); |
| $this->options = new ezcGraphFlashDriverOptions( $options ); |
| } |
| |
| /** |
| * Returns unique movie object as a parent canvas for all swf objects. |
| * |
| * @return SWFMovie |
| */ |
| public function getDocument() |
| { |
| if ( $this->movie === null ) |
| { |
| ming_setscale( 1.0 ); |
| $this->movie = new SWFMovie(); |
| $this->movie->setDimension( $this->modifyCoordinate( $this->options->width ), $this->modifyCoordinate( $this->options->height ) ); |
| $this->movie->setRate( 1 ); |
| $this->movie->setBackground( 255, 255, 255 ); |
| } |
| |
| return $this->movie; |
| } |
| |
| /** |
| * Set the fill and line properties for a SWWFShape according to the |
| * given parameters. |
| * |
| * @param SWFShape $shape |
| * @param ezcGraphColor $color |
| * @param mixed $thickness |
| * @param mixed $filled |
| * @return void |
| */ |
| protected function setShapeColor( SWFShape $shape, ezcGraphColor $color, $thickness, $filled ) |
| { |
| if ( $filled ) |
| { |
| switch ( true ) |
| { |
| case ( $color instanceof ezcGraphLinearGradient ): |
| $gradient = new SWFGradient(); |
| $gradient->addEntry( |
| 0, |
| $color->startColor->red, |
| $color->startColor->green, |
| $color->startColor->blue, |
| 255 - $color->startColor->alpha |
| ); |
| $gradient->addEntry( |
| 1, |
| $color->endColor->red, |
| $color->endColor->green, |
| $color->endColor->blue, |
| 255 - $color->endColor->alpha |
| ); |
| |
| $fill = $shape->addFill( $gradient, SWFFILL_LINEAR_GRADIENT ); |
| |
| // Calculate desired length of gradient |
| $length = sqrt( |
| pow( $color->endPoint->x - $color->startPoint->x, 2 ) + |
| pow( $color->endPoint->y - $color->startPoint->y, 2 ) |
| ); |
| |
| $fill->scaleTo( $this->modifyCoordinate( $length ) / 32768 , $this->modifyCoordinate( $length ) / 32768 ); |
| $fill->rotateTo( |
| rad2deg( asin( |
| ( $color->endPoint->x - $color->startPoint->x ) / $length |
| ) + 180 ) |
| ); |
| $fill->moveTo( |
| $this->modifyCoordinate( |
| ( $color->startPoint->x + $color->endPoint->x ) / 2 |
| ), |
| $this->modifyCoordinate( |
| ( $color->startPoint->y + $color->endPoint->y ) / 2 |
| ) |
| ); |
| |
| $shape->setLeftFill( $fill ); |
| break; |
| case ( $color instanceof ezcGraphRadialGradient ): |
| $gradient = new SWFGradient(); |
| $gradient->addEntry( |
| 0, |
| $color->startColor->red, |
| $color->startColor->green, |
| $color->startColor->blue, |
| 255 - $color->startColor->alpha |
| ); |
| $gradient->addEntry( |
| 1, |
| $color->endColor->red, |
| $color->endColor->green, |
| $color->endColor->blue, |
| 255 - $color->endColor->alpha |
| ); |
| |
| $fill = $shape->addFill( $gradient, SWFFILL_RADIAL_GRADIENT ); |
| |
| $fill->scaleTo( $this->modifyCoordinate( $color->width ) / 32768, $this->modifyCoordinate( $color->height ) / 32768 ); |
| $fill->moveTo( $this->modifyCoordinate( $color->center->x ), $this->modifyCoordinate( $color->center->y ) ); |
| |
| $shape->setLeftFill( $fill ); |
| break; |
| default: |
| $fill = $shape->addFill( $color->red, $color->green, $color->blue, 255 - $color->alpha ); |
| $shape->setLeftFill( $fill ); |
| break; |
| } |
| } |
| else |
| { |
| $shape->setLine( $this->modifyCoordinate( $thickness ), $color->red, $color->green, $color->blue, 255 - $color->alpha ); |
| } |
| } |
| |
| /** |
| * Modifies a coordinate value, as flash usally uses twips instead of |
| * pixels for a higher solution, as it only accepts integer values. |
| * |
| * @param float $pointValue |
| * @return float |
| */ |
| protected function modifyCoordinate( $pointValue ) |
| { |
| return $pointValue * 10; |
| } |
| |
| /** |
| * Demodifies a coordinate value, as flash usally uses twips instead of |
| * pixels for a higher solution, as it only accepts integer values. |
| * |
| * @param float $pointValue |
| * @return float |
| */ |
| protected function deModifyCoordinate( $pointValue ) |
| { |
| return $pointValue / 10; |
| } |
| |
| /** |
| * Draws a single polygon. |
| * |
| * @param array $points Point array |
| * @param ezcGraphColor $color Polygon color |
| * @param mixed $filled Filled |
| * @param float $thickness Line thickness |
| * @return void |
| */ |
| public function drawPolygon( array $points, ezcGraphColor $color, $filled = true, $thickness = 1. ) |
| { |
| $movie = $this->getDocument(); |
| |
| if ( !$filled ) |
| { |
| // The middle of the border is on the outline of a polygon in ming, |
| // fix that: |
| try |
| { |
| $points = $this->reducePolygonSize( $points, $thickness / 2 ); |
| } |
| catch ( ezcGraphReducementFailedException $e ) |
| { |
| return false; |
| } |
| } |
| |
| $shape = new SWFShape(); |
| |
| $this->setShapeColor( $shape, $color, $thickness, $filled ); |
| |
| $lastPoint = end( $points ); |
| $shape->movePenTo( $this->modifyCoordinate( $lastPoint->x ), $this->modifyCoordinate( $lastPoint->y ) ); |
| |
| foreach ( $points as $point ) |
| { |
| $shape->drawLineTo( $this->modifyCoordinate( $point->x ), $this->modifyCoordinate( $point->y ) ); |
| } |
| |
| $object = $movie->add( $shape ); |
| $object->setName( $id = 'ezcGraphPolygon_' . $this->id++ ); |
| |
| return $id; |
| } |
| |
| /** |
| * Draws a line |
| * |
| * @param ezcGraphCoordinate $start Start point |
| * @param ezcGraphCoordinate $end End point |
| * @param ezcGraphColor $color Line color |
| * @param float $thickness Line thickness |
| * @return void |
| */ |
| public function drawLine( ezcGraphCoordinate $start, ezcGraphCoordinate $end, ezcGraphColor $color, $thickness = 1. ) |
| { |
| $movie = $this->getDocument(); |
| |
| $shape = new SWFShape(); |
| |
| $this->setShapeColor( $shape, $color, $thickness, false ); |
| |
| $shape->movePenTo( $this->modifyCoordinate( $start->x ), $this->modifyCoordinate( $start->y ) ); |
| $shape->drawLineTo( $this->modifyCoordinate( $end->x ), $this->modifyCoordinate( $end->y ) ); |
| |
| $object = $movie->add( $shape ); |
| $object->setName( $id = 'ezcGraphLine_' . $this->id++ ); |
| |
| return $id; |
| } |
| |
| /** |
| * Returns boundings of text depending on the available font extension |
| * |
| * @param float $size Textsize |
| * @param ezcGraphFontOptions $font Font |
| * @param string $text Text |
| * @return ezcGraphBoundings Boundings of text |
| */ |
| protected function getTextBoundings( $size, ezcGraphFontOptions $font, $text ) |
| { |
| $t = new SWFText(); |
| $t->setFont( new SWFFont( $font->path ) ); |
| $t->setHeight( $size ); |
| |
| $boundings = new ezcGraphBoundings( 0, 0, $t->getWidth( $text ), $size ); |
| |
| return $boundings; |
| } |
| |
| /** |
| * Writes text in a box of desired size |
| * |
| * @param string $string Text |
| * @param ezcGraphCoordinate $position Top left position |
| * @param float $width Width of text box |
| * @param float $height Height of text box |
| * @param int $align Alignement of text |
| * @param ezcGraphRotation $rotation |
| * @return void |
| */ |
| public function drawTextBox( $string, ezcGraphCoordinate $position, $width, $height, $align, ezcGraphRotation $rotation = null ) |
| { |
| $padding = $this->options->font->padding + ( $this->options->font->border !== false ? $this->options->font->borderWidth : 0 ); |
| |
| $width = $this->modifyCoordinate( $width - $padding * 2 ); |
| $height = $this->modifyCoordinate( $height - $padding * 2 ); |
| $position = new ezcGraphCoordinate( |
| $this->modifyCoordinate( $position->x + $padding ), |
| $this->modifyCoordinate( $position->y + $padding ) |
| ); |
| |
| // Try to get a font size for the text to fit into the box |
| $maxSize = $this->modifyCoordinate( min( $height, $this->options->font->maxFontSize ) ); |
| $minSize = $this->modifyCoordinate( $this->options->font->minFontSize ); |
| $result = false; |
| for ( $size = $maxSize; $size >= $minSize; ) |
| { |
| $result = $this->testFitStringInTextBox( $string, $position, $width, $height, $size ); |
| if ( is_array( $result ) ) |
| { |
| break; |
| } |
| $size = $this->deModifyCoordinate( $size ); |
| $size = $this->modifyCoordinate( floor( ( $newsize = $size * ( $result ) ) >= $size ? $size - 1 : $newsize ) ); |
| } |
| |
| if ( !is_array( $result ) ) |
| { |
| if ( ( $height >= $this->options->font->minFontSize ) && |
| ( $this->options->autoShortenString ) ) |
| { |
| $result = $this->tryFitShortenedString( $string, $position, $width, $height, $size = $this->modifyCoordinate( $this->options->font->minFontSize ) ); |
| } |
| else |
| { |
| throw new ezcGraphFontRenderingException( $string, $this->options->font->minFontSize, $width, $height ); |
| } |
| } |
| |
| |
| $this->options->font->minimalUsedFont = $this->deModifyCoordinate( $size ); |
| |
| $this->strings[] = array( |
| 'text' => $result, |
| 'id' => $id = 'ezcGraphTextBox_' . $this->id++, |
| 'position' => $position, |
| 'width' => $width, |
| 'height' => $height, |
| 'align' => $align, |
| 'font' => $this->options->font, |
| 'rotation' => $rotation, |
| ); |
| |
| return $id; |
| } |
| |
| /** |
| * Render text depending of font type and available font extensions |
| * |
| * @param string $id |
| * @param string $text |
| * @param string $chars |
| * @param int $type |
| * @param string $path |
| * @param ezcGraphColor $color |
| * @param ezcGraphCoordinate $position |
| * @param float $size |
| * @param float $rotation |
| * @return void |
| */ |
| protected function renderText( $id, $text, $chars, $type, $path, ezcGraphColor $color, ezcGraphCoordinate $position, $size, $rotation = null ) |
| { |
| $movie = $this->getDocument(); |
| |
| $tb = new SWFTextField( SWFTEXTFIELD_NOEDIT ); |
| $tb->setFont( new SWFFont( $path ) ); |
| $tb->setHeight( $size ); |
| $tb->setColor( $color->red, $color->green, $color->blue, 255 - $color->alpha ); |
| $tb->addString( $text ); |
| $tb->addChars( $chars ); |
| |
| $object = $movie->add( $tb ); |
| $object->rotate( |
| ( $rotation !== null ? -$rotation->getRotation() : 0 ) |
| ); |
| $object->moveTo( |
| $position->x + |
| ( $rotation === null ? 0 : $this->modifyCoordinate( $rotation->get( 0, 2 ) ) ), |
| $position->y - |
| $size * ( 1 + $this->options->lineSpacing ) + |
| ( $rotation === null ? 0 : $this->modifyCoordinate( $rotation->get( 1, 2 ) ) ) |
| ); |
| $object->setName( $id ); |
| } |
| |
| /** |
| * Draw all collected texts |
| * |
| * The texts are collected and their maximum possible font size is |
| * calculated. This function finally draws the texts on the image, this |
| * delayed drawing has two reasons: |
| * |
| * 1) This way the text strings are always on top of the image, what |
| * results in better readable texts |
| * 2) The maximum possible font size can be calculated for a set of texts |
| * with the same font configuration. Strings belonging to one chart |
| * element normally have the same font configuration, so that all texts |
| * belonging to one element will have the same font size. |
| * |
| * @access protected |
| * @return void |
| */ |
| protected function drawAllTexts() |
| { |
| // Iterate over all strings to collect used chars per font |
| $chars = array(); |
| foreach ( $this->strings as $text ) |
| { |
| $completeString = ''; |
| foreach ( $text['text'] as $line ) |
| { |
| $completeString .= implode( ' ', $line ); |
| } |
| |
| // Collect chars for each font |
| if ( !isset( $chars[$text['font']->path] ) ) |
| { |
| $chars[$text['font']->path] = $completeString; |
| } |
| else |
| { |
| $chars[$text['font']->path] .= $completeString; |
| } |
| } |
| |
| foreach ( $this->strings as $text ) |
| { |
| $size = $this->modifyCoordinate( $text['font']->minimalUsedFont ); |
| |
| $completeHeight = count( $text['text'] ) * $size + ( count( $text['text'] ) - 1 ) * $this->options->lineSpacing; |
| |
| // Calculate y offset for vertical alignement |
| switch ( true ) |
| { |
| case ( $text['align'] & ezcGraph::BOTTOM ): |
| $yOffset = $text['height'] - $completeHeight; |
| break; |
| case ( $text['align'] & ezcGraph::MIDDLE ): |
| $yOffset = ( $text['height'] - $completeHeight ) / 2; |
| break; |
| case ( $text['align'] & ezcGraph::TOP ): |
| default: |
| $yOffset = 0; |
| break; |
| } |
| |
| $padding = $text['font']->padding + $text['font']->borderWidth / 2; |
| if ( $this->options->font->minimizeBorder === true ) |
| { |
| // Calculate maximum width of text rows |
| $width = false; |
| foreach ( $text['text'] as $line ) |
| { |
| $string = implode( ' ', $line ); |
| $boundings = $this->getTextBoundings( $size, $text['font'], $string ); |
| if ( ( $width === false) || ( $boundings->width > $width ) ) |
| { |
| $width = $boundings->width; |
| } |
| } |
| |
| switch ( true ) |
| { |
| case ( $text['align'] & ezcGraph::LEFT ): |
| $xOffset = 0; |
| break; |
| case ( $text['align'] & ezcGraph::CENTER ): |
| $xOffset = ( $text['width'] - $width ) / 2; |
| break; |
| case ( $text['align'] & ezcGraph::RIGHT ): |
| $xOffset = $text['width'] - $width; |
| break; |
| } |
| |
| $borderPolygonArray = array( |
| new ezcGraphCoordinate( |
| $this->deModifyCoordinate( $text['position']->x - $padding + $xOffset ), |
| $this->deModifyCoordinate( $text['position']->y - $padding + $yOffset ) |
| ), |
| new ezcGraphCoordinate( |
| $this->deModifyCoordinate( $text['position']->x + $padding * 2 + $xOffset + $width ), |
| $this->deModifyCoordinate( $text['position']->y - $padding + $yOffset ) |
| ), |
| new ezcGraphCoordinate( |
| $this->deModifyCoordinate( $text['position']->x + $padding * 2 + $xOffset + $width ), |
| $this->deModifyCoordinate( $text['position']->y + $padding * 2 + $yOffset + $completeHeight ) |
| ), |
| new ezcGraphCoordinate( |
| $this->deModifyCoordinate( $text['position']->x - $padding + $xOffset ), |
| $this->deModifyCoordinate( $text['position']->y + $padding * 2 + $yOffset + $completeHeight ) |
| ), |
| ); |
| } |
| else |
| { |
| $borderPolygonArray = array( |
| new ezcGraphCoordinate( |
| $this->deModifyCoordinate( $text['position']->x - $padding ), |
| $this->deModifyCoordinate( $text['position']->y - $padding ) |
| ), |
| new ezcGraphCoordinate( |
| $this->deModifyCoordinate( $text['position']->x + $padding * 2 + $text['width'] ), |
| $this->deModifyCoordinate( $text['position']->y - $padding ) |
| ), |
| new ezcGraphCoordinate( |
| $this->deModifyCoordinate( $text['position']->x + $padding * 2 + $text['width'] ), |
| $this->deModifyCoordinate( $text['position']->y + $padding * 2 + $text['height'] ) |
| ), |
| new ezcGraphCoordinate( |
| $this->deModifyCoordinate( $text['position']->x - $padding ), |
| $this->deModifyCoordinate( $text['position']->y + $padding * 2 + $text['height'] ) |
| ), |
| ); |
| } |
| |
| if ( $text['rotation'] !== null ) |
| { |
| foreach ( $borderPolygonArray as $nr => $point ) |
| { |
| $borderPolygonArray[$nr] = $text['rotation']->transformCoordinate( $point ); |
| } |
| } |
| |
| if ( $text['font']->background !== false ) |
| { |
| $this->drawPolygon( |
| $borderPolygonArray, |
| $text['font']->background, |
| true |
| ); |
| } |
| |
| if ( $text['font']->border !== false ) |
| { |
| $this->drawPolygon( |
| $borderPolygonArray, |
| $text['font']->border, |
| false, |
| $text['font']->borderWidth |
| ); |
| } |
| |
| // Render text with evaluated font size |
| $completeString = ''; |
| foreach ( $text['text'] as $line ) |
| { |
| $string = implode( ' ', $line ); |
| $completeString .= $string; |
| $boundings = $this->getTextBoundings( $size, $text['font'], $string ); |
| $text['position']->y += $size; |
| |
| switch ( true ) |
| { |
| case ( $text['align'] & ezcGraph::LEFT ): |
| $position = new ezcGraphCoordinate( |
| $text['position']->x, |
| $text['position']->y + $yOffset |
| ); |
| break; |
| case ( $text['align'] & ezcGraph::RIGHT ): |
| $position = new ezcGraphCoordinate( |
| $text['position']->x + ( $text['width'] - $boundings->width ), |
| $text['position']->y + $yOffset |
| ); |
| break; |
| case ( $text['align'] & ezcGraph::CENTER ): |
| $position = new ezcGraphCoordinate( |
| $text['position']->x + ( ( $text['width'] - $boundings->width ) / 2 ), |
| $text['position']->y + $yOffset |
| ); |
| break; |
| } |
| |
| // Optionally draw text shadow |
| if ( $text['font']->textShadow === true ) |
| { |
| $this->renderText( |
| $text['id'], |
| $string, |
| $chars[$text['font']->path], |
| $text['font']->type, |
| $text['font']->path, |
| $text['font']->textShadowColor, |
| new ezcGraphCoordinate( |
| $position->x + $this->modifyCoordinate( $text['font']->textShadowOffset ), |
| $position->y + $this->modifyCoordinate( $text['font']->textShadowOffset ) |
| ), |
| $size, |
| $text['rotation'] |
| ); |
| } |
| |
| // Finally draw text |
| $this->renderText( |
| $text['id'], |
| $string, |
| $chars[$text['font']->path], |
| $text['font']->type, |
| $text['font']->path, |
| $text['font']->color, |
| $position, |
| $size, |
| $text['rotation'] |
| ); |
| |
| $text['position']->y += $size * $this->options->lineSpacing; |
| } |
| } |
| } |
| |
| /** |
| * Draws a sector of cirlce |
| * |
| * @param ezcGraphCoordinate $center Center of circle |
| * @param mixed $width Width |
| * @param mixed $height Height |
| * @param mixed $startAngle Start angle of circle sector |
| * @param mixed $endAngle End angle of circle sector |
| * @param ezcGraphColor $color Color |
| * @param mixed $filled Filled |
| * @return void |
| */ |
| public function drawCircleSector( ezcGraphCoordinate $center, $width, $height, $startAngle, $endAngle, ezcGraphColor $color, $filled = true ) |
| { |
| if ( $startAngle > $endAngle ) |
| { |
| $tmp = $startAngle; |
| $startAngle = $endAngle; |
| $endAngle = $tmp; |
| } |
| |
| $movie = $this->getDocument(); |
| |
| $shape = new SWFShape(); |
| $this->setShapeColor( $shape, $color, 1, $filled ); |
| |
| if ( !$filled ) |
| { |
| try |
| { |
| $reduced = $this->reduceEllipseSize( $center, $width, $height, $startAngle, $endAngle, .5 ); |
| } |
| catch ( ezcGraphReducementFailedException $e ) |
| { |
| return false; |
| } |
| |
| $startAngle = $reduced['startAngle']; |
| $endAngle = $reduced['endAngle']; |
| |
| $width -= 1; |
| $height -= 1; |
| } |
| |
| $shape->movePenTo( $this->modifyCoordinate( $center->x ), $this->modifyCoordinate( $center->y ) ); |
| |
| // @TODO: User SWFShape::curveTo |
| for( |
| $angle = $startAngle; |
| $angle <= $endAngle; |
| $angle = min( $angle + $this->options->circleResolution, $endAngle ) ) |
| { |
| $shape->drawLineTo( |
| $this->modifyCoordinate( $center->x + cos( deg2rad( $angle ) ) * $width / 2 ), |
| $this->modifyCoordinate( $center->y + sin( deg2rad( $angle ) ) * $height / 2 ) |
| ); |
| |
| if ( $angle === $endAngle ) |
| { |
| break; |
| } |
| } |
| |
| $shape->drawLineTo( |
| $this->modifyCoordinate( $center->x ), |
| $this->modifyCoordinate( $center->y ) |
| ); |
| |
| $object = $movie->add( $shape ); |
| $object->setName( $id = 'ezcGraphCircleSector_' . $this->id++ ); |
| |
| return $id; |
| } |
| |
| /** |
| * Draws a circular arc consisting of several minor steps on the bounding |
| * lines. |
| * |
| * @param ezcGraphCoordinate $center |
| * @param mixed $width |
| * @param mixed $height |
| * @param mixed $size |
| * @param mixed $startAngle |
| * @param mixed $endAngle |
| * @param ezcGraphColor $color |
| * @param bool $filled |
| * @return string Element id |
| */ |
| protected function simulateCircularArc( ezcGraphCoordinate $center, $width, $height, $size, $startAngle, $endAngle, ezcGraphColor $color, $filled ) |
| { |
| $movie = $this->getDocument(); |
| $id = 'ezcGraphCircularArc_' . $this->id++; |
| |
| for ( |
| $tmpAngle = min( ceil ( $startAngle / 180 ) * 180, $endAngle ); |
| $tmpAngle <= $endAngle; |
| $tmpAngle = min( ceil ( $startAngle / 180 + 1 ) * 180, $endAngle ) ) |
| { |
| $shape = new SWFShape(); |
| $this->setShapeColor( $shape, $color, 1, $filled ); |
| |
| $shape->movePenTo( |
| $this->modifyCoordinate( $center->x + cos( deg2rad( $startAngle ) ) * $width / 2 ), |
| $this->modifyCoordinate( $center->y + sin( deg2rad( $startAngle ) ) * $height / 2 ) |
| ); |
| |
| // @TODO: Use SWFShape::curveTo |
| for( |
| $angle = $startAngle; |
| $angle <= $tmpAngle; |
| $angle = min( $angle + $this->options->circleResolution, $tmpAngle ) ) |
| { |
| $shape->drawLineTo( |
| $this->modifyCoordinate( $center->x + cos( deg2rad( $angle ) ) * $width / 2 ), |
| $this->modifyCoordinate( $center->y + sin( deg2rad( $angle ) ) * $height / 2 + $size ) |
| ); |
| |
| if ( $angle === $tmpAngle ) |
| { |
| break; |
| } |
| } |
| |
| for( |
| $angle = $tmpAngle; |
| $angle >= $startAngle; |
| $angle = max( $angle - $this->options->circleResolution, $startAngle ) ) |
| { |
| $shape->drawLineTo( |
| $this->modifyCoordinate( $center->x + cos( deg2rad( $angle ) ) * $width / 2 ), |
| $this->modifyCoordinate( $center->y + sin( deg2rad( $angle ) ) * $height / 2 ) |
| ); |
| |
| if ( $angle === $startAngle ) |
| { |
| break; |
| } |
| } |
| |
| $object = $movie->add( $shape ); |
| $object->setName( $id ); |
| |
| $startAngle = $tmpAngle; |
| if ( $tmpAngle === $endAngle ) |
| { |
| break; |
| } |
| } |
| |
| return $id; |
| } |
| |
| /** |
| * Draws a circular arc |
| * |
| * @param ezcGraphCoordinate $center Center of ellipse |
| * @param integer $width Width of ellipse |
| * @param integer $height Height of ellipse |
| * @param integer $size Height of border |
| * @param float $startAngle Starting angle of circle sector |
| * @param float $endAngle Ending angle of circle sector |
| * @param ezcGraphColor $color Color of Border |
| * @param bool $filled |
| * @return void |
| */ |
| public function drawCircularArc( ezcGraphCoordinate $center, $width, $height, $size, $startAngle, $endAngle, ezcGraphColor $color, $filled = true ) |
| { |
| if ( $startAngle > $endAngle ) |
| { |
| $tmp = $startAngle; |
| $startAngle = $endAngle; |
| $endAngle = $tmp; |
| } |
| |
| $id = $this->simulateCircularArc( $center, $width, $height, $size, $startAngle, $endAngle, $color, $filled ); |
| |
| if ( ( $this->options->shadeCircularArc !== false ) && |
| $filled ) |
| { |
| $gradient = new ezcGraphLinearGradient( |
| new ezcGraphCoordinate( |
| $center->x - $width, |
| $center->y |
| ), |
| new ezcGraphCoordinate( |
| $center->x + $width, |
| $center->y |
| ), |
| ezcGraphColor::fromHex( '#FFFFFF' )->transparent( $this->options->shadeCircularArc * 1.5 ), |
| ezcGraphColor::fromHex( '#000000' )->transparent( $this->options->shadeCircularArc * 1.5 ) |
| ); |
| |
| $this->simulateCircularArc( $center, $width, $height, $size, $startAngle, $endAngle, $gradient, $filled ); |
| } |
| |
| return $id; |
| } |
| |
| /** |
| * Draw circle |
| * |
| * @param ezcGraphCoordinate $center Center of ellipse |
| * @param mixed $width Width of ellipse |
| * @param mixed $height height of ellipse |
| * @param ezcGraphColor $color Color |
| * @param mixed $filled Filled |
| * @return void |
| */ |
| public function drawCircle( ezcGraphCoordinate $center, $width, $height, ezcGraphColor $color, $filled = true ) |
| { |
| $movie = $this->getDocument(); |
| |
| $shape = new SWFShape(); |
| $this->setShapeColor( $shape, $color, 1, $filled ); |
| |
| // Reduce size |
| if ( !$filled ) |
| { |
| $width -= 1; |
| $height -= 1; |
| } |
| |
| $shape->movePenTo( |
| $this->modifyCoordinate( $center->x + $width / 2 ), |
| $this->modifyCoordinate( $center->y ) |
| ); |
| |
| // @TODO: User SWFShape::curveTo |
| for ( $angle = $this->options->circleResolution; $angle < 360; $angle += $this->options->circleResolution ) |
| { |
| $shape->drawLineTo( |
| $this->modifyCoordinate( $center->x + cos( deg2rad( $angle ) ) * $width / 2 ), |
| $this->modifyCoordinate( $center->y + sin( deg2rad( $angle ) ) * $height / 2 ) |
| ); |
| } |
| |
| $shape->drawLineTo( |
| $this->modifyCoordinate( $center->x + $width / 2 ), |
| $this->modifyCoordinate( $center->y ) |
| ); |
| |
| $object = $movie->add( $shape ); |
| $object->setName( $id = 'ezcGraphCircle_' . $this->id++ ); |
| |
| return $id; |
| } |
| |
| /** |
| * Draw an image |
| * |
| * The image will be inlined in the SVG document using data URL scheme. For |
| * this the mime type and base64 encoded file content will be merged to |
| * URL. |
| * |
| * @param mixed $file Image file |
| * @param ezcGraphCoordinate $position Top left position |
| * @param float $width Width of image in destination image |
| * @param float $height Height of image in destination image |
| * @return void |
| */ |
| public function drawImage( $file, ezcGraphCoordinate $position, $width, $height ) |
| { |
| $movie = $this->getDocument(); |
| |
| $imageData = getimagesize( $file ); |
| if ( ( $imageData[2] !== IMAGETYPE_JPEG ) && ( $imageData[2] !== IMAGETYPE_PNG ) ) |
| { |
| throw new ezcGraphFlashBitmapTypeException( $imageData[2] ); |
| } |
| |
| // Try to create a new SWFBitmap object from provided file |
| $bitmap = new SWFBitmap( fopen( $file, 'rb' ) ); |
| |
| // Add the image to the movie |
| $object = $this->movie->add( $bitmap ); |
| |
| // Image size is calculated on the base of a tick size of 20, so |
| // that we need to transform this, to our tick size. |
| $factor = $this->modifyCoordinate( 1 ) / 20; |
| $object->scale( $factor, $factor ); |
| |
| // Scale by ratio of requested and original image size |
| $object->scale( |
| $width / $imageData[0], |
| $height / $imageData[1] |
| ); |
| |
| // Move object to the right position |
| $object->moveTo( |
| $this->modifyCoordinate( $position->x ), |
| $this->modifyCoordinate( $position->y ) |
| ); |
| |
| // Create, set and return unique ID |
| $object->setName( $id = 'ezcGraphImage_'. $this->id++ ); |
| return $id; |
| } |
| |
| /** |
| * Return mime type for current image format |
| * |
| * @return string |
| */ |
| public function getMimeType() |
| { |
| return 'application/x-shockwave-flash'; |
| } |
| |
| /** |
| * Finally save image |
| * |
| * @param string $file Destination filename |
| * @return void |
| */ |
| public function render( $file ) |
| { |
| $this->drawAllTexts(); |
| $movie = $this->getDocument(); |
| $movie->save( $file, $this->options->compression ); |
| } |
| |
| /** |
| * Get resource of rendered result |
| * |
| * Return the resource of the rendered result. You should not use this |
| * method before you called either renderToOutput() or render(), as the |
| * image may not be completely rendered until then. |
| * |
| * @return SWFMovie |
| */ |
| public function getResource() |
| { |
| return $this->movie; |
| } |
| } |
| |
| ?> |