SlideShare a Scribd company logo
1 of 9
Download to read offline
COBO
                      Aplicatie Web ce permite editarea
                   colaborativa a unei planse (whiteboard)
                    folosind facilitatile oferite de canvas

                                                       Coscotin Vasilica


       Abstract.        Cobo este o aplicatie web ce permite editarea colaborativa a unei planse
        folosind facilitatile oferite de elementul Canvas din HTML5. Comunicarea intre clienti
(browsere) se face folosind Socket.IO. Aplicatia ofera utilizatorului posibilitatea de a desena cu
diferite “creioane”, de a insera figuri geometrice , poze si text. Plansa poate fi salvata la nivel local si
restaurat ulterior sau exportata in format PNG.

       1 Introducere
         Cobo a fost creata in cadrul laboratorului de Aplicatii Web la Nivel de Client de la Facultatea
de Informatica Iasi sustinut de Ciprian Amariei, profesor de curs fiind Dr. Sabin-Corneliu Buraga
.Aplicatia este Open Source sursa putand fi descarcata la adresa
http://students.info.uaic.ro/~vasilica.coscotin/cobo.

       2 Tehnologii folosite

         Cobo a fost creata folosind HTML5 , Javascript si Socket.IO. Elementul canvas din HTML5 a
permis redare in mod dinamic a scripturilor de redare a formelor 2D si a imaginilor de tip Bitmap. Am
folosit libraria jQuery ,pentru Javascript , pentru a realiza medodele de intercatiunde dintre utilizator si
browser . Pentru a permite comunicare in timp real intre clienti (browsere) am folosit Socket.IO care
este o implementare a interfetei HTTP Socket.
2.1 Canvas si Javascript

       2.1.1 Functii pentru desenare
       Fiecare canvas are un context de desenare in aplicatia COBO este unul 2D si este apelat in felul
urmator :
       var canvas = document.getElementById("sheet");
       var context = canvas.getContext("2d");
unde sheet este ID-ul elementului canvas din index.html.

       Pentru a desena forme geometrice in contextul context folosim urmatoarele functii :

     pentru a desena linii (unde x1,y1 sunt coordonatele mouse-ului cand are loc evenimetnul
mouseDown iar x2,y2 sunt coordonatele mouse-ului cand are loc evenimetnul mouseUp)
       var line = function(x1, y1, x2, y2, s) {
           s.globalCompositeOperation = 'source-over';
           setStyle(s);
           context.beginPath();
           context.moveTo(x1, y1);
           context.lineTo(x2, y2);
           context.closePath();
           context.stroke();
         }

      pentru a desena cu un creion (unde x1,y1 sunt coordonatele mouse-ului cand are loc
evenimetnul mouseDown iar x2,y2 sunt coordonatele mouse-ului cand are loc evenimetnul
mouseMove):
         var pencil = function(x1, y1, x2, y2, s) {
           s.globalCompositeOperation = 'source-over';
           setStyle(s);
           context.beginPath();
           context.moveTo(x1, y1);
           context.lineTo(x2, y2);
           context.closePath();
           context.stroke();
         }

     pentru a desena un cerc (unde x1,y1 sunt coordonatele mouse-ului cand are loc evenimetnul
mouseDown iar x2,y2 sunt coordonatele mouse-ului cand are loc evenimetnul mouseUp)
          var circle = function(x1, y1, x2, y2, s) {
            s.globalCompositeOperation = 'source-over';
            minX = (x1<x2) ? x1 : x2;
            minY = (y1<y2) ? y1 : y2;
            radiusX = Math.abs(x1 - x2) / 2;
            radiusY = Math.abs(y1 - y2) / 2;
            context.beginPath();
            setStyle(s);
            context.arc(minX+radiusX, minY+radiusY, radiusX, 0, 2*Math.PI, false);
            context.closePath();          context.stroke();    }
       pentru a desena un cerc (unde x1,y1 sunt coordonatele mouse-ului cand are loc evenimetnul
mouseDown iar x2,y2 sunt coordonatele mouse-ului cand are loc evenimetnul mouseUp)
         var rectangle = function(x1, y1, x2, y2, s) {
             s.globalCompositeOperation = 'source-over';
             minX = (x1<x2) ? x1 : x2;
             minY = (y1<y2) ? y1 : y2;
             xl = Math.abs(x1-x2);
             yl = Math.abs(y1-y2);
             setStyle(s);
             context.beginPath();
             context.rect(minX, minY, xl, yl);
             context.closePath();
             context.stroke();
           }
        In toate cele 4 functii parametrul s reprezinta stilul formei (culoare, grosime,transparenta,
lineJoin si lineCap).

         2.1.2 Mouse handlers
         Pentru a controla evenimentele mouse-ului am folosit urmatoarele functii:
         // event handler pentru Mouse Down
         $('#sheet').mousedown(function(e) {
            mouseDown = true; // pentru a verifica in mouseMove daca este tinut apasat clik
stanga
            mouseX = e.pageX - this.offsetLeft; // pentru a lua pozitia mouseului fata de
canvas
           mouseY = e.pageY - this.offsetTop;
           context.moveTo(mouseX, mouseY);
          switch(tool){
                    case Pen: // desenam in cazul in care unelata selectata este Pen
                           pencil(mouseX, mouseY, mouseX+1, mouseY, style);
                           msg = { "x1":mouseX, "y1":mouseY, "x2":mouseX+1, "y2":mouseY,
"tool":Pen, "style":style };
                           socket.send(JSON.stringify(msg));
                           break;
                    case Text:
                           if($('#textVal').val() != '')
                           {        //vreificam daca sunt bifate optiunile pentru bold
,italic si underline
                                  font = '';
                                  if($('#bold').is(':checked'))
                                         font += 'bold ';
                                         if($('#underline').is(':checked'))
                                         font += 'underline ';
                                  if($('#italic').is(':checked'))
                                         font += 'italic ';
                                  font += $('#penSize').slider('value')*5 + 'px sans-serif';
                                  context.font = font;
                                  context.fillStyle = style.strokeStyle;
                                  context.fillText($('#textVal').val(), mouseX, mouseY);
                                  msg = { "x":mouseX, "y":mouseY, "tool":Text, "font":font,
"text":$('#textVal').val(), "style":style };
                                  socket.send(JSON.stringify(msg));// trimitem la ceilalti
clienti prin server
                           }
                           break;
                    case IMAGE: // pentru a desa o imagine pe canvas
                           context.drawImage(image, mouseX, mouseY);
                           msg = { "x":mouseX, "y":mouseY, "image":image.src, "tool":Img };
                           socket.send(JSON.stringify(msg));
                           break;
                    break;

                       }
});

       // event handler pentru Mouse Up
       $('#sheet').mouseup(function(e) {
           mouseDown = false; // nu mai este tinut apasat click-ul
            newX = e.pageX - this.offsetLeft;// pentru a lua pozitia mouseului fata de canvas
            newY = e.pageY - this.offsetTop;// pentru a lua pozitia mouseului fata de canvas
            oldX = mouseX;
            oldY = mouseY;
           switch(tool) {
               case Pen: // nu facem nimic pentru ca desenarea s-a facut in cadrul mouseMove
                   break;
               case Circ: // desenam cecul din pozitia oldX oldY in pozitia newX newY si cu
diametrul = distanta dintre oldX newX respectiv oldY newY
                      circle(oldX, oldY, newX, newY, style);
                      msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY, "tool":Circ,
"style":style };
                      socket.send(JSON.stringify(msg));
                      break;
               case Rec:// desenam patratul din pozitia oldX oldY in pozitia newX newY si cu
diametrul = distanta dintre oldX newX respectiv oldY newY
                      rectangle(oldX, oldY, newX, newY, style);
                      msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY, "tool":Rec,
"style":style };
                      socket.send(JSON.stringify(msg));
                      break;
               case Line:// desenam linia din pozitia oldX oldY in pozitia newX newY si cu
diametrul = distanta dintre oldX newX respectiv oldY newY
                      line(oldX, oldY, newX, newY, style);
                      msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY, "tool":Line,
"style":style };
                      socket.send(JSON.stringify(msg));
               break;
               }
       });

      // event handler pentru mouse move

       $('#sheet').mousemove(function(e) {
           newX = e.pageX - this.offsetLeft;
           newY = e.pageY - this.offsetTop;
               if(mouseDown) { //cat timp e tinut apasat butonul de mouse deseneaza sau sterge
                      oldX = mouseX;
                      oldY = mouseY;
                      switch(tool){
                             case Pen:
                                    pencil(oldX, oldY, newX, newY, style);
                                    msg = { "x1":oldX, "y1":oldY, "x2":newX,
"y2":newY,"tool":Pen,"style":style };
                                    socket.send(JSON.stringify(msg));
                                    mouseX = newX;
                                    mouseY = newY;
                                    break;
                             case Eraser:
                                    eraser(oldX, oldY, newX, newY, style);
                                    msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY,
"tool":Eraser, "style":style };
                                    socket.send(JSON.stringify(msg));
                                    mouseX = newX;
                                    mouseY = newY;
                                    break;
                             break;
                      }
                }
       });
       // cand mouse-ul paraseste suprafata canvasului
       $('#sheet').mouseleave(function() {
mouseDown = false;
        });


       Aceste evenimente apar la actiunile mouse-ului pe suprafata browser-ului.

       2.1.3 Alegerea culorii

       Alegerea culorii se face prin alegerea cantitatilor de rosu, albastru si verde prin miscarea la
stanga sau dreapta a slider-elor


      // color and size
      //regleaza in fuctie de slider-e
colaore(cantitatea de Red, Green si Blue)
        $('#red').slider({
            value: 95,
            min: 0,
            max: 255,
            slide: function(event, ui) {
                changeColor();
            }
        }).width(160);

          $('#green').slider({
              value: 221,
              min: 0,
              max: 255,
              slide: function(event, ui) {
                  changeColor();
              }
          }).width(160);

          $('#blue').slider({
              value: 122,
              min: 0,
              max: 255,
              slide: function(event, ui) {
                  changeColor();
              }
          }).width(160);

          $('#opac').slider({
              value: 100,
              min: 0,
              max: 100,
              slide: function(event, ui) {
                  changeColor();
              }
          }).width(160);

      //Schimb culoarea pensulei actualizand style- ul si in acleasi timp schimb
si culoarea fundalului din div-ul Selected color
      var changeColor = function(){
      c = 'rgba(' + $('#red').slider('value') + ',' + $('#green').slider('value') +
',' + $('#blue').slider('value') + ',' + ($('#opac').slider('value') / 100) + ')';
      $('#selectedColor').css({backgroundColor: c});
      style.strokeStyle = 'rgb(' + $('#red').slider('value') + ',' + $
('#green').slider('value') + ',' + $('#blue').slider('value') + ')';
style.globalAlpha = ($('#opac').slider('value') / 100);
       }

       2.1.3 Dimensiune pensulei

       Dimensiune este setata tot cu ajutorul unui slider

       $('#penSize').slider({
       value: 2,
       step: 0.1,
       min: 0.5,
       max: 20,
       slide: function(event, ui) {
           style.lineWidth = ui.value;
       }
       }).width(160);

       2.1.4 Actiuni pe fisier

        Dupa cum am precizat si in abstract aplicatia ofera utilizatului posibiliatatea de a salva desenul
la nivel local , de a restaura desenul salvat si de a exporta desenul in format PNG. Aceste actiuni sunt
realizate in cu jQuery :

// file functions
     //salveaza imaginea canvas la nivel-ul browser-ului
     var saveFile = function(){
           localStorage.setItem("sheet", canvas.toDataURL());
     }
     $('#save').click(function() {
           saveFile();
     });

       //deseneaza imaginea incarcata din "baza de date" a browser-ului
       var load = function(imageSource) {
             image = new Image();
             image.src = imageSource;
             canvas.width = canvas.width;
             context.drawImage(image, 0, 0);
       }
       //incarca imaginea din "baza de date" a browserului
         $('#load').click(function() {
           imageSource = localStorage.getItem("sheet");
           load(imageSource);
           msg = { "tool":Load, "image":imageSource };
           socket.send(JSON.stringify(msg));
         });
       //face o coala noua stergat tot ce este in canvas
       $('#newSheet').click(function(){
             canvas.width = canvas.width;
             msg = { "tool":New };
             socket.send(JSON.stringify(msg));
       });

       //incarca o imagine selectata din dialog de selecare a unui fisier
       $('#imageSource').change(function() {
       var file = document.getElementById('imageSource').files[0];
       reader = new FileReader();
reader.onload = function (event) {
              image = new Image();
              image.src = event.target.result;
        };
        reader.readAsDataURL(file);
        tool = IMAGE;
        });

        //exporta imagina in fomrat Png
          $('#export').click(function() {
              window.open(canvas.toDataURL());
  });

        2.2 Transmiterea datelor

      Transmiterea datelor se cu ajutorul Socket.IO care in functie de browser selecteaza un protocol
de comunicare WebSocket pentru Google Chrome, xhr-multipart pentru Mozilla.

        Functiile pentru trasferul datelor sunt urmatoarele:

        //realoziaza conexiunea la server
          var socket = new io.Socket('localhost',{
              port: 9125
              });

          socket.connect();

      //trimite date la ceilalti clienti in functie de toolul selectat
        socket.on('message', function(msgData) {
          msgData = $.parseJSON(msgData);
            switch(msgData.tool){
                  case Pen:
                        pencil(msgData.x1, msgData.y1, msgData.x2, msgData.y2,
msgData.style);
                        break;
                  case Circ:
                        circle(msgData.x1, msgData.y1, msgData.x2, msgData.y2,
msgData.style);
                        break;
                  case Rec:
                        rectangle(msgData.x1, msgData.y1, msgData.x2, msgData.y2,
msgData.style);
                        break;
                  case Text:
                        context.font = msgData.font;
                              context.fillStyle = msgData.style.strokeStyle;
                              context.fillText(msgData.text, msgData.x, msgData.y);
                        break;
                  case Load:
                        load(msgData.image);
                        break;
                  case New:
                        canvas.width = canvas.width;
                        break;
                  case IMAGE:
                        image = new Image();
                        image.src = msgData.image;
                        context.drawImage(image, msgData.x, msgData.y);
                        break;
case Eraser:
                        eraser(msgData.x1, msgData.y1, msgData.x2, msgData.y2,
msgData.style);
                        break;
                  break;}
       });              break;
                  case Line:
                        line(msgData.x1, msgData.y1, msgData.x2, msgData.y2,
msgData.style);
                        break;
                  case Text:
                        context.font = msgData.font;
                              context.fillStyle = msgData.style.strokeStyle;
                              context.fillText(msgData.text, msgData.x, msgData.y);
                        break;
                  case Load:
                        load(msgData.image);
                        break;
                  case New:
                        canvas.width = canvas.width;
                        break;
                  case IMAGE:
                        image = new Image();
                        image.src = msgData.image;
                        context.drawImage(image, msgData.x, msgData.y);
                        break;
                  case Eraser:
                        eraser(msgData.x1, msgData.y1, msgData.x2, msgData.y2,
msgData.style);
                        break;
                  break;}
       });
3 Modalitate de utilizare




        Din meniul din dreapta sus se alege pensula pentru desenare posibilitatile fii :
Pencil, Line, Recangle, Circle, Eraser dupa care se deseneaza pe canvas ( foaia alba ).
        Meniul din dreapta se poate alege culoare pensulei precum si dimensiunea acestia (la optiunea
size). Tot aici la submeniu text putem scrie textul ce urmeaza sa fie inserat si selecta stilul textului
(Bold,Italic,Underline)
        Din partea de sus meniului putem selecta daca sa salvam imaginea la nivel local , sa reincarcam
imaginea salvata si sa o exportam in format PNG intr-o alta fereastra.



              4 Bibliografie
              http://socket.io/
              http://www.w3schools.com/
              http://docs.jquery.com/Main_Page
              http://profs.info.uaic.ro/~busaco/teach/courses/cliw/web.html

More Related Content

Viewers also liked

Chinawhite Franchise Proposal Ac Version
Chinawhite Franchise Proposal   Ac VersionChinawhite Franchise Proposal   Ac Version
Chinawhite Franchise Proposal Ac Versionrorykeegan
 
Hack for Diversity and Social Justice
Hack for Diversity and Social JusticeHack for Diversity and Social Justice
Hack for Diversity and Social JusticeTyrone Grandison
 
Brochure ete2011 (http://www.bercy.gouv.fr/directions_services/dgccrf/documen...
Brochure ete2011 (http://www.bercy.gouv.fr/directions_services/dgccrf/documen...Brochure ete2011 (http://www.bercy.gouv.fr/directions_services/dgccrf/documen...
Brochure ete2011 (http://www.bercy.gouv.fr/directions_services/dgccrf/documen...Ministère de l'Économie et des Finances
 
A survey of resources for introducing coding into schools
A survey of resources for introducing coding into schoolsA survey of resources for introducing coding into schools
A survey of resources for introducing coding into schoolsGrial - University of Salamanca
 
Blogs, Disruption and Reflective Learning
Blogs, Disruption and Reflective LearningBlogs, Disruption and Reflective Learning
Blogs, Disruption and Reflective Learningvogmae
 
Entrepreneur 2b or not 2 b indo german
Entrepreneur 2b or not 2 b   indo germanEntrepreneur 2b or not 2 b   indo german
Entrepreneur 2b or not 2 b indo germanthinkahead.net
 
Welcome & Introductory Remarks - IEEE 2014 Web 2.0 Security & Privacy Workshop
Welcome & Introductory Remarks - IEEE 2014 Web 2.0 Security & Privacy WorkshopWelcome & Introductory Remarks - IEEE 2014 Web 2.0 Security & Privacy Workshop
Welcome & Introductory Remarks - IEEE 2014 Web 2.0 Security & Privacy WorkshopTyrone Grandison
 
Booklet 4 - Decorative
Booklet 4 - DecorativeBooklet 4 - Decorative
Booklet 4 - DecorativeGemmalea
 
Linked in for career development MBA Talk (08.12.11)
Linked in for career development MBA Talk (08.12.11)Linked in for career development MBA Talk (08.12.11)
Linked in for career development MBA Talk (08.12.11)WalterAkana
 
Evaluation and observations of virtual placements already star ted & Virtua...
Evaluation and observations of virtual placements already star ted & Virtua...Evaluation and observations of virtual placements already star ted & Virtua...
Evaluation and observations of virtual placements already star ted & Virtua...Grial - University of Salamanca
 
Catalogo neckermann
Catalogo neckermannCatalogo neckermann
Catalogo neckermannlortegap
 

Viewers also liked (19)

Firewall
FirewallFirewall
Firewall
 
Chinawhite Franchise Proposal Ac Version
Chinawhite Franchise Proposal   Ac VersionChinawhite Franchise Proposal   Ac Version
Chinawhite Franchise Proposal Ac Version
 
Bni1
Bni1Bni1
Bni1
 
Butterfly
ButterflyButterfly
Butterfly
 
Hack for Diversity and Social Justice
Hack for Diversity and Social JusticeHack for Diversity and Social Justice
Hack for Diversity and Social Justice
 
Yangtze
YangtzeYangtze
Yangtze
 
Brochure ete2011 (http://www.bercy.gouv.fr/directions_services/dgccrf/documen...
Brochure ete2011 (http://www.bercy.gouv.fr/directions_services/dgccrf/documen...Brochure ete2011 (http://www.bercy.gouv.fr/directions_services/dgccrf/documen...
Brochure ete2011 (http://www.bercy.gouv.fr/directions_services/dgccrf/documen...
 
A survey of resources for introducing coding into schools
A survey of resources for introducing coding into schoolsA survey of resources for introducing coding into schools
A survey of resources for introducing coding into schools
 
Blogs, Disruption and Reflective Learning
Blogs, Disruption and Reflective LearningBlogs, Disruption and Reflective Learning
Blogs, Disruption and Reflective Learning
 
Entrepreneur 2b or not 2 b indo german
Entrepreneur 2b or not 2 b   indo germanEntrepreneur 2b or not 2 b   indo german
Entrepreneur 2b or not 2 b indo german
 
Welcome & Introductory Remarks - IEEE 2014 Web 2.0 Security & Privacy Workshop
Welcome & Introductory Remarks - IEEE 2014 Web 2.0 Security & Privacy WorkshopWelcome & Introductory Remarks - IEEE 2014 Web 2.0 Security & Privacy Workshop
Welcome & Introductory Remarks - IEEE 2014 Web 2.0 Security & Privacy Workshop
 
Booklet 4 - Decorative
Booklet 4 - DecorativeBooklet 4 - Decorative
Booklet 4 - Decorative
 
Linked in for career development MBA Talk (08.12.11)
Linked in for career development MBA Talk (08.12.11)Linked in for career development MBA Talk (08.12.11)
Linked in for career development MBA Talk (08.12.11)
 
Evaluation and observations of virtual placements already star ted & Virtua...
Evaluation and observations of virtual placements already star ted & Virtua...Evaluation and observations of virtual placements already star ted & Virtua...
Evaluation and observations of virtual placements already star ted & Virtua...
 
Happiness
HappinessHappiness
Happiness
 
110330 rap-cheques
110330 rap-cheques110330 rap-cheques
110330 rap-cheques
 
Catalogo neckermann
Catalogo neckermannCatalogo neckermann
Catalogo neckermann
 
Dl Airport Diplays4[1]
Dl Airport Diplays4[1]Dl Airport Diplays4[1]
Dl Airport Diplays4[1]
 
Droits taxes-produits-energie-juillet 2011 dgddi
Droits taxes-produits-energie-juillet 2011 dgddiDroits taxes-produits-energie-juillet 2011 dgddi
Droits taxes-produits-energie-juillet 2011 dgddi
 

Cobo Coscotin Vasilica documentatie

  • 1. COBO Aplicatie Web ce permite editarea colaborativa a unei planse (whiteboard) folosind facilitatile oferite de canvas Coscotin Vasilica Abstract. Cobo este o aplicatie web ce permite editarea colaborativa a unei planse folosind facilitatile oferite de elementul Canvas din HTML5. Comunicarea intre clienti (browsere) se face folosind Socket.IO. Aplicatia ofera utilizatorului posibilitatea de a desena cu diferite “creioane”, de a insera figuri geometrice , poze si text. Plansa poate fi salvata la nivel local si restaurat ulterior sau exportata in format PNG. 1 Introducere Cobo a fost creata in cadrul laboratorului de Aplicatii Web la Nivel de Client de la Facultatea de Informatica Iasi sustinut de Ciprian Amariei, profesor de curs fiind Dr. Sabin-Corneliu Buraga .Aplicatia este Open Source sursa putand fi descarcata la adresa http://students.info.uaic.ro/~vasilica.coscotin/cobo. 2 Tehnologii folosite Cobo a fost creata folosind HTML5 , Javascript si Socket.IO. Elementul canvas din HTML5 a permis redare in mod dinamic a scripturilor de redare a formelor 2D si a imaginilor de tip Bitmap. Am folosit libraria jQuery ,pentru Javascript , pentru a realiza medodele de intercatiunde dintre utilizator si browser . Pentru a permite comunicare in timp real intre clienti (browsere) am folosit Socket.IO care este o implementare a interfetei HTTP Socket.
  • 2. 2.1 Canvas si Javascript 2.1.1 Functii pentru desenare Fiecare canvas are un context de desenare in aplicatia COBO este unul 2D si este apelat in felul urmator : var canvas = document.getElementById("sheet"); var context = canvas.getContext("2d"); unde sheet este ID-ul elementului canvas din index.html. Pentru a desena forme geometrice in contextul context folosim urmatoarele functii : pentru a desena linii (unde x1,y1 sunt coordonatele mouse-ului cand are loc evenimetnul mouseDown iar x2,y2 sunt coordonatele mouse-ului cand are loc evenimetnul mouseUp) var line = function(x1, y1, x2, y2, s) { s.globalCompositeOperation = 'source-over'; setStyle(s); context.beginPath(); context.moveTo(x1, y1); context.lineTo(x2, y2); context.closePath(); context.stroke(); } pentru a desena cu un creion (unde x1,y1 sunt coordonatele mouse-ului cand are loc evenimetnul mouseDown iar x2,y2 sunt coordonatele mouse-ului cand are loc evenimetnul mouseMove): var pencil = function(x1, y1, x2, y2, s) { s.globalCompositeOperation = 'source-over'; setStyle(s); context.beginPath(); context.moveTo(x1, y1); context.lineTo(x2, y2); context.closePath(); context.stroke(); } pentru a desena un cerc (unde x1,y1 sunt coordonatele mouse-ului cand are loc evenimetnul mouseDown iar x2,y2 sunt coordonatele mouse-ului cand are loc evenimetnul mouseUp) var circle = function(x1, y1, x2, y2, s) { s.globalCompositeOperation = 'source-over'; minX = (x1<x2) ? x1 : x2; minY = (y1<y2) ? y1 : y2; radiusX = Math.abs(x1 - x2) / 2; radiusY = Math.abs(y1 - y2) / 2; context.beginPath(); setStyle(s); context.arc(minX+radiusX, minY+radiusY, radiusX, 0, 2*Math.PI, false); context.closePath(); context.stroke(); } pentru a desena un cerc (unde x1,y1 sunt coordonatele mouse-ului cand are loc evenimetnul
  • 3. mouseDown iar x2,y2 sunt coordonatele mouse-ului cand are loc evenimetnul mouseUp) var rectangle = function(x1, y1, x2, y2, s) { s.globalCompositeOperation = 'source-over'; minX = (x1<x2) ? x1 : x2; minY = (y1<y2) ? y1 : y2; xl = Math.abs(x1-x2); yl = Math.abs(y1-y2); setStyle(s); context.beginPath(); context.rect(minX, minY, xl, yl); context.closePath(); context.stroke(); } In toate cele 4 functii parametrul s reprezinta stilul formei (culoare, grosime,transparenta, lineJoin si lineCap). 2.1.2 Mouse handlers Pentru a controla evenimentele mouse-ului am folosit urmatoarele functii: // event handler pentru Mouse Down $('#sheet').mousedown(function(e) { mouseDown = true; // pentru a verifica in mouseMove daca este tinut apasat clik stanga mouseX = e.pageX - this.offsetLeft; // pentru a lua pozitia mouseului fata de canvas mouseY = e.pageY - this.offsetTop; context.moveTo(mouseX, mouseY); switch(tool){ case Pen: // desenam in cazul in care unelata selectata este Pen pencil(mouseX, mouseY, mouseX+1, mouseY, style); msg = { "x1":mouseX, "y1":mouseY, "x2":mouseX+1, "y2":mouseY, "tool":Pen, "style":style }; socket.send(JSON.stringify(msg)); break; case Text: if($('#textVal').val() != '') { //vreificam daca sunt bifate optiunile pentru bold ,italic si underline font = ''; if($('#bold').is(':checked')) font += 'bold '; if($('#underline').is(':checked')) font += 'underline '; if($('#italic').is(':checked')) font += 'italic '; font += $('#penSize').slider('value')*5 + 'px sans-serif'; context.font = font; context.fillStyle = style.strokeStyle; context.fillText($('#textVal').val(), mouseX, mouseY); msg = { "x":mouseX, "y":mouseY, "tool":Text, "font":font, "text":$('#textVal').val(), "style":style }; socket.send(JSON.stringify(msg));// trimitem la ceilalti clienti prin server } break; case IMAGE: // pentru a desa o imagine pe canvas context.drawImage(image, mouseX, mouseY); msg = { "x":mouseX, "y":mouseY, "image":image.src, "tool":Img }; socket.send(JSON.stringify(msg)); break; break; }
  • 4. }); // event handler pentru Mouse Up $('#sheet').mouseup(function(e) { mouseDown = false; // nu mai este tinut apasat click-ul newX = e.pageX - this.offsetLeft;// pentru a lua pozitia mouseului fata de canvas newY = e.pageY - this.offsetTop;// pentru a lua pozitia mouseului fata de canvas oldX = mouseX; oldY = mouseY; switch(tool) { case Pen: // nu facem nimic pentru ca desenarea s-a facut in cadrul mouseMove break; case Circ: // desenam cecul din pozitia oldX oldY in pozitia newX newY si cu diametrul = distanta dintre oldX newX respectiv oldY newY circle(oldX, oldY, newX, newY, style); msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY, "tool":Circ, "style":style }; socket.send(JSON.stringify(msg)); break; case Rec:// desenam patratul din pozitia oldX oldY in pozitia newX newY si cu diametrul = distanta dintre oldX newX respectiv oldY newY rectangle(oldX, oldY, newX, newY, style); msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY, "tool":Rec, "style":style }; socket.send(JSON.stringify(msg)); break; case Line:// desenam linia din pozitia oldX oldY in pozitia newX newY si cu diametrul = distanta dintre oldX newX respectiv oldY newY line(oldX, oldY, newX, newY, style); msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY, "tool":Line, "style":style }; socket.send(JSON.stringify(msg)); break; } }); // event handler pentru mouse move $('#sheet').mousemove(function(e) { newX = e.pageX - this.offsetLeft; newY = e.pageY - this.offsetTop; if(mouseDown) { //cat timp e tinut apasat butonul de mouse deseneaza sau sterge oldX = mouseX; oldY = mouseY; switch(tool){ case Pen: pencil(oldX, oldY, newX, newY, style); msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY,"tool":Pen,"style":style }; socket.send(JSON.stringify(msg)); mouseX = newX; mouseY = newY; break; case Eraser: eraser(oldX, oldY, newX, newY, style); msg = { "x1":oldX, "y1":oldY, "x2":newX, "y2":newY, "tool":Eraser, "style":style }; socket.send(JSON.stringify(msg)); mouseX = newX; mouseY = newY; break; break; } } }); // cand mouse-ul paraseste suprafata canvasului $('#sheet').mouseleave(function() {
  • 5. mouseDown = false; }); Aceste evenimente apar la actiunile mouse-ului pe suprafata browser-ului. 2.1.3 Alegerea culorii Alegerea culorii se face prin alegerea cantitatilor de rosu, albastru si verde prin miscarea la stanga sau dreapta a slider-elor // color and size //regleaza in fuctie de slider-e colaore(cantitatea de Red, Green si Blue) $('#red').slider({ value: 95, min: 0, max: 255, slide: function(event, ui) { changeColor(); } }).width(160); $('#green').slider({ value: 221, min: 0, max: 255, slide: function(event, ui) { changeColor(); } }).width(160); $('#blue').slider({ value: 122, min: 0, max: 255, slide: function(event, ui) { changeColor(); } }).width(160); $('#opac').slider({ value: 100, min: 0, max: 100, slide: function(event, ui) { changeColor(); } }).width(160); //Schimb culoarea pensulei actualizand style- ul si in acleasi timp schimb si culoarea fundalului din div-ul Selected color var changeColor = function(){ c = 'rgba(' + $('#red').slider('value') + ',' + $('#green').slider('value') + ',' + $('#blue').slider('value') + ',' + ($('#opac').slider('value') / 100) + ')'; $('#selectedColor').css({backgroundColor: c}); style.strokeStyle = 'rgb(' + $('#red').slider('value') + ',' + $ ('#green').slider('value') + ',' + $('#blue').slider('value') + ')';
  • 6. style.globalAlpha = ($('#opac').slider('value') / 100); } 2.1.3 Dimensiune pensulei Dimensiune este setata tot cu ajutorul unui slider $('#penSize').slider({ value: 2, step: 0.1, min: 0.5, max: 20, slide: function(event, ui) { style.lineWidth = ui.value; } }).width(160); 2.1.4 Actiuni pe fisier Dupa cum am precizat si in abstract aplicatia ofera utilizatului posibiliatatea de a salva desenul la nivel local , de a restaura desenul salvat si de a exporta desenul in format PNG. Aceste actiuni sunt realizate in cu jQuery : // file functions //salveaza imaginea canvas la nivel-ul browser-ului var saveFile = function(){ localStorage.setItem("sheet", canvas.toDataURL()); } $('#save').click(function() { saveFile(); }); //deseneaza imaginea incarcata din "baza de date" a browser-ului var load = function(imageSource) { image = new Image(); image.src = imageSource; canvas.width = canvas.width; context.drawImage(image, 0, 0); } //incarca imaginea din "baza de date" a browserului $('#load').click(function() { imageSource = localStorage.getItem("sheet"); load(imageSource); msg = { "tool":Load, "image":imageSource }; socket.send(JSON.stringify(msg)); }); //face o coala noua stergat tot ce este in canvas $('#newSheet').click(function(){ canvas.width = canvas.width; msg = { "tool":New }; socket.send(JSON.stringify(msg)); }); //incarca o imagine selectata din dialog de selecare a unui fisier $('#imageSource').change(function() { var file = document.getElementById('imageSource').files[0]; reader = new FileReader();
  • 7. reader.onload = function (event) { image = new Image(); image.src = event.target.result; }; reader.readAsDataURL(file); tool = IMAGE; }); //exporta imagina in fomrat Png $('#export').click(function() { window.open(canvas.toDataURL()); }); 2.2 Transmiterea datelor Transmiterea datelor se cu ajutorul Socket.IO care in functie de browser selecteaza un protocol de comunicare WebSocket pentru Google Chrome, xhr-multipart pentru Mozilla. Functiile pentru trasferul datelor sunt urmatoarele: //realoziaza conexiunea la server var socket = new io.Socket('localhost',{ port: 9125 }); socket.connect(); //trimite date la ceilalti clienti in functie de toolul selectat socket.on('message', function(msgData) { msgData = $.parseJSON(msgData); switch(msgData.tool){ case Pen: pencil(msgData.x1, msgData.y1, msgData.x2, msgData.y2, msgData.style); break; case Circ: circle(msgData.x1, msgData.y1, msgData.x2, msgData.y2, msgData.style); break; case Rec: rectangle(msgData.x1, msgData.y1, msgData.x2, msgData.y2, msgData.style); break; case Text: context.font = msgData.font; context.fillStyle = msgData.style.strokeStyle; context.fillText(msgData.text, msgData.x, msgData.y); break; case Load: load(msgData.image); break; case New: canvas.width = canvas.width; break; case IMAGE: image = new Image(); image.src = msgData.image; context.drawImage(image, msgData.x, msgData.y); break;
  • 8. case Eraser: eraser(msgData.x1, msgData.y1, msgData.x2, msgData.y2, msgData.style); break; break;} }); break; case Line: line(msgData.x1, msgData.y1, msgData.x2, msgData.y2, msgData.style); break; case Text: context.font = msgData.font; context.fillStyle = msgData.style.strokeStyle; context.fillText(msgData.text, msgData.x, msgData.y); break; case Load: load(msgData.image); break; case New: canvas.width = canvas.width; break; case IMAGE: image = new Image(); image.src = msgData.image; context.drawImage(image, msgData.x, msgData.y); break; case Eraser: eraser(msgData.x1, msgData.y1, msgData.x2, msgData.y2, msgData.style); break; break;} });
  • 9. 3 Modalitate de utilizare Din meniul din dreapta sus se alege pensula pentru desenare posibilitatile fii : Pencil, Line, Recangle, Circle, Eraser dupa care se deseneaza pe canvas ( foaia alba ). Meniul din dreapta se poate alege culoare pensulei precum si dimensiunea acestia (la optiunea size). Tot aici la submeniu text putem scrie textul ce urmeaza sa fie inserat si selecta stilul textului (Bold,Italic,Underline) Din partea de sus meniului putem selecta daca sa salvam imaginea la nivel local , sa reincarcam imaginea salvata si sa o exportam in format PNG intr-o alta fereastra. 4 Bibliografie http://socket.io/ http://www.w3schools.com/ http://docs.jquery.com/Main_Page http://profs.info.uaic.ro/~busaco/teach/courses/cliw/web.html