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

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

Dans ce billet on va voir plusieurs choses: l’ajout d’un webservice, la possibilité de sélectionner un objet sur le dessin et enfin la possibilité de dupliquer un objet.

Ajout d’un webservice
Il peut être utile de pouvoir générer un schéma à la volée. Ceci va être permis grâce à l’installation d’un webservice.
C’est également l’occasion de montrer comment développer un serveur webservice.

D’abord un fichier webservice.php dans le répertoire public/
Dans celui-ci on inclut le fichier index.php et l’on force le lancement du module de webservice

1
2
$_GET['nav']='webservice::index';
include('index.php');

Ensuite on créé un module webservice dans le répertoire module/

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
class module_webservice{
   
    public function _index(){
        ini_set("soap.wsdl_cache_enabled","0");

        $oPluginWsdl=new plugin_wsdl;
        $oPluginWsdl->setName('mkdraw');
        $oPluginWsdl->setUrl('http://localhost/mkframework/data/genere/mkdraw/public/webservice.php');
        $oPluginWsdl->addFunction('setContent');
            $oPluginWsdl->addParameter('id','int');
            $oPluginWsdl->addParameter('tObject','string');
            $oPluginWsdl->addParameter('tMenuLayerObject','string');
            $oPluginWsdl->addReturn('return','string');
            $oPluginWsdl->addReturn('ok','int');
           
        if(isset($_GET['WSDL'])) {
            //affichage du wsdl
            $oPluginWsdl->show();
           
        }else {
           
            $oServer = new SoapServer( 'http://localhost/mkframework/data/genere/mkdraw/public/webservice.php?WSDL', array('cache_wsdl' => WSDL_CACHE_NONE));                   
            $oServer->setClass('webservice');
            $oServer->handle();
           
           
        }
        exit;
    }
}
class webservice{
    public function setContent($id,$tObject,$tMenuLayerObject){
         
        $oSchema=model_schema::getInstance()->findById($id);
        $oSchema->tObject=$tObject;
        $oSchema->tMenuLayerObject=$tMenuLayerObject;
        $oSchema->save();
         
        return array('return'=>'test','ok'=>1);
       
    }
}

Ici, à la récupération de deux paramètres que sont le tableau d’objet sérialisé ainsi que le tableau de l’ordre des calques objets.

Possibilité de sélectionner un objet sur le dessin
L’idée c’est de permettre de cliquer sur un objet sur le dessin pour pouvoir l’éditer plutot que de cliquer à droite dans les calques objets.
Pour cela on va afficher un crayon cliquable sur les objets dont on veut permettre cette fonctionnalité: les carrés et bdd

Premièrement, on permet d’afficher un icone de crayon au dessus des objets
Ajout d’une méthode enableEdit sur la classe Data (data.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
enableEdit:function(){
       
        var divEdit=getById('edit_'+this.id);
        if(divEdit){
            divEdit.style.top=(this.y-5)+'px';
            divEdit.style.left=(this.x+10)+'px';
           
        }else{
       
            var sHtml='';
            sHtml+='<div id="edit_'+this.id+'" class="edit">';

            sHtml+='&nbsp;';

            sHtml+='</div>';

            oApplication.addContent('tEdit',sHtml);
        }
    },

note: on ne voit pas dans l’extrait de code le onClic (il a du être filtré), regardez cette methode dans le code via github: https://github.com/imikado/mkdraw/blob/master/public/js/data.js
Qui créé une cellule div avec une action lors du clic pour selectionner l’objet en question.
La question qui se pose ensute c’est quand afficher cette fonctionnalité, je suis parti sur le fait de cliquer sur un calque pour afficher tous les « crayons » des objets sur le calque.

Ensuite on va boucler pour afficher ces boutons d’édition lorsque l’on selectionne un calque.
Editez la méthode selectLayer() de la classe application.js
En ajoutant à la fin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        //on commence par effacer le div qui contient nos boutons
        var a=getById('tEdit');
        if(a){
            a.innerHTML='';
        }
        //puis en boucle on affiche le bouton si l'objet est un carre ou une bdd
        for(var i=0;i&lt;this.tObject.length;i++){
            if(!this.tObject[i]){ continue; }
            if(this.tObject[i].idLayer==idLayer &amp;&amp; (this.tObject[i].type==&quot;carre&quot; || this.tObject[i].type==&quot;bdd&quot;) ){
               
                this.tObject[i].enableEdit();
            }
           
        }

Permettre de dupliquer un objet
Il est souvent utile lorsque l’on fait un shéma de dupliquer un objet, on va le permettre en ajoutant un bouton dans le formulaire d’édition d’un objet.
Dans la méthode getForm() de data.js

1
2
3
4
if(this.type=='carre' || this.type=='bdd' || this.type=='losange'){
           
            sHtml+='<p></p>';
        }

On ajoute un bouton qui appelera la methode duplicate de la classe Application

Et dans la classe application, cette méthode de duplication:

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
duplicateObject:function(idObject){
        //on recupere l'objet à dupliquer
        var oTmpData=this.getObject(idObject);
       
        //on cree un nouvel objet
        var oNewData=new Data(oTmpData.type,oTmpData.idLayer);
        //que l'on decale de 10, afin de le voir
        oNewData.x=oTmpData.x+10;
       
        //liste des propriétés à copier
        var tColumn=Array(
                    'strokeStyle',
                    'fillStyle',
                    'width',
                    'height',
                    'from',
                    'comment',
                    'to',
                    'lineWidth',
                    'y',
                    'x2',
                    'y2',
                    'texte',
                    'size',
                    'info',
                    'relativeObject',
                    'relativeX',
                    'relativeY',
                    'textAlign',
                    'strokeStyleText',
                    'fromPosition',
                    'toPosition'
           
                );
       
        //on boucle sur ce tableau pour copier les propriétés
        //sur le nouvel objet
        for(var i=0;i&lt;tColumn.length;i++){
            oNewData[tColumn[i] ]=oTmpData[tColumn[i] ];
        }
        //on demande à l&#039;afficher.
        oNewData.build();
       
        this.addLayerObject(oTmpData.idLayer,oNewData);
       
        this.selectObject(oNewData.id);
       
    },

Voila pour les dernières fonctionnalités ajoutées.
On continue petit à petit à améliorer l'ergonomie et le confort de création de schéma avec cette application

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

Patreon ou la VOD 2.0

J’écoutes depuis quelques années pas mal de podcasts sur des sujets plus ou moins variés (dont vous pouvez retrouver un échantillon dans la rubrique podcasts du blog)
Je vais vous parler ici non pas d’un podcast spécifique mais d’une initiative qui devrait être suivi dans quelques temps par d’autres podcasts: patreon.

Aujourd’hui, vous connaissez la TV, le podcast, et la VOD, mais sur chacun de ces moyens vous ne pouvez pas « contribuer/remercier » leur auteurs.
Ici l’idée, plutôt que de s’abonner à une émission en payant une somme défini et identique pour tout le monde, vous donner ce que vous voulez par épisode avec quelques contreparties en échange.

Le crowfounding à le vent en poupe
A l’heure où on entend chaque semaine un défendant des « ayant droits » clamés haut et fort que les internautes d’aujourd’hui veulent tout sans jamais rien payer.
On a une monté en puissance des plateformes de financement participatif ou « crowfounding », que ce soit kickstarter, Ulule ou Indiegogo, de nombreux internautes décident d’investir dans des projets auxquels ils croient.

Patreon kesako ?
Patreon est un service de mise en relation/gestion de mécènat.
Patreon ne signifie pas patron mais mécène, en effet ici vous ne devenez pas le supérieur de la personne/émission rétribué mais un mécène: un soutient financier en quelque sorte.
Chaque émission/intervenant définit une liste de montant de rétribution (comme kickstarter/ulule..) avec des contreparties, vous définissez le montant que vous souhaitez investir par épisode/mois (selon les modalité définies par l’auteur) avec dans le cas d’un paiement par épisode la possibilité de mettre une limite mensuelle ;)
L’adresse du site: http://www.patreon.com/

Les rétributions
Elles sont plus ou moins nombreuses selon les projets.
patreonPledge

Les paliers
Ce sont les différentes étapes définis par l’auteur: elles permettent de « motiver » les donneurs/mécenes afin d’avoir un but à atteindre qui permettra d’améliorer la qualité production, de créer ou participer à un évenement…
patreonPaliers

On vote avec son portefeuille
Vous aussi, vous devez payer comme moi la redevance TV, celle permet officiellement de financer la création audiovisuelle nationale.
Ici vous choisissez de financer les émissions qui vous plaise, et contrairement à un abonnement à une chaine TV, vous pouvez

  • 1. définir la somme que vous donnez
  • 2. donner plus pour remercier davantage sur un ou plusieurs episodes
  • 3. arrêter du jour au lendemain de financer si l’emission perd en qualité

On aimerai bien avoir la même chose pour la TV, quels types d’émissions resteraient à l’antenne ou disparaitrait si ses spectateurs choisissaient de payer ou non pour celle-ci ?

Le rendez-vous tech, tente l’aventure
C’est suite à un tweet de @notPatrick que j’ai pu découvrir à travers l’initiative du rdvTech de passer par Patreon ce service.
Patrick Beja, l’animateur du rdvTech, appload, Positron est également régulièrement invité dans le podcast Anglophone TWIT (This week in tech)
Il propose à travers son émission de faire une revue des dernières actualités accompagnés d’intervenants toujours plus intéréssants et pertinent.
Je vous invite à le découvrir sur mon billet: http://blog.developpez.com/ducodeetdulibre/p12487/podcasts/presentation-dun-podcast-le-rendez-vous-tech

Conclusion
Comme vous avez pu le lire, ce site est interessant et propose une nouvelle forme de financement du podcasting ou tout autre création artistique ou non ;)

Présentation d’un podcast: le rendez-vous Tech

J’écoute de nombreux podcasts en plus de ma veille quotidienne, c’est un autre moyen de se tenir informé de l’actualité tech.
Mais c’est également l’occasion d’entendre des points du vues différents et pertinent qui aident à se faire un idée ou mieux comprendre une actualité.

Un podcast récurrent de qualité
Environ deux fois par mois, Patrick Beja vous propose dans son émission de débroussailler l’actualité tech avec deux ou trois intervenants.
Cette fréquence permet d’avoir un compte rendu de l’actualité assez frais et intéressant à écouter.

Des intervenants et un traitement de qualité
Dans chaque émission, Patrick essaie d’avoir un traitement de l’actualité tech dépouillé, pour cela il invite d’autres intervenants comme par exemple

  • Jeff Clavier (un investisseur vivant dans la silicon valley et fondateur de softTechVC)
  • Benoit Curdy (animateur phare du Podcast NipTech)
  • Jerome Keinbord (ex animateur du podcast SCUDS, animateur de NowTech.tv et co-animateur d’Appload)
  • Cédric Bonnet (animateur de GeekInc et co-animateur d’Appload)
  • ou le non moins célèbre Emmanuel Dorne alias Korben (auteur du célèbre blog éponyme Korben.info)

Ce ne sont pas les seuls, mais ce sont les plus connus aujourd’hui.
Ces intervenant ainsi que la volonté de Patrick de traiter au mieux les sujets permet d’avoir une information assez creusé et interessante.

Le podcast
Le podcast est disponible sur iTunes et également sur le site frenchspin à l’adresse http://frenchspin.com/category/le-rdv-tech/

Conclusion
Je vous invite à vous intéresser aux podcasts en général, de nombreux animateurs s’évertuent chaque jour à vous proposer un contenu de qualité sur des sujets divers et variés.
Le rendez-vous tech fait partie de ces podcasts francophone qui gagnent à être connus.

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

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

Dans ce billet, je vais expliquer la méthode pour enregistrer un schéma et le charger.
Je vais également indiquer les dernières avancées.

Enregistrer un schéma
L’idée est simple: sérialiser les éléments et les enregistrer en base de données.
Pour cela, un bouton « save » qui fait appel à une function save()

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
function loadSave(){
    //on serialize le tableau tObject
    var stObject=JSON.stringify( oApplication.tObject);
   
    //on enregistre la serialisation dans l'input tObject
    var b=getById('tObject');
    if(b){
        b.value=stObject;
    }
   
    //on fait de meme pour les calques objet, afin de conserver l'ordre
    var stMenuLayerObject=JSON.stringify( oApplication.tMenuLayerObject);
   
    var c=getById('tMenuLayerObject');
    if(c){
        c.value=stMenuLayerObject;
    }
}
function save(){
   
    loadSave();
   
    //une fois le chargement fait, on soumet le formulaire
    var a=getById('formSave');
    if(a){
        a.submit();
    }
}

Et coté php, dans le framework dans me module default

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private function processSave($oSchema){
        if(!_root::getRequest()-&gt;isPost()){
            return;
        }
       
        //on modifie les proporiétés tObject et tMenuLayerObject
        $oSchema-&gt;tObject=_root::getParam('tObject');
        $oSchema-&gt;tMenuLayerObject=_root::getParam('tMenuLayerObject');
        //on enregistre le shema
        $oSchema-&gt;save();
       
        //on redirige sur la page
        _root::redirect('default::schema',array('id'=&gt;$oSchema-&gt;id));
    }

Processus de chargement du shéma
L’idée est simple: on récupère le tableau d’objet sérialisé ainsi que le tableau indiquant l’ordre des calques objets
Données que l’on assigne à la vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//dans l'action schema
public function _schema(){
        //on initialize les variables a vide
        $tObject=null;
        $tMenuLayerObject=null;
       
        //on recupere l'enregistrement du shema en base
        $oSchema=model_schema::getInstance()-&gt;findById(_root::getParam('id'));
        if($oSchema){
            //on appel le processus d'enregistrement
            $this-&gt;processSave($oSchema);
           
            //on recupere les valeurs serialises
            $tObject=$oSchema-&gt;tObject;
            $tMenuLayerObject=$oSchema-&gt;tMenuLayerObject;
        }
       
       
        $oView=new _view('default::index');
        $oView-&gt;tObject=html_entity_decode($tObject);
        $oView-&gt;tMenuLayerObject=html_entity_decode($tMenuLayerObject);
       
        $this-&gt;oLayout-&gt;add('main',$oView);
    }

Ensuite dans la vue, on va reconstruire le schéma: on instancie un tableau avec la valeur serialisé de tObject (malheureusement, la coloration syntaxique ne permet pas de le voir correctement)

1
var tObject=tObject?&gt;;

On boucle sur ce tableau serialisé pour recréé les objets Datas

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
for(var i=0;i&lt; tObject.length;i++){
    if(!tObject[i]){ continue; }
    var oData=new Data(tObject[i].type,tObject[i].idLayer);
    oData.x=tObject[i].x;
    oData.y=tObject[i].y;
    oData.strokeStyle=tObject[i].strokeStyle;
    oData.fillStyle=tObject[i].fillStyle;
    oData.width=tObject[i].width;
    oData.height=tObject[i].height;
    oData.from=tObject[i].from;
    oData.comment=tObject[i].comment;
    oData.to=tObject[i].to;
    oData.lineWidth=tObject[i].lineWidth;
    oData.x2=tObject[i].x2;
    oData.y2=tObject[i].y2;
    oData.texte=tObject[i].texte;
    oData.size=tObject[i].size;
    oData.info=tObject[i].info;
    oData.relativeObject=tObject[i].relativeObject;
    oData.relativeX=tObject[i].relativeX;
    oData.relativeY=tObject[i].relativeY;
    oData.textAlign=tObject[i].textAlign;
    oData.strokeStyleText=tObject[i].strokeStyleText;
   
    oData.fromPosition=tObject[i].fromPosition;
    oData.toPosition=tObject[i].toPosition;
   
   
    oData.build();
   
    oApplication.addLayerObject(1,oData);
}

On fait de même pour le tableau de calques objet: sauf que cette fois on l’enregistre dans l’objet application, puis on boucle pour reconstruire les différents calques.

1
2
3
4
5
6
7
oApplication.tMenuLayerObject=tMenuLayerObject?&gt;;

for(var i=1;i&lt;=iMax;i++){
   
    oApplication.clearMenuObject(i);
    oApplication.builListMenuLayerObject(i);
}

Les avancées
On peut désormais ordonner les calques objets et cliquer sur un objet pour l’envoyer sur un autre calque.

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

Réviser ses expressions régulières en s’amusant

regex0Introduction
Dans la plupart des languages on a la possibilité d’utiliser des expressions régulières.
C’est d’habitude une chose plus ou moins complexe a écrire (selon son expérience). Un site a eu la bonne idée de mixer les mots croisés et les expressions régulières.
Ainsi, il nous faut comprendre les expressions pour remplir correctement les cases vides.

Comment jouer ?
Chaque couple de case représente une chaine de caractère, celle-ci doit respecter les expressions en abscisse et en ordonnée.
Par exemple pour cet exemple:
regex
Vous avez une chaine de 2 caractères qui doit respecter les expressions « AB » « [CA]* » et « (B|C)*
Ainsi pour la première case c’est B: l’expression en abscisse nous indique attendre « A puis B »: et la première case est déjà occupé par le A
Et en ordonné on a « B ou C »
Pour la seconde case, on a en abscisse: « C ou A » et en ordonnée « B ou C », c’est donc C

Vous avez compris le principe, je vous invite à vous y essayer c’est une autre manière de réviser en s’amusant :)

Le site: http://regexcrossword.com/

Comment choisir son framework php

siteBlogMVC
Introduction
Depuis quelques années, nous avons vu se developper sur notre plateforme php de nombreux frameworks.
Le plus difficile aujourd’hui est de choisir parmi eux.
Jusque là, vous aviez à votre disposition un tableau comparatif: http://socialcompare.com…
Aujourd’hui grâce à l’initiative du site grafikart, vous avez une autre manière de comparer: le projet blogmvc.com (http://blogmvc.com)

Présentation du projet
L’idée est simple: montrer comment coder la même application avec différents frameworks du marché.
Pour cela, l’auteur met à disposition un projet github + des spécifications + une demo HTML du rendu attendu.
Ensuite libre à chacun de proposer une version de ce projet développé avec son framework préféré.
siteBlogMVCgithub
Le projet github: https://github.com/Grafikart/BlogMVC

Les frameworks php présentées actuellement
Actuellement, seuls 5 frameworks php sont représentés:

L’adresse du site du projet:
http://blogmvc.com/

L’adresse du billet expliquant l’initiative: http://www.grafikart.fr/blog/comparer-frameworks-mvc

Présentation des arborescences des 5 projets
Arborescence fermée
blogMVCclosed

Arborescence dépliée
blogMVC

En espérant que cette initiative vous aide à trouver votre framework ;)

note: pour information, le projet n’est pas restreint aux frameworks php (il y a par exemple RoR et Django), libre à vous de proposer votre framework peut importe son langage (ruby, python, perl…)

Retour au menu principal

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&gt;=0;i--){
            var tmpObj=this.getObject(this.tMenuLayerObject[idLayer][i]);
            if(tmpObj &amp;&amp; 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

Journal de bord: création d’un bomberman-like en HTML5, jour 5

Introduction
Ce billet fait suite au billet: http://blog.developpez.com/ducodeetdulibre/p12456/developpement/journal-de-bord-creation-dun-bomberman-like-en-html5-jour-4

Plusieurs choses dans ce billet:
Premièrement je souhaiterais rappeler comment faire fonctionner le jeu (suite à une question sur github).
Deuxièmement je vais faire un petit point sur la séparation du code client / serveur
Enfin j’indiquerais les prochaines améliorations à venir

Comment faire fonctionner cette application
Cette application HTML5 se divise en 2 parties: la partie cliente : qui sera utilisée par les joueurs et la partie serveur qui non seulement fera tourner le jeu mais broadcastera également l’evolution du jeu à tous les joueurs.

Partie serveur
Pour la partie serveur, on utilise ici 2 choses: node.js et socket.io qui interprète le fichier « serverBomberM.js »
Pour le lancer

1
nodejs serverBomberM.js

Cette ligne de commande doit lancer le serveur et ne doit pas rendre la main, il rend la main qu’en cas d’erreur ;)
Cette partie serveur fait donc tourner le jeu, et écoute le port 1338
Il recalcule à intervale régulier la position de chaque joueur, bombes et gère les animations de ceux-ci + diffuse à chaque joueur des commandes pour mettre à jour la partie sur son navigateur.

Partie cliente
Cette partie là a été épurée, désormais elle contient uniquement la partie écoute d’action socket et dessin de la partie à l’écran + une partie pour envoyer ses commandes au serveur (action de presser une touche de clavier ou de la relacher)
Elle ouvre 2 choses sur le serveur:

  • le fichier socket.io qui est diffusé par le serveur http://votreserveur:1338/socket.io/socket.io.js
  • elle ouvre une connection socket (sur le meme port) http://votreserveur:1338

Avancement de la séparation client/serveur
Le chantier a bien avancé, la séparation est quasiment finie, j’aimerais vraiment au maximum épurée la partie cliente avant de commencer les prochaines mises à jour.
Cela permettra de vraiment tout gerer coté serveur node.js

Améliorations à venir
Le jeu est déjà jouable, mais il lui manque des choses de base comme le fait de ne pas avoir de Game Over, gérer plusieurs parties, il manque également des éléments de jeux comme les murs destructibles, et les bonus d’amélioration de bombes: (plus grand périmètre d’explosion), bombes uniquement horizontal/vertical…
Bref il y a matière à améliorer cette base pour avoir une jeu sympa et envisager de le mettre en ligne

Voila pour ce jour 5, ce projet est un peu en pause actuellement car je profites de ce que j’ai appris pour faire une autre application en parallèle, dont je fais également un journal de bord ;)
Pour les curieux: http://www.developpez.net/forums/d1413605/webmasters-developpement-web/javascript/journal-bord-creation-d-application-dessin/

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