Prototype et SVG
Introduction
Pour créer un objet vectoriel , vous pouvez le faire directement dans votre
document SVG, ou bien le faire grâce aux méthodes DOM.
Dans la logique des docuuments structurés , il faut en premier lieu créer
l'élément (objet vectoriel) et ensuite lui rajouter les attributs dont il a besoin pour
exister (ou tous les cas être afficher sur la fenêtre de votre navigateur).
Le code a effectué est assez simple et pour une bonne pratique de programmation, nous mettons ses instructions dans une fonction .
Code 1
function addtosvg() {
/*this se refere a l'objet qui appelle la
méthode 'addtosvg'.
Ajoute l'objet Rectangle créer a la zone de dessin Svg
methode classique d'ajout d'element avec methode DOM */
// espace de nom svg
var svgns = "http://www.w3.org/2000/svg";
// creation d'un objet de type rect
var obj = svgDocument.createElementNS(svgns,'rect');
// ajout des attributs a cet objet
obj.setAttributeNS(null,'x',this.x);
obj.setAttributeNS(null,'y',this.y);
obj.setAttributeNS(null,'height',this.height);
obj.setAttributeNS(null,'width',this.width);
obj.setAttributeNS(null,'width',this.fill);
// on attache le tout au Svg (element racine dans ce cas)
svgDocument.documentElement.appendChild(obj);
}
... et fin de notre fonction ajoutant un nouvel objet (ici un objet rectangulaire) à
un document SVG.
En lançant votre fonction (lors du chargement du document par exemple) l'objet sera
créer et attacher à la balise racine <svg>
Pour être complet vous pouvez tout à fait faire ceci dans un test :
Code 2
fichier svg
<svg version="1.1"
baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="text/ecmascript" xlink:href="votre_nom_de fichier_JS.js"/>
</svg>
Plus simple je ne peux pas ...
Code 3
fichier javascript
var svgDocument = null;
svgDocument = window.document;
function Rectangle () {
// on donne des valeur 'statique'
this.x = 10;
this.y = 10;
this.height = 100;
this.width = 100;
this.fill = 'red';
/* et une 'methode de classe'*/
this.addtosvg = addtosvg;
}
/*pour faire tourner le tout il faut creer
un objet rectange et appeller sa propriété 'addtosvg' */
function addtosvg() {
var svgns = "http://www.w3.org/2000/svg";
var obj = svgDocument.createElementNS(svgns,'rect');
obj.setAttributeNS(null,'x',this.x);
obj.setAttributeNS(null,'y',this.y);
obj.setAttributeNS(null,'height',this.height);
obj.setAttributeNS(null,'width',this.width);
obj.setAttributeNS(null,'fill',this.fill);
svgDocument.documentElement.appendChild(obj);
}
// toujour les instructions dans une fonction
function Main () {
var r = new Rectangle();
r.addtosvg();
}
/*on lance cette fonction main lors du chargement
du document cia son objet global 'window'*/
window.onload = Main;
Mais à chaque fois que l'on crée une instance
d'un objet , on crée également autant de propriété et de méthodes
de classe Rectangle.
Ce qui peut vite poser des problèmes d'utilisation de processsus et d'espace mémoire.
Notre méthode addtosvg reste la même quelque soit le nombre d'objet rectangulaire créé.
Le but est que cette fonction soit prétente une seule fois et
ce pour tout nouvel objet.
Nous allons en faire une propriété d'objet que va hériter tout nouvel objet de
type Rectangle.
La propriété prototype
En svg , il existe d'autre forme de base que le rectangle ( cercle , chemin, ...) et la fa¸on de les ajouter
à un document SVG est toujours la m≖me.
Seul les attributs changent .
Nous pouvons donc facilement imaginer un ensemble de formes vectorielles avec des
des sous-ensembles pour chaque type d'objet répertorié par la DTD du SVG.
Cette ensemble peut comporter des propriété et méthodes commune à tous les types (comme une fonction d'ajout dynamique au fichier SVG),
et où chaqu sous-ensemble définit par son type d'objet comporte ses
spécificités.
Chaque nouvel instance d'objet créé avec le mot-clé new crée
automatiquement (depuis javascript 1.5) un objet prototype.
Lors de l'utilisation de propriétés et de méthodes de l'objet instancié par var objet = new Rectangle,
Javascript regarde en premier lieu si elle existe en tant que propriété de l'instance ((objet.addtosvg), sinon regarde dans celle
présente dans l'objet prototype.
Il faut bien sûr ajouter cette méthode à l'objet prototype.
En reprenant notre exemple d'ensemble(les objets vectoriels) et de sous-ensemble (les types d'objets), nous allons créer
un objet global pour toutes les propriété communes (un modè ou prototype d'objet) et
des objets spécifique à chaque type.
Code 4
function ObjetVectoriel() {
/*propri&eéacute;té et méthodes
communes à tous les types d'objets*/
}
function Rectangle () {
/*définition d'un type d'objet*/
}
/* Le type Rectangle devient une extension de
l'objet global 'ObjetVectoriel' et hérite de ses propriétés et
méthodes */
Rectangle.prototype = new ObjetVectoriel();
Dans cette syntaxe comprenez bien que l'objet Rectangle est une extension de l'objet
ObjetVectoriel.
Le langage Java utiliserait : class Rectangle extends ObjetVectoriel.
L'objet Rectangle dérive de l'objet ObjetVectoriel,
permettant à une instance de l'objet Rectangle d'utiliser ses propriétés mais aussi celle
de ObjetVectoriel.
De plus les propriétés de notre objet global ne sont pas re-copié , mais hérité grâce à l'objet prototype. (=> gain d'espace et de traitement) .
Mise en place du code
Reprenons le canevas de notre exemple :
- ObjetVectoriel : l'objet global
- methodes globales
- propriété globales
- Type d'objet
- Rectangle
- propriés de l'objet Rectangle
- méthodes de l'objet Rectangle
- Cercle
- propriété de l'objet Cercle
- méthodes de l'objet Cercle
...ect ...
- Rectangle
Et ainsi de suite pour autant de d'objet de type différents !
Pour notre exemple, et compliqué un peu les choses (quoi que ) j'ajoute un objet typeofobjet où l'on pourra mettre des propriétés et méthodes partagées par tous les types d'objets (rect, circle, ...) et également d'autres type d'objets si on le désire.
Dans ce cas il ne servira qu'à mettre une valeur PI (qui existe déjà en tant que constante) pour démontrer
un peu plus l'héritage.
Mais commençons à écrire notre code.
Définition des constructeurs
Restons logique et concis au maimum , en réalisant ce code étape par étape :
//ensemble globale function ObjetVectoriel() { { //sous-ensemble typeofobject function typeofobject() { } // constructeur des types function Rectangle() { } function Cercle() { } // definition des heritages typeofobject.prototype=new ObjetVectoriel; Rectangle.prototype = new typeofobject; Cercle.prototype = new typeofobject;
Notre code est presque terminé ...
Il nous suffit de définir qui fait quoi , et de gérer (contrôler) nos
appels de fonctions et de constructeur .
Vous devriez , avec les codes déjà proposés, pouvoir terminer ce script .
Etablir ce que fait chaque constructeur
Que fait function ObjectVectoriel
Elle a une méthode globale que tous les objets hériterons.
Il faut donc définir la propriété et la fonction associée :
Code 6
function ObjetVectoriel() {
this.addtosvg = addtosvg;
// methode de classe
}
/* definition de cette fonction ou vous
voulez , MAIS avant qu'elle ne soit appellee ..*/
function addtosvg() {
var svgns = 'http://www.w3.org/2000/svg';
var obj = svgDocument.createElementNS(svgns,this.type);
//selon le type choix des attributs
switch(this.type) {
case 'rect' : {
obj.setAttributeNS(null,'x',this.x);
obj.setAttributeNS(null,'y',this.y);
obj.setAttributeNS(null,'height',this.height);
obj.setAttributeNS(null,'width',this.width);
// particularite de la valeur de remplissage
obj.setAttributeNS(null,'fill',this.fill);
} break;
case 'circle' : {
obj.setAttributeNS(null,'r',this.r);
obj.setAttributeNS(null,'cx',this.cx);
obj.setAttributeNS(null,'cy',this.cy);
obj.setAttributeNS(null,'fill',this.fill);
} break;
default : {
// on genere une erreur si aucun des type reference
alert("le type d'objet n'est pas un type vectoriel");
}
}
//on attache au SVG
svgDocument.documentElement.appendChild(obj);
}
Quelques explications
Lors de la crétion d'objets vectoriels, et comme ils n'ont pas tous les mêmes
attributs, nous allons indiquer quel type d'objet nous créons ('rect', 'circle', ....).
L'instance d'objet 'o' ( var o = new Rectangle va appeller
la méthode 'o' (o.addtosvg()) et donc
le mot clé this va automatiquement se référer à l'objet qui l'appelle.
Passons au constructeur des types d'objets ,ce sera de suite plus clair .
Que font les constructeur de type
Code 7
function Rectangle(type,fill,x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.type = type;
this.fill = fill;
}
function Cercle(type, fill,r, cx, cy) {
this.r = r;
this.cx = cx;
this.cy = cy;
this.type = type;
this.fill = fill;
}
Le type est indiqué en tant qu'argument , et va être rediriger (switch) vers les instructions
a exécuter selon sa valeur.
TODO : code répété (this.type = type;
this.fill = fill;) | => voir pour generaliser les attributs communs)