Journal de bord: création d’une application de création de schéma en HTML5: Jour 2

Introduction
Ce billet fait suite au billet: http://blog.developpez.com/ducodeetdulibre/p12464/developpement/journal-de-bord-creation-dune-application-de-creation-de-schema-en-html5-jour-1

Dans ce billet je vais un peu plus expliquer comment fonctionne l’application, puis dans un second temps j’indiquerai les modifications du jour.

Les calques
L’application à la manière d’un photoshop/inkscape ou Gimp gère les calques: il y a un bouton pour ajouter des calques qui fait appel à la méthode addLayer de la classe application
Dans le fichier public/js/application.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
addLayer:function(){
    this.addMenuLayer(this.idLayer);
       
    var sCanvas='';
       
    this.addContent('tCanvas',sCanvas);
       
       
    this.tLayer[this.idLayer]=new Canvas('canvas_'+this.idLayer);
       
    this.tLayer[this.idLayer].fillText(0,0,'Nouveau calque '+this.idLayer,'#000');
       
    this.selectLayer(this.idLayer);
       
    this.idLayer++;
},

Cette méthode créé un canvas sur la page + instancie un objet Canvas puis le stoque dans un tableau indexé par un id pour que l’on puisse interagir par la suite à chaque calque.
Puis le selectionne, pour que l’on puisse facilement lui ajouter des éléments

Pour information la classe Canvas se situe dans public/js/canvas.js elle permet de simplifier le dessin sur le canvas.

Les calques objets
Plutot que de dessiner simplement sur le canvas, comme on le ferait sur paint, l’idée est de créer des objets que l’on dessine sur les calques afin de pouvoir les modifier individuellement par la suite.
Pour cela, à chaque fois que l’on dessine un élement, on instancie un objet en utilisant la classe Data ( et en lui indiquant son calque).
Puis on lui demande de se dessiner sur le calque en appelant sa méthode build
Fichier public/js/data.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
build:function(){
       
        if(this.relativeObject!=''){
            var tmpRelativeObject=oApplication.getObject(this.relativeObject);
            if(tmpRelativeObject){
                this.x=this.relativeX+tmpRelativeObject.x;
                this.y=this.relativeY+tmpRelativeObject.y;
            }
        }
       
        if(this.type=='carre'){
            oApplication.tLayer[this.idLayer].drawRect(this.x,this.y,this.width,this.height,this.lineWidth,this.strokeStyle,this.fillStyle);
            oApplication.tLayer[this.idLayer].fillText(this.x+10,this.y+10,this.texte,this.strokeStyle,this.size);
        }else if(this.type=='texte'){
            oApplication.tLayer[this.idLayer].fillText(this.x,this.y,this.texte,this.strokeStyle,this.size);
        }else if(this.type=='ligne'){
            oApplication.tLayer[this.idLayer].line(this.x,this.y,this.x2,this.y2,this.strokeStyle,this.lineWidth);
        }else if(this.type=='fleche'){
            oApplication.tLayer[this.idLayer].arrow(this.x,this.y,this.x2,this.y2,this.strokeStyle,this.lineWidth);
        }else if(this.type=='bdd'){
            oApplication.tLayer[this.idLayer].drawBdd(this.x,this.y,this.width,this.height,this.lineWidth,this.strokeStyle,this.fillStyle);
            oApplication.tLayer[this.idLayer].fillText(this.x+10,this.y+30,this.texte,this.strokeStyle,this.size);
        }else if(this.type=='link'){
           
            var oFrom=oApplication.getObject(this.from);
            var oTo=oApplication.getObject(this.to);
            console.log('build link from:'+this.from+' to:'+this.to);
           
            if(!oFrom || !oTo){
            }else if(this.points!=''){
                if(oApplication.pointIdSelected!==''){
                    oApplication.tLayer[this.idLayer].linkPointWithSelected(oFrom,oTo,this.points,oApplication.pointIdSelected,this.strokeStyle,this.lineWidth);
                }else{
                    oApplication.tLayer[this.idLayer].linkPoint(oFrom,oTo,this.points,this.strokeStyle,this.lineWidth);
                }
            }else{
                console.log('oFrom et oTo'+oFrom+' '+oTo);
                oApplication.tLayer[this.idLayer].link(oFrom,oTo,this.strokeStyle,this.lineWidth);
               
            }
        }
       
        this.updateInfo();
    },

Comme vous pouvez le voir: en fonction du type d’element on va appeler une méthode différente de dessin sur le layer où est dessiné l’objet.

A partir de là on peut cocher/decocher un objet pour l’afficher ou non sur son calque.
Pour ce faire, on joue sur la propriété visible de l’objet et on demande à l’application de redessiner le calque:
Fichier public/js/application.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
showHideObject:function(idObject){
        var a=getById('checkbox_object_'+idObject);
        if(a){
            var oObject=this.getObject(idObject);
           
            if(a.checked){
                oObject.visible=1;
            }else{
                oObject.visible=0;
            }
           
            this.buildLayer(oObject.idLayer);
        }
       
    },

Qui appelle ensuite la methode de reconstruction du calque (toujours dans le même fichier)

1
2
3
4
5
6
7
8
9
10
11
12
13
buildLayer:function(idLayer){
        oApplication.tLayer[idLayer].clear();
       
        var iLength=this.tMenuLayerObject[idLayer].length-1;
       
        for(var i=iLength;i>=0;i--){
            var tmpObj=this.getObject(this.tMenuLayerObject[idLayer][i]);
            if(tmpObj && tmpObj.visible==1){
                tmpObj.build();
            }
        }
       
    },

Qui comme vous le voyez efface le calque (canvas) avant de boucler sur les claques objets pour dessiner ou non celui-ci en fonction de sa propriété visible.

Voila pour ce premier tour d’explication du fonctionnement de l’application

Les modifications du jour
On pouvait créer des liens dynamiques entre les objets: en créant un objet « link » et en indiquant les id from et to à relier dynamiquement.
A chaque re-dessin du calque il recuperait les coordonnées des deux elements pour construire un lien « cassé » entre les deux
Le problème c’est que si il y avait plusieurs liens dans le schémas on était frustré de ne pas avoir un peu la main sur chemin emprunté par ses liens.
Pour cela, on peut désormais cliquer sur le calque pour ajouter les points à utiliser pour faire son lien.
Ensuite on voit se lister les différents points ajouté comme « contrainte » avec la possibilité de les supprimer individuellement
Enfin on peut cliquer sur l’un de ces points pour le déplacer en cliquant (une fois sélectionné) sur son nouvel emplacement sur le calque

Le rendu en image
projets_mkdraw4

Dépot Github
Le dépot github: https://github.com/imikado/mkdraw