extend Canvas-Framwork-prototype mit CRC2D-props/meths
Laura
- javascript
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
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
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ß
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..
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
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 :)
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ß