使用Backbone.js创建视图在画布上绘制对象

8

我正在开发一个应用程序,在画布上绘制不同的矩形,我正在尝试使用Backbone完成。我有一个名为box的模型:

    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      
        }
    });

我也有一个关于盒子模型的收藏:

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

我想要创建一个视图,在画布上使用Box模型的drawBox方法放置BoxSet集合中的每个Box模型,但目前所有的教程和示例都是处理简单的文本模板,我无法弄清如何完成这个操作。有没有任何使用Backbone视图的想法?提前感谢您。
2个回答

18
我会遵循Backbone提供的模型和视图分离原则。将您的模型保留为数据存储库:
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
});

定义视图以在画布上渲染不同的元素:

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();
        })
    }
});

最后实例化和渲染:

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();

一个演示这两个漂亮方块的jsFiddle:http://jsfiddle.net/JB9yg/

另一个例子,其中更改集合会导致重新渲染:http://jsfiddle.net/JB9yg/1/

这个例子可能可以进一步建立以提供更清洁的操纵,但应该可以让您入门。


谢谢@nikoshr,这是一个很棒的解决方案。它让我对正方形有更多的控制,并且使进一步修改更加灵活。 - rpabon
有什么想法可以让SetView在每次从集合中添加/删除一个框时,从画布上绘制或擦除它? - rpabon
1
@rpabon,我添加了一个可能的解决方案,其中所有内容都会被重新绘制。定义一组指令作为对象并在画布上独立操作可能是有趣的。 - nikoshr
谢谢@nikoshr。在提问之前我也做了同样的事情,但不是使用“全部(all)”,而是使用“添加(add)”/“推送(push)”和“弹出(pop)”/“删除(remove)”,但没有成功。你知道为什么吗? - rpabon
@rpabon 听取 addremove 事件也可以,参见 http://jsfiddle.net/JB9yg/2/ 或许绑定时缺少了 this - nikoshr

2
此外,您可以尝试使用Backbone.KineticView插件来为Backbone添加画布支持。 它通过KineticJS工作,因此还可以利用事件委托对画布节点进行控制。
示例:
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();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接