使用fabricjs时遇到Javascript new关键字问题

时间:2014-03-31 21:53:34

标签: javascript canvas svg new-operator fabricjs

我正在使用FabricJS将SVG对象放在HTML中的Canvas元素上。 但是由于FabricJS使用new关键字来实例化类,我认为该类的属性与global命名空间相关联。

下面是我的参考代码

我正在解析的JSON对象

var defaultSceneObj = [
        {
            "eyes": "res/img/animals/cat/cat_part_eye.svg",
            "skin": "res/img/animals/cat/cat_skin.svg",
            "mouth": "res/img/animals/cat/cat_part_mouth_happy.svg",
            "pos": {
                "ground" : "right_back", 
                "sky" : "none", //other values ["none"]
                "relative" : "none" //other values ["none", "top", "bottom"]
            }  
        },
        {
            "eyes": "res/img/animals/cat/cat_part_eye.svg",
            "skin": "res/img/animals/cat/cat_skin.svg",
            "mouth": "res/img/animals/cat/cat_part_mouth_happy.svg",
            "pos": {
                "ground" : "left_back", 
                "sky" : "none", //other values ["none"]
                "relative" : "none" //other values ["none", "top", "bottom"]
            }  
        }
    ];

这意味着我的对象中有2个animals,其中每个animaleyeskinmouth个svg文件组成。

我正在我的javascript代码中循环浏览它们

var renderObjOnCanvas = function(cObj, cDim){
        // console.log("Object, Dimension:", cObj, cDim);
        // var canvas = new fabric.Canvas('elem-frame-svg');
        var canvas = this.__canvas = new fabric.Canvas('elem-frame-svg');

        imgwidth = 200; //default image width
        imgheight = 255; //default image height
        imgScale = 0.6;
        imgOffsetX = Math.floor(imgwidth*imgScale/2);
        imgOffsetY = Math.floor(imgheight*imgScale/2);

        canvaswidth = canvas.width;
        canvasheight = canvas.height;

        // console.log("render canvas dimensions:", canvaswidth, canvasheight); 
        if (cObj.length > 0){

            for (var c =0; c < cObj.length; c++){
                var noun = cObj[c]; //assign the noun object

                if (noun.skin !== 'Undefined'){
                    var animalParts = ['skin', 'eyes', 'mouth'];
                    var pos = cDim.ground[noun.pos.ground];

                    for (var g = 0; g < animalParts.length; g++){

                        var part_top = canvasheight - (pos[1] + imgOffsetY);
                        var part_left = pos[0] - imgOffsetX;
                        console.log("part:", noun[animalParts[g]], "part_position: ", part_top, part_left);

                        var img = new fabric.Image.fromURL(noun[animalParts[g]], function(s){
                            this.top = part_top;
                            this.left = part_left;
                            // this.scale(imgScale);

                            s = this;

                            console.log("part:", part_top, part_left);

                            canvas.add();

                        }); 
                    }
                }
            }   
        }
    };

第一个console.log输出正确的topleft坐标,但第二个只输出分配的最后一个值,因此我的所有对象都放在画布上的相同位置

第一个console.log的输出:

part: res/img/animals/cat/cat_skin.svg part_position:  282 574 main.js:126
part: res/img/animals/cat/cat_part_eye.svg part_position:  282 574 main.js:126
part: res/img/animals/cat/cat_part_mouth_happy.svg part_position:  282 574 main.js:126
part: res/img/animals/cat/cat_skin.svg part_position:  282 135 main.js:126
part: res/img/animals/cat/cat_part_eye.svg part_position:  282 135 main.js:126
part: res/img/animals/cat/cat_part_mouth_happy.svg part_position:  282 135

第二个console.log的输出:

(6) part: 282 135 

2 个答案:

答案 0 :(得分:1)

这是因为forEach为您管理变量的范围,而不是。例如,

var arr = [1,2,3];
for (var i=0;i<arr.length;i++){
   var r = 100;
}
console.log(r); //prints 100 

arr.forEach(function(){
  var w = 100;
});
console.log(w); //prints "w is not defined"

所以在你的情况下,part_top,part_left变量存在于for循环之外,只有最后指定的值将被回调函数占用,因为变量是通过引用传递的。看看这个答案

scope of variables in JavaScript callback functions

答案 1 :(得分:0)

使用forEach()方法代替for循环为我工作。虽然我不确定,为什么

我们最接近的解释是,由于forEach()接受匿名函数,因此在调用new运算符时,它会将变量的范围绑定到闭包中。

...
if (noun.skin !== 'Undefined'){
                    var animalParts = ['skin', 'eyes', 'mouth'];
                    var pos = cDim.ground[noun.pos.ground];

                    animalParts.forEach(function(item, g){ // <-works
                    // for (var g = 0; g < animalParts.length; g++){

                        var part_top = canvasheight - (pos[1] + imgOffsetY);
                        var part_left = pos[0] - imgOffsetX;
                        console.log("part:", noun[animalParts[g]], "part_position: ", part_top, part_left);

                        var img = new fabric.Image.fromURL(noun[animalParts[g]], function(s){
                            s.top = part_top;
                            s.left = part_left;
                            s.scale(imgScale);
                            // console.log(s, s.top,s.left, part_top, part_left);
                            canvas.add(s);
                        });
                    });
                }
...