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

Introduction
Depuis quelques temps déjà j’ai besoin de créer des schémas, si possible interactif.
Principalement des schémas d’architecture avec des serveurs, des bases de données ainsi que des liens entre eux.

Avec le développement des derniers jeux RTS et Bomberman en HTML5, j’ai appris à utiliser les canvas.

Je viens donc vous présenter ici l’application sur laquelle je travaille en ce moment: MkDraw.
Comme d’habitude, vous trouverez en bas de ce billet le lien vers le github du projet.

Présentation fonctionnelle de l’application
Cette application, basée sur le mkframework, permet de créer des schémas si besoin interactif.
Vous pouvez actuellement:

  • gérer des calques
  • afficher/cacher des calques/objets
  • créer des rectangles, lignes, flèches et bases de données
  • créer des liens entre certains éléments
  • placer des éléments de manière fixe ou relative (comme un aimant)
  • définir une couleur de fond, de bord ainsi que son épaisseur
  • écrire un texte sur un rectangle/base de données
  • créer une infobulle (avec html si besoin)
  • enregistrer votre schéma

Présentation technique
Dans cette application, je créé autant de canvas que de calques, chaque objet ajouté sur la map est un objet javascript.
Chaque objet est une instanciation de la classe Data dans le fichier public/js/data.js
Le constructeur:

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
function Data(type,idLayer){
    this.type=type;
    this.idLayer=idLayer;
    this.x;
    this.y;
    this.x2;
    this.y2;
   
    this.texte='';
    this.id=oApplication.idObject;
    this.size=11;
    this.visible=1;
   
    this.fillStyle='#ffffff';
    this.lineWidth=2;
    this.strokeStyle='#000000';
   
    this.from;
    this.to;
   
    this.comment='comment';
   
    this.info='';
   
    this.relativeObject='';
   
    this.relativeX=0;
    this.relativeY=0;
   
    this.points='';
   
    oApplication.tObject[this.id]=this;
   
    oApplication.idObject++;
   
    if(!oApplication.tMenuLayerObject[idLayer]){
        oApplication.tMenuLayerObject[idLayer]=Array();
    }
   
   
    oApplication.tMenuLayerObject[idLayer].unshift(this.id);
     
   
}

Dans ce constructeur, on définit les variables par défaut, incrément l’id général et on ajoute le nouvel objet en début de tableau d’objet.
Au moment de dessiner un objet sur la map, on appelle la méthode build() de l’objet:

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
Data.prototype={
    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!=''){
                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();
    },

Ci dessous un exemple de méthodes de dessin utilisées dans l’objet Canvas, notamment drawBdd()

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
,
    drawBdd:function(x,y,ilargeur,ihauteur,lineWidth,strokeStyle,fillStyle){
       
        this.ctx.lineWidth=lineWidth;
        this.ctx.strokeStyle=strokeStyle;
        this.ctx.fillStyle=fillStyle;
       
        var hauteurEllipse=30;
         
        //this.line(x,y,x,y+ihauteur);
        //this.line(x+ilargeur,y,x+ilargeur,y+ihauteur);
               
        var centerX=x+(ilargeur/2);
        var centerY=y;
       
        var width=ilargeur;
        var height=5;
       
        x=parseFloat(x);
        y=parseFloat(y);
        ilargeur=parseFloat(ilargeur);
        ihauteur=parseFloat(ihauteur);
               
        //fond
        this.ctx.beginPath();
       
            this.ctx.moveTo(x,y);
            this.ctx.bezierCurveTo(
                            x,y-hauteurEllipse,
                            x+ilargeur,y-hauteurEllipse,
                            x+ilargeur,y
            );
                                   
            this.ctx.moveTo(x+ilargeur,y);
            this.ctx.lineTo(x+ilargeur,y+ihauteur);
           
            this.ctx.moveTo(x,y);
            this.ctx.lineTo(x,y+ihauteur);
           
            this.ctx.moveTo(x+ilargeur,y);
            this.ctx.lineTo(x+ilargeur,y+ihauteur);
           
            this.ctx.moveTo(x+ilargeur,y+ihauteur   );
            this.ctx.bezierCurveTo(
                            x+ilargeur,y+ihauteur+hauteurEllipse,
                            x,y+hauteurEllipse+ihauteur,
                            x,y+ihauteur
            );                 
                               
            this.ctx.moveTo(x,y+ihauteur);
                                   
            this.ctx.lineTo(x,y+ihauteur);
            this.ctx.moveTo(x,y);
       
            this.ctx.fillRect(x,y,ilargeur,ihauteur);
           
            this.ctx.fill();
       
        this.ctx.closePath();
       
        //trait
       
        this.ctx.beginPath();
            this.ctx.moveTo(x,y);
            this.ctx.bezierCurveTo(
                                    x,y+hauteurEllipse,
                                    x+ilargeur,y+hauteurEllipse,
                                    x+ilargeur,y
                                    );
            this.ctx.moveTo(x,y);
            this.ctx.bezierCurveTo(
                                    x,y-hauteurEllipse,
                                    x+ilargeur,y-hauteurEllipse,
                                    x+ilargeur,y
                                    );
           
            this.ctx.moveTo(x,y+ihauteur);
            this.ctx.bezierCurveTo(
                                    x,y+hauteurEllipse+ihauteur,
                                    x+ilargeur,y+hauteurEllipse+ihauteur,
                                    x+ilargeur,y+ihauteur
                                    );
                                   
            this.ctx.moveTo(x,y);
            this.ctx.lineTo(x,y+ihauteur);
           
            this.ctx.moveTo(x+ilargeur,y);
            this.ctx.lineTo(x+ilargeur,y+ihauteur);
           
            this.ctx.stroke();
       
        this.ctx.closePath();
       
       
         
    }

ou link()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
,
    link:function(oFrom,oTo,color,border){
       
        var x1=oFrom.x+(oFrom.width/2);
        var y1=oFrom.y+(oFrom.height/2);
       
        var x2=oTo.x+(oTo.width/2);
        var y2=oTo.y+(oTo.height/2);
       
        //calcul centre
        var xCenter=x1+((x2-x1)/2);
       
        this.ctx.beginPath();
        this.ctx.lineWidth=border;
        this.ctx.strokeStyle = color;
        this.ctx.moveTo(x1,y1);
        this.ctx.lineTo(xCenter,y1);
        this.ctx.lineTo(xCenter,y2);
        this.ctx.lineTo(x2,y2);
        this.ctx.stroke();
    },

Quelques images de l’application
projets_mkdraw1

projets_mkdraw2

projets_mkdraw3

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