2012-05-23 14 views
8

Estoy haciendo una aplicación donde se pintan diferentes rectángulos en un lienzo y estoy tratando de hacerlo con Backbone. Tengo un modelo llamado cuadro:Hacer una vista de Backbone.js para dibujar objetos en un lienzo

Box = Backbone.Model.extend({ 
     defaults: { 
      x: 0, 
      y: 0, 
      w: 1, 
      h: 1, 
      color: "#FF9000", 
      linewidth: 3, 
      id: 0, 
     }, 

     drawBox: function(ctx) { 
      ctx.fillStyle = "#FF9000"; 
      ctx.globalAlpha = 0.1; 
      ctx.fillRect(this.get("x"), this.get("y"), this.get("w"), this.get("h")); //transparent box in the back 
      ctx.globalAlpha = 1; 
      ctx.strokeStyle = this.get("color"); 
      ctx.lineWidth = this.get("linewidth"); 
      ctx.strokeRect(this.get("x"), this.get("y"), this.get("w"), this.get("h")); //rectangle on top  
     } 
    }); 

Y también tengo una colección de este modelo Box:

BoxSet = Backbone.Collection.extend({ 
     model: Box   
    }); 

Lo que tengo en mente es tener un punto de vista en el que puedo poner a cada modelo de caja de la colección BoxSet en un lienzo usando el método drawBox en el modelo Box, pero hasta ahora todos los tutoriales y ejemplos tratan con plantillas de texto simples y no puedo encontrar la manera de lograrlo.

¿Alguna idea sobre cómo se puede hacer esto usando las vistas de Backbone?

Gracias de antemano.

Respuesta

18

Seguiría la separación de modelos y vistas que ofrece Backbone. Mantenga sus modelos como repositorios de datos:

var Box = Backbone.Model.extend({ 
    defaults: { 
     x: 0, 
     y: 0, 
     w: 1, 
     h: 1, 
     color: "#FF9000", 
     linewidth: 3 
     // don't define a default id, that leads to strange behaviors 
    } 
}); 

var BoxSet = Backbone.Collection.extend({ 
    model:Box 
}); 

y definir los puntos de vista para hacer que las diferentes piezas sobre un lienzo:

var BoxView = Backbone.View.extend({ 
    render: function() { 
     var model = this.model, ctx = this.options.ctx; 

     ctx.fillStyle = "#FF9000"; 
     ctx.globalAlpha = 0.1; 
     ctx.fillRect(
      model.get("x"), model.get("y"), 
      model.get("w"), model.get("h") 
     ); 

     ctx.globalAlpha = 1; 
     ctx.strokeStyle = model.get("color"); 
     ctx.lineWidth = model.get("linewidth"); 
     ctx.strokeRect(
      model.get("x"), model.get("y"), 
      model.get("w"), model.get("h") 
     ); 
    } 
}); 

var SetView= Backbone.View.extend({ 
    initialize: function() { 
     this.listenTo(this.collection, "all", this.render); 
    }, 

    render: function() { 
     var canvas = this.el, ctx = canvas.getContext("2d"); 
     ctx.clearRect(0, 0, canvas.width, canvas.height); 

     this.collection.each(function(model) { 
      var view = new BoxView({ctx: ctx, model: model}); 
      view.render(); 
     }) 
    } 
}); 

Y por último una instancia y render:

var c = new BoxSet(); 
c.add({x: 150, y: 150, w: 100, h: 100}); 
c.add({x: 10, y: 10, w: 100, h: 100}); 

var v = new SetView({ 
    el: $("canvas"), 
    collection : c 
}); 
v.render(); 

un violín de ver esos dos bonitos cuadrados http://jsfiddle.net/JB9yg/

Otro donde un cambio a t La colección conduce a la re-representación http://jsfiddle.net/JB9yg/1/

Este ejemplo probablemente se puede construir para proporcionar manipulaciones más limpias, pero eso debería comenzar.

+0

Gracias @nikoshr, esta es una gran solución. Me da más control sobre los cuadrados y lo hace más flexible para hacer más modificaciones. – rpabon

+0

¿Alguna idea sobre cómo hacer que SetView pinte o borre un cuadro del lienzo cada vez que se agrega/elimina de la colección? – rpabon

+1

@rpabon Agregué una posible solución donde todo se vuelve a dibujar. Podría ser interesante comprobar si un conjunto de instrucciones se puede definir como un objeto y manipularse de forma independiente en un lienzo. – nikoshr

2

También puede intentar utilizar el complemento Backbone.KineticView para agregar soporte de lienzo a Backbone. Funciona a través de KineticJS, por lo que también puede usar toda la delegación de poder de evento para nodos de lienzo.

Ejemplo:

var MyView = Backbone.KineticView.extend({ 
    // build Kineticjs object, then return it. 
    el : function(){ 
    var rect = new Kinetic.Rect({ 
     x : 100, 
     y : 100, 
     width : 50, 
     height : 50, 
     fill : 'green', 
     id : 'rect' 
    }); 
    var circle = new Kinetic.Circle({ 
     x : 200, 
     y : 100, 
     radius : 50, 
     fill : 'red', 
     name : 'circle' 
    }); 
    var group = new Kinetic.Group(); 
    group.add(rect).add(circle); 
    return group; 
    }, 
    // setup events 
    events : { 
    'click #rect' : function(){ 
     console.log("on rectangle clicked"); 
    }, 
    'mouseover .circle' : 'onMouseOverCircle' 
    }, 
    onMouseOverCircle : function(){ 
    console.log('Mouse is over circle'); 
    }, 
    render : function(){ 
    // this.$el - cached kineticjs object. 
    this.options.layer.add(this.$el); 
    layer.draw(); 
    } 
}); 

var stage = new Kinetic.Stage({ 
    container : 'container', 
    width : 300, 
    height : 300 
}); 
var layer = new Kinetic.Layer(); 
stage.add(layer); 

view = new MyView({layer:layer}); 
view.render(); 
Cuestiones relacionadas