在另一个画布中添加画布:obj.setCoords不是一个函数(fabric js)

时间:2017-06-08 11:48:04

标签: javascript html canvas html5-canvas fabricjs

开始使用fabric.js并尝试在另一个画布中添加画布,以便顶部画布保持不变,并且我将向内部画布添加对象。

以下是将画布添加到另一个画布的片段。

canvas  = new fabric.Canvas('artcanvas');
innerCanvas = new fabric.Canvas("innerCanvas");
canvas.add(innerCanvas);

我的html看起来像这样

<canvas id="artcanvas" width="500" height="500"></canvas>
<canvas id="innerCanvas" width="200" height="200" ></canvas>

成功添加这些后,我要做的是,将坐标添加到内部画布,使其看起来像是最终用户的另一个。

但是,尝试过的代码

遇到了以下错误
    Uncaught TypeError: obj.setCoords is not a function
    at klass._onObjectAdded (fabric.js:6894)
    at klass.add (fabric.js:231)
    at main.js:60
    at fabric.js:19435
    at HTMLImageElement.fabric.util.loadImage.img.onload (fabric.js:754)
_onObjectAdded @ fabric.js:6894
add @ fabric.js:231
(anonymous) @ main.js:60
(anonymous) @ fabric.js:19435
fabric.util.loadImage.img.onload @ fabric.js:754

查看错误消息,只是转到错误行,这是我在chrome console中找到的

enter image description here

有人可以在我的代码中指出错误吗?

5 个答案:

答案 0 :(得分:6)

经过讨论和互联网解决方案之后,暂时我使用Fabric Rectangle作为限幅器并设置它的边界,以便用户能够在该特定限幅器中放弃/播放。

虚线红色(图像在下面)是我的剪辑器,现在我可以绑定下方了,下面是使用限幅器添加图像的代码。

function addLayerToCanvas(laImg) {

    var height = $(laImg).height();
    var width = $(laImg).width();
    var clickedImage = new Image();
    clickedImage.onload = function(img) {

        var pug = new fabric.Image(clickedImage, {

            width: width,
            height: height,
            left: 150,
            top: 150,
            clipName: 'layer',
            clipTo: function(ctx) {
                return _.bind(clipByName, pug)(ctx)
            }
        });
        canvas.add(pug);
    };
    clickedImage.src = $(laImg).attr("src");

}

enter image description here

现在,在将任何图像/图层附加到画布时,我将该图像/图层/文本绑定到我创建的剪辑器上。

{{1}}

在限制边界之后看起来像enter image description here

这是我用一些静态图片网址创建的小提琴。

https://jsfiddle.net/sureshatta/yxuoav39/

所以我现在仍然坚持使用这个解决方案,我觉得这很糟糕。寻找其他一些清洁的解决方案。

答案 1 :(得分:4)

据我所知,您无法将画布添加到另一个画布 - 当您尝试在已添加的对象上调用setCoords()时,您会收到该错误,但在此如果它是另一个画布和布料.Canvas不包含该方法(参见docs)。我认为更好的方法是使用两个画布并使用CSS相对定位它们 - 请参阅this simple fiddle

<强> HTML

<div class="parent">
  <div class="artcanvas">
    <canvas id="artcanvas"  width="500" height="500"></canvas>  
  </div>
  <div class="innerCanvas">
    <canvas id="innerCanvas" width="200" height="200" ></canvas>  
  </div>
</div>

<强> CSS

.parent {
  position: relative;
  background: black;
}


.artcanvas {
  position: absolute;
  left: 0;
  top: 0;
}

.innerCanvas {
  position: absolute;
  left: 150px;
  top: 150px;
}

<强> JS

$(document).ready(function() {
    canvas  = new fabric.Canvas('artcanvas');
  innerCanvas = new fabric.Canvas("innerCanvas");
  var rect = new fabric.Rect({
    fill: 'grey',
    width: 500,
    height: 500
  });
  canvas.add(rect);
  var rect2 = new fabric.Rect({
    fill: 'green',
    width: 200,
    height: 200
  });
  innerCanvas.add(rect2);
})

要处理对象序列化,您可以执行以下操作:

var innerObjs = innerCanvas.toObject();
console.dir(innerObjs);
var outerObjs = canvas.toObject();
innerObjs.objects.forEach(function (obj) {
    obj.left += leftOffset; // offset of inner canvas
  obj.top += topOffset;
  outerObjs.objects.push(obj);
    });
var json = JSON.stringify(outerObjs);

然后,这将为您提供两个画布上所有对象的JSON

答案 2 :(得分:2)

我不明白你为什么要做这件事,但是把画布放在另一个画布里面,你有一个简单的方法:

canvas  = new fabric.Canvas('artcanvas');
innerCanvas = new fabric.Canvas("innerCanvas");
imageContainer = new fabric.Image(innerCanvas.lowerCanvasEl);
canvas.add(imageContainer);

然后根据你想做的事情,你可能需要额外的调整,但这应该是开箱即用的。

答案 3 :(得分:1)

不要创建画布

织物中的大多数物体(来自我有限的经验)在某些时候被转换为画布。创建一个额外的结构画布来管理一组对象是没有意义的,因为你只是增加了开销并模仿了在group对象中构建的结构。

Fabric对象基本上是DOM画布包装器。

以下示例显示了Fabric如何使用画布存储组的内容。该演示创建一个组并将其添加到结构画布,然后获取组画布并将其添加到DOM。单击组的画布将添加一个圆圈。请注意它如何增长以适应新的圈子。

const radius = 50;
const fill = "#0F0";
var pos = 60;

const canvas = new fabric.Canvas('fCanvas');

// create a fabric group and add two circles
const group = new fabric.Group([
    new fabric.Circle({radius, top : 5, fill,  left : 20 }),
    new fabric.Circle({radius, top : 5, fill,  left : 120 })
], { left: 0, top: 0 });

// add group to the fabric canvas;
canvas.add(group);

// get the groups canvas and add it to the DOM
document.body.appendChild(group._cacheContext.canvas);

// add event listener to add circles to the group
group._cacheContext.canvas.addEventListener("click",(e)=>{
  group.addWithUpdate(
      new fabric.Circle({radius, top : pos, fill : "blue",  left : 60 }) 
  );
  canvas.renderAll();
  pos += 60;
});
canvas {
   border : 2px solid black;
}
div {
   margin : 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.13/fabric.min.js"></script>
<div>Fabric's canvas  "canvas = new fabric.Canvas('fCanvas');"</div>
<canvas id="fCanvas" width="256" height="140"></canvas>
<div>Fabric group canvas below. Click on it to add a circle.</div>

使用组而不是结构画布的新实例。

正如您所见,为您生成了一个画布。添加另一个结构画布(请注意,结构画布与DOM画布不同)只会为结构添加更多工作,这已经有很多工作要做。

您最好使用一个组,并保留您希望隐藏的其他结构对象的内容。这也包含其在组中的内容。

只是一张图片

只有一面不是,DOM画布是一个图像,可以像任何其他图像一样被面料使用。有时最好直接渲染到画布而不是通过结构,这样就可以避免渲染结构需要操作的开销。

要将DOM画布添加到结构,只需将其添加为图像即可。边框和文本不是结构对象,除了渲染它们的代码之外不占用任何内存,并且如果使用结构画布和对象,则不会产生额外的CPU开销。

const canvas = new fabric.Canvas('fCanvas');

// create a standard DOM canvas
const myImage = document.createElement("canvas");

// size it add borders and text
myImage.width = myImage.height = 256;
const ctx = myImage.getContext("2d");
ctx.fillRect(0,0,256,256);
ctx.fillStyle = "white";
ctx.fillRect(4,4,248,248);
ctx.fillStyle = "black";
ctx.font = "32px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("The DOM canvas!",128,128);

// use the canvas to create a fabric image and add it to fabrics canvas.
canvas.add( new fabric.Image(myImage, {
  left: (400 - 256) / 2,
  top: (400 - 256) / 2,
}));
canvas {
   border : 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.13/fabric.min.js"></script>
<canvas id="fCanvas" width="400" height="400"></canvas>

答案 4 :(得分:0)

innerCanvas.setCoords();是一个函数,但只有在设置坐标后才需要它。或者更确切地说,设置这四个要素:

innerCanvas.scaleX = 1;
innerCanvas.scaleY = 1;
innerCanvas.left = 150;
innerCanvas.top = 150;
innerCanvas.setCoords();
canvas.renderAll();