Laura: extend Canvas-Framwork-prototype mit CRC2D-props/meths

Hallo,
ich bastel gerade an einem kleinen Canvas-Framework -> new Canvas( canvasId ).
In einigen anderen Frameworks habe ich gesehen, dass die Methoden/Props von
CanvasRenderingContext2D an den prototype des constructors gehängt werden,
etwa so:

  
 function Canvas( canvasId ) {  
   var canv = document.getElementById( canvas );  
   this.ctx = canv.getContext( '2d' );  
   // more code  
 }  
 Canvas.prototype = {  
   stroke: function() { this.ctx.stroke(); },  
   // etc.  
 }  

Dachte, man kann das auch in einer for-Schleife abwickeln, statt alles manuell anzuhängen, etwa so:

  
function Canvas( canvasId ) {  
  var canv = document.getElementById( canvasId );  
  this.ctx = canv.getContext( '2d' );  
  for ( var m in CanvasRenderingContext2D.prototype ) {  
    (function( that, m ) {  
      if ( typeof that.ctx[m] === 'function' ) {  
        // spendabel sein mit Anzahl Parameter, s.d. nie zu wenig:  
        Canvas.prototype[m] = function( a,b,c,d,e,f,g,h,i,j,k,l ) {  
	  that.ctx[m]( a,b,c,d,e,f,g,h,i,j,k,l );  
	}  
      } else {  
	Canvas.prototype[m] = function( a ) {  
	  that.ctx[m] = a;  
	}				  
      }  
    })( this, m );  
  }  
  // weiterer Code  
}  

Jetzt denke ich mir aber, dass die Entwickler gut funktionierender libs Profis sind
und ihre Gründe dafür haben, das manuell zu machen - nur kenne ich diese Gründe
nicht.
Kann mir jemand sagen, ob meine Methode Schwierigkeiten/Fehlerquellen/... birgt?

Vielen Dank und liebe Grüße, Merle

  1. Hallo,

    function Canvas( canvasId ) {
      var canv = document.getElementById( canvasId );
      this.ctx = canv.getContext( '2d' );
      for ( var m in CanvasRenderingContext2D.prototype ) {

    Diesen Code solltest du nicht im Konstruktor ausführen, schließlich soll er nur einmal ausgeführt werden, nicht für jede Instanz. Der Prototyp wird ja von allen Instanzen geteilt.

    (function( that, m ) {

    Indem du that verwendest, welches auf die aktuelle Instanz zeigt, und mit jeder Instanz die Methoden am Prototyp überschreibst, ist effektiv nur eine Instanz von Canvas möglich. (Wenn ich das richtig sehe.)

    Wenn du einfach this verwendest und die Methoden nur einmal außerhalb des Konstruktors anlegst, sind mehrere möglich.

    if ( typeof that.ctx[m] === 'function' ) {
            // spendabel sein mit Anzahl Parameter, s.d. nie zu wenig:
            Canvas.prototype[m] = function( a,b,c,d,e,f,g,h,i,j,k,l ) {
      that.ctxm;

    Du suchst hier

    Canvas.prototype[m] = function () {  
      this.ctx[m].[link:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply@title=apply](this, [link:https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments@title=arguments]);  
    };
    

    Das gibt sämtliche Parameter weiter, egal wieviele es gibt.

    Jetzt denke ich mir aber, dass die Entwickler gut funktionierender libs Profis sind
    und ihre Gründe dafür haben, das manuell zu machen - nur kenne ich diese Gründe
    nicht.

    Es spricht m.E. nichts dagegen, sämtliche Methoden erst einmal weiterzureichen und gleichzeitig einige Methoden neu zu implementieren, zu erweitern sowie eigene, zusätzliche Methoden anzubieten. Das würde ich von einer Canvas-Abstraktion erwarten: Dass ich sowohl einfachen Zugriff auf die Standard-Low-Level-Funktionen habe als auch Zusatzfunktionen und Helferlein nutzen kann.

    Kann mir jemand sagen, ob meine Methode Schwierigkeiten/Fehlerquellen/... birgt?

    Nö, das sieht schon sehr gut aus. Ob alle Browser, die Canvas können, auch Zugriff auf CanvasRenderingContext2D erlauben, müsstest du testen.

    Mathias

    1. Hallo Mathias,

      Diesen Code solltest du nicht im Konstruktor ausführen, schließlich soll er nur einmal ausgeführt werden, nicht für jede Instanz. Der Prototyp wird ja von allen Instanzen geteilt.

      »»
      Ja, stimmt, hatte ich zunächst nur da reingeschrieben, um erstmal überhaupt schnell zu
      testen, ob das so funktioniert.
      Wird dann natürlich später (sobald ich mir überlegt hab, wie genau das Framwork aufgebaut sein soll) nach außen verlagert.

      Du suchst hier

      Canvas.prototype[m] = function () {

      this.ctx[m].[link:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply@title=apply](this, [link:https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments@title=arguments]);
      };

      
      >   
      
      Also, apply kenne ich und hatte das vorher auch anwenden wollen. aber dann  
      hatte ich das Problem, dass ich ja erst testen muss, ob es sich um eine Funktion  
      handelt und irgendwie landete ich immer bei folgender Fehlermeldung:  
      Illegal operation on WrappedNative prototype object  
        
      Danke für Deine Antwort, glaube ich nähere mich dem Ziel allmählich :)  
      Lieben Gruß
      
    2. Nachtrag:

      Du suchst hier

      Canvas.prototype[m] = function () {

      this.ctx[m].[link:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply@title=apply](this, [link:https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments@title=arguments]);
      };

        
      Folgender Code (außerhalb des Konstruktors) funktioniert.  
      Wenn ich aber statt this.ctx[m](a,b,c,d,...) this.ctx[m].apply(this,arguments)  
      schreibe, bekomme ich oben genannte Fehlermeldung in der firebug-Konsole:  
      Illegal operation on WrappedNative prototype object  
      ~~~javascript
        
      for ( var m in CanvasRenderingContext2D.prototype ) {  
        (function( m ) {	  
      	Canvas.prototype[m] = function ( a,b,c,d,e,f,g,h,i,j ) {  
      		if ( typeof ctx[m] === 'function' ) {  
      			this.ctx[m]( a,b,c,d,e,f,g,h,i,j );  
      		} else {  
      			this.ctx[m] = a;  
      		}  
      	};  
        })( m );  
      }  
      
      

      Hab das mal nachgegooglet, scheint eine neuere Restriktion durch den Browser zu sein(?), hmm..

      1. Wenn ich aber statt this.ctxm this.ctx[m].apply(this,arguments)
        schreibe, bekomme ich oben genannte Fehlermeldung in der firebug-Konsole:
        Illegal operation on WrappedNative prototype object

        Der Fehler ist eigentlich zu erwarten, schließlich wird eine Methode des Canvas-Kontexts auf mit deiner Instanz als this aufgerufen. Das habe ich falsch gemacht, es müsste eher so lauten:

        this.ctx[m].apply(this.ctx, arguments)

        Das wäre dann äquivalent zu

        this.ctx[m](a, b, c, d, usw.)

        Mathias

        1. Der Fehler ist eigentlich zu erwarten, schließlich wird eine Methode des Canvas-Kontexts auf mit deiner Instanz als this aufgerufen. Das habe ich falsch gemacht, es müsste eher so lauten:

          this.ctx[m].apply(this.ctx, arguments)

          Ah, claro,
          vielen Dank Dir Mathias :)

  2. Nachtrag:
    Habe leider immer noch nicht verstanden, warum folgendes funktioniert:

      
    console.log( typeof CanvasRenderingContext2D.prototype.save );  
    
    

    dies aber nicht:

      
    console.log( typeof CanvasRenderingContext2D.prototype.fillStyle );  
    
    

    CanvasRenderingContext2D.prototype.save ist eine Funktion/Methode,
    CanvasRenderingContext2D.prototype.fillStyle ist zwar noch undefined, bevor ein
    neuer context instantiiert wurde, trotzdem müsste doch
    der Rückgabewert für obiges Beispiel undefined sein(?)
    Gruß