Subversion Repositories Applications.gtt

Compare Revisions

Ignore whitespace Rev 60 → Rev 61

/trunk/bibliotheque/artichow/inc/Mark.class.php
New file
0,0 → 1,490
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Draw marks
*
* @package Artichow
*/
class awMark {
 
/**
* Circle mark
*
* @var int
*/
const CIRCLE = 1;
 
/**
* Square mark
*
* @var int
*/
const SQUARE = 2;
 
/**
* Triangle mark
*
* @var int
*/
const TRIANGLE = 3;
/**
* Inverted triangle mark
*
* @var int
*/
const INVERTED_TRIANGLE = 4;
 
/**
* Rhombus mark
*
* @var int
*/
const RHOMBUS = 5;
 
/**
* Cross (X) mark
*
* @var int
*/
const CROSS = 6;
 
/**
* Plus mark
*
* @var int
*/
const PLUS = 7;
 
/**
* Image mark
*
* @var int
*/
const IMAGE = 8;
 
/**
* Star mark
*
* @var int
*/
const STAR = 9;
 
/**
* Paperclip mark
*
* @var int
*/
const PAPERCLIP = 10;
 
/**
* Book mark
*
* @var int
*/
const BOOK = 11;
 
/**
* Must marks be hidden ?
*
* @var bool
*/
protected $hide;
 
/**
* Mark type
*
* @var int
*/
protected $type;
 
/**
* Mark size
*
* @var int
*/
protected $size = 8;
 
/**
* Fill mark
*
* @var Color, Gradient
*/
protected $fill;
 
/**
* Mark image
*
* @var Image
*/
protected $image;
 
/**
* To draw marks
*
* @var Driver
*/
protected $driver;
 
/**
* Move position from this vector
*
* @var Point
*/
protected $move;
/**
* Marks border
*
* @var Border
*/
public $border;
 
/**
* Build the mark
*/
public function __construct() {
$this->fill = new awColor(255, 0, 0, 0);
$this->border = new awBorder;
$this->border->hide();
$this->move = new awPoint(0, 0);
}
/**
* Change mark position
*
* @param int $x Add this interval to X coord
* @param int $y Add this interval to Y coord
*/
public function move($x, $y) {
$this->move = $this->move->move($x, $y);
}
/**
* Hide marks ?
*
* @param bool $hide TRUE to hide marks, FALSE otherwise
*/
public function hide($hide = TRUE) {
$this->hide = (bool)$hide;
}
/**
* Show marks ?
*
* @param bool $show
*/
public function show($show = TRUE) {
$this->hide = (bool)!$show;
}
/**
* Change mark type
*
* @param int $size Size in pixels
*/
public function setSize($size) {
$this->size = (int)$size;
}
/**
* Change mark type
*
* @param int $type New mark type
* @param int $size Mark size (can be NULL)
*/
public function setType($type, $size = NULL) {
$this->type = (int)$type;
if($size !== NULL) {
$this->setSize($size);
}
}
/**
* Fill the mark with a color or a gradient
*
* @param mixed $fill A color or a gradient
*/
public function setFill($fill) {
if($fill instanceof awColor or $fill instanceof awGradient) {
$this->fill = $fill;
}
}
/**
* Set an image
* Only for awMark::IMAGE type.
*
* @param Image An image
*/
public function setImage(awImage $image) {
$this->image = $image;
}
/**
* Draw the mark
*
* @param awDriver $driver
* @param awPoint $point Mark center
*/
public function draw(awDriver $driver, awPoint $point) {
// Hide marks ?
if($this->hide) {
return;
}
// Check if we can print marks
if($this->type !== NULL) {
$this->driver = $driver;
$realPoint = $this->move->move($point->x, $point->y);
switch($this->type) {
case awMark::CIRCLE :
$this->drawCircle($realPoint);
break;
case awMark::SQUARE :
$this->drawSquare($realPoint);
break;
case awMark::TRIANGLE :
$this->drawTriangle($realPoint);
break;
 
case awMark::INVERTED_TRIANGLE :
$this->drawTriangle($realPoint, TRUE);
break;
case awMark::RHOMBUS :
$this->drawRhombus($realPoint);
break;
 
case awMark::CROSS :
$this->drawCross($realPoint);
break;
case awMark::PLUS :
$this->drawCross($realPoint, TRUE);
break;
case awMark::IMAGE :
$this->drawImage($realPoint);
break;
case awMark::STAR :
$this->changeType('star');
$this->draw($driver, $point);
break;
case awMark::PAPERCLIP :
$this->changeType('paperclip');
$this->draw($driver, $point);
break;
case awMark::BOOK :
$this->changeType('book');
$this->draw($driver, $point);
break;
}
}
}
protected function changeType($image) {
$this->setType(awMARK::IMAGE);
$this->setImage(new awFileImage(ARTICHOW_IMAGE.DIRECTORY_SEPARATOR.$image.'.png'));
}
protected function drawCircle(awPoint $point) {
$this->driver->filledEllipse(
$this->fill,
$point,
$this->size, $this->size
);
$this->border->ellipse(
$this->driver,
$point,
$this->size, $this->size
);
}
protected function drawSquare(awPoint $point) {
list($x, $y) = $point->getLocation();
$x1 = (int)($x - $this->size / 2);
$x2 = $x1 + $this->size;
$y1 = (int)($y - $this->size / 2);
$y2 = $y1 + $this->size;
$this->border->rectangle($this->driver, new awPoint($x1, $y1), new awPoint($x2, $y2));
$size = $this->border->visible() ? 1 : 0;
$this->driver->filledRectangle(
$this->fill,
new awLine(
new awPoint($x1 + $size, $y1 + $size),
new awPoint($x2 - $size, $y2 - $size)
)
);
}
protected function drawTriangle(awPoint $point, $inverted = FALSE) {
list($x, $y) = $point->getLocation();
$size = $this->size;
$triangle = new awPolygon;
// Set default style and thickness
$triangle->setStyle(awPolygon::SOLID);
$triangle->setThickness(1);
if($inverted === TRUE) {
// Bottom of the triangle
$triangle->append(new awPoint($x, $y + $size / sqrt(3)));
// Upper left corner
$triangle->append(new awPoint($x - $size / 2, $y - $size / (2 * sqrt(3))));
 
// Upper right corner
$triangle->append(new awPoint($x + $size / 2, $y - $size / (2 * sqrt(3))));
} else {
// Top of the triangle
$triangle->append(new awPoint($x, $y - $size / sqrt(3)));
// Lower left corner
$triangle->append(new awPoint($x - $size / 2, $y + $size / (2 * sqrt(3))));
// Lower right corner
$triangle->append(new awPoint($x + $size / 2, $y + $size / (2 * sqrt(3))));
}
 
$this->driver->filledPolygon($this->fill, $triangle);
if($this->border->visible()) {
$this->border->polygon($this->driver, $triangle);
}
}
protected function drawRhombus(awPoint $point) {
list($x, $y) = $point->getLocation();
 
$rhombus = new awPolygon;
// Set default style and thickness
$rhombus->setStyle(awPolygon::SOLID);
$rhombus->setThickness(1);
// Top of the rhombus
$rhombus->append(new awPoint($x, $y - $this->size / 2));
// Right of the rhombus
$rhombus->append(new awPoint($x + $this->size / 2, $y));
// Bottom of the rhombus
$rhombus->append(new awPoint($x, $y + $this->size / 2));
// Left of the rhombus
$rhombus->append(new awPoint($x - $this->size / 2, $y));
$this->driver->filledPolygon($this->fill, $rhombus);
if($this->border->visible()) {
$this->border->polygon($this->driver, $rhombus);
}
}
protected function drawCross(awPoint $point, $upright = FALSE) {
list($x, $y) = $point->getLocation();
 
if($upright === TRUE) {
$x11 = (int)($x);
$y11 = (int)($y - $this->size / 2);
$x12 = (int)($x);
$y12 = (int)($y + $this->size / 2);
$y21 = (int)($y);
$y22 = (int)($y);
} else {
$x11 = (int)($x - $this->size / 2);
$y11 = (int)($y + $this->size / 2);
$x12 = (int)($x + $this->size / 2);
$y12 = (int)($y - $this->size / 2);
 
$y21 = (int)($y - $this->size / 2);
$y22 = (int)($y + $this->size / 2);
}
$x21 = (int)($x - $this->size / 2);
$x22 = (int)($x + $this->size / 2);
$this->driver->line(
$this->fill,
new awLine(
new awPoint($x11, $y11),
new awPoint($x12, $y12)
)
);
$this->driver->line(
$this->fill,
new awLine(
new awPoint($x21, $y21),
new awPoint($x22, $y22)
)
);
}
 
protected function drawImage(awPoint $point) {
if($this->image instanceof awImage) {
$width = $this->image->width;
$height = $this->image->height;
list($x, $y) = $point->getLocation();
$x1 = (int)($x - $width / 2);
$x2 = $x1 + $width;
$y1 = (int)($y - $width / 2);
$y2 = $y1 + $height;
$this->border->rectangle($this->driver, new awPoint($x1 - 1, $y1 - 1), new awPoint($x2 + 1, $y2 + 1));
$this->driver->copyImage($this->image, new awPoint($x1, $y1), new awPoint($x2, $y2));
}
}
 
}
 
registerClass('Mark');
?>
/trunk/bibliotheque/artichow/inc/Tick.class.php
New file
0,0 → 1,344
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Handle ticks
*
* @package Artichow
*/
class awTick {
 
/**
* Ticks style
*
* @var int
*/
protected $style = awTick::IN;
 
/**
* Ticks size
*
* @var int
*/
protected $size;
 
/**
* Ticks color
*
* @var Color
*/
protected $color;
 
/**
* Ticks number
*
* @var int
*/
protected $number;
 
/**
* Ticks number by other tick
*
* @var array
*/
protected $numberByTick;
 
/**
* Ticks interval
*
* @var int
*/
protected $interval = 1;
 
/**
* Hide ticks
*
* @var bool
*/
protected $hide = FALSE;
 
/**
* Hide first tick
*
* @var bool
*/
protected $hideFirst = FALSE;
 
/**
* Hide last tick
*
* @var bool
*/
protected $hideLast = FALSE;
/**
* In mode
*
* @param int
*/
const IN = 0;
/**
* Out mode
*
* @param int
*/
const OUT = 1;
/**
* In and out mode
*
* @param int
*/
const IN_OUT = 2;
/**
* Build the ticks
*
* @param int $number Number of ticks
* @param int $size Ticks size
*/
public function __construct($number, $size) {
$this->setSize($size);
$this->setNumber($number);
$this->setColor(new awBlack);
$this->style = awTick::IN;
}
/**
* Change ticks style
*
* @param int $style
*/
public function setStyle($style) {
$this->style = (int)$style;
}
/**
* Get ticks style
*
* @return int
*/
public function getStyle() {
return $this->style;
}
/**
* Change ticks color
*
* @param awColor $color
*/
public function setColor(awColor $color) {
$this->color = $color;
}
/**
* Change ticks size
*
* @param int $size
*/
public function setSize($size) {
$this->size = (int)$size;
}
/**
* Change interval of ticks
*
* @param int $interval
*/
public function setInterval($interval) {
$this->interval = (int)$interval;
}
/**
* Get interval between each tick
*
* @return int
*/
public function getInterval() {
return $this->interval;
}
/**
* Change number of ticks
*
* @param int $number
*/
public function setNumber($number) {
$this->number = (int)$number;
}
/**
* Get number of ticks
*
* @return int
*/
public function getNumber() {
return $this->number;
}
/**
* Change number of ticks relative to others ticks
*
* @param awTick $tick Ticks reference
* @param int $number Number of ticks
*/
public function setNumberByTick(awTick $tick, $number) {
$this->numberByTick = array($tick, (int)$number);
}
/**
* Hide ticks
*
* @param bool $hide
*/
public function hide($hide) {
$this->hide = (bool)$hide;
}
/**
* Hide first tick
*
* @param bool $hide
*/
public function hideFirst($hide) {
$this->hideFirst = (bool)$hide;
}
/**
* Hide last tick
*
* @param bool $hide
*/
public function hideLast($hide) {
$this->hideLast = (bool)$hide;
}
/**
* Draw ticks on a vector
*
* @param awDriver $driver A driver
* @param awVector $vector A vector
*/
public function draw(awDriver $driver, awVector $vector) {
if($this->numberByTick !== NULL) {
list($tick, $number) = $this->numberByTick;
$this->number = 1 + ($tick->getNumber() - 1) * ($number + 1);
$this->interval = $tick->getInterval();
}
if($this->number < 2 or $this->hide) {
return;
}
$angle = $vector->getAngle();
// echo "INIT:".$angle."<br>";
switch($this->style) {
case awTick::IN :
$this->drawTicks($driver, $vector, NULL, $angle + M_PI / 2);
break;
case awTick::OUT :
$this->drawTicks($driver, $vector, $angle + 3 * M_PI / 2, NULL);
break;
default :
$this->drawTicks($driver, $vector, $angle + M_PI / 2, $angle + 3 * M_PI / 2);
break;
}
}
protected function drawTicks(awDriver $driver, awVector $vector, $from, $to) {
// Draw last tick
if($this->hideLast === FALSE) {
//echo '<b>';
if(($this->number - 1) % $this->interval === 0) {
$this->drawTick($driver, $vector->p2, $from, $to);
}
//echo '</b>';
}
$number = $this->number - 1;
$size = $vector->getSize();
// Get tick increment in pixels
$inc = $size / $number;
// Check if we must hide the first tick
$start = $this->hideFirst ? $inc : 0;
$stop = $inc * $number;
$position = 0;
for($i = $start; round($i, 6) < $stop; $i += $inc) {
if($position % $this->interval === 0) {
$p = $vector->p1->move(
round($i * cos($vector->getAngle()), 6),
round($i * sin($vector->getAngle() * -1), 6)
);
$this->drawTick($driver, $p, $from, $to);
}
$position++;
}
//echo '<br><br>';
}
protected function drawTick(awDriver $driver, awPoint $p, $from, $to) {
// echo $this->size.':'.$angle.'|<b>'.cos($angle).'</b>/';
// The round avoid some errors in the calcul
// For example, 12.00000008575245 becomes 12
$p1 = $p;
$p2 = $p;
if($from !== NULL) {
$p1 = $p1->move(
round($this->size * cos($from), 6),
round($this->size * sin($from) * -1, 6)
);
}
if($to !== NULL) {
$p2 = $p2->move(
round($this->size * cos($to), 6),
round($this->size * sin($to) * -1, 6)
);
}
//echo $p1->x.':'.$p2->x.'('.$p1->y.':'.$p2->y.')'.'/';
$vector = new awVector(
$p1, $p2
);
$driver->line(
$this->color,
$vector
);
}
 
}
 
registerClass('Tick');
?>
/trunk/bibliotheque/artichow/inc/Driver.class.php
New file
0,0 → 1,725
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Draw your objects
*
* @package Artichow
*/
abstract class awDriver {
/**
* Image width
*
* @var int
*/
public $imageWidth;
/**
* Image height
*
* @var int
*/
public $imageHeight;
/**
* Driver X position
*
* @var int
*/
public $x;
/**
* Driver Y position
*
* @var int
*/
public $y;
/**
* Use anti-aliasing ?
*
* @var bool
*/
protected $antiAliasing = FALSE;
/**
* The FontDriver object that will be used to draw text
* with PHP fonts.
*
* @var awPHPFontDriver
*/
protected $phpFontDriver;
/**
* The FontDriver object that will be used to draw text
* with TTF or FDB fonts.
*
* @var awFileFontDriver
*/
protected $fileFontDriver;
/**
* A string representing the type of the driver
*
* @var string
*/
protected $driverString;
 
private $w;
private $h;
public function __construct() {
$this->phpFontDriver = new awPHPFontDriver();
$this->fileFontDriver = new awFileFontDriver();
}
 
/**
* Initialize the driver for a particular awImage object
*
* @param awImage $image
*/
abstract public function init(awImage $image);
/**
* Initialize the Driver for a particular FileImage object
*
* @param awFileImage $fileImage The FileImage object to work on
* @param string $file Image filename
*/
abstract public function initFromFile(awFileImage $fileImage, $file);
/**
* Change the image size
*
* @param int $width Image width
* @param int $height Image height
*/
abstract public function setImageSize($width, $height);
/**
* Inform the driver of the position of your image
*
* @param float $x Position on X axis of the center of the component
* @param float $y Position on Y axis of the center of the component
*/
abstract public function setPosition($x, $y);
/**
* Inform the driver of the position of your image
* This method need absolutes values
*
* @param int $x Left-top corner X position
* @param int $y Left-top corner Y position
*/
abstract public function setAbsPosition($x, $y);
/**
* Move the position of the image
*
* @param int $x Add this value to X axis
* @param int $y Add this value to Y axis
*/
abstract public function movePosition($x, $y);
/**
* Inform the driver of the size of your image
* Height and width must be between 0 and 1.
*
* @param int $w Image width
* @param int $h Image height
* @return array Absolute width and height of the image
*/
abstract public function setSize($w, $h);
/**
* Inform the driver of the size of your image
* You can set absolute size with this method.
*
* @param int $w Image width
* @param int $h Image height
*/
abstract public function setAbsSize($w, $h);
/**
* Get the size of the component handled by the driver
*
* @return array Absolute width and height of the component
*/
abstract public function getSize();
/**
* Turn antialiasing on or off
*
* @var bool $bool
*/
abstract public function setAntiAliasing($bool);
/**
* When passed a Color object, returns the corresponding
* color identifier (driver dependant).
*
* @param awColor $color A Color object
* @return int $rgb A color identifier representing the color composed of the given RGB components
*/
abstract public function getColor(awColor $color);
/**
* Draw an image here
*
* @param awImage $image Image
* @param int $p1 Image top-left point
* @param int $p2 Image bottom-right point
*/
abstract public function copyImage(awImage $image, awPoint $p1, awPoint $p2);
/**
* Draw an image here
*
* @param awImage $image Image
* @param int $d1 Destination top-left position
* @param int $d2 Destination bottom-right position
* @param int $s1 Source top-left position
* @param int $s2 Source bottom-right position
* @param bool $resample Resample image ? (default to TRUE)
*/
abstract public function copyResizeImage(awImage $image, awPoint $d1, awPoint $d2, awPoint $s1, awPoint $s2, $resample = TRUE);
/**
* Draw a string
*
* @var awText $text Text to print
* @param awPoint $point Draw the text at this point
* @param int $width Text max width
*/
abstract public function string(awText $text, awPoint $point, $width = NULL);
/**
* Draw a pixel
*
* @param awColor $color Pixel color
* @param awPoint $p
*/
abstract public function point(awColor $color, awPoint $p);
/**
* Draw a colored line
*
* @param awColor $color Line color
* @param awLine $line
* @param int $thickness Line tickness
*/
abstract public function line(awColor $color, awLine $line);
/**
* Draw a color arc
* @param awColor $color Arc color
* @param awPoint $center Point center
* @param int $width Ellipse width
* @param int $height Ellipse height
* @param int $from Start angle
* @param int $to End angle
*/
abstract public function arc(awColor $color, awPoint $center, $width, $height, $from, $to);
/**
* Draw an arc with a background color
*
* @param awColor $color Arc background color
* @param awPoint $center Point center
* @param int $width Ellipse width
* @param int $height Ellipse height
* @param int $from Start angle
* @param int $to End angle
*/
abstract public function filledArc(awColor $color, awPoint $center, $width, $height, $from, $to);
/**
* Draw a colored ellipse
*
* @param awColor $color Ellipse color
* @param awPoint $center Ellipse center
* @param int $width Ellipse width
* @param int $height Ellipse height
*/
abstract public function ellipse(awColor $color, awPoint $center, $width, $height);
/**
* Draw an ellipse with a background
*
* @param mixed $background Background (can be a color or a gradient)
* @param awPoint $center Ellipse center
* @param int $width Ellipse width
* @param int $height Ellipse height
*/
abstract public function filledEllipse($background, awPoint $center, $width, $height);
/**
* Draw a colored rectangle
*
* @param awColor $color Rectangle color
* @param awLine $line Rectangle diagonale
* @param awPoint $p2
*/
abstract public function rectangle(awColor $color, awLine $line);
/**
* Draw a rectangle with a background
*
* @param mixed $background Background (can be a color or a gradient)
* @param awLine $line Rectangle diagonale
*/
abstract public function filledRectangle($background, awLine $line);
/**
* Draw a polygon
*
* @param awColor $color Polygon color
* @param Polygon A polygon
*/
abstract public function polygon(awColor $color, awPolygon $polygon);
/**
* Draw a polygon with a background
*
* @param mixed $background Background (can be a color or a gradient)
* @param Polygon A polygon
*/
abstract public function filledPolygon($background, awPolygon $polygon);
 
/**
* Sends the image, as well as the correct HTTP headers, to the browser
*
* @param awImage $image The Image object to send
*/
abstract public function send(awImage $image);
/**
* Get the image as binary data
*
* @param awImage $image
*/
abstract public function get(awImage $image);
/**
* Return the width of some text
*
* @param awText $text
*/
abstract public function getTextWidth(awText $text);
/**
* Return the height of some text
*
* @param awText $text
*/
abstract public function getTextHeight(awText $text);
/**
* Return the string representing the type of driver
*
* @return string
*/
public function getDriverString() {
return $this->driverString;
}
/**
* Returns whether or not the driver is compatible with the given font type
*
* @param awFont $font
* @return bool
*/
abstract protected function isCompatibleWithFont(awFont $font);
// abstract private function drawImage(awImage $image, $return = FALSE, $header = TRUE);
}
 
registerClass('Driver', TRUE);
 
/**
* Abstract class for font drivers.
* Those are used to do all the grunt work on fonts.
*
* @package Artichow
*/
 
abstract class awFontDriver {
public function __construct() {
}
/**
* Draw the actual text.
*
* @param awDriver $driver The Driver object to draw upon
* @param awText $text The Text object
* @param awPoint $point Where to draw the text
* @param float $width The width of the area containing the text
*/
abstract public function string(awDriver $driver, awText $text, awPoint $point, $width = NULL);
/**
* Calculate the width of a given Text.
*
* @param awText $text The Text object
* @param awDriver $driver The awDriver object used to draw the graph
*/
abstract public function getTextWidth(awText $text, awDriver $driver);
 
/**
* Calculate the height of a given Text.
*
* @param awText $text The Text object
* @param awDriver $driver The awDriver object used to draw the graph
*/
abstract public function getTextHeight(awText $text, awDriver $driver);
}
 
registerClass('FontDriver', TRUE);
 
/**
* Class to handle calculations on PHPFont objects
*
* @package Artichow
*/
class awPHPFontDriver extends awFontDriver {
public function __construct() {
parent::__construct();
}
public function string(awDriver $driver, awText $text, awPoint $point, $width = NULL) {
 
switch ($driver->getDriverString()) {
case 'gd':
$this->gdString($driver, $text, $point, $width);
break;
default:
awImage::drawError('Class PHPFontDriver: Incompatibility between driver and font - You should never see this error message: have you called awDriver::isCompatibleWithFont() properly?');
break;
}
}
/**
* Draw a string onto a GDDriver object
*
* @param awGDDriver $driver The GDDriver to draw the text upon
* @param awText $text The awText object containing the string to draw
* @param awPoint $point Where to draw the text
* @param float $width The width of the text
*/
private function gdString(awGDDriver $driver, awText $text, awPoint $point, $width = NULL) {
$angle = $text->getAngle();
if($angle !== 90 and $angle !== 0) {
awImage::drawError("Class PHPFontDriver: You can only use 0° and 90° angles.");
}
 
if($angle === 90) {
$function = 'imagestringup';
$addAngle = $this->getGDTextHeight($text);
} else {
$function = 'imagestring';
$addAngle = 0;
}
 
$color = $text->getColor();
$rgb = $driver->getColor($color);
 
$textString = $text->getText();
$textString = str_replace("\r", "", $textString);
$textHeight = $this->getGDTextHeight($text);
// Split text if needed
if($width !== NULL) {
 
$characters = floor($width / ($this->getGDTextWidth($text) / strlen($textString)));
 
if($characters > 0) {
$textString = wordwrap($textString, $characters, "\n", TRUE);
}
 
}
$font = $text->getFont();
$lines = explode("\n", $textString);
 
foreach($lines as $i => $line) {
 
// Line position handling
if($angle === 90) {
$addX = $i * $textHeight;
$addY = 0;
} else {
$addX = 0;
$addY = $i * $textHeight;
}
 
$function(
$driver->resource,
$font->font,
$driver->x + $point->x + $addX,
$driver->y + $point->y + $addY + $addAngle,
$line,
$rgb
);
 
}
}
public function getTextWidth(awText $text, awDriver $driver) {
switch ($driver->getDriverString()) {
case 'gd':
return $this->getGDTextWidth($text);
default:
awImage::drawError('Class PHPFontDriver: Cannot get text width - incompatibility between driver and font');
break;
}
}
public function getTextHeight(awText $text, awDriver $driver) {
switch ($driver->getDriverString()) {
case 'gd':
return $this->getGDTextHeight($text);
default:
awImage::drawError('Class PHPFontDriver: Cannot get text height - incompatibility between driver and font');
break;
}
}
/**
* Return the width of a text for a GDDriver
*
* @param awText $text
* @return int $fontWidth
*/
private function getGDTextWidth(awText $text) {
$font = $text->getFont();
if($text->getAngle() === 90) {
$text->setAngle(45);
return $this->getGDTextHeight($text);
} else if($text->getAngle() === 45) {
$text->setAngle(90);
}
 
$fontWidth = imagefontwidth($font->font);
 
if($fontWidth === FALSE) {
awImage::drawError("Class PHPFontDriver: Unable to get font size.");
}
 
return (int)$fontWidth * strlen($text->getText());
}
/**
* Return the height of a text for a GDDriver
*
* @param awText $text
* @return int $fontHeight
*/
private function getGDTextHeight(awText $text) {
$font = $text->getFont();
if($text->getAngle() === 90) {
$text->setAngle(45);
return $this->getGDTextWidth($text);
} else if($text->getAngle() === 45) {
$text->setAngle(90);
}
 
$fontHeight = imagefontheight($font->font);
 
if($fontHeight === FALSE) {
awImage::drawError("Class PHPFontDriver: Unable to get font size.");
}
 
return (int)$fontHeight;
}
}
 
registerClass('PHPFontDriver');
 
/**
* Class to handle calculations on FileFont objects
*
* @package Artichow
*/
class awFileFontDriver extends awFontDriver {
public function __construct() {
parent::__construct();
}
public function string(awDriver $driver, awText $text, awPoint $point, $width = NULL) {
switch ($driver->getDriverString()) {
case 'gd':
$this->gdString($driver, $text, $point, $width);
break;
default:
awImage::drawError('Class fileFontDriver: Incompatibility between driver and font - You should never see this error message: have you called awDriver::isCompatibleWithFont() properly?');
break;
}
}
/**
* Draw an awFileFont object on a GD ressource
*
* @param awGDDriver $driver The awGDDriver object containing the ressource to draw upon
* @param awText $text The awText object containing the string to draw
* @param awPoint $point Where to draw the string from
* @param float $width The width of the area containing the text
*/
private function gdString(awGDDriver $driver, awText $text, awPoint $point, $width = NULL) {
// Make easier font positionment
$text->setText($text->getText()." ");
 
$font = $text->getFont();
if($font instanceof awTTFFont === FALSE and $font->getExtension() === NULL) {
$font->setExtension('ttf');
}
$filePath = $font->getName().'.'.$font->getExtension();
 
$box = imagettfbbox($font->getSize(), $text->getAngle(), $filePath, $text->getText());
$textHeight = - $box[5];
 
$box = imagettfbbox($font->getSize(), 90, $filePath, $text->getText());
$textWidth = abs($box[6] - $box[2]);
 
// Restore old text
$text->setText(substr($text->getText(), 0, strlen($text->getText()) - 1));
 
$textString = $text->getText();
 
// Split text if needed
if($width !== NULL) {
 
$characters = floor($width / $this->getGDAverageWidth($font));
$textString = wordwrap($textString, $characters, "\n", TRUE);
 
}
$color = $text->getColor();
$rgb = $driver->getColor($color);
imagettftext(
$driver->resource,
$font->getSize(),
$text->getAngle(),
$driver->x + $point->x + $textWidth * sin($text->getAngle() / 180 * M_PI),
$driver->y + $point->y + $textHeight,
$rgb,
$filePath,
$textString
);
}
public function getTextWidth(awText $text, awDriver $driver) {
switch ($driver->getDriverString()) {
case 'gd':
return $this->getGDTextWidth($text);
default:
awImage::drawError('Class FileFontDriver: Cannot get text width - incompatibility between driver and font');
break;
}
}
public function getTextHeight(awText $text, awDriver $driver) {
switch ($driver->getDriverString()) {
case 'gd':
return $this->getGDTextHeight($text);
default:
awImage::drawError('Class FileFontDriver: Cannot get text height - incompatibility between driver and font');
break;
}
}
private function getGDTextWidth(awText $text) {
$font = $text->getFont();
if($font->getExtension() === NULL) {
$font->setExtension('ttf');
}
$filePath = $font->getName().'.'.$font->getExtension();
$box = imagettfbbox($font->getSize(), $text->getAngle(), $filePath, $text->getText());
 
if($box === FALSE) {
awImage::drawError("Class FileFontDriver: Unable to get font width (GD).");
}
 
list(, , $x2, , , , $x1, ) = $box;
 
return abs($x2 - $x1);
}
private function getGDTextHeight(awText $text) {
$font = $text->getFont();
if($font->getExtension() === NULL) {
$font->setExtension('ttf');
}
$filePath = $font->getName().'.'.$font->getExtension();
$box = imagettfbbox($font->getSize(), $text->getAngle(), $filePath, $text->getText());
 
if($box === FALSE) {
awImage::drawError("Class FileFontDriver: Unable to get font height (GD).");
}
 
list(, , , $y2, , , , $y1) = $box;
 
return abs($y2 - $y1);
}
private function getGDAverageWidth(awFileFont $font) {
 
$text = "azertyuiopqsdfghjklmmmmmmmwxcvbbbn,;:!?.";
 
$box = imagettfbbox($font->getSize(), 0, $font->getName().'.'.$font->getExtension(), $text);
 
if($box === FALSE) {
awImage::drawError("Class FileFontDriver: Unable to get font average width.");
}
 
list(, , $x2, $y2, , , $x1, $y1) = $box;
 
return abs($x2 - $x1) / strlen($text);
 
}
}
 
registerClass('FileFontDriver');
 
// Include ARTICHOW_DRIVER by default to preserve backward compatibility.
require_once dirname(__FILE__).'/drivers/'.ARTICHOW_DRIVER.'.class.php';
 
?>
/trunk/bibliotheque/artichow/inc/Gradient.class.php
New file
0,0 → 1,135
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
 
require_once dirname(__FILE__)."/../Graph.class.php";
 
 
/**
* Create your gradients
*
* @package Artichow
*/
abstract class awGradient {
 
/**
* From color
*
* @var Color
*/
public $from;
 
/**
* To color
*
* @var Color
*/
public $to;
/**
* Build the gradient
*
* @param awColor $from From color
* @param awColor $to To color
*/
public function __construct(awColor $from, awColor $to) {
$this->from = $from;
$this->to = $to;
}
 
}
 
registerClass('Gradient', TRUE);
 
 
/**
* Create a linear gradient
*
* @package Artichow
*/
class awLinearGradient extends awGradient {
 
/**
* Gradient angle
*
* @var int
*/
public $angle;
/**
* Build the linear gradient
*
* @param awColor $from From color
* @param awColor $to To color
* @param int $angle Gradient angle
*/
public function __construct($from, $to, $angle) {
parent::__construct(
$from, $to
);
$this->angle = (int)$angle;
}
 
}
 
registerClass('LinearGradient');
 
 
/**
* Create a bilinear gradient
*
* @package Artichow
*/
class awBilinearGradient extends awLinearGradient {
 
/**
* Gradient center
*
* @var float Center between 0 and 1
*/
public $center;
/**
* Build the bilinear gradient
*
* @param awColor $from From color
* @param awColor $to To color
* @param int $angle Gradient angle
* @param int $center Gradient center
*/
public function __construct($from, $to, $angle, $center = 0.5) {
parent::__construct(
$from, $to, $angle
);
$this->center = (float)$center;
}
 
}
 
registerClass('BilinearGradient');
 
/**
* Create a radial gradient
*
* @package Artichow
*/
class awRadialGradient extends awGradient {
 
}
 
registerClass('RadialGradient');
?>
/trunk/bibliotheque/artichow/inc/Legend.class.php
New file
0,0 → 1,710
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
 
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Some legends
*
* @package Artichow
*/
class awLegend implements awPositionable {
 
/**
* Legends added
*
* @var array
*/
protected $legends = array();
 
/**
* The current component
*
* @var Component
*/
protected $component;
/**
* Background color or gradient
*
* @var Color, Gradient
*/
protected $background;
/**
* Text color
*
* @var Color
*/
protected $textColor;
/**
* Text font
*
* @var Font
*/
protected $textFont;
/**
* Text margin
*
* @var Side
*/
protected $textMargin;
/**
* Number of columns
*
* @var int
*/
protected $columns = NULL;
/**
* Number of rows
*
* @var int
*/
protected $rows = NULL;
/**
* Legend position
*
* @var Point
*/
protected $position;
/**
* Hide legend ?
*
* @var bool
*/
protected $hide = FALSE;
/**
* Space between each legend
*
* @var int
*/
protected $space = 4;
/**
* Horizontal alignment
*
* @var int
*/
protected $hAlign;
/**
* Vertical alignment
*
* @var int
*/
protected $vAlign;
 
/**
* Margin
*
* @var array Array for left, right, top and bottom margins
*/
private $margin;
/**
* Legend shadow
*
* @var Shadow
*/
public $shadow;
/**
* Legend border
*
* @var Border
*/
public $border;
/**
* Line legend
*
* @var int
*/
const LINE = 1;
/**
* Color/Gradient background legend
*
* @var int
*/
const BACKGROUND = 2;
/**
* Use marks and line as legend
*
* @var int
*/
const MARK = 3;
/**
* Use marks as legend
*
* @var int
*/
const MARKONLY = 4;
/**
* Right side model
*
* @var int
*/
const MODEL_RIGHT = 1;
/**
* Bottom side model
*
* @var int
*/
const MODEL_BOTTOM = 2;
 
/**
* Build the legend
*
* @param int $model Legend model
*/
public function __construct($model = awLegend::MODEL_RIGHT) {
$this->shadow = new awShadow(awShadow::LEFT_BOTTOM);
$this->border = new awBorder;
$this->textMargin = new awSide(4);
$this->setModel($model);
}
/**
* Set a predefined model for the legend
*
* @param int $model
*/
public function setModel($model) {
$this->setBackgroundColor(new awColor(255, 255, 255, 15));
$this->setPadding(8, 8, 8, 8);
$this->setTextFont(new awFont2);
$this->shadow->setSize(3);
switch($model) {
case awLegend::MODEL_RIGHT :
$this->setColumns(1);
$this->setAlign(awLegend::RIGHT, awLegend::MIDDLE);
$this->setPosition(0.96, 0.50);
break;
case awLegend::MODEL_BOTTOM :
$this->setRows(1);
$this->setAlign(awLegend::CENTER, awLegend::TOP);
$this->setPosition(0.50, 0.92);
break;
default :
$this->setPosition(0.5, 0.5);
break;
}
}
/**
* Hide legend ?
*
* @param bool $hide TRUE to hide legend, FALSE otherwise
*/
public function hide($hide = TRUE) {
$this->hide = (bool)$hide;
}
/**
* Show legend ?
*
* @param bool $show
*/
public function show($show = TRUE) {
$this->hide = (bool)!$show;
}
/**
* Add a Legendable object to the legend
*
* @param awLegendable $legendable
* @param string $title Legend title
* @param int $type Legend type (default to awLegend::LINE)
*/
public function add(awLegendable $legendable, $title, $type = awLegend::LINE) {
$legend = array($legendable, $title, $type);
$this->legends[] = $legend;
}
/**
* Change legend padding
*
* @param int $left
* @param int $right
* @param int $top
* @param int $bottom
*/
public function setPadding($left, $right, $top, $bottom) {
$this->padding = array((int)$left, (int)$right, (int)$top, (int)$bottom);
}
/**
* Change space between each legend
*
* @param int $space
*/
public function setSpace($space) {
$this->space = (int)$space;
}
/**
* Change alignment
*
* @param int $h Horizontal alignment
* @param int $v Vertical alignment
*/
public function setAlign($h = NULL, $v = NULL) {
if($h !== NULL) {
$this->hAlign = (int)$h;
}
if($v !== NULL) {
$this->vAlign = (int)$v;
}
}
/**
* Change number of columns
*
* @param int $columns
*/
public function setColumns($columns) {
$this->rows = NULL;
$this->columns = (int)$columns;
}
/**
* Change number of rows
*
* @param int $rows
*/
public function setRows($rows) {
$this->columns = NULL;
$this->rows = (int)$rows;
}
/**
* Change legend position
* X and Y positions must be between 0 and 1.
*
* @param float $x
* @param float $y
*/
public function setPosition($x = NULL, $y = NULL) {
$x = (is_null($x) and !is_null($this->position)) ? $this->position->x : $x;
$y = (is_null($y) and !is_null($this->position)) ? $this->position->y : $y;
$this->position = new awPoint($x, $y);
}
/**
* Get legend position
*
* @return Point
*/
public function getPosition() {
return $this->position;
}
/**
* Change text font
*
* @param awFont $font
*/
public function setTextFont(awFont $font) {
$this->textFont = $font;
}
/**
* Change text margin
*
* @param int $left
* @param int $right
*/
public function setTextMargin($left, $right) {
$this->textMargin->set($left, $right);
}
/**
* Change text color
*
* @param awColor $color
*/
public function setTextColor(awColor $color) {
$this->textColor = $color;
}
/**
* Change background
*
* @param mixed $background
*/
public function setBackground($background) {
$this->background = $background;
}
/**
* Change background color
*
* @param awColor $color
*/
public function setBackgroundColor(awColor $color) {
$this->background = $color;
}
/**
* Change background gradient
*
* @param awGradient $gradient
*/
public function setBackgroundGradient(awGradient $gradient) {
$this->background = $gradient;
}
/**
* Count the number of Legendable objects in the legend
*
* @return int
*/
public function count() {
return count($this->legends);
}
public function draw(awDriver $driver) {
if($this->hide) {
return;
}
$count = $this->count();
// No legend to print
if($count === 0) {
return;
}
// Get text widths and heights of each element of the legend
$widths = array();
$heights = array();
$texts = array();
for($i = 0; $i < $count; $i++) {
list(, $title, ) = $this->legends[$i];
$text = new awText(
$title,
$this->textFont,
$this->textColor,
0
);
// $font = $text->getFont();
$widths[$i] = $driver->getTextWidth($text) + $this->textMargin->left + $this->textMargin->right;
$heights[$i] = $driver->getTextHeight($text);
$texts[$i] = $text;
}
// Maximum height of the font used
$heightMax = array_max($heights);
// Get number of columns
if($this->columns !== NULL) {
$columns = $this->columns;
} else if($this->rows !== NULL) {
$columns = ceil($count / $this->rows);
} else {
$columns = $count;
}
// Number of rows
$rows = (int)ceil($count / $columns);
// Get maximum with of each column
$widthMax = array();
for($i = 0; $i < $count; $i++) {
// Get column width
$column = $i % $columns;
if(array_key_exists($column, $widthMax) === FALSE) {
$widthMax[$column] = $widths[$i];
} else {
$widthMax[$column] = max($widthMax[$column], $widths[$i]);
}
}
$width = $this->padding[0] + $this->padding[1] - $this->space;
for($i = 0; $i < $columns; $i++) {
$width += $this->space + 5 + 10 + $widthMax[$i];
}
$height = ($heightMax + $this->space) * $rows - $this->space + $this->padding[2] + $this->padding[3];
// Look for legends position
list($x, $y) = $driver->getSize();
$p = new awPoint(
$this->position->x * $x,
$this->position->y * $y
);
switch($this->hAlign) {
case awLegend::CENTER :
$p->x -= $width / 2;
break;
case awLegend::RIGHT :
$p->x -= $width;
break;
}
switch($this->vAlign) {
case awLegend::MIDDLE :
$p->y -= $height / 2;
break;
case awLegend::BOTTOM :
$p->y -= $height;
break;
}
// Draw legend shadow
$this->shadow->draw(
$driver,
$p,
$p->move($width, $height),
awShadow::OUT
);
// Draw legends base
$this->drawBase($driver, $p, $width, $height);
// Draw each legend
for($i = 0; $i < $count; $i++) {
list($component, $title, $type) = $this->legends[$i];
$column = $i % $columns;
$row = (int)floor($i / $columns);
// Get width of all previous columns
$previousColumns = 0;
for($j = 0; $j < $column; $j++) {
$previousColumns += $this->space + 10 + 5 + $widthMax[$j];
}
// Draw legend text
$driver->string(
$texts[$i],
$p->move(
$this->padding[0] + $previousColumns + 10 + 5 + $this->textMargin->left,
$this->padding[2] + $row * ($heightMax + $this->space) + $heightMax / 2 - $heights[$i] / 2
)
);
// Draw legend icon
switch($type) {
case awLegend::LINE :
case awLegend::MARK :
case awLegend::MARKONLY :
// Get vertical position
$x = $this->padding[0] + $previousColumns;
$y = $this->padding[2] + $row * ($heightMax + $this->space) + $heightMax / 2 - $component->getLegendLineThickness();
// Draw two lines
if($component->getLegendLineColor() !== NULL) {
$color = $component->getLegendLineColor();
if($color instanceof awColor and $type !== awLegend::MARKONLY) {
$driver->line(
$color,
new awLine(
$p->move(
$x, // YaPB ??
$y + $component->getLegendLineThickness() / 2
),
$p->move(
$x + 10,
$y + $component->getLegendLineThickness() / 2
),
$component->getLegendLineStyle(),
$component->getLegendLineThickness()
)
);
unset($color);
}
}
if($type === awLegend::MARK or $type === awLegend::MARKONLY) {
$mark = $component->getLegendMark();
if($mark !== NULL) {
$mark->draw(
$driver,
$p->move(
$x + 5.5,
$y + $component->getLegendLineThickness() / 2
)
);
}
unset($mark);
}
break;
case awLegend::BACKGROUND :
// Get vertical position
$x = $this->padding[0] + $previousColumns;
$y = $this->padding[2] + $row * ($heightMax + $this->space) + $heightMax / 2 - 5;
$from = $p->move(
$x,
$y
);
$to = $p->move(
$x + 10,
$y + 10
);
$background = $component->getLegendBackground();
if($background !== NULL) {
$driver->filledRectangle(
$component->getLegendBackground(),
new awLine($from, $to)
);
// Draw rectangle border
$this->border->rectangle(
$driver,
$from->move(0, 0),
$to->move(0, 0)
);
}
unset($background, $from, $to);
break;
}
}
}
private function drawBase(awDriver $driver, awPoint $p, $width, $height) {
 
$this->border->rectangle(
$driver,
$p,
$p->move($width, $height)
);
$size = $this->border->visible() ? 1 : 0;
$driver->filledRectangle(
$this->background,
new awLine(
$p->move($size, $size),
$p->move($width - $size, $height - $size)
)
);
}
 
}
 
registerClass('Legend');
 
/**
* You can add a legend to components which implements this interface
*
* @package Artichow
*/
interface awLegendable {
 
/**
* Get the line type
*
* @return int
*/
public function getLegendLineStyle();
 
/**
* Get the line thickness
*
* @return int
*/
public function getLegendLineThickness();
 
/**
* Get the color of line
*
* @return Color
*/
public function getLegendLineColor();
 
/**
* Get the background color or gradient of an element of the component
*
* @return Color, Gradient
*/
public function getLegendBackground();
 
/**
* Get a Mark object
*
* @return Mark
*/
public function getLegendMark();
 
}
 
registerInterface('Legendable');
?>
/trunk/bibliotheque/artichow/inc/Tools.class.php
New file
0,0 → 1,175
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Objects capable of being positioned
*
* @package Artichow
*/
interface awPositionable {
 
/**
* Left align
*
* @var int
*/
const LEFT = 1;
 
/**
* Right align
*
* @var int
*/
const RIGHT = 2;
 
/**
* Center align
*
* @var int
*/
const CENTER = 3;
 
/**
* Top align
*
* @var int
*/
const TOP = 4;
 
/**
* Bottom align
*
* @var int
*/
const BOTTOM = 5;
 
/**
* Middle align
*
* @var int
*/
const MIDDLE = 6;
/**
* Change alignment
*
* @param int $h Horizontal alignment
* @param int $v Vertical alignment
*/
public function setAlign($h = NULL, $v = NULL);
}
 
registerInterface('Positionable');
 
/**
* Manage left, right, top and bottom sides
*
* @package Artichow
*/
class awSide {
 
/**
* Left side
*
* @var int
*/
public $left = 0;
 
/**
* Right side
*
* @var int
*/
public $right = 0;
 
/**
* Top side
*
* @var int
*/
public $top = 0;
 
/**
* Bottom side
*
* @var int
*/
public $bottom = 0;
/**
* Build the side
*
* @param mixed $left
* @param mixed $right
* @param mixed $top
* @param mixed $bottom
*/
public function __construct($left = NULL, $right = NULL, $top = NULL, $bottom = NULL) {
$this->set($left, $right, $top, $bottom);
}
/**
* Change side values
*
* @param mixed $left
* @param mixed $right
* @param mixed $top
* @param mixed $bottom
*/
public function set($left = NULL, $right = NULL, $top = NULL, $bottom = NULL) {
if($left !== NULL) {
$this->left = (float)$left;
}
if($right !== NULL) {
$this->right = (float)$right;
}
if($top !== NULL) {
$this->top = (float)$top;
}
if($bottom !== NULL) {
$this->bottom = (float)$bottom;
}
}
/**
* Add values to each side
*
* @param mixed $left
* @param mixed $right
* @param mixed $top
* @param mixed $bottom
*/
public function add($left = NULL, $right = NULL, $top = NULL, $bottom = NULL) {
if($left !== NULL) {
$this->left += (float)$left;
}
if($right !== NULL) {
$this->right += (float)$right;
}
if($top !== NULL) {
$this->top += (float)$top;
}
if($bottom !== NULL) {
$this->bottom += (float)$bottom;
}
}
 
}
 
registerClass('Side');
?>
/trunk/bibliotheque/artichow/inc/Axis.class.php
New file
0,0 → 1,769
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
 
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Handle axis
*
* @package Artichow
*/
class awAxis {
 
/**
* Axis line
*
* @var Line
*/
public $line;
 
/**
* Axis labels
*
* @var Label
*/
public $label;
 
/**
* Axis title
*
* @var Label
*/
public $title;
 
/**
* Title position
*
* @var float
*/
protected $titlePosition = 0.5;
 
/**
* Labels number
*
* @var int
*/
protected $labelNumber;
 
/**
* Axis ticks
*
* @var array
*/
protected $ticks = array();
 
/**
* Axis and ticks color
*
* @var Color
*/
protected $color;
 
/**
* Axis left and right padding
*
* @var Side
*/
protected $padding;
 
/**
* Axis range
*
* @var array
*/
protected $range;
 
/**
* Hide axis
*
* @var bool
*/
protected $hide = FALSE;
 
/**
* Auto-scaling mode
*
* @var bool
*/
protected $auto = TRUE;
 
/**
* Axis range callback function
*
* @var array
*/
protected $rangeCallback = array(
'toValue' => 'toProportionalValue',
'toPosition' => 'toProportionalPosition'
);
 
/**
* Build the axis
*
* @param float $min Begin of the range of the axis
* @param float $max End of the range of the axis
*/
public function __construct($min = NULL, $max = NULL) {
 
$this->line = new awVector(
new awPoint(0, 0),
new awPoint(0, 0)
);
 
$this->label = new awLabel;
$this->padding = new awSide;
 
$this->title = new awLabel(
NULL,
NULL,
NULL,
0
);
 
$this->setColor(new awBlack);
 
if($min !== NULL and $max !== NULL) {
$this->setRange($min, $max);
}
 
}
 
/**
* Enable/disable auto-scaling mode
*
* @param bool $auto
*/
public function auto($auto) {
$this->auto = (bool)$auto;
}
 
/**
* Get auto-scaling mode status
*
* @return bool
*/
public function isAuto() {
return $this->auto;
}
 
/**
* Hide axis
*
* @param bool $hide
*/
public function hide($hide = TRUE) {
$this->hide = (bool)$hide;
}
 
/**
* Show axis
*
* @param bool $show
*/
public function show($show = TRUE) {
$this->hide = !(bool)$show;
}
 
/**
* Return a tick object from its name
*
* @param string $name Tick object name
* @return Tick
*/
public function tick($name) {
return array_key_exists($name, $this->ticks) ? $this->ticks[$name] : NULL;
}
 
/**
* Add a tick object
*
* @param string $name Tick object name
* @param awTick $tick Tick object
*/
public function addTick($name, awTick $tick) {
$this->ticks[$name] = $tick;
}
 
/**
* Delete a tick object
*
* @param string $name Tick object name
*/
public function deleteTick($name) {
if(array_key_exists($name, $this->ticks)) {
unset($this->ticks[$name]);
}
}
 
/**
* Hide all ticks
*
* @param bool $hide Hide or not ?
*/
public function hideTicks($hide = TRUE) {
foreach($this->ticks as $tick) {
$tick->hide($hide);
}
}
 
/**
* Change ticks style
*
* @param int $style Ticks style
*/
public function setTickStyle($style) {
foreach($this->ticks as $tick) {
$tick->setStyle($style);
}
}
 
/**
* Change ticks interval
*
* @param int $interval Ticks interval
*/
public function setTickInterval($interval) {
foreach($this->ticks as $tick) {
$tick->setInterval($interval);
}
}
 
/**
* Change number of ticks relative to others ticks
*
* @param awTick $to Change number of theses ticks
* @param awTick $from Ticks reference
* @param float $number Number of ticks by the reference
*/
public function setNumberByTick($to, $from, $number) {
$this->ticks[$to]->setNumberByTick($this->ticks[$from], $number);
}
 
/**
* Reverse ticks style
*/
public function reverseTickStyle() {
foreach($this->ticks as $tick) {
if($tick->getStyle() === awTick::IN) {
$tick->setStyle(awTick::OUT);
} else if($tick->getStyle() === awTick::OUT) {
$tick->setStyle(awTick::IN);
}
}
}
 
/**
* Change interval of labels
*
* @param int $interval Interval
*/
public function setLabelInterval($interval) {
$this->auto(FALSE);
$this->setTickInterval($interval);
$this->label->setInterval($interval);
}
 
/**
* Change number of labels
*
* @param int $number Number of labels to display (can be NULL)
*/
public function setLabelNumber($number) {
$this->auto(FALSE);
$this->labelNumber = is_null($number) ? NULL : (int)$number;
}
 
/**
* Get number of labels
*
* @return int
*/
public function getLabelNumber() {
return $this->labelNumber;
}
 
/**
* Change precision of labels
*
* @param int $precision Precision
*/
public function setLabelPrecision($precision) {
$this->auto(FALSE);
$function = 'axis'.time().'_'.(microtime() * 1000000);
eval('function '.$function.'($value) {
return sprintf("%.'.(int)$precision.'f", $value);
}');
$this->label->setCallbackFunction($function);
}
 
/**
* Change text of labels
*
* @param array $texts Some texts
*/
public function setLabelText($texts) {
if(is_array($texts)) {
$this->auto(FALSE);
$function = 'axis'.time().'_'.(microtime() * 1000000);
eval('function '.$function.'($value) {
$texts = '.var_export($texts, TRUE).';
return isset($texts[$value]) ? $texts[$value] : \'?\';
}');
$this->label->setCallbackFunction($function);
}
}
 
/**
* Get the position of a point
*
* @param awAxis $xAxis X axis
* @param awAxis $yAxis Y axis
* @param awPoint $p Position of the point
* @return Point Position on the axis
*/
public static function toPosition(awAxis $xAxis, awAxis $yAxis, awPoint $p) {
 
$p1 = $xAxis->getPointFromValue($p->x);
$p2 = $yAxis->getPointFromValue($p->y);
 
return new awPoint(
round($p1->x),
round($p2->y)
);
 
}
 
/**
* Change title alignment
*
* @param int $alignment New Alignment
*/
public function setTitleAlignment($alignment) {
 
switch($alignment) {
 
case awLabel::TOP :
$this->setTitlePosition(1);
$this->title->setAlign(NULL, awLabel::BOTTOM);
break;
 
case awLabel::BOTTOM :
$this->setTitlePosition(0);
$this->title->setAlign(NULL, awLabel::TOP);
break;
 
case awLabel::LEFT :
$this->setTitlePosition(0);
$this->title->setAlign(awLabel::LEFT);
break;
 
case awLabel::RIGHT :
$this->setTitlePosition(1);
$this->title->setAlign(awLabel::RIGHT);
break;
 
}
 
}
 
/**
* Change title position on the axis
*
* @param float $position A new awposition between 0 and 1
*/
public function setTitlePosition($position) {
$this->titlePosition = (float)$position;
}
 
/**
* Change axis and axis title color
*
* @param awColor $color
*/
public function setColor(awColor $color) {
$this->color = $color;
$this->title->setColor($color);
}
 
/**
* Change axis padding
*
* @param int $left Left padding in pixels
* @param int $right Right padding in pixels
*/
public function setPadding($left, $right) {
$this->padding->set($left, $right);
}
 
/**
* Get axis padding
*
* @return Side
*/
public function getPadding() {
return $this->padding;
}
 
/**
* Change axis range
*
* @param float $min
* @param float $max
*/
public function setRange($min, $max) {
if($min !== NULL) {
$this->range[0] = (float)$min;
}
if($max !== NULL) {
$this->range[1] = (float)$max;
}
}
 
/**
* Get axis range
*
* @return array
*/
public function getRange() {
return $this->range;
}
 
/**
* Change axis range callback function
*
* @param string $toValue Transform a position between 0 and 1 to a value
* @param string $toPosition Transform a value to a position between 0 and 1 on the axis
*/
public function setRangeCallback($toValue, $toPosition) {
$this->rangeCallback = array(
'toValue' => (string)$toValue,
'toPosition' => (string)$toPosition
);
}
 
/**
* Center X values of the axis
*
* @param awAxis $axis An axis
* @param float $value The reference value on the axis
*/
public function setXCenter(awAxis $axis, $value) {
 
// Check vector angle
if($this->line->isVertical() === FALSE) {
awImage::drawError("Class Axis: setXCenter() can only be used on vertical axes.");
}
 
$p = $axis->getPointFromValue($value);
 
$this->line->setX(
$p->x,
$p->x
);
 
}
 
/**
* Center Y values of the axis
*
* @param awAxis $axis An axis
* @param float $value The reference value on the axis
*/
public function setYCenter(awAxis $axis, $value) {
 
// Check vector angle
if($this->line->isHorizontal() === FALSE) {
awImage::drawError("Class Axis: setYCenter() can only be used on horizontal axes.");
}
 
$p = $axis->getPointFromValue($value);
 
$this->line->setY(
$p->y,
$p->y
);
 
}
 
/**
* Get the distance between to values on the axis
*
* @param float $from The first value
* @param float $to The last value
* @return Point
*/
public function getDistance($from, $to) {
 
$p1 = $this->getPointFromValue($from);
$p2 = $this->getPointFromValue($to);
 
return $p1->getDistance($p2);
 
}
 
/**
* Get a point on the axis from a value
*
* @param float $value
* @return Point
*/
protected function getPointFromValue($value) {
 
$callback = $this->rangeCallback['toPosition'];
 
list($min, $max) = $this->range;
$position = $callback($value, $min, $max);
 
return $this->getPointFromPosition($position);
 
}
 
/**
* Get a point on the axis from a position
*
* @param float $position A position between 0 and 1
* @return Point
*/
protected function getPointFromPosition($position) {
 
$vector = $this->getVector();
 
$angle = $vector->getAngle();
$size = $vector->getSize();
 
return $vector->p1->move(
cos($angle) * $size * $position,
-1 * sin($angle) * $size * $position
);
 
}
 
/**
* Draw axis
*
* @param awDriver $driver A driver
*/
public function draw(awDriver $driver) {
 
if($this->hide) {
return;
}
 
$vector = $this->getVector();
 
// Draw axis ticks
$this->drawTicks($driver, $vector);
 
// Draw axis line
$this->line($driver);
 
// Draw labels
$this->drawLabels($driver);
 
// Draw axis title
$p = $this->getPointFromPosition($this->titlePosition);
$this->title->draw($driver, $p);
 
}
 
public function autoScale() {
 
if($this->isAuto() === FALSE) {
return;
}
 
list($min, $max) = $this->getRange();
$interval = $max - $min;
 
if($interval > 0) {
$partMax = $max / $interval;
$partMin = $min / $interval;
} else {
$partMax = 0;
$partMin = 0;
}
 
$difference = log($interval) / log(10);
$difference = floor($difference);
 
$pow = pow(10, $difference);
 
if($pow > 0) {
$intervalNormalize = $interval / $pow;
} else {
$intervalNormalize = 0;
}
 
if($difference <= 0) {
 
$precision = $difference * -1 + 1;
 
if($intervalNormalize > 2) {
$precision--;
}
 
} else {
$precision = 0;
}
 
if($min != 0 and $max != 0) {
$precision++;
}
 
if($this->label->getCallbackFunction() === NULL) {
$this->setLabelPrecision($precision);
}
 
if($intervalNormalize <= 1.5) {
$intervalReal = 1.5;
$labelNumber = 4;
} else if($intervalNormalize <= 2) {
$intervalReal = 2;
$labelNumber = 5;
} else if($intervalNormalize <= 3) {
$intervalReal = 3;
$labelNumber = 4;
} else if($intervalNormalize <= 4) {
$intervalReal = 4;
$labelNumber = 5;
} else if($intervalNormalize <= 5) {
$intervalReal = 5;
$labelNumber = 6;
} else if($intervalNormalize <= 8) {
$intervalReal = 8;
$labelNumber = 5;
} else if($intervalNormalize <= 10) {
$intervalReal = 10;
$labelNumber = 6;
}
 
if($min == 0) {
 
$this->setRange(
$min,
$intervalReal * $pow
);
 
} else if($max == 0) {
 
$this->setRange(
$intervalReal * $pow * -1,
0
);
 
}
 
$this->setLabelNumber($labelNumber);
 
}
 
protected function line(awDriver $driver) {
 
$driver->line(
$this->color,
$this->line
);
 
}
 
protected function drawTicks(awDriver $driver, awVector $vector) {
 
foreach($this->ticks as $tick) {
$tick->setColor($this->color);
$tick->draw($driver, $vector);
}
 
}
 
protected function drawLabels($driver) {
 
if($this->labelNumber !== NULL) {
list($min, $max) = $this->range;
$number = $this->labelNumber - 1;
if($number < 1) {
return;
}
$function = $this->rangeCallback['toValue'];
$labels = array();
for($i = 0; $i <= $number; $i++) {
$labels[] = $function($i / $number, $min, $max);
}
$this->label->set($labels);
}
 
$labels = $this->label->count();
 
for($i = 0; $i < $labels; $i++) {
 
$p = $this->getPointFromValue($this->label->get($i));
$this->label->draw($driver, $p, $i);
 
}
 
}
 
protected function getVector() {
 
$angle = $this->line->getAngle();
 
// Compute paddings
$vector = new awVector(
$this->line->p1->move(
cos($angle) * $this->padding->left,
-1 * sin($angle) * $this->padding->left
),
$this->line->p2->move(
-1 * cos($angle) * $this->padding->right,
-1 * -1 * sin($angle) * $this->padding->right
)
);
 
return $vector;
 
}
 
public function __clone() {
 
$this->label = clone $this->label;
$this->line = clone $this->line;
$this->title = clone $this->title;
 
foreach($this->ticks as $name => $tick) {
$this->ticks[$name] = clone $tick;
}
 
}
 
}
 
registerClass('Axis');
 
function toProportionalValue($position, $min, $max) {
return $min + ($max - $min) * $position;
}
 
function toProportionalPosition($value, $min, $max) {
if($max - $min == 0) {
return 0;
}
return ($value - $min) / ($max - $min);
}
?>
/trunk/bibliotheque/artichow/inc/Font.class.php
New file
0,0 → 1,263
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
 
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Common font characteristics and methods.
* Declared abstract only so that it can't be instanciated.
* Users have to call 'new awPHPFont' or 'new awFileFont',
* or any of their inherited classes (awFont1, awTuffy, awTTFFont, etc.)
*
* @package Artichow
*/
abstract class awFont {
 
/**
* Build the font
*
*/
public function __construct() {
}
 
/**
* Draw a text
*
* @param awDriver $driver
* @param awPoint $p Draw text at this point
* @param awText $text The text
* @param int $width Text box width
*/
public function draw(awDriver $driver, awPoint $point, awText $text, $width = NULL) {
$driver->string($this, $text, $point, $width);
}
 
}
 
registerClass('Font', TRUE);
 
/**
* Class for fonts that cannot be transformed,
* like the built-in PHP fonts for example.
*
* @package Artichow
*/
class awPHPFont extends awFont {
/**
* The used font identifier
*
* @var int
*/
public $font;
public function __construct($font = NULL) {
parent::__construct();
if($font !== NULL) {
$this->font = (int)$font;
}
}
}
 
registerClass('PHPFont');
 
/**
* Class for fonts that can be transformed (rotated, skewed, etc.),
* like TTF or FDB fonts for example.
*
* @package Artichow
*/
class awFileFont extends awFont {
/**
* The name of the font, without the extension
*
* @var string
*/
protected $name;
/**
* The size of the font
*
* @var int
*/
protected $size;
/**
* The font filename extension
*
* @var string
*/
protected $extension;
public function __construct($name, $size) {
parent::__construct();
$this->setName($name);
$this->setSize($size);
}
/**
* Set the name of the font. The $name variable can contain the full path,
* or just the filename. Artichow will try to do The Right Thing,
* as well as set the extension property correctly if possible.
*
* @param string $name
*/
public function setName($name) {
$fontInfo = pathinfo((string)$name);
if(strpos($fontInfo['dirname'], '/') !== 0) {
// Path is not absolute, use ARTICHOW_FONT
$name = ARTICHOW_FONT.DIRECTORY_SEPARATOR.$fontInfo['basename'];
$fontInfo = pathinfo($name);
}
$this->name = $fontInfo['dirname'].DIRECTORY_SEPARATOR.$fontInfo['basename'];
if(array_key_exists('extension', $fontInfo) and $fontInfo['extension'] !== '') {
$this->setExtension($fontInfo['extension']);
}
}
/**
* Return the name of the font, i.e. the absolute path and the filename, without the extension.
*
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Set the size of the font, in pixels
*
* @param int $size
*/
public function setSize($size) {
$this->size = (int)$size;
}
/**
* Return the size of the font, in pixels
*
* @return int
*/
public function getSize() {
return $this->size;
}
/**
* Set the extension, without the dot
*
* @param string $extension
*/
public function setExtension($extension) {
$this->extension = (string)$extension;
}
/**
* Get the filename extension for that font
*
* @return string
*/
public function getExtension() {
return $this->extension;
}
 
}
 
registerClass('FileFont');
 
/**
* Class representing TTF fonts
*
* @package Artichow
*/
class awTTFFont extends awFileFont {
public function __construct($name, $size) {
parent::__construct($name, $size);
if($this->getExtension() === NULL) {
$this->setExtension('ttf');
}
}
 
}
 
registerClass('TTFFont');
 
 
 
$php = '';
 
for($i = 1; $i <= 5; $i++) {
 
$php .= '
class awFont'.$i.' extends awPHPFont {
 
public function __construct() {
parent::__construct('.$i.');
}
 
}
';
 
if(ARTICHOW_PREFIX !== 'aw') {
$php .= '
class '.ARTICHOW_PREFIX.'Font'.$i.' extends awFont'.$i.' {
}
';
}
 
}
 
eval($php);
 
$php = '';
 
foreach($fonts as $font) {
 
$php .= '
class aw'.$font.' extends awFileFont {
 
public function __construct($size) {
parent::__construct(\''.$font.'\', $size);
}
 
}
';
 
if(ARTICHOW_PREFIX !== 'aw') {
$php .= '
class '.ARTICHOW_PREFIX.$font.' extends aw'.$font.' {
}
';
}
 
}
 
eval($php);
 
 
 
/*
* Environment modification for GD2 and TTF fonts
*/
if(function_exists('putenv')) {
putenv('GDFONTPATH='.ARTICHOW_FONT);
}
 
?>
/trunk/bibliotheque/artichow/inc/Border.class.php
New file
0,0 → 1,198
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
/**
* Draw border
*
* @package Artichow
*/
class awBorder {
 
/**
* Border color
*
* @var Color
*/
protected $color;
 
/**
* Hide border ?
*
* @var bool
*/
protected $hide = FALSE;
 
/**
* Border line style
*
* @var int
*/
protected $style;
/**
* Build the border
*
* @param awColor $color Border color
* @param int $style Border style
*/
public function __construct($color = NULL, $style = awLine::SOLID) {
$this->setStyle($style);
if($color instanceof awColor) {
$this->setColor($color);
} else {
$this->setColor(new awBlack);
}
}
/**
* Change border color
* This method automatically shows the border if it is hidden
*
* @param awColor $color
*/
public function setColor(awColor $color) {
$this->color = $color;
$this->show();
}
/**
* Change border style
*
* @param int $style
*/
public function setStyle($style) {
$this->style = (int)$style;
}
/**
* Hide border ?
*
* @param bool $hide
*/
public function hide($hide = TRUE) {
$this->hide = (bool)$hide;
}
/**
* Show border ?
*
* @param bool $show
*/
public function show($show = TRUE) {
$this->hide = (bool)!$show;
}
/**
* Is the border visible ?
*
* @return bool
*/
public function visible() {
return !$this->hide;
}
/**
* Draw border as a rectangle
*
* @param awDriver $driver
* @param awPoint $p1 Top-left corner
* @param awPoint $p2 Bottom-right corner
*/
public function rectangle(awDriver $driver, awPoint $p1, awPoint $p2) {
// Border is hidden
if($this->hide) {
return;
}
$line = new awLine;
$line->setStyle($this->style);
$line->setLocation($p1, $p2);
$driver->rectangle($this->color, $line);
}
/**
* Draw border as an ellipse
*
* @param awDriver $driver
* @param awPoint $center Ellipse center
* @param int $width Ellipse width
* @param int $height Ellipse height
*/
public function ellipse(awDriver $driver, awPoint $center, $width, $height) {
// Border is hidden
if($this->hide) {
return;
}
switch($this->style) {
case awLine::SOLID :
$driver->ellipse($this->color, $center, $width, $height);
break;
default :
awImage::drawError("Class Border: Dashed and dotted borders and not yet implemented on ellipses.");
break;
}
}
/**
* Draw border as a polygon
*
* @param awDriver $driver A Driver object
* @param awPolygon $polygon A Polygon object
*/
public function polygon(awDriver $driver, awPolygon $polygon) {
// Border is hidden
if($this->hide) {
return;
}
$polygon->setStyle($this->style);
$driver->polygon($this->color, $polygon);
// In case of Line::SOLID, Driver::polygon() uses imagepolygon()
// which automatically closes the shape. In any other case,
// we have to do it manually here.
if($this->style !== Line::SOLID) {
$this->closePolygon($driver, $polygon);
}
}
/**
* Draws the last line of a Polygon, between the first and last point
*
* @param awDriver $driver A Driver object
* @param awPolygon $polygon The polygon object to close
*/
private function closePolygon(awDriver $driver, awPolygon $polygon) {
$first = $polygon->get(0);
$last = $polygon->get($polygon->count() - 1);
$line = new awLine($first, $last, $this->style, $polygon->getThickness());
$driver->line($this->color, $line);
}
}
 
registerClass('Border');
?>
/trunk/bibliotheque/artichow/inc/Color.class.php
New file
0,0 → 1,165
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Create your colors
*
* @package Artichow
*/
class awColor {
public $red;
public $green;
public $blue;
public $alpha;
 
/**
* Build your color
*
* @var int $red Red intensity (from 0 to 255)
* @var int $green Green intensity (from 0 to 255)
* @var int $blue Blue intensity (from 0 to 255)
* @var int $alpha Alpha channel (from 0 to 100)
*/
public function __construct($red, $green, $blue, $alpha = 0) {
$this->red = (int)$red;
$this->green = (int)$green;
$this->blue = (int)$blue;
$this->alpha = (int)round($alpha * 127 / 100);
}
/**
* Get RGB and alpha values of your color
*
* @return array
*/
public function getColor() {
return $this->rgba();
}
/**
* Change color brightness
*
* @param int $brightness Add this intensity to the color (betweeen -255 and +255)
*/
public function brightness($brightness) {
$brightness = (int)$brightness;
$this->red = min(255, max(0, $this->red + $brightness));
$this->green = min(255, max(0, $this->green + $brightness));
$this->blue = min(255, max(0, $this->blue + $brightness));
}
 
/**
* Get RGB and alpha values of your color
*
* @return array
*/
public function rgba() {
return array($this->red, $this->green, $this->blue, $this->alpha);
}
 
}
 
registerClass('Color');
 
$colors = array(
'Black' => array(0, 0, 0),
'AlmostBlack' => array(48, 48, 48),
'VeryDarkGray' => array(88, 88, 88),
'DarkGray' => array(128, 128, 128),
'MidGray' => array(160, 160, 160),
'LightGray' => array(195, 195, 195),
'VeryLightGray' => array(220, 220, 220),
'White' => array(255, 255, 255),
'VeryDarkRed' => array(64, 0, 0),
'DarkRed' => array(128, 0, 0),
'MidRed' => array(192, 0, 0),
'Red' => array(255, 0, 0),
'LightRed' => array(255, 192, 192),
'VeryDarkGreen' => array(0, 64, 0),
'DarkGreen' => array(0, 128, 0),
'MidGreen' => array(0, 192, 0),
'Green' => array(0, 255, 0),
'LightGreen' => array(192, 255, 192),
'VeryDarkBlue' => array(0, 0, 64),
'DarkBlue' => array(0, 0, 128),
'MidBlue' => array(0, 0, 192),
'Blue' => array(0, 0, 255),
'LightBlue' => array(192, 192, 255),
'VeryDarkYellow' => array(64, 64, 0),
'DarkYellow' => array(128, 128, 0),
'MidYellow' => array(192, 192, 0),
'Yellow' => array(255, 255, 2),
'LightYellow' => array(255, 255, 192),
'VeryDarkCyan' => array(0, 64, 64),
'DarkCyan' => array(0, 128, 128),
'MidCyan' => array(0, 192, 192),
'Cyan' => array(0, 255, 255),
'LightCyan' => array(192, 255, 255),
'VeryDarkMagenta' => array(64, 0, 64),
'DarkMagenta' => array(128, 0, 128),
'MidMagenta' => array(192, 0, 192),
'Magenta' => array(255, 0, 255),
'LightMagenta' => array(255, 192, 255),
'DarkOrange' => array(192, 88, 0),
'Orange' => array(255, 128, 0),
'LightOrange' => array(255, 168, 88),
'VeryLightOrange' => array(255, 220, 168),
'DarkPink' => array(192, 0, 88),
'Pink' => array(255, 0, 128),
'LightPink' => array(255, 88, 168),
'VeryLightPink' => array(255, 168, 220),
'DarkPurple' => array(88, 0, 192),
'Purple' => array(128, 0, 255),
'LightPurple' => array(168, 88, 255),
'VeryLightPurple' => array(220, 168, 255),
);
 
 
 
$php = '';
 
foreach($colors as $name => $color) {
 
list($red, $green, $blue) = $color;
 
$php .= '
class aw'.$name.' extends awColor {
public function __construct($alpha = 0) {
parent::__construct('.$red.', '.$green.', '.$blue.', $alpha);
}
}
';
if(ARTICHOW_PREFIX !== 'aw') {
$php .= '
class '.ARTICHOW_PREFIX.$name.' extends aw'.$name.' {
}
';
}
 
}
 
eval($php);
 
 
 
?>
/trunk/bibliotheque/artichow/inc/Label.class.php
New file
0,0 → 1,588
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
/**
* Draw labels
*
* @package Artichow
*/
class awLabel implements awPositionable {
 
/**
* Label border
*
* @var int
*/
public $border;
 
/**
* Label texts
*
* @var array
*/
protected $texts;
 
/**
* Text font
*
* @var int
*/
protected $font;
 
/**
* Text angle
*
* @var int
*/
protected $angle = 0;
 
/**
* Text color
*
* @var Color
*/
protected $color;
 
/**
* Text background
*
* @var Color, Gradient
*/
private $background;
 
/**
* Callback function
*
* @var string
*/
private $function;
 
/**
* Padding
*
* @var int
*/
private $padding;
 
/**
* Move position from this vector
*
* @var Point
*/
protected $move;
 
/**
* Label interval
*
* @var int
*/
protected $interval = 1;
 
/**
* Horizontal align
*
* @var int
*/
protected $hAlign = awLabel::CENTER;
 
/**
* Vertical align
*
* @var int
*/
protected $vAlign = awLabel::MIDDLE;
/**
* Hide all labels ?
*
* @var bool
*/
protected $hide = FALSE;
/**
* Keys to hide
*
* @var array
*/
protected $hideKey = array();
/**
* Values to hide
*
* @var array
*/
protected $hideValue = array();
/**
* Hide first label
*
* @var bool
*/
protected $hideFirst = FALSE;
/**
* Hide last label
*
* @var bool
*/
protected $hideLast = FALSE;
/**
* Build the label
*
* @param string $label First label
*/
public function __construct($label = NULL, $font = NULL, $color = NULL, $angle = 0) {
if(is_array($label)) {
$this->set($label);
} else if(is_string($label)) {
$this->set(array($label));
}
if($font === NULL) {
$font = new awFont2;
}
$this->setFont($font);
$this->setAngle($angle);
if($color instanceof awColor) {
$this->setColor($color);
} else {
$this->setColor(new awColor(0, 0, 0));
}
$this->move = new awPoint(0, 0);
$this->border = new awBorder;
$this->border->hide();
}
/**
* Get an element of the label from its key
*
* @param int $key Element key
* @return string A value
*/
public function get($key) {
return array_key_exists($key, $this->texts) ? $this->texts[$key] : NULL;
}
/**
* Get all labels
*
* @return array
*/
public function all() {
return $this->texts;
}
/**
* Set one or several labels
*
* @param array $labels Array of string or a string
*/
public function set($labels) {
if(is_array($labels)) {
$this->texts = $labels;
} else {
$this->texts = array((string)$labels);
}
}
/**
* Count number of texts in the label
*
* @return int
*/
public function count() {
return is_array($this->texts) ? count($this->texts) : 0;
}
/**
* Set a callback function for labels
*
* @param string $function
*/
public function setCallbackFunction($function) {
$this->function = is_null($function) ? $function : (string)$function;
}
/**
* Return the callback function for labels
*
* @return string
*/
public function getCallbackFunction() {
return $this->function;
}
/**
* Change labels format
*
* @param string $format New format (printf style: %.2f for example)
*/
public function setFormat($format) {
$function = 'label'.time().'_'.(microtime() * 1000000);
eval('function '.$function.'($value) {
return sprintf("'.addcslashes($format, '"').'", $value);
}');
$this->setCallbackFunction($function);
}
/**
* Change font for label
*
* @param awFont $font New font
* @param awColor $color Font color (can be NULL)
*/
public function setFont(awFont $font, $color = NULL) {
$this->font = $font;
if($color instanceof awColor) {
$this->setColor($color);
}
}
/**
* Change font angle
*
* @param int $angle New angle
*/
public function setAngle($angle) {
$this->angle = (int)$angle;
}
/**
* Change font color
*
* @param awColor $color
*/
public function setColor(awColor $color) {
$this->color = $color;
}
/**
* Change text background
*
* @param mixed $background
*/
public function setBackground($background) {
$this->background = $background;
}
/**
* Change text background color
*
* @param Color
*/
public function setBackgroundColor(awColor $color) {
$this->background = $color;
}
/**
* Change text background gradient
*
* @param Gradient
*/
public function setBackgroundGradient(awGradient $gradient) {
$this->background = $gradient;
}
 
/**
* Change padding
*
* @param int $left Left padding
* @param int $right Right padding
* @param int $top Top padding
* @param int $bottom Bottom padding
*/
public function setPadding($left, $right, $top, $bottom) {
$this->padding = array((int)$left, (int)$right, (int)$top, (int)$bottom);
}
/**
* Hide all labels ?
*
* @param bool $hide
*/
public function hide($hide = TRUE) {
$this->hide = (bool)$hide;
}
/**
* Show all labels ?
*
* @param bool $show
*/
public function show($show = TRUE) {
$this->hide = (bool)!$show;
}
/**
* Hide a key
*
* @param int $key The key to hide
*/
public function hideKey($key) {
$this->hideKey[$key] = TRUE;
}
/**
* Hide a value
*
* @param int $value The value to hide
*/
public function hideValue($value) {
$this->hideValue[] = $value;
}
/**
* Hide first label
*
* @param bool $hide
*/
public function hideFirst($hide) {
$this->hideFirst = (bool)$hide;
}
/**
* Hide last label
*
* @param bool $hide
*/
public function hideLast($hide) {
$this->hideLast = (bool)$hide;
}
/**
* Set label interval
*
* @param int
*/
public function setInterval($interval) {
$this->interval = (int)$interval;
}
/**
* Change label position
*
* @param int $x Add this interval to X coord
* @param int $y Add this interval to Y coord
*/
public function move($x, $y) {
$this->move = $this->move->move($x, $y);
}
/**
* Change alignment
*
* @param int $h Horizontal alignment
* @param int $v Vertical alignment
*/
public function setAlign($h = NULL, $v = NULL) {
if($h !== NULL) {
$this->hAlign = (int)$h;
}
if($v !== NULL) {
$this->vAlign = (int)$v;
}
}
/**
* Get a text from the labele
*
* @param mixed $key Key in the array text
* @return Text
*/
public function getText($key) {
if(is_array($this->texts) and array_key_exists($key, $this->texts)) {
$value = $this->texts[$key];
if(is_string($this->function)) {
$value = call_user_func($this->function, $value);
}
$text = new awText($value);
$text->setFont($this->font);
$text->setAngle($this->angle);
$text->setColor($this->color);
if($this->background instanceof awColor) {
$text->setBackgroundColor($this->background);
} else if($this->background instanceof awGradient) {
$text->setBackgroundGradient($this->background);
}
$text->border = $this->border;
if($this->padding !== NULL) {
call_user_func_array(array($text, 'setPadding'), $this->padding);
}
return $text;
} else {
return NULL;
}
}
/**
* Get max width of all texts
*
* @param awDriver $driver A driver
* @return int
*/
public function getMaxWidth(awDriver $driver) {
return $this->getMax($driver, 'getTextWidth');
}
/**
* Get max height of all texts
*
* @param awDriver $driver A driver
* @return int
*/
public function getMaxHeight(awDriver $driver) {
return $this->getMax($driver, 'getTextHeight');
}
/**
* Draw the label
*
* @param awDriver $driver
* @param awPoint $p Label center
* @param int $key Text position in the array of texts (default to zero)
*/
public function draw(awDriver $driver, awPoint $p, $key = 0) {
if(($key % $this->interval) !== 0) {
return;
}
// Hide all labels
if($this->hide) {
return;
}
// Key is hidden
if(array_key_exists($key, $this->hideKey)) {
return;
}
// Hide first label
if($key === 0 and $this->hideFirst) {
return;
}
// Hide last label
if($key === count($this->texts) - 1 and $this->hideLast) {
return;
}
$text = $this->getText($key);
if($text !== NULL) {
// Value must be hidden
if(in_array($text->getText(), $this->hideValue)) {
return;
}
$x = $p->x;
$y = $p->y;
// Get padding
list($left, $right, $top, $bottom) = $text->getPadding();
// $font = $text->getFont();
$width = $driver->getTextWidth($text);
$height = $driver->getTextHeight($text);
switch($this->hAlign) {
case awLabel::RIGHT :
$x -= ($width + $right);
break;
case awLabel::CENTER :
$x -= ($width - $left + $right) / 2;
break;
case awLabel::LEFT :
$x += $left;
break;
}
switch($this->vAlign) {
case awLabel::TOP :
$y -= ($height + $bottom);
break;
case awLabel::MIDDLE :
$y -= ($height - $top + $bottom) / 2;
break;
case awLabel::BOTTOM :
$y += $top;
break;
}
$driver->string($text, $this->move->move($x, $y));
}
}
protected function getMax(awDriver $driver, $function) {
$max = NULL;
foreach($this->texts as $key => $text) {
$text = $this->getText($key);
$font = $text->getFont();
if(is_null($max)) {
$max = $font->{$function}($text);
} else {
$max = max($max, $font->{$function}($text));
}
}
return $max;
}
 
}
 
registerClass('Label');
?>
/trunk/bibliotheque/artichow/inc/Text.class.php
New file
0,0 → 1,233
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* To handle text
*
* @package Artichow
*/
class awText {
 
/**
* Your text
*
* @var string
*/
private $text;
 
/**
* Text font
*
* @var Font
*/
private $font;
 
/**
* Text angle
* Can be 0 or 90
*
* @var int
*/
private $angle;
 
/**
* Text color
*
* @var Color
*/
private $color;
 
/**
* Text background
*
* @var Color, Gradient
*/
private $background;
 
/**
* Padding
*
* @var array Array for left, right, top and bottom paddings
*/
private $padding;
 
/**
* Text border
*
* @var Border
*/
public $border;
/**
* Build a new awtext
*
* @param string $text Your text
*/
public function __construct($text, $font = NULL, $color = NULL, $angle = 0) {
if(is_null($font)) {
$font = new awFont2;
}
$this->setText($text);
$this->setFont($font);
// Set default color to black
if($color === NULL) {
$color = new awColor(0, 0, 0);
}
$this->setColor($color);
$this->setAngle($angle);
$this->border = new awBorder;
$this->border->hide();
}
/**
* Get text
*
* @return string
*/
public function getText() {
return $this->text;
}
/**
* Change text
*
* @param string $text New text
*/
public function setText($text) {
$this->text = (string)$text;
$this->text = str_replace("\r", "", $text);
}
 
/**
* Change text font
*
* @param Font
*/
public function setFont(awFont $font) {
$this->font = $font;
}
/**
* Get text font
*
* @return int
*/
public function getFont() {
return $this->font;
}
 
/**
* Change text angle
*
* @param int
*/
public function setAngle($angle) {
$this->angle = (int)$angle;
}
/**
* Get text angle
*
* @return int
*/
public function getAngle() {
return $this->angle;
}
 
/**
* Change text color
*
* @param Color
*/
public function setColor(awColor $color) {
$this->color = $color;
}
/**
* Get text color
*
* @return Color
*/
public function getColor() {
return $this->color;
}
/**
* Change text background
*
* @param mixed $background
*/
public function setBackground($background) {
if($background instanceof awColor) {
$this->setBackgroundColor($background);
} elseif($background instanceof awGradient) {
$this->setBackgroundGradient($background);
}
}
/**
* Change text background color
*
* @param awColor $color
*/
public function setBackgroundColor(awColor $color) {
$this->background = $color;
}
/**
* Change text background gradient
*
* @param awGradient $gradient
*/
public function setBackgroundGradient(awGradient $gradient) {
$this->background = $gradient;
}
/**
* Get text background
*
* @return Color, Gradient
*/
public function getBackground() {
return $this->background;
}
 
/**
* Change padding
*
* @param int $left Left padding
* @param int $right Right padding
* @param int $top Top padding
* @param int $bottom Bottom padding
*/
public function setPadding($left, $right, $top, $bottom) {
$this->padding = array((int)$left, (int)$right, (int)$top, (int)$bottom);
}
/**
* Get current padding
*
* @return array
*/
public function getPadding() {
return $this->padding;
}
 
}
 
registerClass('Text');
?>
/trunk/bibliotheque/artichow/inc/drivers/gd.class.php
New file
0,0 → 1,1336
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Driver.class.php";
 
/**
* Draw your objects
*
* @package Artichow
*/
 
class awGDDriver extends Driver {
/**
* A GD resource
*
* @var $resource
*/
public $resource;
public function __construct() {
parent::__construct();
$this->driverString = 'gd';
}
 
public function init(awImage $image) {
if($this->resource === NULL) {
$this->setImageSize($image->width, $image->height);
// Create image
$this->resource = imagecreatetruecolor($this->imageWidth, $this->imageHeight);
if(!$this->resource) {
awImage::drawError("Class Image: Unable to create a graph.");
}
imagealphablending($this->resource, TRUE);
// Antialiasing is now handled by the Driver object
$this->setAntiAliasing($image->getAntiAliasing());
// Original color
$this->filledRectangle(
new awWhite,
new awLine(
new awPoint(0, 0),
new awPoint($this->imageWidth, $this->imageHeight)
)
);
$shadow = $image->shadow;
if($shadow !== NULL) {
$shadow = $shadow->getSpace();
$p1 = new awPoint($shadow->left, $shadow->top);
$p2 = new awPoint($this->imageWidth - $shadow->right - 1, $this->imageHeight - $shadow->bottom - 1);
// Draw image background
$this->filledRectangle($image->getBackground(), new awLine($p1, $p2));
// Draw image border
$image->border->rectangle($this, $p1, $p2);
}
}
}
public function initFromFile(awFileImage $fileImage, $file) {
$image = @getimagesize((string)$file);
if($image and in_array($image[2], array(2, 3))) {
$fileImage->setSize($image[0], $image[1]);
switch($image[2]) {
case 2 :
$this->resource = imagecreatefromjpeg($file);
break;
case 3 :
$this->resource = imagecreatefrompng($file);
break;
}
 
$this->setImageSize($fileImage->width, $fileImage->height);
} else {
awImage::drawError("Class FileImage: Artichow does not support the format of this image (must be in PNG or JPEG)");
}
}
public function setImageSize($width, $height) {
$this->imageWidth = $width;
$this->imageHeight = $height;
}
public function setPosition($x, $y) {
// Calculate absolute position
$this->x = round($x * $this->imageWidth - $this->w / 2);
$this->y = round($y * $this->imageHeight - $this->h / 2);
}
public function setAbsPosition($x, $y) {
$this->x = $x;
$this->y = $y;
}
public function movePosition($x, $y) {
 
$this->x += (int)$x;
$this->y += (int)$y;
}
public function setSize($w, $h) {
// Calcul absolute size
$this->w = round($w * $this->imageWidth);
$this->h = round($h * $this->imageHeight);
return $this->getSize();
}
public function setAbsSize($w, $h) {
$this->w = $w;
$this->h = $h;
return $this->getSize();
}
public function getSize() {
return array($this->w, $this->h);
}
public function setAntiAliasing($bool) {
if(function_exists('imageantialias')) {
imageantialias($this->resource, (bool)$bool);
 
$this->antiAliasing = (bool)$bool;
} else {
awImage::drawErrorFile('missing-anti-aliasing');
}
}
public function getColor(awColor $color) {
 
if($color->alpha === 0 or function_exists('imagecolorallocatealpha') === FALSE) {
$gdColor = imagecolorallocate($this->resource, $color->red, $color->green, $color->blue);
} else {
$gdColor = imagecolorallocatealpha($this->resource, $color->red, $color->green, $color->blue, $color->alpha);
}
 
return $gdColor;
}
public function copyImage(awImage $image, awPoint $p1, awPoint $p2) {
list($x1, $y1) = $p1->getLocation();
list($x2, $y2) = $p2->getLocation();
$driver = $image->getDriver();
imagecopy($this->resource, $driver->resource, $this->x + $x1, $this->y + $y1, 0, 0, $x2 - $x1, $y2 - $y1);
}
public function copyResizeImage(awImage $image, awPoint $d1, awPoint $d2, awPoint $s1, awPoint $s2, $resample = TRUE) {
if($resample) {
$function = 'imagecopyresampled';
} else {
$function = 'imagecopyresized';
}
$driver = $image->getDriver();
$function(
$this->resource,
$driver->resource,
$this->x + $d1->x, $this->y + $d1->y,
$s1->x, $s1->y,
$d2->x - $d1->x, $d2->y - $d1->y,
$s2->x - $s1->x, $s2->y - $s1->y
);
}
public function string(awText $text, awPoint $point, $width = NULL) {
$font = $text->getFont();
// Can we deal with that font?
if($this->isCompatibleWithFont($font) === FALSE) {
awImage::drawError('Class GDDriver: Incompatible font type (\''.get_class($font).'\')');
}
// Check which FontDriver to use
if($font instanceof awPHPFont) {
$fontDriver = $this->phpFontDriver;
} else {
$fontDriver = $this->fileFontDriver;
}
if($text->getBackground() !== NULL or $text->border->visible()) {
list($left, $right, $top, $bottom) = $text->getPadding();
 
$textWidth = $fontDriver->getTextWidth($text, $this);
$textHeight = $fontDriver->getTextHeight($text, $this);
$x1 = floor($point->x - $left);
$y1 = floor($point->y - $top);
$x2 = $x1 + $textWidth + $left + $right;
$y2 = $y1 + $textHeight + $top + $bottom;
$this->filledRectangle(
$text->getBackground(),
awLine::build($x1, $y1, $x2, $y2)
);
$text->border->rectangle(
$this,
new awPoint($x1 - 1, $y1 - 1),
new awPoint($x2 + 1, $y2 + 1)
);
}
$fontDriver->string($this, $text, $point, $width);
}
public function point(awColor $color, awPoint $p) {
if($p->isHidden() === FALSE) {
$rgb = $this->getColor($color);
imagesetpixel($this->resource, $this->x + round($p->x), $this->y + round($p->y), $rgb);
}
}
public function line(awColor $color, awLine $line) {
if($line->thickness > 0 and $line->isHidden() === FALSE) {
$rgb = $this->getColor($color);
$thickness = $line->thickness;
list($p1, $p2) = $line->getLocation();
$this->startThickness($thickness);
switch($line->getStyle()) {
case awLine::SOLID :
imageline($this->resource, $this->x + round($p1->x), $this->y + round($p1->y), $this->x + round($p2->x), $this->y + round($p2->y), $rgb);
break;
case awLine::DOTTED :
$size = sqrt(pow($p2->y - $p1->y, 2) + pow($p2->x - $p1->x, 2));
$cos = ($p2->x - $p1->x) / $size;
$sin = ($p2->y - $p1->y) / $size;
for($i = 0; $i <= $size; $i += 2) {
$p = new awPoint(
round($i * $cos + $p1->x),
round($i * $sin + $p1->y)
);
$this->point($color, $p);
}
break;
case awLine::DASHED :
$width = $p2->x - $p1->x;
$height = $p2->y - $p1->y;
$size = sqrt(pow($height, 2) + pow($width, 2));
if($size == 0) {
return;
}
$cos = $width / $size;
$sin = $height / $size;
$functionX = ($width > 0) ? 'min' : 'max';
$functionY = ($height > 0) ? 'min' : 'max';
for($i = 0; $i <= $size; $i += 6) {
$t1 = new awPoint(
round($i * $cos + $p1->x),
round($i * $sin + $p1->y)
);
$t2 = new awPoint(
round($functionX(($i + 3) * $cos, $width) + $p1->x),
round($functionY(($i + 3) * $sin, $height) + $p1->y)
);
$this->line($color, new awLine($t1, $t2));
}
break;
}
$this->stopThickness($thickness);
}
}
public function arc(awColor $color, awPoint $center, $width, $height, $from, $to) {
imagefilledarc(
$this->resource,
$this->x + $center->x, $this->y + $center->y,
$width, $height,
$from, $to,
$this->getColor($color),
IMG_ARC_EDGED | IMG_ARC_NOFILL
);
}
public function filledArc(awColor $color, awPoint $center, $width, $height, $from, $to) {
imagefilledarc(
$this->resource,
$this->x + $center->x, $this->y + $center->y,
$width, $height,
$from, $to,
$this->getColor($color),
IMG_ARC_PIE
);
}
public function ellipse(awColor $color, awPoint $center, $width, $height) {
list($x, $y) = $center->getLocation();
$rgb = $this->getColor($color);
imageellipse(
$this->resource,
$this->x + $x,
$this->y + $y,
$width,
$height,
$rgb
);
}
public function filledEllipse($background, awPoint $center, $width, $height) {
if($background instanceof awColor) {
list($x, $y) = $center->getLocation();
$rgb = $this->getColor($background);
imagefilledellipse(
$this->resource,
$this->x + $x,
$this->y + $y,
$width,
$height,
$rgb
);
} else if($background instanceof awGradient) {
list($x, $y) = $center->getLocation();
$x1 = $x - round($width / 2);
$y1 = $y - round($height / 2);
$x2 = $x1 + $width;
$y2 = $y1 + $height;
$gradientDriver = new awGDGradientDriver($this);
$gradientDriver->filledEllipse(
$background,
$x1, $y1,
$x2, $y2
);
}
}
public function rectangle(awColor $color, awLine $line) {
list($p1, $p2) = $line->getLocation();
switch($line->getStyle()) {
case awLine::SOLID :
$thickness = $line->getThickness();
$this->startThickness($thickness);
$rgb = $this->getColor($color);
imagerectangle($this->resource, $this->x + $p1->x, $this->y + $p1->y, $this->x + $p2->x, $this->y + $p2->y, $rgb);
$this->stopThickness($thickness);
break;
default :
$side = clone $line;
// Top side
$side->setLocation(
new awPoint($p1->x, $p1->y),
new awPoint($p2->x, $p1->y)
);
$this->line($color, $side);
// Right side
$side->setLocation(
new awPoint($p2->x, $p1->y),
new awPoint($p2->x, $p2->y)
);
$this->line($color, $side);
// Bottom side
$side->setLocation(
new awPoint($p1->x, $p2->y),
new awPoint($p2->x, $p2->y)
);
$this->line($color, $side);
// Left side
$side->setLocation(
new awPoint($p1->x, $p1->y),
new awPoint($p1->x, $p2->y)
);
$this->line($color, $side);
break;
}
}
public function filledRectangle($background, awLine $line) {
$p1 = $line->p1;
$p2 = $line->p2;
if($background instanceof awColor) {
$rgb = $this->getColor($background);
imagefilledrectangle($this->resource, $this->x + $p1->x, $this->y + $p1->y, $this->x + $p2->x, $this->y + $p2->y, $rgb);
} else if($background instanceof awGradient) {
$gradientDriver = new awGDGradientDriver($this);
$gradientDriver->filledRectangle($background, $p1, $p2);
}
}
public function polygon(awColor $color, awPolygon $polygon) {
switch($polygon->getStyle()) {
case awPolygon::SOLID :
$thickness = $polygon->getThickness();
$this->startThickness($thickness);
$points = $this->getPolygonPoints($polygon);
$rgb = $this->getColor($color);
imagepolygon($this->resource, $points, $polygon->count(), $rgb);
$this->stopThickness($thickness);
break;
default :
if($polygon->count() > 1) {
$prev = $polygon->get(0);
$line = new awLine;
$line->setStyle($polygon->getStyle());
$line->setThickness($polygon->getThickness());
for($i = 1; $i < $polygon->count(); $i++) {
$current = $polygon->get($i);
$line->setLocation($prev, $current);
$this->line($color, $line);
$prev = $current;
}
// Close the polygon
$line->setLocation($prev, $polygon->get(0));
$this->line($color, $line);
}
}
}
public function filledPolygon($background, awPolygon $polygon) {
if($background instanceof awColor) {
$points = $this->getPolygonPoints($polygon);
$rgb = $this->getColor($background);
imagefilledpolygon($this->resource, $points, $polygon->count(), $rgb);
} else if($background instanceof awGradient) {
$gradientDriver = new awGDGradientDriver($this);
$gradientDriver->filledPolygon($background, $polygon);
}
 
}
 
public function send(awImage $image) {
 
$this->drawImage($image);
 
}
public function get(awImage $image) {
return $this->drawImage($image, TRUE, FALSE);
}
public function getTextWidth(awText $text) {
$font = $text->getFont();
if($font instanceof awPHPFont) {
$fontDriver = $this->phpFontDriver;
} else {
$fontDriver = $this->fileFontDriver;
}
return $fontDriver->getTextWidth($text, $this);
}
public function getTextHeight(awText $text) {
$font = $text->getFont();
if($font instanceof awPHPFont) {
$fontDriver = $this->phpFontDriver;
} else {
$fontDriver = $this->fileFontDriver;
}
return $fontDriver->getTextHeight($text, $this);
}
protected function isCompatibleWithFont(awFont $font) {
if($font instanceof awFDBFont) {
return FALSE;
} else {
return TRUE;
}
}
private function drawImage(awImage $image, $return = FALSE, $header = TRUE) {
$format = $image->getFormatString();
// Test if format is available
if((imagetypes() & $image->getFormat()) === FALSE) {
awImage::drawError("Class Image: Format '".$format."' is not available on your system. Check that your PHP has been compiled with the good libraries.");
}
// Get some infos about this image
switch($format) {
case 'jpeg' :
$function = 'imagejpeg';
break;
case 'png' :
$function = 'imagepng';
break;
case 'gif' :
$function = 'imagegif';
break;
}
// Send headers to the browser
if($header === TRUE) {
$image->sendHeaders();
}
if($return) {
ob_start();
}
$function($this->resource);
if($return) {
return ob_get_clean();
}
}
private function getPolygonPoints(awPolygon $polygon) {
$points = array();
foreach($polygon->all() as $point) {
$points[] = $point->x + $this->x;
$points[] = $point->y + $this->y;
}
return $points;
}
private function startThickness($thickness) {
if($thickness > 1) {
// Beurk :'(
if($this->antiAliasing and function_exists('imageantialias')) {
imageantialias($this->resource, FALSE);
}
imagesetthickness($this->resource, $thickness);
}
}
private function stopThickness($thickness) {
if($thickness > 1) {
if($this->antiAliasing and function_exists('imageantialias')) {
imageantialias($this->resource, TRUE);
}
imagesetthickness($this->resource, 1);
}
}
 
}
 
registerClass('GDDriver');
 
/**
* To your gradients
*
* @package Artichow
*/
 
class awGDGradientDriver {
 
/**
* A driver
*
* @var awGDDriver
*/
protected $driver;
 
/**
* Build your GDGradientDriver
*
* @var awGDDriver $driver
*/
public function __construct(awGDDriver $driver) {
$this->driver = $driver;
}
public function drawFilledFlatTriangle(awGradient $gradient, awPoint $a, awPoint $b, awPoint $c) {
if($gradient->angle !== 0) {
awImage::drawError("Class GDGradientDriver: Flat triangles can only be used with 0 degree gradients.");
}
// Look for right-angled triangle
if($a->x !== $b->x and $b->x !== $c->x) {
awImage::drawError("Class GDGradientDriver: Not right-angled flat triangles are not supported yet.");
}
if($a->x === $b->x) {
$d = $a;
$e = $c;
} else {
$d = $c;
$e = $a;
}
$this->init($gradient, $b->y - $d->y);
for($i = $c->y + 1; $i < $b->y; $i++) {
$color = $this->color($i - $d->y);
$pos = ($i - $d->y) / ($b->y - $d->y);
$p1 = new awPoint($e->x, $i);
$p2 = new awPoint(1 + floor($e->x - $pos * ($e->x - $d->x)), $i);
$this->driver->filledRectangle($color, new awLine($p1, $p2));
unset($color);
}
}
protected function drawFilledTriangle(awGradient $gradient, awPolygon $polygon) {
if($gradient->angle === 0) {
$this->drawFilledTriangleVertically($gradient, $polygon);
} elseif($gradient->angle === 90) {
$this->drawFilledTriangleHorizontally($gradient, $polygon);
}
}
private function drawFilledTriangleVertically(awGradient $gradient, awPolygon $polygon) {
list($yMin, $yMax) = $polygon->getBoxYRange();
$this->init($gradient, $yMax - $yMin);
// Get the triangle line we will draw our lines from
$fromLine = NULL;
$lines = $polygon->getLines();
$count = count($lines);
// Pick the side of the triangle going from the top
// to the bottom of the surrounding box
for($i = 0; $i < $count; $i++) {
if($lines[$i]->isTopToBottom($polygon)) {
list($fromLine) = array_splice($lines, $i, 1);
break;
}
}
// If for some reason the three points are aligned,
// $fromLine will still be NULL
if($fromLine === NULL) {
return;
}
$fillLine = NULL;
for($y = round($yMin); $y < round($yMax); $y++) {
$fromX = $fromLine->getXFrom($y);
$toX = array();
foreach($lines as $line) {
$xValue = $line->getXFrom($y);
if(!is_null($xValue)) {
$toX[] = $xValue;
}
}
if(count($toX) === 1) {
$fillLine = new Line(
new Point($fromX, $y),
new Point($toX[0], $y)
);
} else {
$line1 = new Line(
new Point($fromX, $y),
new Point($toX[0], $y)
);
$line2 = new Line(
new Point($fromX, $y),
new Point($toX[1], $y)
);
if($line1->getSize() < $line2->getSize()) {
$fillLine = $line1;
} else {
$fillLine = $line2;
}
}
if(!$fillLine->isPoint()) {
$color = $this->color($y - $yMin);
$this->driver->line($color, $fillLine);
unset($color);
}
}
}
private function drawFilledTriangleHorizontally(awGradient $gradient, awPolygon $polygon) {
list($xMin, $xMax) = $polygon->getBoxXRange();
$this->init($gradient, $xMax - $xMin);
// Get the triangle line we will draw our lines from
$fromLine = NULL;
$lines = $polygon->getLines();
$count = count($lines);
// Pick the side of the triangle going all the way
// from the left side to the right side of the surrounding box
for($i = 0; $i < $count; $i++) {
if($lines[$i]->isLeftToRight($polygon)) {
list($fromLine) = array_splice($lines, $i, 1);
break;
}
}
// If for some reason the three points are aligned,
// $fromLine will still be NULL
if($fromLine === NULL) {
return;
}
 
$fillLine = NULL;
for($x = round($xMin); $x < round($xMax); $x++) {
$fromY = floor($fromLine->getYFrom($x));
$toY = array();
foreach($lines as $line) {
$yValue = $line->getYFrom($x);
if(!is_null($yValue)) {
$toY[] = floor($yValue);
}
}
if(count($toY) === 1) {
$fillLine = new Line(
new Point($x, $fromY),
new Point($x, $toY[0])
);
} else {
$line1 = new Line(
new Point($x, $fromY),
new Point($x, $toY[0])
);
$line2 = new Line(
new Point($x, $fromY),
new Point($x, $toY[1])
);
if($line1->getSize() < $line2->getSize()) {
$fillLine = $line1;
} else {
$fillLine = $line2;
}
}
$color = $this->color($x - $xMin);
if($fillLine->isPoint()) {
$this->driver->point($color, $fillLine->p1);
} elseif($fillLine->getSize() >= 1) {
$this->driver->line($color, $fillLine);
}
unset($color);
}
}
public function filledRectangle(awGradient $gradient, awPoint $p1, awPoint $p2) {
list($x1, $y1) = $p1->getLocation();
list($x2, $y2) = $p2->getLocation();
if($y1 < $y2) {
$y1 ^= $y2 ^= $y1 ^= $y2;
}
if($x2 < $x1) {
$x1 ^= $x2 ^= $x1 ^= $x2;
}
if($gradient instanceof awLinearGradient) {
$this->rectangleLinearGradient($gradient, new awPoint($x1, $y1), new awPoint($x2, $y2));
} else {
awImage::drawError("Class GDGradientDriver: This gradient is not supported by rectangles.");
}
}
public function filledPolygon(awGradient $gradient, awPolygon $polygon) {
if($gradient instanceof awLinearGradient) {
$this->polygonLinearGradient($gradient, $polygon);
} else {
awImage::drawError("Class GDGradientDriver: This gradient is not supported by polygons.");
}
}
protected function rectangleLinearGradient(awLinearGradient $gradient, awPoint $p1, awPoint $p2) {
list($x1, $y1) = $p1->getLocation();
list($x2, $y2) = $p2->getLocation();
if($y1 - $y2 > 0) {
if($gradient->angle === 0) {
$this->init($gradient, $y1 - $y2);
for($i = $y2; $i <= $y1; $i++) {
$color = $this->color($i - $y2);
$p1 = new awPoint($x1, $i);
$p2 = new awPoint($x2, $i);
$this->driver->filledRectangle($color, new awLine($p1, $p2));
unset($color);
}
} else if($gradient->angle === 90) {
$this->init($gradient, $x2 - $x1);
for($i = $x1; $i <= $x2; $i++) {
$color = $this->color($i - $x1);
$p1 = new awPoint($i, $y2);
$p2 = new awPoint($i, $y1);
$this->driver->filledRectangle($color, new awLine($p1, $p2));
unset($color);
}
}
}
}
public function filledEllipse(awGradient $gradient, $x1, $y1, $x2, $y2) {
if($y1 < $y2) {
$y1 ^= $y2 ^= $y1 ^= $y2;
}
if($x2 < $x1) {
$x1 ^= $x2 ^= $x1 ^= $x2;
}
if($gradient instanceof awRadialGradient) {
$this->ellipseRadialGradient($gradient, $x1, $y1, $x2, $y2);
} else if($gradient instanceof awLinearGradient) {
$this->ellipseLinearGradient($gradient, $x1, $y1, $x2, $y2);
} else {
awImage::drawError("Class GDGradientDriver: This gradient is not supported by ellipses.");
}
}
protected function ellipseRadialGradient(awGradient $gradient, $x1, $y1, $x2, $y2) {
if($y1 - $y2 > 0) {
if($y1 - $y2 != $x2 - $x1) {
awImage::drawError("Class GDGradientDriver: Radial gradients are only implemented on circle, not ellipses.");
}
$c = new awPoint($x1 + ($x2 - $x1) / 2, $y1 + ($y2 - $y1) / 2);
$r = ($x2 - $x1) / 2;
$ok = array();
// Init gradient
$this->init($gradient, $r);
for($i = 0; $i <= $r; $i += 0.45) {
$p = ceil((2 * M_PI * $i));
if($p > 0) {
$interval = 360 / $p;
} else {
$interval = 360;
}
$color = $this->color($i);
for($j = 0; $j < 360; $j += $interval) {
$rad = ($j / 360) * (2 * M_PI);
$x = round($i * cos($rad));
$y = round($i * sin($rad));
$l = sqrt($x * $x + $y * $y);
if($l <= $r) {
if(
array_key_exists((int)$x, $ok) === FALSE or
array_key_exists((int)$y, $ok[$x]) === FALSE
) {
// Print the point
$this->driver->point($color, new awPoint($c->x + $x, $c->y + $y));
$ok[(int)$x][(int)$y] = TRUE;
}
}
}
unset($color);
}
}
}
protected function ellipseLinearGradient(awGradient $gradient, $x1, $y1, $x2, $y2) {
// Gauche->droite : 90°
if($y1 - $y2 > 0) {
if($y1 - $y2 != $x2 - $x1) {
awImage::drawError("Class GDGradientDriver: Linear gradients are only implemented on circle, not ellipses.");
}
$r = ($x2 - $x1) / 2;
// Init gradient
$this->init($gradient, $x2 - $x1);
for($i = -$r; $i <= $r; $i++) {
$h = sin(acos($i / $r)) * $r;
$color = $this->color($i + $r);
if($gradient->angle === 90) {
// Print the line
$p1 = new awPoint(
$x1 + $i + $r,
round(max($y2 + $r - $h + 1, $y2))
);
$p2 = new awPoint(
$x1 + $i + $r,
round(min($y1 - $r + $h - 1, $y1))
);
} else {
// Print the line
$p1 = new awPoint(
round(max($x1 + $r - $h + 1, $x1)),
$y2 + $i + $r
);
$p2 = new awPoint(
round(min($x2 - $r + $h - 1, $x2)),
$y2 + $i + $r
);
}
$this->driver->filledRectangle($color, new awLine($p1, $p2));
unset($color);
}
}
}
protected function polygonLinearGradient(awLinearGradient $gradient, awPolygon $polygon) {
$count = $polygon->count();
if($count >= 4) {
$left = $polygon->get(0);
$right = $polygon->get($count - 1);
if($gradient->angle === 0) {
// Get polygon maximum and minimum
$offset = $polygon->get(0);
$max = $min = $offset->y;
for($i = 1; $i < $count - 1; $i++) {
$offset = $polygon->get($i);
$max = max($max, $offset->y);
$min = min($min, $offset->y);
}
$this->init($gradient, $max - $min);
$prev = $polygon->get(1);
$sum = 0;
for($i = 2; $i < $count - 1; $i++) {
$current = $polygon->get($i);
$interval = 1;
if($i !== $count - 2) {
$current->x -= $interval;
}
if($current->x - $prev->x > 0) {
// Draw rectangle
$x1 = $prev->x;
$x2 = $current->x;
$y1 = max($prev->y, $current->y);
$y2 = $left->y;
$gradient = new awLinearGradient(
$this->color($max - $min - ($y2 - $y1)),
$this->color($max - $min),
0
);
if($y1 > $y2) {
$y2 = $y1;
}
$this->driver->filledRectangle(
$gradient,
awLine::build($x1, $y1, $x2, $y2)
);
$top = ($prev->y < $current->y) ? $current : $prev;
$bottom = ($prev->y >= $current->y) ? $current : $prev;
$gradient = new awLinearGradient(
$this->color($bottom->y - $min),
$this->color($max - $min - ($y2 - $y1)),
0
);
$gradientDriver = new awGDGradientDriver($this->driver);
$gradientDriver->drawFilledFlatTriangle(
$gradient,
new awPoint($prev->x, min($prev->y, $current->y)),
$top,
new awPoint($current->x, min($prev->y, $current->y))
);
unset($gradientDriver);
$sum += $current->x - $prev->x;
}
$prev = $current;
$prev->x += $interval;
}
} else if($gradient->angle === 90) {
$width = $right->x - $left->x;
$this->init($gradient, $width);
$pos = 1;
$next = $polygon->get($pos++);
$this->next($polygon, $pos, $prev, $next);
for($i = 0; $i <= $width; $i++) {
$x = $left->x + $i;
$y1 = round($prev->y + ($next->y - $prev->y) * (($i + $left->x - $prev->x) / ($next->x - $prev->x)));
$y2 = $left->y;
// Draw line
$color = $this->color($i);
// YaPB : PHP does not handle alpha on lines
$this->driver->filledRectangle($color, awLine::build($x, $y1, $x, $y2));
 
unset($color);
// Jump to next point
if($next->x == $i + $left->x) {
$this->next($polygon, $pos, $prev, $next);
}
}
}
} else if($count === 3) {
$this->drawFilledTriangle(
$gradient,
$polygon
);
}
}
private function next($polygon, &$pos, &$prev, &$next) {
do {
$prev = $next;
$next = $polygon->get($pos++);
}
while($next->x - $prev->x == 0 and $pos < $polygon->count());
}
/**
* Start colors
*
* @var int
*/
private $r1, $g1, $b1, $a1;
/**
* Stop colors
*
* @var int
*/
private $r2, $g2, $b2, $a2;
/**
* Gradient size in pixels
*
* @var int
*/
private $size;
private function init(awGradient $gradient, $size) {
list(
$this->r1, $this->g1, $this->b1, $this->a1
) = $gradient->from->rgba();
list(
$this->r2, $this->g2, $this->b2, $this->a2
) = $gradient->to->rgba();
$this->size = $size;
}
private function color($pos) {
return new awColor(
$this->getRed($pos),
$this->getGreen($pos),
$this->getBlue($pos),
$this->getAlpha($pos)
);
}
private function getRed($pos) {
if((float)$this->size !== 0.0) {
return (int)round($this->r1 + ($pos / $this->size) * ($this->r2 - $this->r1));
} else {
return 0;
}
}
private function getGreen($pos) {
if((float)$this->size !== 0.0) {
return (int)round($this->g1 + ($pos / $this->size) * ($this->g2 - $this->g1));
} else {
return 0;
}
}
private function getBlue($pos) {
if((float)$this->size !== 0.0) {
return (int)round($this->b1 + ($pos / $this->size) * ($this->b2 - $this->b1));
} else {
return 0;
}
}
private function getAlpha($pos) {
if((float)$this->size !== 0.0) {
return (int)round(($this->a1 + ($pos / $this->size) * ($this->a2 - $this->a1)) / 127 * 100);
} else {
return 0;
}
}
 
}
 
registerClass('GDGradientDriver');
 
/*
* Check for GD2
*/
if(function_exists('imagecreatetruecolor') === FALSE) {
awImage::drawErrorFile('missing-gd2');
}
 
?>
/trunk/bibliotheque/artichow/inc/drivers/ming.class.php
New file
0,0 → 1,774
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Driver.class.php";
 
/**
* Draw your objects
*
* @package Artichow
*/
class awMingDriver extends awDriver {
/**
* The Flash movie
*
* @var $movie
*/
public $movie;
public function __construct() {
parent::__construct();
$this->driverString = 'ming';
// Nice defaults
ming_setScale(20.0);
ming_useswfversion(6);
 
}
/**
* Initialize the driver for a particular awImage object
*
* @param awImage $image
*/
public function init(awImage $image) {
 
if($this->movie === NULL) {
$this->setImageSize($image->width, $image->height);
// Create movie
$this->movie = new SWFMovie();
if(!$this->movie) {
awImage::drawError("Class Image: Unable to create a graph.");
}
$this->movie->setDimension($image->width, $image->height);
$this->setAntiAliasing($image->getAntiAliasing());
// Original color
$this->filledRectangle(
new awWhite,
new awLine(
new awPoint(0, 0),
new awPoint($this->imageWidth, $this->imageHeight)
)
);
$shadow = $image->shadow;
if($shadow !== NULL) {
$shadow = $shadow->getSpace();
$p1 = new awPoint($shadow->left, $shadow->top);
$p2 = new awPoint($this->imageWidth - $shadow->right - 1, $this->imageHeight - $shadow->bottom - 1);
// Draw image background
$this->filledRectangle($image->getBackground(), new awLine($p1, $p2));
// Draw image border
$image->border->rectangle($this, $p1, $p2);
}
}
}
/**
* Initialize the Driver for a particular FileImage object
*
* @param awFileImage $fileImage The FileImage object to work on
* @param string $file Image filename
*/
public function initFromFile(awFileImage $fileImage, $file) {
}
/**
* Change the image size
*
* @param int $width Image width
* @param int $height Image height
*/
public function setImageSize($width, $height) {
$this->imageWidth = $width;
$this->imageHeight = $height;
}
/**
* Inform the driver of the position of your image
*
* @param float $x Position on X axis of the center of the component
* @param float $y Position on Y axis of the center of the component
*/
public function setPosition($x, $y) {
// Calculate absolute position
$this->x = round($x * $this->imageWidth - $this->w / 2);
$this->y = round($y * $this->imageHeight - $this->h / 2);
}
/**
* Inform the driver of the position of your image
* This method need absolutes values
*
* @param int $x Left-top corner X position
* @param int $y Left-top corner Y position
*/
public function setAbsPosition($x, $y) {
$this->x = $x;
$this->y = $y;
}
/**
* Move the position of the image
*
* @param int $x Add this value to X axis
* @param int $y Add this value to Y axis
*/
public function movePosition($x, $y) {
$this->x += (int)$x;
$this->y += (int)$y;
}
/**
* Inform the driver of the size of your image
* Height and width must be between 0 and 1.
*
* @param int $w Image width
* @param int $h Image height
* @return array Absolute width and height of the image
*/
public function setSize($w, $h) {
// Calcul absolute size
$this->w = round($w * $this->imageWidth);
$this->h = round($h * $this->imageHeight);
return $this->getSize();
}
/**
* Inform the driver of the size of your image
* You can set absolute size with this method.
*
* @param int $w Image width
* @param int $h Image height
*/
public function setAbsSize($w, $h) {
$this->w = $w;
$this->h = $h;
return $this->getSize();
}
/**
* Get the size of the component handled by the driver
*
* @return array Absolute width and height of the component
*/
public function getSize() {
return array($this->w, $this->h);
}
/**
* Turn antialiasing on or off
*
* @var bool $bool
*/
public function setAntiAliasing($bool) {
if($this->movie !== NULL) {
 
$actionscript = '
_quality = "%s";
';
 
if((bool)$bool) {
$actionscript = sprintf($actionscript, 'high');
} else {
$actionscript = sprintf($actionscript, 'low');
}
$this->movie->add(new SWFAction(str_replace("\r", "", $actionscript)));
}
}
/**
* When passed a Color object, returns the corresponding
* color identifier (driver dependant).
*
* @param awColor $color A Color object
* @return array $rgba A color identifier representing the color composed of the given RGB components
*/
public function getColor(awColor $color) {
// Ming simply works with R, G, B and Alpha values.
list($red, $green, $blue, $alpha) = $color->rgba();
// However, the Ming alpha channel ranges from 255 (opaque) to 0 (transparent),
// while the awColor alpha channel ranges from 0 (opaque) to 100 (transparent).
// First, we convert from 0-100 to 0-255.
$alpha = (int)($alpha * 255 / 100);
// Then from 0-255 to 255-0.
$alpha = abs($alpha - 255);
return array($red, $green, $blue, $alpha);
}
/**
* Draw an image here
*
* @param awImage $image Image
* @param int $p1 Image top-left point
* @param int $p2 Image bottom-right point
*/
public function copyImage(awImage $image, awPoint $p1, awPoint $p2) {
}
/**
* Draw an image here
*
* @param awImage $image Image
* @param int $d1 Destination top-left position
* @param int $d2 Destination bottom-right position
* @param int $s1 Source top-left position
* @param int $s2 Source bottom-right position
* @param bool $resample Resample image ? (default to TRUE)
*/
public function copyResizeImage(awImage $image, awPoint $d1, awPoint $d2, awPoint $s1, awPoint $s2, $resample = TRUE) {
}
/**
* Draw a string
*
* @var awText $text Text to print
* @param awPoint $point Draw the text at this point
* @param int $width Text max width
*/
public function string(awText $text, awPoint $point, $width = NULL) {
$font = $text->getFont();
// Can we deal with that font?
if($this->isCompatibleWithFont($font) === FALSE) {
awImage::drawError('Class MingDriver: Incompatible font type (\''.get_class($font).'\')');
}
// Ming can only work with awFileFont objects for now
// (i.e. awFDBFont, or awTuffy et al.)
$fontDriver = $this->fileFontDriver;
if($text->getBackground() !== NULL or $text->border->visible()) {
list($left, $right, $top, $bottom) = $text->getPadding();
 
$textWidth = $fontDriver->getTextWidth($text, $this);
$textHeight = $fontDriver->getTextHeight($text, $this);
$x1 = floor($point->x - $left);
$y1 = floor($point->y - $top);
$x2 = $x1 + $textWidth + $left + $right;
$y2 = $y1 + $textHeight + $top + $bottom;
$this->filledRectangle(
$text->getBackground(),
awLine::build($x1, $y1, $x2, $y2)
);
$text->border->rectangle(
$this,
new awPoint($x1 - 1, $y1 - 1),
new awPoint($x2 + 1, $y2 + 1)
);
}
$fontDriver->string($this, $text, $point, $width);
}
/**
* Draw a pixel
*
* @param awColor $color Pixel color
* @param awPoint $p
*/
public function point(awColor $color, awPoint $p) {
if($p->isHidden() === FALSE) {
list($red, $green, $blue, $alpha) = $this->getColor($color);
$point = new SWFShape();
$point->setLine(1, $red, $green, $blue, $alpha);
$point->movePenTo($this->x + round($p->x), $this->y + round($p->y));
$point->drawLine(0.5, 0.5);
$point->movePen(-0.5, 0);
$point->drawLine(0.5, -0.5);
$this->movie->add($point);
}
}
/**
* Draw a colored line
*
* @param awColor $color Line color
* @param awLine $line
* @param int $thickness Line tickness
*/
public function line(awColor $color, awLine $line) {
if($line->getThickness() > 0 and $line->isHidden() === FALSE) {
list($red, $green, $blue, $alpha) = $this->getColor($color);
 
$mingLine = new SWFShape();
$mingLine->setLine($line->getThickness(), $red, $green, $blue, $alpha);
 
list($p1, $p2) = $line->getLocation();
$mingLine->movePenTo($this->x + round($p1->x), $this->y + round($p1->y));
 
switch($line->getStyle()) {
case awLine::SOLID :
$mingLine->drawLineTo($this->x + round($p2->x), $this->y + round($p2->y));
$this->movie->add($mingLine);
break;
case awLine::DOTTED :
$size = sqrt(pow($p2->y - $p1->y, 2) + pow($p2->x - $p1->x, 2));
$cos = ($p2->x - $p1->x) / $size;
$sin = ($p2->y - $p1->y) / $size;
for($i = 0; $i <= $size; $i += 2) {
$p = new awPoint(
round($i * $cos + $p1->x),
round($i * $sin + $p1->y)
);
$this->point($color, $p);
}
break;
case awLine::DASHED :
$width = $p2->x - $p1->x;
$height = $p2->y - $p1->y;
$size = sqrt(pow($height, 2) + pow($width, 2));
if($size == 0) {
return;
}
$cos = $width / $size;
$sin = $height / $size;
$functionX = ($width > 0) ? 'min' : 'max';
$functionY = ($height > 0) ? 'min' : 'max';
for($i = 0; $i <= $size; $i += 6) {
$t1 = new awPoint(
round($i * $cos + $p1->x),
round($i * $sin + $p1->y)
);
$t2 = new awPoint(
round($functionX(($i + 3) * $cos, $width) + $p1->x),
round($functionY(($i + 3) * $sin, $height) + $p1->y)
);
$this->line($color, new awLine($t1, $t2));
}
break;
}
}
}
/**
* Draw a color arc
* @param awColor $color Arc color
* @param awPoint $center Point center
* @param int $width Ellipse width
* @param int $height Ellipse height
* @param int $from Start angle
* @param int $to End angle
*/
public function arc(awColor $color, awPoint $center, $width, $height, $from, $to) {
}
/**
* Draw an arc with a background color
*
* @param awColor $color Arc background color
* @param awPoint $center Point center
* @param int $width Ellipse width
* @param int $height Ellipse height
* @param int $from Start angle
* @param int $to End angle
*/
public function filledArc(awColor $color, awPoint $center, $width, $height, $from, $to) {
}
/**
* Draw a colored ellipse
*
* @param awColor $color Ellipse color
* @param awPoint $center Ellipse center
* @param int $width Ellipse width
* @param int $height Ellipse height
*/
public function ellipse(awColor $color, awPoint $center, $width, $height) {
}
/**
* Draw an ellipse with a background
*
* @param mixed $background Background (can be a color or a gradient)
* @param awPoint $center Ellipse center
* @param int $width Ellipse width
* @param int $height Ellipse height
*/
public function filledEllipse($background, awPoint $center, $width, $height) {
}
/**
* Draw a colored rectangle
*
* @param awColor $color Rectangle color
* @param awLine $line Rectangle diagonale
* @param awPoint $p2
*/
public function rectangle(awColor $color, awLine $line) {
list($p1, $p2) = $line->getLocation();
// Get Red, Green, Blue and Alpha values for the line
list($r, $g, $b, $a) = $this->getColor($color);
// Calculate the coordinates of the two other points of the rectangle
$p3 = new Point($p1->x, $p2->y);
$p4 = new Point($p2->x, $p1->y);
$side = clone $line;
// Draw the four sides of the rectangle, clockwise
if(
($p1->x <= $p2->x and $p1->y <= $p2->y)
or
($p1->x >= $p2->x and $p1->y >= $p2->y)
) {
$side->setLocation($p1, $p4);
$this->line($color, $side);
$side->setLocation($p4, $p2);
$this->line($color, $side);
$side->setLocation($p2, $p3);
$this->line($color, $side);
$side->setLocation($p3, $p1);
$this->line($color, $side);
} else {
$side->setLocation($p1, $p3);
$this->line($color, $side);
$side->setLocation($p3, $p2);
$this->line($color, $side);
$side->setLocation($p2, $p4);
$this->line($color, $side);
$side->setLocation($p4, $p1);
$this->line($color, $side);
}
}
/**
* Draw a rectangle with a background
*
* @param mixed $background Background (can be a color or a gradient)
* @param awLine $line Rectangle diagonale
*/
public function filledRectangle($background, awLine $line) {
list($p1, $p2) = $line->getLocation();
// Common shape settings
$shape = new SWFShape();
$shape->setLine(0);
if($background instanceof awColor) {
// Get the Red, Green, Blue and Alpha values
list($r, $g, $b, $a) = $this->getColor($background);
$shape->setRightFill($r, $g, $b, $a);
} else if($background instanceof awGradient) {
// Get the Gradient object as an SWFGradient one
list($flashGradient, $style) = $this->getGradient($background);
$fill = $shape->addFill($flashGradient, $style);
// Angles between Artichow and Ming don't match.
// Don't use abs() or vertical gradients get inverted.
$angle = $background->angle - 90;
$fill->rotateTo($angle);
// Move the gradient based on the position of the rectangle we're drawing
$centerX = min($p1->x, $p2->y) + abs($p1->x - $p2->x) / 2;
$centerY = min($p1->y, $p2->y) + abs($p1->y - $p2->y) / 2;
$fill->moveTo($centerX, $centerY);
// Ming draws its gradients on a 1600x1600 image,
// so we have to resize it.
if($angle === -90) {
$ratio = abs($p1->y - $p2->y) / 1600;
} else {
$ratio = abs($p1->x - $p2->x) / 1600;
}
$fill->scaleTo($ratio);
$shape->setRightFill($fill);
}
// Set starting position
$shape->movePenTo($this->x + round($p1->x), $this->y + round($p1->y));
// Depending on the points' relative positions,
// we have two drawing possibilities
if(
($p1->x <= $p2->x and $p1->y <= $p2->y)
or
($p1->x >= $p2->x and $p1->y >= $p2->y)
) {
$shape->drawLineTo($this->x + round($p2->x), $this->y + round($p1->y));
$shape->drawLineTo($this->x + round($p2->x), $this->y + round($p2->y));
$shape->drawLineTo($this->x + round($p1->x), $this->y + round($p2->y));
$shape->drawLineTo($this->x + round($p1->x), $this->y + round($p1->y));
} else {
$shape->drawLineTo($this->x + round($p1->x), $this->y + round($p2->y));
$shape->drawLineTo($this->x + round($p2->x), $this->y + round($p2->y));
$shape->drawLineTo($this->x + round($p2->x), $this->y + round($p1->y));
$shape->drawLineTo($this->x + round($p1->x), $this->y + round($p1->y));
}
$this->movie->add($shape);
}
/**
* Draw a polygon
*
* @param awColor $color Polygon color
* @param Polygon A polygon
*/
public function polygon(awColor $color, awPolygon $polygon) {
$points = $polygon->all();
$count = count($points);
if($count > 1) {
$side = new awLine;
$side->setStyle($polygon->getStyle());
$side->setThickness($polygon->getThickness());
$prev = $points[0];
for($i = 1; $i < $count; $i++) {
$current = $points[$i];
$side->setLocation($prev, $current);
$this->line($color, $side);
$prev = $current;
}
// Close the polygon
$side->setLocation($prev, $points[0]);
$this->line($color, $side);
}
}
/**
* Draw a polygon with a background
*
* @param mixed $background Background (can be a color or a gradient)
* @param Polygon A polygon
*/
public function filledPolygon($background, awPolygon $polygon) {
$shape = new SWFShape();
if($background instanceof awColor) {
list($red, $green, $blue, $alpha) = $this->getColor($background);
$shape->setRightFill($red, $green, $blue, $alpha);
} elseif($background instanceof awGradient) {
list($flashGradient, $style) = $this->getGradient($background);
$fill = $shape->addFill($flashGradient, $style);
list($xMin, $xMax) = $polygon->getBoxXRange();
list($yMin, $yMax) = $polygon->getBoxYRange();
if($background->angle === 0) {
$fill->scaleTo(($yMax - $yMin) / 1600);
} else {
$fill->scaleTo(($xMax - $xMin) / 1600);
}
$fill->moveTo($xMin + ($xMax - $xMin) / 2, $yMin + ($yMax - $yMin) / 2);
$shape->setRightFill($fill);
}
$points = $polygon->all();
$count = count($points);
if($count > 1) {
$prev = $points[0];
$shape->movePenTo($prev->x, $prev->y);
for($i = 1; $i < $count; $i++) {
$current = $points[$i];
$shape->drawLineTo($current->x, $current->y);
}
// Close the polygon
$shape->drawLineTo($prev->x, $prev->y);
$this->movie->add($shape);
}
}
 
/**
* Sends the image, as well as the correct HTTP headers, to the browser
*
* @param awImage $image The Image object to send
*/
public function send(awImage $image) {
$this->drawImage($image);
}
/**
* Get the image as binary data
*
* @param awImage $image
*/
public function get(awImage $image) {
return $this->drawImage($image, TRUE, FALSE);
}
public function getTextWidth(awText $text) {
$font = $text->getFont();
if($this->isCompatibleWithFont($font) === FALSE) {
awImage::drawError('Class MingDriver: Incompatible font type (\''.get_class($font).'\')');
}
// Ming only supports FileFont
$fontDriver = $this->fileFontDriver;
return $fontDriver->getTextWidth($text, $this);
}
public function getTextHeight(awText $text) {
$font = $text->getFont();
if($this->isCompatibleWithFont($font) === FALSE) {
awImage::drawError('Class MingDriver: Incompatible font type (\''.get_class($font).'\')');
}
// Ming only supports FileFont
$fontDriver = $this->fileFontDriver;
return $fontDriver->getTextHeight($text, $this);
}
protected function isCompatibleWithFont(awFont $font) {
if($font instanceof awTTFFont or $font instanceof awPHPFont) {
return FALSE;
} else {
return TRUE;
}
}
private function drawImage(awImage $image, $return = FALSE, $header = TRUE) {
// Send headers to the browser
if($header === TRUE) {
$image->sendHeaders();
}
if($return) {
ob_start();
}
$this->movie->output();
if($return) {
return ob_get_clean();
}
}
 
/**
* Convert an awGradient object to an SWFGradient one.
* Returns an object as well as the style of the Flash gradient.
*
* @param awGradient $gradient The awGradient object to convert
* @return array
*/
private function getGradient(awGradient $gradient) {
$flashGradient = new SWFGradient();
// Get RGBA values for the gradient boundaries
list($r1, $g1, $b1, $a1) = $this->getColor($gradient->from);
list($r2, $g2, $b2, $a2) = $this->getColor($gradient->to);
$flashGradient->addEntry(0, $r1, $g1, $b1, $a1);
if($gradient instanceof awBilinearGradient) {
$flashGradient->addEntry($gradient->center, $r2, $g2, $b2, $a2);
$flashGradient->addEntry(1, $r1, $g1, $b1, $a1);
return array($flashGradient, SWFFILL_LINEAR_GRADIENT);
} else {
 
$flashGradient->addEntry(1, $r2, $g2, $b2, $a2);
if($gradient instanceof awLinearGradient) {
return array($flashGradient, SWFFILL_LINEAR_GRADIENT);
} else {
return array($flashGradient, SWFFILL_RADIAL_GRADIENT);
}
}
}
// abstract private function getPolygonPoints(awPolygon $polygon);
 
}
 
registerClass('MingDriver');
 
/*
* Check for ming presence
*/
if(function_exists('ming_useswfversion') === FALSE) {
awImage::drawErrorFile('missing-ming');
}
 
?>
/trunk/bibliotheque/artichow/inc/Grid.class.php
New file
0,0 → 1,291
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
/**
* Grid
*
* @package Artichow
*/
class awGrid {
/**
* Vertical lines of the grid
*
* @var array
*/
private $xgrid = array();
/**
* Horizontal lines of the grid
*
* @var array
*/
private $ygrid = array();
 
/**
* Is the component grid hidden ?
*
* @var bool
*/
private $hide = FALSE;
 
/**
* Are horizontal lines hidden ?
*
* @var bool
*/
private $hideHorizontal = FALSE;
 
/**
* Are vertical lines hidden ?
*
* @var bool
*/
private $hideVertical = FALSE;
/**
* Grid color
*
* @var Color
*/
private $color;
/**
* Grid space
*
* @var int
*/
private $space;
/**
* Line type
*
* @var int
*/
private $type = awLine::SOLID;
/**
* Grid interval
*
* @var int
*/
private $interval = array(1, 1);
/**
* Grid background color
*
* @var Color
*/
private $background;
/**
* Build the factory
*/
public function __construct() {
// Set a grid default color
$this->color = new awColor(210, 210, 210);
$this->background = new awColor(255, 255, 255, 100);
}
/**
* Hide grid ?
*
* @param bool $hide
*/
public function hide($hide = TRUE) {
$this->hide = (bool)$hide;
}
/**
* Hide horizontal lines ?
*
* @param bool $hideHorizontal
*/
public function hideHorizontal($hide = TRUE) {
$this->hideHorizontal = (bool)$hide;
}
/**
* Hide vertical lines ?
*
* @param bool $hideVertical
*/
public function hideVertical($hide = TRUE) {
$this->hideVertical = (bool)$hide;
}
/**
* Change grid color
*
* @param awColor $color
*/
public function setColor(awColor $color) {
$this->color = $color;
}
/**
* Remove grid background
*/
public function setNoBackground() {
$this->background = NULL;
}
/**
* Change grid background color
*
* @param awColor $color
*/
public function setBackgroundColor(awColor $color) {
$this->background = $color;
}
/**
* Change line type
*
* @param int $type
*/
public function setType($type) {
$this->type = (int)$type;
}
/**
* Change grid interval
*
* @param int $hInterval
* @param int $vInterval
*/
public function setInterval($hInterval, $vInterval) {
$this->interval = array((int)$hInterval, (int)$vInterval);
}
/**
* Set grid space
*
* @param int $left Left space in pixels
* @param int $right Right space in pixels
* @param int $top Top space in pixels
* @param int $bottom Bottom space in pixels
*/
public function setSpace($left, $right, $top, $bottom) {
$this->space = array((int)$left, (int)$right, (int)$top, (int)$bottom);
}
/**
* Change the current grid
*
* @param array $xgrid Vertical lines
* @param array $ygrid Horizontal lines
*/
public function setGrid($xgrid, $ygrid) {
if(empty($this->xgrid)) {
$this->xgrid = $xgrid;
}
if(empty($this->ygrid)) {
$this->ygrid = $ygrid;
}
}
/**
* Draw grids
*
* @param awDriver $driver A driver object
* @param int $x1
* @param int $y1
* @param int $x2
* @param int $y2
*/
public function draw(awDriver $driver, $x1, $y1, $x2, $y2) {
if($this->background instanceof awColor) {
// Draw background color
$driver->filledRectangle(
$this->background,
awLine::build($x1, $y1, $x2, $y2)
);
}
 
if($this->hide === FALSE) {
$this->drawGrid(
$driver,
$this->color,
$this->hideVertical ? array() : $this->xgrid,
$this->hideHorizontal ? array() : $this->ygrid,
$x1, $y1, $x2, $y2,
$this->type,
$this->space,
$this->interval[0],
$this->interval[1]
);
}
}
private function drawGrid(
awDriver $driver, awColor $color,
$nx, $ny, $x1, $y1, $x2, $y2,
$type, $space, $hInterval, $vInterval
) {
list($left, $right, $top, $bottom) = $space;
$width = $x2 - $x1 - $left - $right;
$height = $y2 - $y1 - $top - $bottom;
foreach($nx as $key => $n) {
if(($key % $vInterval) === 0) {
$pos = (int)round($x1 + $left + $n * $width);
$driver->line(
$color,
new awLine(
new awPoint($pos, $y1),
new awPoint($pos, $y2),
$type
)
);
}
}
foreach($ny as $key => $n) {
if(($key % $hInterval) === 0) {
$pos = (int)round($y1 + $top + $n * $height);
$driver->line(
$color,
new awLine(
new awPoint($x1, $pos),
new awPoint($x2, $pos),
$type
)
);
}
}
}
 
}
 
registerClass('Grid');
?>
/trunk/bibliotheque/artichow/inc/Shadow.class.php
New file
0,0 → 1,406
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
 
/**
* Draw shadows
*
*/
class awShadow {
 
/**
* Shadow on left and top sides
*
* @var int
*/
const LEFT_TOP = 1;
 
/**
* Shadow on left and bottom sides
*
* @var int
*/
const LEFT_BOTTOM = 2;
 
/**
* Shadow on right and top sides
*
* @var int
*/
const RIGHT_TOP = 3;
 
/**
* Shadow on right and bottom sides
*
* @var int
*/
const RIGHT_BOTTOM = 4;
/**
* In mode
*
* @var int
*/
const IN = 1;
/**
* Out mode
*
* @var int
*/
const OUT = 2;
 
/**
* Shadow size
*
* @var int
*/
private $size = 0;
/**
* Hide shadow ?
*
* @var bool
*/
protected $hide = FALSE;
 
/**
* Shadow color
*
* @var Color
*/
private $color;
 
/**
* Shadow position
*
* @var int
*/
private $position;
 
/**
* Smooth shadow ?
*
* @var bool
*/
private $smooth = FALSE;
/**
* Shadow constructor
*
* @param int $position Shadow position
*/
public function __construct($position) {
$this->setPosition($position);
}
/**
* Hide shadow ?
*
* @param bool $hide
*/
public function hide($hide = TRUE) {
$this->hide = (bool)$hide;
}
/**
* Show shadow ?
*
* @param bool $show
*/
public function show($show = TRUE) {
$this->hide = (bool)!$show;
}
/**
* Change shadow size
*
* @param int $size
* @param bool $smooth Smooth the shadow (facultative argument)
*/
public function setSize($size, $smooth = NULL) {
$this->size = (int)$size;
if($smooth !== NULL) {
$this->smooth($smooth);
}
}
/**
* Change shadow color
*
* @param awColor $color
*/
public function setColor(awColor $color) {
$this->color = $color;
}
/**
* Change shadow position
*
* @param int $position
*/
public function setPosition($position) {
$this->position = (int)$position;
}
/**
* Smooth shadow ?
*
* @param bool $smooth
*/
public function smooth($smooth) {
$this->smooth = (bool)$smooth;
}
/**
* Get the space taken by the shadow
*
* @return Side
*/
public function getSpace() {
return new awSide(
($this->position === awShadow::LEFT_TOP or $this->position === awShadow::LEFT_BOTTOM) ? $this->size : 0,
($this->position === awShadow::RIGHT_TOP or $this->position === awShadow::RIGHT_BOTTOM) ? $this->size : 0,
($this->position === awShadow::LEFT_TOP or $this->position === awShadow::RIGHT_TOP) ? $this->size : 0,
($this->position === awShadow::LEFT_BOTTOM or $this->position === awShadow::RIGHT_BOTTOM) ? $this->size : 0
);
}
/**
* Draw shadow
*
* @param awDriver $driver
* @param awPoint $p1 Top-left point
* @param awPoint $p2 Right-bottom point
* @param int Drawing mode
*/
public function draw(awDriver $driver, awPoint $p1, awPoint $p2, $mode) {
if($this->hide) {
return;
}
if($this->size <= 0) {
return;
}
$driver = clone $driver;
$color = ($this->color instanceof awColor) ? $this->color : new awColor(125, 125, 125);
switch($this->position) {
case awShadow::RIGHT_BOTTOM :
if($mode === awShadow::OUT) {
$t1 = $p1->move(0, 0);
$t2 = $p2->move($this->size + 1, $this->size + 1);
} else { // PHP 4 compatibility
$t1 = $p1->move(0, 0);
$t2 = $p2->move(0, 0);
}
$width = $t2->x - $t1->x;
$height = $t2->y - $t1->y;
$driver->setAbsPosition($t1->x + $driver->x, $t1->y + $driver->y);
$driver->filledRectangle(
$color,
new awLine(
new awPoint($width - $this->size, $this->size),
new awPoint($width - 1, $height - 1)
)
);
$driver->filledRectangle(
$color,
new awLine(
new awPoint($this->size, $height - $this->size),
new awPoint($width - $this->size - 1, $height - 1)
)
);
$this->smoothPast($driver, $color, $width, $height);
break;
case awShadow::LEFT_TOP :
if($mode === awShadow::OUT) {
$t1 = $p1->move(- $this->size, - $this->size);
$t2 = $p2->move(0, 0);
} else { // PHP 4 compatibility
$t1 = $p1->move(0, 0);
$t2 = $p2->move(0, 0);
}
$width = $t2->x - $t1->x;
$height = $t2->y - $t1->y;
$driver->setAbsPosition($t1->x + $driver->x, $t1->y + $driver->y);
$height = max($height + 1, $this->size);
$driver->filledRectangle(
$color,
new awLine(
new awPoint(0, 0),
new awPoint($this->size - 1, $height - $this->size - 1)
)
);
$driver->filledRectangle(
$color,
new awLine(
new awPoint($this->size, 0),
new awPoint($width - $this->size - 1, $this->size - 1)
)
);
$this->smoothPast($driver, $color, $width, $height);
break;
case awShadow::RIGHT_TOP :
if($mode === awShadow::OUT) {
$t1 = $p1->move(0, - $this->size);
$t2 = $p2->move($this->size + 1, 0);
} else { // PHP 4 compatibility
$t1 = $p1->move(0, 0);
$t2 = $p2->move(0, 0);
}
$width = $t2->x - $t1->x;
$height = $t2->y - $t1->y;
$driver->setAbsPosition($t1->x + $driver->x, $t1->y + $driver->y);
$height = max($height + 1, $this->size);
$driver->filledRectangle(
$color,
new awLine(
new awPoint($width - $this->size, 0),
new awPoint($width - 1, $height - $this->size - 1)
)
);
$driver->filledRectangle(
$color,
new awLine(
new awPoint($this->size, 0),
new awPoint($width - $this->size - 1, $this->size - 1)
)
);
$this->smoothFuture($driver, $color, $width, $height);
break;
case awShadow::LEFT_BOTTOM :
if($mode === awShadow::OUT) {
$t1 = $p1->move(- $this->size, 0);
$t2 = $p2->move(0, $this->size + 1);
} else { // PHP 4 compatibility
$t1 = $p1->move(0, 0);
$t2 = $p2->move(0, 0);
}
$width = $t2->x - $t1->x;
$height = $t2->y - $t1->y;
$driver->setAbsPosition($t1->x + $driver->x, $t1->y + $driver->y);
$driver->filledRectangle(
$color,
new awLine(
new awPoint(0, $this->size),
new awPoint($this->size - 1, $height - 1)
)
);
$driver->filledRectangle(
$color,
new awLine(
new awPoint($this->size, $height - $this->size),
new awPoint($width - $this->size - 1, $height - 1)
)
);
$this->smoothFuture($driver, $color, $width, $height);
break;
}
}
private function smoothPast(awDriver $driver, awColor $color, $width, $height) {
if($this->smooth) {
for($i = 0; $i < $this->size; $i++) {
for($j = 0; $j <= $i; $j++) {
$driver->point(
$color,
new awPoint($i, $j + $height - $this->size)
);
}
}
for($i = 0; $i < $this->size; $i++) {
for($j = 0; $j <= $i; $j++) {
$driver->point(
$color,
new awPoint($width - $this->size + $j, $i)
);
}
}
}
}
private function smoothFuture(awDriver $driver, awColor $color, $width, $height) {
if($this->smooth) {
for($i = 0; $i < $this->size; $i++) {
for($j = 0; $j <= $i; $j++) {
$driver->point(
$color,
new awPoint($i, $this->size - $j - 1)
);
}
}
for($i = 0; $i < $this->size; $i++) {
for($j = 0; $j <= $i; $j++) {
$driver->point(
$color,
new awPoint($width - $this->size + $j, $height - $i - 1)
);
}
}
}
}
 
}
 
registerClass('Shadow');
?>
/trunk/bibliotheque/artichow/inc/Math.class.php
New file
0,0 → 1,832
<?php
/*
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
*/
require_once dirname(__FILE__)."/../Graph.class.php";
 
abstract class awShape {
/**
* Is the shape hidden ?
*
* @var bool
*/
protected $hide = FALSE;
/**
* Shape style
*
* @var int
*/
public $style;
/**
* Shape thickness
*
* @var int
*/
public $thickness;
/**
* Solid shape
*
* @var int
*/
const SOLID = 1;
/**
* Dotted shape
*
* @var int
*/
const DOTTED = 2;
/**
* Dashed shape
*
* @var int
*/
const DASHED = 3;
/**
* Change shape style
*
* @param int $style Line style
*/
public function setStyle($style) {
$this->style = (int)$style;
}
/**
* Return shape style
*
* @return int
*/
public function getStyle() {
return $this->style;
}
/**
* Change shape thickness
*
* @param int $thickness Shape thickness in pixels
*/
public function setThickness($thickness) {
$this->thickness = (int)$thickness;
}
/**
* Return shape thickness
*
* @return int
*/
public function getThickness() {
return $this->thickness;
}
/**
* Hide the shape
*
* @param bool $hide
*/
public function hide($hide) {
$this->hide = (bool)$hide;
}
/**
* Show the shape
*
* @param bool $shape
*/
public function show($shape) {
$this->hide = (bool)!$shape;
}
/**
* Is the line hidden ?
*
* @return bool
*/
public function isHidden() {
return $this->hide;
}
}
 
registerClass('Shape', TRUE);
 
/**
* Describe a point
*
* @package Artichow
*/
class awPoint extends awShape {
 
/**
* X coord
*
* @var float
*/
public $x;
 
/**
* Y coord
*
* @var float
*/
public $y;
/**
* Build a new awpoint
*
* @param float $x
* @param float $y
*/
public function __construct($x, $y) {
$this->setLocation($x, $y);
}
/**
* Change X value
*
* @param float $x
*/
public function setX($x) {
$this->x = (float)$x;
}
/**
* Change Y value
*
* @param float $y
*/
public function setY($y) {
$this->y = (float)$y;
}
/**
* Change point location
*
* @param float $x
* @param float $y
*/
public function setLocation($x, $y) {
$this->setX($x);
$this->setY($y);
}
/**
* Get point location
*
* @param array Point location
*/
public function getLocation() {
return array($this->x, $this->y);
}
/**
* Get distance to another point
*
* @param awPoint $p A point
* @return float
*/
public function getDistance(awPoint $p) {
return sqrt(pow($p->x - $this->x, 2) + pow($p->y - $this->y, 2));
}
/**
* Move the point to another location
*
* @param Point A Point with the new awlocation
*/
public function move($x, $y) {
return new awPoint(
$this->x + $x,
$this->y + $y
);
}
 
}
 
registerClass('Point');
 
/**
* Describe a line
*
* @package Artichow
*/
class awLine extends awShape {
 
/**
* Line first point
*
* @param Point
*/
public $p1;
 
/**
* Line second point
*
* @param Point
*/
public $p2;
/**
* The line slope (the m in y = mx + p)
*
* @param float
*/
private $slope;
/**
* The y-intercept value of the line (the p in y = mx + p)
*
* @param float
*/
private $origin;
/**
* Build a new awline
*
* @param awPoint $p1 First point
* @param awPoint $p2 Second point
* @param int $type Style of line (default to solid)
* @param int $thickness Line thickness (default to 1)
*/
public function __construct($p1 = NULL, $p2 = NULL, $type = awLine::SOLID, $thickness = 1) {
$this->setLocation($p1, $p2);
$this->setStyle($type);
$this->setThickness($thickness);
}
/**
* Build a line from 4 coords
*
* @param int $x1 Left position
* @param int $y1 Top position
* @param int $x2 Right position
* @param int $y2 Bottom position
*/
public static function build($x1, $y1, $x2, $y2) {
return new awLine(
new awPoint($x1, $y1),
new awPoint($x2, $y2)
);
}
/**
* Change X values of the line
*
* @param int $x1 Begin value
* @param int $x2 End value
*/
public function setX($x1, $x2) {
$this->p1->setX($x1);
$this->p2->setX($x2);
// Resets slope and origin values so they are
// recalculated when and if needed.
$this->slope = NULL;
$this->origin = NULL;
}
/**
* Change Y values of the line
*
* @param int $y1 Begin value
* @param int $y2 End value
*/
public function setY($y1, $y2) {
$this->p1->setY($y1);
$this->p2->setY($y2);
// Resets slope and origin values so they are
// recalculated when and if needed.
$this->slope = NULL;
$this->origin = NULL;
}
/**
* Change line location
*
* @param awPoint $p1 First point
* @param awPoint $p2 Second point
*/
public function setLocation($p1, $p2) {
if(is_null($p1) or $p1 instanceof awPoint) {
$this->p1 = $p1;
}
if(is_null($p2) or $p2 instanceof awPoint) {
$this->p2 = $p2;
}
// Resets slope and origin values so they are
// recalculated when and if needed.
$this->slope = NULL;
$this->origin = NULL;
}
/**
* Get line location
*
* @param array Line location
*/
public function getLocation() {
return array($this->p1, $this->p2);
}
/**
* Get the line size
*
* @return float
*/
public function getSize() {
$square = pow($this->p2->x - $this->p1->x, 2) + pow($this->p2->y - $this->p1->y, 2);
return sqrt($square);
}
/**
* Calculate the line slope
*
*/
private function calculateSlope() {
if($this->isHorizontal()) {
$this->slope = 0;
} else {
$slope = ($this->p1->y - $this->p2->y) / ($this->p1->x - $this->p2->x);
$this->slope = $slope;
}
}
/**
* Calculate the y-intercept value of the line
*
*/
private function calculateOrigin() {
if($this->isHorizontal()) {
$this->origin = $this->p1->y; // Or p2->y
} else {
$y1 = $this->p1->y;
$y2 = $this->p2->y;
$x1 = $this->p1->x;
$x2 = $this->p2->x;
$origin = ($y2 * $x1 - $y1 * $x2) / ($x1 - $x2);
$this->origin = $origin;
}
}
/**
* Calculate the slope and y-intercept value of the line
*
*/
private function calculateEquation() {
$this->calculateSlope();
$this->calculateOrigin();
}
/**
* Get the line slope value
*
* @return float
*/
public function getSlope() {
if($this->isVertical()) {
return NULL;
} elseif($this->slope !== NULL) {
return $this->slope;
} else {
$this->calculateSlope();
return $this->slope;
}
}
/**
* Get the line y-intercept value
*
* @return float
*/
public function getOrigin() {
if($this->isVertical()) {
return NULL;
} elseif($this->origin !== NULL) {
return $this->origin;
} else {
$this->calculateOrigin();
return $this->origin;
}
}
/**
* Get the line equation
*
* @return array An array containing the slope and y-intercept value of the line
*/
public function getEquation() {
$slope = $this->getSlope();
$origin = $this->getOrigin();
return array($slope, $origin);
}
/**
* Return the x coordinate of a point on the line
* given its y coordinate.
*
* @param float $y The y coordinate of the Point
* @return float $x The corresponding x coordinate
*/
public function getXFrom($y) {
$x = NULL;
if($this->isVertical()) {
list($p, ) = $this->getLocation();
$x = $p->x;
} else {
list($slope, $origin) = $this->getEquation();
if($slope !== 0) {
$y = (float)$y;
$x = ($y - $origin) / $slope;
}
}
return $x;
}
/**
* Return the y coordinate of a point on the line
* given its x coordinate.
*
* @param float $x The x coordinate of the Point
* @return float $y The corresponding y coordinate
*/
public function getYFrom($x) {
$y = NULL;
if($this->isHorizontal()) {
list($p, ) = $this->getLocation();
$y = $p->y;
} else {
list($slope, $origin) = $this->getEquation();
if($slope !== NULL) {
$x = (float)$x;
$y = $slope * $x + $origin;
}
}
return $y;
}
/**
* Test if the line can be considered as a point
*
* @return bool
*/
public function isPoint() {
return ($this->p1->x === $this->p2->x and $this->p1->y === $this->p2->y);
}
/**
* Test if the line is a vertical line
*
* @return bool
*/
public function isVertical() {
return ($this->p1->x === $this->p2->x);
}
/**
* Test if the line is an horizontal line
*
* @return bool
*/
public function isHorizontal() {
return ($this->p1->y === $this->p2->y);
}
/**
* Returns TRUE if the line is going all the way from the top
* to the bottom of the polygon surrounding box.
*
* @param $polygon Polygon A Polygon object
* @return bool
*/
public function isTopToBottom(awPolygon $polygon) {
list($xMin, $xMax) = $polygon->getBoxXRange();
list($yMin, $yMax) = $polygon->getBoxYRange();
if($this->isHorizontal()) {
return FALSE;
} else {
if($this->p1->y < $this->p2->y) {
$top = $this->p1;
$bottom = $this->p2;
} else {
$top = $this->p2;
$bottom = $this->p1;
}
return (
$this->isOnBoxTopSide($top, $xMin, $xMax, $yMin)
and
$this->isOnBoxBottomSide($bottom, $xMin, $xMax, $yMax)
);
}
}
/**
* Returns TRUE if the line is going all the way from the left side
* to the right side of the polygon surrounding box.
*
* @param $polygon Polygon A Polygon object
* @return bool
*/
public function isLeftToRight(awPolygon $polygon) {
list($xMin, $xMax) = $polygon->getBoxXRange();
list($yMin, $yMax) = $polygon->getBoxYRange();
if($this->isVertical()) {
return FALSE;
} else {
if($this->p1->x < $this->p2->x) {
$left = $this->p1;
$right = $this->p2;
} else {
$left = $this->p2;
$right = $this->p1;
}
}
return (
$this->isOnBoxLeftSide($left, $yMin, $yMax, $xMin)
and
$this->isOnBoxRightSide($right, $yMin, $yMax, $xMax)
);
}
private function isOnBoxTopSide(awPoint $point, $xMin, $xMax, $yMin) {
if(
$point->y === $yMin
and
$point->x >= $xMin
and
$point->x <= $xMax
) {
return TRUE;
} else {
return FALSE;
}
}
 
private function isOnBoxBottomSide(awPoint $point, $xMin, $xMax, $yMax) {
if(
$point->y === $yMax
and
$point->x >= $xMin
and
$point->x <= $xMax
) {
return TRUE;
} else {
return FALSE;
}
}
private function isOnBoxLeftSide(awPoint $point, $yMin, $yMax, $xMin) {
if(
$point->x === $xMin
and
$point->y >= $yMin
and
$point->y <= $yMax
) {
return TRUE;
} else {
return FALSE;
}
}
private function isOnBoxRightSide(awPoint $point, $yMin, $yMax, $xMax) {
if(
$point->x === $xMax
and
$point->y >= $yMin
and
$point->y <= $yMax
) {
return TRUE;
} else {
return FALSE;
}
}
}
 
registerClass('Line');
 
/**
* A vector is a type of line
* The sense of the vector goes from $p1 to $p2.
*
* @package Artichow
*/
class awVector extends awLine {
/**
* Get vector angle in radians
*
* @return float
*/
public function getAngle() {
if($this->isPoint()) {
return 0.0;
}
$size = $this->getSize();
$width = ($this->p2->x - $this->p1->x);
$height = ($this->p2->y - $this->p1->y) * -1;
if($width >= 0 and $height >= 0) {
return acos($width / $size);
} else if($width <= 0 and $height >= 0) {
return acos($width / $size);
} else {
$height *= -1;
if($width >= 0 and $height >= 0) {
return 2 * M_PI - acos($width / $size);
} else if($width <= 0 and $height >= 0) {
return 2 * M_PI - acos($width / $size);
}
}
}
 
}
 
registerClass('Vector');
 
/**
* Describe a polygon
*
* @package Artichow
*/
class awPolygon extends awShape {
 
/**
* Polygon points
*
* @var array
*/
protected $points = array();
 
/**
* Set a point in the polygon
*
* @param int $pos Point position
* @param awPoint $point
*/
public function set($pos, $point) {
if(is_null($point) or $point instanceof awPoint) {
$this->points[$pos] = $point;
}
}
/**
* Add a point at the end of the polygon
*
* @param awPoint $point
*/
public function append($point) {
if(is_null($point) or $point instanceof awPoint) {
$this->points[] = $point;
}
}
/**
* Get a point at a position in the polygon
*
* @param int $pos Point position
* @return Point
*/
public function get($pos) {
return $this->points[$pos];
}
/**
* Count number of points in the polygon
*
* @return int
*/
public function count() {
return count($this->points);
}
/**
* Returns all points in the polygon
*
* @return array
*/
public function all() {
return $this->points;
}
/**
* Returns the different lines formed by the polygon vertices
*
* @return array
*/
public function getLines() {
$lines = array();
$count = $this->count();
for($i = 0; $i < $count - 1; $i++) {
$lines[] = new Line($this->get($i), $this->get($i + 1));
}
// "Close" the polygon
$lines[] = new Line($this->get($count - 1), $this->get(0));
 
return $lines;
}
/**
* Get the upper-left and lower-right points
* of the bounding box around the polygon
*
* @return array An array of two Point objects
*/
public function getBoxPoints() {
$count = $this->count();
$x = $y = array();
for($i = 0; $i < $count; $i++) {
$point = $this->get($i);
list($x[], $y[]) = $point->getLocation();
}
$upperLeft = new Point(min($x), min($y));
$lowerRight = new Point(max($x), max($y));
return array($upperLeft, $lowerRight);
}
/**
* Return the range of the polygon on the y axis,
* i.e. the minimum and maximum y value of any point in the polygon
*
* @return array
*/
public function getBoxYRange() {
list($p1, $p2) = $this->getBoxPoints();
list(, $yMin) = $p1->getLocation();
list(, $yMax) = $p2->getLocation();
return array($yMin, $yMax);
}
/**
* Return the range of the polygon on the x axis,
* i.e. the minimum and maximum x value of any point in the polygon
*
* @return array
*/
public function getBoxXRange() {
list($p1, $p2) = $this->getBoxPoints();
list($xMin, ) = $p1->getLocation();
list($xMax, ) = $p2->getLocation();
return array($xMin, $xMax);
}
 
}
 
registerClass('Polygon');
?>