Reprise du projet MkDraw en SVG jour 3

Introduction
Pour le jour 2, on profite des avantages du SVG:

  • on peut selectionner un objet en cliquant dessus sur le dessin
  • on peut deplacer un objet par drag and drop
  • on peut exporter l’image généré

Sélection d’objet sur le dessin
Lorsque l’on dessine un objet, on met en temporaire l’id de celui-ci,
Dans le fichier public/js/data.js

1
2
3
build:function(){
  oApplication.dataIdDrawed=this.id;
(...)

Et dans le fichier public/js/canvas.js

1
2
3
4
drawRect : function(x,y,ilargeur,ihauteur,lineWidth,strokeStyle,fillStyle){
 
  //on ajoute la methode onMouseDown où l'on indique d'editer l'objet
  sSvg+='onMouseDown="oApplication.selectObject('+oApplication.dataIdDrawed+')" ';

Deplacement des objets en drag and drop
Ici la modification se fait en plusieurs endroits:
Dans public/js/canvas.js on active le drag and drop via l’event onMouseDown/onMouseUp

1
2
3
4
5
6
7
8
drawRect : function(x,y,ilargeur,ihauteur,lineWidth,strokeStyle,fillStyle){
 
  //on ajoute la methode onMouseDown où l'on indique d'editer l'objet
  // + on indique que l'on demarre le drag and drop
  sSvg+=' onMouseDown="oApplication.startDrag('+oApplication.dataIdDrawed+');oApplication.selectObject('+oApplication.dataIdDrawed+')"  ';

  //on stope le drag and drop lorsque l'on l'ache la souris
  sSvg+=' onMouseUp="oApplication.endDrag()" ';

La méthode startDrag() dans la classe public/js/application.js

1
2
3
startDrag:function(id){
    this.dragId=id;
},

Et endDrag()

1
2
3
endDrag:function(id){
    this.dragId=null;
},

Ensuite, sur la div où l’on affiche le svg, on ajoute un attribut onMouseMove

1
onmousemove="oApplication.mousemove(event)"

Qui permet de gérer le moment où l’on déplace l’objet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mousemove:function(e){
    var x=this.getXmouse(e);
    var y=this.getYmouse(e);
       
    var iWidth=(x-this.tmpX);
    var iHeight=(y-this.tmpY);
       
    if(this.dragId){


        oApplication.updateObject(this.dragId,'x',x-40);
        oApplication.updateObject(this.dragId,'y',y-40);
           
           
        return;
    }
(...)

Exportation de l’image
On ajoute ici un bouton pour exporter l’image

1
 

et la fonction concerné qui récupère le svg généré via la méthode innerHTML du dom

1
2
3
4
5
6
7
8
9
10
11
12
function exportPicture(){
    var oSvg=getById('tCanvas');
    sSvg=oSvg.innerHTML;
   
    var oContent=getById('content');
    oContent.value=sSvg;
   
    var oForm=getById('formexport');
    if(oForm){
        oForm.submit();
    }
}

Le formulaire soumis

1
2
3
<form target="_blank" id="formexport" action="" method="POST">
<textarea id="
content" name="content"></textarea>
</form>

Enfin, coté php pour afficher le code svg envoyé dans le module default, action « export »

1
2
3
4
5
6
7
8
9
public function _export(){
    _root::setConfigVar('site.mode','prod');
       
    $this-&gt;oLayout-&gt;setLayout('download');
    $this-&gt;oLayout-&gt;sFileName='export.svg';
    $this-&gt;oLayout-&gt;sExtension='svg';
       
    $this-&gt;oLayout-&gt;content=$_POST['content'];
}

Le fichier layout layout/download.php

1
2
3
4
5
6
7
sFileName."\"");
header('Content-Transfer-Encoding:binary');
header("Content-Type: application/".$this-&gt;sExtension.";name=\"".$this-&gt;sFileName."\"");

flush();
echo '';
echo $this-&gt;content;

Projet Github
Le projet est toujours hebergé ici: https://github.com/imikado/mkdrawsvg

Reprise du projet MkDraw en SVG jour 2

Introduction
Dans le précedent billet, je vous indiquais avoir entrepris la migration du projet MkDraw de canvas à SVG.

Etat d’avancement
La migration s’est plutot bien passé, la majorité du code à migrer étant centralisé dans les classes javascript Canvas.js et Application.js

application

Les gros changements canvas vers SVG
Si la migration a été rapide, je me retrouvais dans une situation peu propre, et surtout non satisfaisante:
En remplacant le code dessinant sur un objet canvas par le code SVG adéquat, je me retrouvais dans une situation, ou j’avais des div qui remplaçait mes canvas, je faisais comme pour l’application canvas, j’affichait ou cachait des calques en jouant sur l’attribut display de la div.
Mais cela ne donnait pas le resultat escompté: impossible d’interagir avec les objets sur l’espace de travail: en effet, chaque forme dessiné étant dans un div posé les uns aux dessus des autres il m’etait impossible d’user des avantages du format SVG.
J’ai donc repenser le mode de fonctionnement des calques pour qu’on arrive au final à générer un seul fichier SVG

Les avantages de cette version par rapport à MkDraw
Vous pouvez cliquer sur les objets sur l’espace de travail: chaque groupe contient un attribut onClick qui permet de passer l’objet en édition.
Vous pouvez donc cliquer sur un objet pour le sélectionner, puis cliquer à un autre endroit pour l’y déplacer.
Ensuite, lorsque vous souhaitez dessiner un nouvel objet, l’espace de travail passe en rouge, avec une opacité de 50%: en effet, lorsque vous dessiner une nouvelle figure, il me faut la créer en SVG, et je ne peux pas l’inclure dans le SVG global, car c’est une figure temporaire.
Par exemple quand vous créer un rectangle, vous cliquez une première fois pour debuter l’angle haut gauche, puis vous deplacer la souris pour definir les dimensions de celui-ci. Ce faisant, il faut à chaque déplacement de la souris modifier cet objet temporaire, et ce n’est qu’une fois le second clic effectué que la nouvelle figure sera ajoutée au calque sélectionnée:
application2
Il y a un attribut onMousemove permettant de dessiner « à la volée » le futur objet
application3
Pour permettre ceci, j’ai toujours un div « canvas_tmp » dont l’attribut display passe à bloc (avec une transparence de 50%) seulement lorsqu’on clique sur un objet à ajouter, sinon ça cacherait mon svg et annulerait les interactions des objets :(

Projet Github
Le projet est toujours hebergé ici: https://github.com/imikado/mkdrawsvg

Reprise du projet MkDraw en SVG

Introduction
Il y a quelques mois j’ai travaillé sur un projet d’application web permettant de dessiner des schémas en utilisant le canvas.
Un membre du forum « SylvainPV » (que je remercie au passage) m’avais demandé pourquoi je n’avais pas utilisé SVG à la place du canvas.
Le projet étant bien avancé (sans parler du fait que je connaissais plus canvas qu’SVG) je ne me voyais pas tout reprendre de zéro en changeant de technologie de dessin.

Mais suite à des retours sur l’application actuelle, j’ai remis les mains dans le code et analysé l’effort à faire pour modifier la méthode de dessin du canvas au SVG

Canvas VS SVG
Deux technologies qui ont leurs avantages et inconvénients, deux technologies différentes de dessin l’un dessine en bitmap (canvas) l’autre en vectoriel (SVG)
Les avantages dont je souhaite profiter en migrant cette application

  • Permettre de selectionner un objet sur le calque en cliquant dessus
  • Profiter du format vectoriel: on peut ainsi augmenter la taille du schéma sans perdre en qualité
  • Permettre d’ajouter des fenêtre contextuel + des liens sur les objets

Un des défauts de la version Canvas, c’est que l’on dessine sur une image, mais il est ensuite difficile de sélectionner sur l’espace de travail un objet pour pouvoir le déplacer, redimensionner ou autre. Pour pallier à ce problème j’ai ajouté des petits icones de crayons en utilisant des « div » avec un lien javascript.

L’objet de la migration
Pour migrer en SVG, il faut supprimer toute trace de canvas: on garde les div utilisés mais on ne dessine plus sur le canvas.
Pour dessiner en SVG on créé dans le DOM de la page HTML du code SVG.

Quelques exemples de migration
On modifie ici principalement le fichier public/js/canvas.js
On passe de ceci:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
drawRect : function(x,y,ilargeur,ihauteur,lineWidth,strokeStyle,fillStyle){
 
    this.ctx.beginPath();
 
    this.ctx.lineWidth=lineWidth;
    this.ctx.strokeStyle=strokeStyle;
    this.ctx.fillStyle=fillStyle;
 
    this.ctx.fillRect(x,y,ilargeur,ihauteur);
    this.ctx.strokeRect(x,y,ilargeur,ihauteur);
 
    this.ctx.closePath();
 
},

A ceci (note je ne peut pas mettre les chevrons inférieur et suppérieur remplacé ici par « [ » et « ] »)

1
2
3
4
5
6
7
drawRect : function(x,y,ilargeur,ihauteur,lineWidth,strokeStyle,fillStyle){
 
    var sSvg='[rect class="chartRect" id="rect'+x+''+y+'" x="'+x+'" y="'+y+'" width="'+ilargeur+'" height="'+ihauteur+'" style="fill:'+fillStyle+';stroke-width:'+lineWidth+';stroke:'+strokeStyle+'"][/rect]';
 
    this.addObject(sSvg);
 
},

Projet Github
Le projet est disponible sous licence LGPLv3 ici https://github.com/imikado/mkdrawsvg