22-01-2007, 11:59 PM
Voila, je viens de me "passionner" pour le svg, suite à l'exemple impressionnant donné dans un autre sujet, et donc je suis en train de faire une petite classe pour générer des dessins en svg. A terme, je voudrais pouvoir charger une image JPG et l'integrer dans un fichier svg, et quelques autres fonctions... enfin vous verrez ;-)
Mais j'aimerais quelques avis sur la première version de la classe (ou plutôt des classes, puisque j'en utilise deux), que voici. Elle nécessite en théorie PHP5, même si elle pourrait être adapté en PHP4, mais je compte utiliser certaines fonctions de PHP5.
Donc voici le fichier classe_svg.php :
Mais j'aimerais quelques avis sur la première version de la classe (ou plutôt des classes, puisque j'en utilise deux), que voici. Elle nécessite en théorie PHP5, même si elle pourrait être adapté en PHP4, mais je compte utiliser certaines fonctions de PHP5.
Donc voici le fichier classe_svg.php :
Code PHP :
<?php
class svg_drawer
{
private $last = 0;
private $balises = array();
public function __construct($height, $width)
{
//On créé la balise SVG
$this->balises[$this->last] = new balise('svg', true);
//On ajoute les attributs
$this->set_attr('xmlns', 'http://www.w3.org/2000/svg');
$this->set_attr('version', '1.1');
$this->set_attr('width', $width);
$this->set_attr('height', $height);
//On passe à la balise suivante
$this->nextBalise();
}
public function set_attr($attribut, $valeure, $separateur = ' ', $balise = false)
{
//On assigne éventuellement une valeure à $balise
if($balise === false)
{
$balise = $this->last;
}
//On vérifie qu'une balise soit bien ouverte
if(!is_object($this->balises[$balise]))
{
return;
}
//On assigne un attribut
$this->balises[$balise]->extendAttr($attribut, $valeure, $separateur);
}
public function resetAttr($attribut, $balise = false)
{
//On assigne éventuellement une valeure à $balise
if($balise === false)
{
$balise = $this->last;
}
//On remet l'attribut à 0
$this->balises[$balise]->addAttr($attribut, '');
}
public function addStyle($propriete, $valeur, $balise = false)
{
//On assigne éventuellement une valeure à $balise
if($balise === false)
{
$balise = $this->last;
}
//On ajoute le style
$this->balises[$balise]->addStyle($propriete, $valeur);
}
public function addBalise($baliseName, $toClose)
{
//On vérifie qu'il n'y ai pas une balise ouverte
if(isset($this->balises[$this->last]))
{
$this->closeBalise();
}
//On ajoute la balise
$this->balises[$this->last] = new balise($baliseName, $toClose);
}
public function closeBalise()
{
$this->balises[$this->last + 1] = 'CLOSE';
$this->last += 2;
}
public function nextBalise()
{
$this->last++;
}
public function drawRect($x, $y, $height, $width, $rx = 0, $ry = 0)
{
//On créé la balise
$this->addBalise('rect', false);
//On ajoute les attributs
$this->set_attr('x', $x);
$this->set_attr('y', $y);
$this->set_attr('height', $height);
$this->set_attr('width', $width);
//On vérifie pour les coins arrondis
if($rx != 0 || $ry != 0)
{
//On en met un
$this->set_attr('rx', $rx);
//Si les deux attributs sont égaux, inutile de mettre l'autre
if($rx != $ry)
{
$this->set_attr('ry', $ry);
}
}
//On récupère le numéro de la balise
$num = $this->last;
//On ferme la balise (on pourra toujours y ajouter des attributs, et elle n'est pas censée contenir d'autres balises)
$this->closeBalise();
//On renvoi le numéro
return $num;
}
public function drawCarre($x, $y, $cote, $rx = 0, $ry = 0)
{
//On fait un rectangle particulier
return $this->drawRect($x, $y, $cote, $cote, $rx, $ry);
}
public function drawEllipse($x, $y, $rx, $ry)
{
//On créé la balise
$this->addBalise('ellipse', false);
//On ajoute les attributs
$this->set_attr('cx', $x);
$this->set_attr('cy', $y);
$this->set_attr('rx', $rx);
$this->set_attr('ry', $ry);
//On récupère le numéro de la balise
$num = $this->last;
//On ferme la balise (on pourra toujours y ajouter des attributs, et elle n'est pas censée contenir d'autres balises)
$this->closeBalise();
//On renvoi le numéro
return $num;
}
public function drawCercle($x, $y, $r)
{
//On créé la balise
$this->addBalise('circle', false);
//On ajoute les attributs
$this->set_attr('cx', $x);
$this->set_attr('cy', $y);
$this->set_attr('r', $r);
//On récupère le numéro de la balise
$num = $this->last;
//On ferme la balise (on pourra toujours y ajouter des attributs, et elle n'est pas censée contenir d'autres balises)
$this->closeBalise();
//On renvoi le numéro
return $num;
}
public function drawLigne($x1, $y1, $x2, $y2, $couleur)
{
//On créé la balise
$this->addBalise('line', false);
//On ajoute les attributs
$this->set_attr('x1', $x1);
$this->set_attr('y1', $y1);
$this->set_attr('x2', $x2);
$this->set_attr('y2', $y2);
//On ajoute ensuite la couleure
$this->addStyle('stroke', $couleur);
//On récupère le numéro de la balise
$num = $this->last;
//On ferme la balise (on pourra toujours y ajouter des attributs, et elle n'est pas censée contenir d'autres balises)
$this->closeBalise();
//On renvoi le numéro
return $num;
}
public function drawPolyline()
{
//On fait juste une balise ici
$this->addBalise('polyline', false);
//On récupère le numéro de la balise
$num = $this->last;
//On ferme la balise (on pourra toujours y ajouter des attributs, et elle n'est pas censée contenir d'autres balises)
$this->closeBalise();
//On renvoi le numéro
return $num;
}
public function drawPolygone()
{
//On fait juste une balise ici
$this->addBalise('polygon', false);
//On récupère le numéro de la balise
$num = $this->last;
//On ferme la balise (on pourra toujours y ajouter des attributs, et elle n'est pas censée contenir d'autres balises)
$this->closeBalise();
//On renvoi le numéro
return $num;
}
public function addPoint($x, $y, $balise)
{
//On ajoute le point à la balise
$this->set_attr('points', $x . ',' . $y, ' ', $balise);
}
public function drawBox($x, $y, $height, $width, $hauteur, $angle, $ligneCouleur)
{
//Cette figure est assez compliquée.
//En gros, c'est un polygone complexe, dans lequel on ajoute des lignes.
//Donc on va calculer la position des différents points. Les plus simples sont ceux de base : ceux du rectangle de base.
$point1 = array($x, $y); // Le point d'origine.
$point2 = array(($x + $width), $y); //Le second point, en haut à droite.
$point3 = array(($x + $width), ($y + $height)); //Le troisième point, en bas à droite.
$point4 = array($x, ($y + $height)); //Le troisième point, en bas à gauche.
//Maintenant un peu plus compliqué. Il nous faut calculer les trois points supplémentaires.
//Le plus simple à calculer est celui en haut à gauche : on utilise le théorème d'Al-Kashi pour calculer ses coordonnées.
$point5 = array(($x - ($hauteur * cos(deg2rad($angle)))), ($y - ($hauteur * cos(deg2rad(90 - $angle))))); //En haut à gauche
//Puis les autres sur cette base
$point6 = array(($x - ($hauteur * cos(deg2rad($angle)))), (($y - ($hauteur * cos(deg2rad(90 - $angle)))) + $height)); //En bas à gauche
$point7 = array((($x - ($hauteur * cos(deg2rad($angle)))) + $width), ($y - ($hauteur * cos(deg2rad(90 - $angle))))); //En haut à droite
//Maintenant on a tous nos points.
//On va donc les tracer.
//On commence par le polyline
$lstFig = array();
$lstFig[] = $this->drawPolygone();
//On défini son style
$this->addStyle('stroke', $ligneCouleur, $lstFig[0]);
//On ajoute les différents points, dans l'ordre
$this->addPoint($point4[0], $point4[1], $lstFig[0]);
$this->addPoint($point3[0], $point3[1], $lstFig[0]);
$this->addPoint($point2[0], $point2[1], $lstFig[0]);
$this->addPoint($point7[0], $point7[1], $lstFig[0]);
$this->addPoint($point5[0], $point5[1], $lstFig[0]);
$this->addPoint($point6[0], $point6[1], $lstFig[0]);
//On va maintenant tracer les trois lignes qui nous manque pour donner l'impression de 3d
$lstFig[] = $this->drawLigne($point1[0], $point1[1], $point4[0], $point4[1], $ligneCouleur);
$lstFig[] = $this->drawLigne($point1[0], $point1[1], $point2[0], $point2[1], $ligneCouleur);
$lstFig[] = $this->drawLigne($point1[0], $point1[1], $point5[0], $point5[1], $ligneCouleur);
//On va renvoyer l'ensemble des numéros des figures, c'est plus pratique
return $lstFig;
}
public function save($fileName)
{
//On ouvre le fichier
$fHandle = fopen($fileName, 'w+');
//On écrit d'abord le header
fwrite($fHandle, '<?xml version="1.0" standalone="no"?>' . "\n");
//Le DTD
fwrite($fHandle, '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' . "\n");
//On ajoute toutes les balises une après l'autre
$closeList = array();
$actuBalise = 1;
foreach ($this->balises as $objBalise)
{
if(is_object($objBalise))
{
//On doit ecrire une balise
$balise = $objBalise->make();
fwrite($fHandle, '<!-- Ouverture : Balise #' . $actuBalise . ' -->' . "\n");
$actuBalise++;
fwrite($fHandle, $balise . "\n");
$closeList[] = $objBalise->close();
} else {
//On doit fermer une balise
$actuBalise--;
fwrite($fHandle, '<!-- Fermeture : Balise #' . $actuBalise . ' -->' . "\n");
fwrite($fHandle, $closeList[count($closeList) - 1] . "\n");
unset($closeList[count($closeList) - 1]);
}
}
//On fini de fermer ce qui reste à fermer
if(count($closeList) > 0)
{
for($t = count($closeList) - 1; $t >= 0; $t--)
{
$actuBalise--;
fwrite($fHandle, '<!-- Fermeture : Balise #' . $actuBalise . ' -->' . "\n");
fwrite($fHandle, $closeList[$t] . "\n");
}
}
//On a fini, on ferme le fichier
fclose($fHandle);
}
}
class balise
{
private $baliseName;
private $toClose;
private $attrList = array();
public function __construct($baliseName, $toClose)
{
$this->baliseName = (string) $baliseName;
$this->toClose = (bool) $toClose;
}
public function addAttr($attribut, $value)
{
$this->attrList[$attribut] = $value;
}
public function extendAttr($attribut, $value, $separateur = ' ')
{
if(isset($this->attrList[$attribut]))
{
$this->attrList[$attribut] .= $separateur . $value;
} else {
$this->addAttr($attribut, $value);
}
}
public function addStyle($propriete, $valeur)
{
$style = $propriete . ': ' . $valeur;
$this->extendAttr('style', $style, ';');
}
public function close()
{
if($this->toClose)
{
return '</' . $this->baliseName . '>';
} else {
return '';
}
}
public function make()
{
$balise = '<' . $this->baliseName;
//On vérifie si il y a des arguements
if(count($this->attrList) > 0)
{
foreach ($this->attrList as $attribut => $valeure)
{
$balise .= ' ' . $attribut . '="' . $valeure . '"';
}
}
//On ferme la balise
$balise .= ($this->toClose) ? '>' : ' />';
//On renvoi le tout
return $balise;
}
}
?>
Et pour tester, voici un fichier tout bête : index.php
Code PHP :
<?php
include('classe_svg.php');
//On créé un svg
$svg = new svg_drawer(500, 500);
//On y ajoute un cube
$lstFig = $svg->drawBox(150, 150, 100, 80, 60, 30, '#000000');
//On va ajouter de la couleur à la figure de base
$svg->addStyle('fill', '#FFDDAA', $lstFig[0]);
//Et on enregistre le tout
$svg->save('monfichier.svg');
//On affiche un gentil lien
echo '<a href="monfichier.svg">Petit rectangle</a>';
?>