JeuWeb - Crée ton jeu par navigateur
Votre avis sur deux petites classes - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Votre avis sur deux petites classes (/showthread.php?tid=638)



Votre avis sur deux petites classes - Aramiil - 22-01-2007

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 :

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>';
?>

Ce n'est pas encore parfaitement commenté, je finalise les commentaires en général quand j'ai terminé la classe.

Voici un exemple de ce que ça donne : http://rpg-pentacle.info/svg/monfichier.svg (testé uniquement avec Firefox, je n'ai pas encore installé le plugin pour IE)

Voilou voilou :-) merci d'avance pour vos commentaires !


RE: Votre avis sur deux petites classes - LittleQI - 23-01-2007

Tu as fais du super boulot bravo
Cependant il existe deja une librairie qui genere du SVG avec PHP (http://phphtmllib.newsblob.com/), si tu veux t'en inspirer ou tout simplement la reutiliser.
Bon courage pour la suite


RE: Votre avis sur deux petites classes - X-ZoD - 23-01-2007

on peut faire quoi avec svg ?
je veux dire moi pour generer des images j'utilise la librairie gd mai ca doit etre hors sujet
svg je connais pas


RE: Votre avis sur deux petites classes - Aramiil - 23-01-2007

LittleQI : Le lien a l'air hs Undecided sinon merci pour le bon boulot :-)

X-ZoD : Avec du svg, on peut faire du dessin vectoriel. donc tout bêtement, du dessin (comme en flash par exemple), mais qui peut être zoomé sans perte de qualité (pratique pour les cartes, par exemple). Une démonstration impressionnante de ce que peux faire svg : http://empiresdorient.com/3D.svg (lien donné par LittleQI dans un autre sujet). Bon, ma classe n'en fait pas encore autant ^^"


RE: Votre avis sur deux petites classes - X-ZoD - 23-01-2007

ha oui kan mem !


ca sent les math la non?


RE: Votre avis sur deux petites classes - Aramiil - 23-01-2007

Yep, c'est pas mal de calcul pour trouver la formule à utiliser pour calculer la position des points ^^ Mais c'est amusant (enfin je trouve :-p)

Sinon, voici la version 0.2b des classes, qui sont maintenant au nombre de trois. Cette nouvelle version apporte pas mal de chose, notement la correction de plusieurs bugs ou erreurs de code (non-utilisation de la fonction addBalise(), par exemple, et un gros bug dans la fermeture des balises qui se déclarait pour les balises qui ne se fermaient pas seules), un nouveau moyen de déclarer les styles de base, à priori plus simple, et surtout la possibilité d'ajouter du texte ! Cela peut se faire de trois manières : en commentaire dans le fichier svg, en tant que texte affiché (le svg 1.1 ne gère pas nativement le texte sur plusieurs lignes, mais la classe corrige de manière transparente le problème : il suffit de séparer les lignes par un classique \n et la classe se charge du reste) ou en tant que titre (à mon grand regret, Firefox ne gère pas cette fonctionnalité...). En vrac, j'ai aussi ajouté la gestion des <defs> et plus particulierement des dégradés, qui peuvent maintenant assez facilement être créés par la classe.

Voici donc le code :

Code PHP :
<?php

class svg_drawer
{
private
$last = 0;
private
$balises = array();

public function
__construct($height, $width)
{
//On créé la balise SVG
$this->addBalise('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
addText($texte, $type)
{
//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 texte($texte, $type);
}

public function
closeBalise()
{
if(isset(
$this->balises[$this->last]))
{
$this->balises[$this->last + 1] = 'CLOSE';
$this->last += 2;
} else {
$this->balises[$this->last] = 'CLOSE';
$this->last += 1;
}
}

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(round(($x - ($hauteur * cos(deg2rad($angle))))), round(($y - ($hauteur * cos(deg2rad(90 - $angle)))))); //En haut à gauche

//Puis les autres sur cette base
$point6 = array(round(($x - ($hauteur * cos(deg2rad($angle))))), round((($y - ($hauteur * cos(deg2rad(90 - $angle)))) + $height))); //En bas à gauche
$point7 = array(round((($x - ($hauteur * cos(deg2rad($angle)))) + $width)), round(($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
drawTexte($texte, $fontSize, $x, $y, $interligne = 1)
{
//On commence par regarder si il y a plusieurs lignes de texte
//Note: Cette façon d'afficher plusieurs lignes de texte n'est pas correcte d'un point de vue sémantique, mais moins complexe à coder...
if(strstr($texte, "\n") !== false)
{
//On va séparer les différentes lignes
$texte = explode("\n", $texte);

//On prépare le tableau de résultats
$lstFig = array();
$t = 0;

//On ajoute chaque ligne de texte
foreach($texte as $phrase)
{
$lstFig[] = $this->drawTexte($phrase, $fontSize, $x, ($y + ($t * $fontSize) + $interligne));
$t++;
}

return
$lstFig;
} else {
//On ouvre une balise de texte
$this->addBalise('text', true);

//On lui donne les propriétés X et Y
$this->set_attr('x', $x);
$this->set_attr('y', $y);

//Et on ajoute le style de caractère
$this->addStyle('font-size', $fontSize . 'px');

//Puis on récupère le numéro
$num = $this->last;

//On passe à la balise suivante
$this->nextBalise();

//On ajoute ensuite la pseudo-balise de texte.
$this->addText(htmlentities($texte), texte::CDATA);

//On ferme les deux balises
$this->closeBalise();
$this->closeBalise();

//On renvoi le résultat
//On ne renvoi pas le numéro de la pseudo-balise de texte, qui ne peux de toutes façons pas être modifiée
return $num;
}
}

public function
addComment($commentaire)
{
//On ajoute simplement un texte de type commentaire
$this->addText($commentaire, texte::COMMENT);

//On récupère le numéro
$num = $this->last;

//On ferme la balise
$this->closeBalise();

//On renvoi le numéro
return $num;
}

public function
addDefs()
{
//On ajoute la balise
$this->addBalise('defs', true);

//On récupère le numéro
$num = $this->last;

//On passe à la balise suivante
$this->nextBalise();

//On renvoi le numéro
return $num;
}

public function
addTitre($titre)
{
//Attention, si cette fonction est appellée en-dehors d'une balise <defs>, je ne garantie rien...
//On ajoute d'abord une balise titre
$this->addBalise('title', true);

//On passe ensuite à la balise suivante, sans fermer la balise titre
$this->nextBalise();

//On ajoute le texte
$this->addText($titre, texte::LIBRE);

//On ferme les deux balise (la balise <title> et la pseudo-balise de texte)
$this->closeBalise();
$this->closeBalise();
}

public function
addLinearGradient($id, $x1, $y1, $x2, $y2)
{
//Attention, si cette fonction est appellée en-dehors d'une balise <defs>, je ne garantie rien...
//On ajoute la balise
$this->addBalise('linearGradient', true);

//On ajoute les cinq attributs
$this->set_attr('id', $id);
$this->set_attr('x1', $x1 . '%');
$this->set_attr('y1', $y1 . '%');
$this->set_attr('x2', $x2 . '%');
$this->set_attr('y2', $y2 . '%');

//On récupère le numéro
$num = $this->last;

//On passe à la balise suivante
$this->nextBalise();

//On renvoi le numéro
return $num;
}

public function
addRadialGradient($id, $r, $fx, $fy, $cx, $cy)
{
//Attention, si cette fonction est appellée en-dehors d'une balise <defs>, je ne garantie rien...
//On ajoute la balise
$this->addBalise('radialGradient', true);

//On ajoute les six attributs
$this->set_attr('id', $id);
$this->set_attr('r', $r . '%');
$this->set_attr('fx', $fx . '%');
$this->set_attr('fy', $fy . '%');
$this->set_attr('cx', $cx . '%');
$this->set_attr('cy', $cy . '%');

//On récupère le numéro
$num = $this->last;

//On passe à la balise suivante
$this->nextBalise();

//On renvoi le numéro
return $num;
}

public function
addStop($offset, $couleur, $opacity = 1)
{
//A utiliser uniquement dans un dégradé, à priori !

//On vérifie que l'opacité soit entre 0 et 1
//On vérifie que $valeur soit entre 0 et 1
if($opacity < 0.0 || $opacity > 1.0)
{
return;
}

//Contrairement aux dégradés, ces balises sont auto-fermantes.
$this->addBalise('stop', false);

//On ajoute la propriété offset
$this->set_attr('offset', $offset . '%');

//Et les deux propriétés de remplissage passées en style
$this->addStyle('stop-color', $couleur);
$this->addStyle('stop-opacity', $opacity);

//On garde l'id
$num = $this->last;

//On ferme la balise puisqu'elle n'est pas censée contenir autre chose
$this->closeBalise();

//Et on renvoi l'id
return $num;
}

public function
styleFill($couleur, $balise = false)
{
//On assigne éventuellement une valeure à $balise
if($balise === false)
{
$balise = $this->last;
}

$this->addStyle('fill', $couleur, $balise);
}

public function
styleStroke($couleur, $balise = false)
{
//On assigne éventuellement une valeure à $balise
if($balise === false)
{
$balise = $this->last;
}

$this->addStyle('stroke', $couleur, $balise);
}

public function
styleFillOpacity($valeur, $balise = false)
{
//On vérifie que $valeur soit entre 0 et 1
if($valeur < 0.0 || $valeur > 1.0)
{
return;
}

//On assigne éventuellement une valeure à $balise
if($balise === false)
{
$balise = $this->last;
}

$this->addStyle('fill-opacity', $valeur, $balise);
}

public function
styleStrokeOpacity($valeur, $balise = false)
{
//On vérifie que $valeur soit entre 0 et 1
if($valeur < 0.0 || $valeur > 1.0)
{
return;
}

//On assigne éventuellement une valeure à $balise
if($balise === false)
{
$balise = $this->last;
}

$this->addStyle('stroke-opacity', $valeur, $balise);
}

public function
styleUseID($IDName)
{
return
'url(#' . $IDName . ')';
}

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();
foreach (
$this->balises as $objBalise)
{
if(
is_object($objBalise))
{
//On doit ecrire une balise
$balise = $objBalise->make();
fwrite($fHandle, $balise . "\n");
$closeList[] = $objBalise->close();
} else {
//On doit fermer une balise
//Pour ça, on récupère la clef du dernier element
$close = end($closeList);

//On ecrit la fermeture
fwrite($fHandle, $close . "\n");

//Et on détruit l'élement
unset($closeList[key($closeList)]);
}
}

//On fini de fermer ce qui reste à fermer
if(count($closeList) > 0)
{
for(
$t = count($closeList) - 1; $t >= 0; $t--)
{
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;
}
}

class
texte
{
private
$type;
private
$value;

const
LIBRE = 0;
const
CDATA = 1;
const
COMMENT = 2;

public function
__construct($texte, $type)
{
$this->value = $texte;
$this->type = $type;
}

public function
close()
{
return
'';
}

public function
make()
{
switch (
$this->type)
{
case
self::LIBRE :
return
$this->value;
break;

case
self::CDATA :
return
'<![CDATA[' . "\n" . $this->value . "\n" . ']]>';
break;

case
self::COMMENT :
return
'<!-- ' . "\n" . $this->value . "\n" . '-->';
break;
}
}
}
?>

Et un fichier d'exemple (les classes sont supposées contenues dans le fichier classe_svg.php) :

Code PHP :
<?php

include('classe_svg.php');

//On créé un svg
$svg = new svg_drawer(500, 500);

//On y met les définitions
$svg->addDefs();

//On y ajoute un titre
$svg->addTitre('SVG Drawer version 0.2a');

//On ajoute un dégradé
$svg->addLinearGradient('degrade', 0, 0, 100, 100);

//On y met les couleurs
$svg->addStop(0, '#FFFFFF');
$svg->addStop(50, '#FFDDAA');
$svg->addStop(100, '#FFFFFF');

//On ferme le dégradé et les définitions
$svg->closeBalise();
$svg->closeBalise();

//Un petit commentaire pour tester
$svg->addComment('On devrait avoir fermé les defs ici, on passe au dessin');

//On trace un fond
$fond = $svg->drawCarre(0, 0, 500);

//On le rempli de noir
$svg->styleFill('#000000', $fond);

//On ajoute une boite
$lstFig = $svg->drawBox(80, 80, 300, 300, 80, 30, '#000000');

//On lui applique le dégradé
$svg->addStyle('fill', $svg->styleUseID('degrade'), $lstFig[0]);

//On créé un petit rectangle pour y mettre du texte
$texteRect = $svg->drawRect(50, 40, 40, 300, 10, 10);

//On le rempli de blanc transparent
$svg->styleFill('#FFFFFF', $texteRect);
$svg->styleFillOpacity('0.9', $texteRect);

//On y écrit ensuite du texte
$svg->drawTexte('SVG Drawer version 0.2b.' . "\n" . 'Le dessin vectoriel facile.', 15, 55, 55, 5);

//Et on enregistre le tout
$svg->save('monfichier.svg');

//On affiche un gentil lien
echo '<a href="monfichier.svg">Petit exemple</a>';
?>

Ce fichier d'exemple est un peu plus long que le précédent parce que j'ai eu envi de tester et de montrer un peu plus les fonctions disponibles dans la classe... Le résultat peut être vu ici : http://rpg-pentacle.info/svg/monfichier.svg

J'attends vos remarques et suggestions ^^ (prévu pour la prochaine version : ajout d'images non-svg en utilisant la balise prévue à cet effet, chargement d'images svg, et surtout transformations d'une image non-svg en image svg - si j'y arrive ^^")


RE: Votre avis sur deux petites classes - LittleQI - 23-01-2007

Aramiil a écrit :LittleQI : Le lien a l'air hs Undecided sinon merci pour le bon boulot :-)

Le lien est ok chez moi meme si j'ai besoin d'actualiser plusieurs fois pour que ça marche, sinon j'ai telechargé la librairie : empiresdorient.com/phphtmllib-2.5.4.tgz


RE: Votre avis sur deux petites classes - Aramiil - 23-01-2007

Merci, je vais regarder ce que ça donne et ce qu'il serait interessant d'integrer :-)