2010-11-23 4 views
2

Je crée un petit wrapper pour canvas HTML5, et une chose que je fais est de renvoyer self/this de chacune de mes méthodes enveloppées pour faciliter le chaînage d'appel.Création de délégué répétitif JavaScript

Faute d'un meilleur nom, j'appelle mon emballage Toile. Il enveloppe essentiellement la toile et le contexte ensemble.

Une chose que je l'ai fait est d'ajouter les méthodes ci-dessous pour la Canvas.prototype

Canvas.fn = Canvas.prototype = { 
    save: function() { this.ctx.save(); return this; }, 
    restore: function() { this.ctx.restore(); return this; }, 
    scale: function (x, y) { this.ctx.scale(x, y); return this; }, 
    rotate: function (angle) { this.ctx.rotate(angle); return this; }, 
    translate: function (x, y) { this.ctx.translate(x, y); return this; }, 
    transform: function (a,b,c,d,e,f) { this.ctx.transform(a,b,c,d,e,f); return this; }, 

est-il un moyen plus facile d'ajouter ces méthodes à l'aide de certains délégués? Peut-être avec un tableau ou les noms de fonctions? Notez que certaines méthodes prennent des arguments et que je veux les passer telles quelles à la méthode self.ctx actuelle.

Répondre

2

Quelque chose comme ça?

var functionNames = ['save', 'restore', 'scale', 'rotate', 'translate', 'transform']; 

for(var i = 0; i < functionNames.length; i++) { 
    (function(funcName) { 
     this[funcName] = function() { 
      this.ctx[funcName].apply(this.ctx, arguments); 
      return this; 
     }; 
    )(functionNames[i]); 
} 
+0

Vous avez des fautes de frappe: int => var, fonctions => functionNames. – Ayman

+0

Cela ne fonctionnerait pas, car au moment de l'appel, le nom de fonction [i] n'est pas connu, donc j'obtiens une erreur d'application appelée non définie. – Ayman

+0

@Ayman: Ok, je pense que cela devrait être corrigé maintenant. J'ai corrigé les fautes de frappe et introduit des fermetures. – Eric

0

Une suite de la réponse d'Eric qui fonctionne est donnée ci-dessous:

var funs = ['save', 'restore', 'scale', 'rotate', 'translate', 
    'transform']; 
var f; 
for(var i = 0; i < funs.length; i++) { 
    f = funs[i]; 
    self[f] = new Function("this.ctx." + 
      f + ".apply(this.ctx, arguments); return this;"); 
} 

Mais je n'aime pas l'utilisation du constructeur Function et que ma fonction est un fait à partir d'une chaîne.

1

similaires à Eric's answer, également basée sur http://seewhatever.de/blog/?p=440:

function CanvasWrapper(canvas) 
{ 
    // Call this with new ... or not 
    if(!(this instanceof CanvasWrapper)){ 
     return new CanvasWrapper(canvas); 
    } 

    var self = this, 
     ctx = canvas.getContext('2d'), 
     props = [ 
      'fillStyle', 'strokeStyle' 
      // ... 
     ], 
     meths = [ 
      'fillRect', 'strokeRect', 'clearRect', 
      'beginPath', 'closePath', 
      'moveTo', 'lineTo', 'arc', 
      'stroke' 
      // ... 
     ], 
     nonChainableMeths = [ 
      'createLinearGradient' 
     ], 
     i, prop, meth; 

    // Create and set jQuery-like property accessors 
    // With no arguments they return the prop value 
    // With one argument they set the prop value and return self 
    function createAccessor(ctx, prop, self) 
    { 
     return function(){ 
      if(arguments.length == 1) 
      { 
       ctx[prop] = arguments[0]; 
       return self; 
      } 
      else 
      { 
       return ctx[prop]; 
      } 
     } 
    } 
    for(i = 0; i < props.length; ++i) 
    { 
     prop = props[i]; 
     self[prop] = createAccessor(ctx, prop, self); 
    } 

    // Create and set chainable delegate methods 
    function createDelegate(ctx, meth, self) 
    { 
     return function(){ 
      ctx[meth].apply(ctx, arguments); 
      return self; 
     } 
    } 
    for(i = 0; i < meths.length; ++i) 
    { 
     meth = meths[i]; 
     self[meth] = createDelegate(ctx, meth, self); 
    } 

    // Create and set non-chainable delegate methods 
    function createNCDelegate(ctx, meth, self) 
    { 
     return function(){ 
      return ctx[meth].apply(ctx, arguments); 
     } 
    } 
    for(i = 0; i < nonChainableMeths.length; ++i) 
    { 
     meth = nonChainableMeths[i]; 
     self[meth] = createNCDelegate(ctx, meth, self); 
    } 
    return self; 
} 
+0

Si vous pensez que cela semble plus propre, vous pouvez également supprimer 'ctx' et' self' des signatures des fonctions de créateur de délégué; donc 'createAccessor (ctx, prop, self)' devient 'createAccessor (prop)', etc. Ces fonctions créatrices agissent comme des fermetures où les noms des propriétés sont conservés en toute sécurité, ainsi ils peuvent être utilisés dans les fonctions anonymes à l'intérieur. ' – Zecc