2013-05-16 7 views
50

Gibt es bereits eine Anweisung zum Zeichnen/Malen von Dingen auf einer Leinwand? Sie können also etwas wie Paint oder sogar etwas größeres wie Photoshop usw. implementieren, aber ein sehr einfaches Beispiel würde ausreichen.Gibt es bereits eine Canvas-Zeichnungsanweisung für AngularJS?

Ich habe keins in meiner Suche gefunden, und wenn es bereits eins gibt, das als Best Practice gilt, würde ich es gerne verwenden. Ansonsten muss ich selbst eines implementieren.

+3

Angular zielt auf die Schaffung von Datenmanagement (CRUD) Anwendungen hilft - für die Leinwand Anwendungen, die Sie etwas anderes, zum Beispiel versuchen sollte: http://www.createjs.com/#!/EaselJS – mirrormx

Antwort

82

Ok ich tat, und es ist eigentlich recht einfach:

app.directive("drawing", function(){ 
    return { 
    restrict: "A", 
    link: function(scope, element){ 
     var ctx = element[0].getContext('2d'); 

     // variable that decides if something should be drawn on mousemove 
     var drawing = false; 

     // the last coordinates before the current move 
     var lastX; 
     var lastY; 

     element.bind('mousedown', function(event){ 
     if(event.offsetX!==undefined){ 
      lastX = event.offsetX; 
      lastY = event.offsetY; 
     } else { // Firefox compatibility 
      lastX = event.layerX - event.currentTarget.offsetLeft; 
      lastY = event.layerY - event.currentTarget.offsetTop; 
     } 

     // begins new line 
     ctx.beginPath(); 

     drawing = true; 
     }); 
     element.bind('mousemove', function(event){ 
     if(drawing){ 
      // get current mouse position 
      if(event.offsetX!==undefined){ 
      currentX = event.offsetX; 
      currentY = event.offsetY; 
      } else { 
      currentX = event.layerX - event.currentTarget.offsetLeft; 
      currentY = event.layerY - event.currentTarget.offsetTop; 
      } 

      draw(lastX, lastY, currentX, currentY); 

      // set current coordinates to last one 
      lastX = currentX; 
      lastY = currentY; 
     } 

     }); 
     element.bind('mouseup', function(event){ 
     // stop drawing 
     drawing = false; 
     }); 

     // canvas reset 
     function reset(){ 
     element[0].width = element[0].width; 
     } 

     function draw(lX, lY, cX, cY){ 
     // line from 
     ctx.moveTo(lX,lY); 
     // to 
     ctx.lineTo(cX,cY); 
     // color 
     ctx.strokeStyle = "#4bf"; 
     // draw it 
     ctx.stroke(); 
     } 
    } 
    }; 
}); 

Und dann kann man es auf Leinwand wie folgt verwenden:

<canvas drawing></canvas> 

Hier ist eine Demo auf Plunkr: http://plnkr.co/aG4paH

+0

Was macht die Reset-Funktion mit dem Zuweisungselement [0 ] .width = element [0] .width;? –

+0

Hmm, eigentlich habe ich vergessen, es hatte etwas damit zu tun, einige Transformationsmatrizen zurückzusetzen ... ich kann mich nicht erinnern EDIT: ah hier habe ich es gefunden, es ist eine Funktion Um die Leinwand zu löschen: http://StackOverflow.com/Questions/2142535/How-to-clear-the-canvas-for-redrawing – JustGoscha

+2

Ich schrieb auch einen Testfall in JsPerf für die Leinwand Clearing: weil ich zwei Wege wie weiß Sie können eine Leinwand reinigen: http://jsperf.com/canvas-clearing-test – JustGoscha

12

Angular eignet sich ideal zum Schreiben von Anwendungen im deklarativen Stil. Sobald Sie das Canvas-Element gedrückt haben, können Sie nicht weiter mit deklarativen Schritten gehen und Sie müssen zu einem imperativen Schreibmechanismus wechseln. Wenn der Großteil Ihrer Anwendung eine Benutzeroberfläche bereitstellt, die Sie im Rest Ihrer Anwendung in HTML definieren, würde ich Ihnen sehr empfehlen, AngularJS zu verwenden. Es ist ein erstaunlicher Rahmen dafür.

Auf der anderen Seite, wenn der Großteil Ihres Codes innerhalb des Canvas-Elements sein wird, dann ist AngularJS vielleicht nicht das ideale Werkzeug für Sie. Wenn Sie wirklich darauf bestehen, AngularJS für den Großteil Ihrer Anwendung zu verwenden, würde ich Ihnen empfehlen, etwas wie D3 zu verwenden, das eine ausgezeichnete Alternative ist und SVG hinter den Kulissen verwendet (was deklarativ ist und daher ein toller Kumpel für AngularJS ist).

+0

Ich weiß, ich habe eine Anwendung, die meistens deklarativ ist. Und die meisten Dinge brauchen keine Leinwand. Aber dann habe ich auch ein Feature, das Zeichenkompatibilität auf einer Leinwand benötigt ... Ich dachte, vielleicht gibt es da draußen schon etwas, das es in einer Direktive macht. Oder importiert eine andere Zeichnungsbibliothek in eine Direktive, aber wenn das nicht der Fall ist, muss ich es selbst herausfinden. – JustGoscha

+12

Die obige Antwort ist irreführend. AngularJS (und deklarative Programmierung) behindert nicht die Verwendung eines Canvas. Es ist alles, wie Sie das Problem angehen. Viele der beliebten JS-Bibliotheken zum Charting und zur grafischen Darstellung fangen an, AngularJS zu unterstützen, indem sie die Anweisungen für ihre Komponenten bereitstellen.Somit ist der Imperativcode in der wiederverwendbaren Implementierung der Direktive verborgen. Dies ist die Schönheit von AngularJS, Sie müssen den Imperativcode einmal schreiben und ihn deklarativ verwenden, wie die folgende Lösung zeigt. –

+7

Die Antwort ist nicht irreführend. Wenn Sie eine Menge JQuery-Spaghetti schreiben und alles innerhalb der Konstruktorfunktion einer Direktive ausblenden, haben Sie keine "Winkeldirektive" geschrieben. Du hast einen Haufen imperativer Trödel geschrieben und dich getröstet, indem du ihn in einer Weise organisiert hast, die * Angular ähnelt. Und das ist mit Code, der mit Angular * richtig geschrieben worden sein könnte. Aber es gibt keine $ Digest-Schleife, die den Zustand eines Canvas überwacht, und keine 2-Way-Angular-Datenbindung an Canvas. Sie können so tun, als würden Sie imperativen Canvas-Code in eine Direktive einfügen. Aber das wird es nicht kantig machen. – XML

5

Vor einiger Zeit habe ich eine konfigurierbare Direktive dafür gebaut.

https://github.com/pwambach/angular-canvas-painter

Die Richtlinie schafft das Canvas-Element und fügt Handler für mousedown-/mousemove-/mouseup Ereignisse (und die entsprechenden Berührungsereignisse) an das Element. Mauszeiger und nachfolgende Mauszeiger-Ereignisse zeichnen Bezier-Kurven mit der canvasContext.quadraticCurveTo() Methode für glattere Striche (statt nur Kreise für jeden Punkt zu malen). Details zum Zeichnungsalgorithmus finden Sie in diesem Artikel: http://codetheory.in/html5-canvas-drawing-lines-with-smooth-edges/

+0

Während dies theoretisch die Frage beantworten könnte, [wäre es vorzuziehen] (http: //meta.stackoverflow.com/q/8259), um die wesentlichen Teile der Antwort hier einzubeziehen und den Link als Referenz zur Verfügung zu stellen. – Yuriy

0

Das ist eine wirklich nette Umsetzung! Ich konnte die Methode hinzufügen, wenn Sie die Leinwand auf ein Bild konvertieren möchten

function convertCanvasToImage(canvas) { 
     var image = new Image(); 
     image.src = canvas.toDataURL("image/png"); 
     return image; 
    } 

Dies wird Ihnen ein Image-Tag mit der Quelle als base64 Element machen.

Hoffe, dass es Sie