date de creation : April 06 2008 23:41:08.

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
    globale signifie ici , partagé par les différents types d'objets
  • 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 ...

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)

go to

@Todo

1. Il faut absolument afficher tous les codes des tutos de la même manière ...
Cela fait pas sérieux !

2. Encore vérifier les fautes d'orthographes et de frappes (amperstand)