开始使用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中找到的
有人可以在我的代码中指出错误吗?
答案 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");
}
现在,在将任何图像/图层附加到画布时,我将该图像/图层/文本绑定到我创建的剪辑器上。
{{1}}
这是我用一些静态图片网址创建的小提琴。
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。单击组的画布将添加一个圆圈。请注意它如何增长以适应新的圈子。
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();