在另一个画布中添加画布:obj.setCoords 不是函数(fabric js)
Posted
技术标签:
【中文标题】在另一个画布中添加画布:obj.setCoords 不是函数(fabric js)【英文标题】:Adding canvas inside another canvas: obj.setCoords is not a function( fabric js) 【发布时间】:2017-11-10 02:57:02 【问题描述】:开始使用 fabric.js 并尝试在另一个画布中添加一个画布,以便顶部画布保持不变,我将向内部画布添加对象。
这是将一个画布添加到另一个画布的 sn-p。
canvas = new fabric.Canvas('artcanvas');
innerCanvas = new fabric.Canvas("innerCanvas");
canvas.add(innerCanvas);
我的html看起来像这样
<canvas id="artcanvas" ></canvas>
<canvas id="innerCanvas" ></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 控制台中找到的内容
有人可以指出我的代码中的错误吗?
【问题讨论】:
你确定面料允许嵌套画布吗?如果目标是相互覆盖画布,您也可以使用 CSS 定位。console.log(t)
说什么?
@PraveenKumar t 是缩小版。它是提取版本中的 obj。更新了截图
你试过我的答案了吗?应该是你正在寻找的东西
【参考方案1】:
innerCanvas.setCoords();
ì 是一个函数,但只有在设置好坐标后才需要它。或者更准确地说,设置这四个元素:
innerCanvas.scaleX = 1;
innerCanvas.scaleY = 1;
innerCanvas.left = 150;
innerCanvas.top = 150;
innerCanvas.setCoords();
canvas.renderAll();
【讨论】:
【参考方案2】:不要创建画布
大多数织物中的物体(根据我有限的经验)在某些时候都会转换为画布。创建额外的织物画布来管理一组对象是毫无意义的,因为您只是在添加开销并模仿组对象中内置的织物。
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" ></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" ></canvas>
【讨论】:
【参考方案3】:我不明白你为什么要这样做,但是要将一个画布放在另一个画布中,你有一个简单的方法:
canvas = new fabric.Canvas('artcanvas');
innerCanvas = new fabric.Canvas("innerCanvas");
imageContainer = new fabric.Image(innerCanvas.lowerCanvasEl);
canvas.add(imageContainer);
然后,根据您想要做什么,您可能需要进行额外的调整,但这应该是开箱即用的。
【讨论】:
【参考方案4】:经过大量讨论和互联网解决方案后,我暂时使用 Fabric Rectangle 作为剪裁器并设置它的边界,以便用户可以在该特定剪裁器中放置/播放。
红色虚线(image below)是我的剪辑器,现在我可以绑定拖放,下面是使用剪辑器添加图像的代码。
function addImageToCanvas(imgSrc)
fabric.Object.prototype.transparentCorners = false;
fabric.Image.fromURL(imgSrc, function(myImg)
var img1 = myImg.set(
left: 20,
top: 20,
width: 460,
height: 460
);
img1.selectable = false;
canvas.add(img1);
var clipRectangle = new fabric.Rect(
originX: 'left',
originY: 'top',
left: 150,
top: 150,
width: 200,
height: 200,
fill: 'transparent',
/* use transparent for no fill */
strokeDashArray: [10, 10],
stroke: 'red',
selectable: false
);
clipRectangle.set(
clipFor: 'layer'
);
canvas.add(clipRectangle);
);
现在,在将任何图像/图层附加到画布时,我将该图像/图层/文本绑定到我创建的剪辑器。
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");
看起来像,在限制后,
这是我用一些静态图片 url 创建的小提琴。
https://jsfiddle.net/sureshatta/yxuoav39/
所以我现在一直使用这个解决方案,我真的觉得这很老套和肮脏。正在寻找其他一些干净的解决方案。
【讨论】:
哇,Suresh,这是一个很好的例子!感谢您的努力【参考方案5】:据我所知,您无法将画布添加到另一个画布 - 当它尝试在您添加的对象上调用 setCoords() 时,您会遇到该错误,但在这种情况下,它是另一个画布和织物.Canvas 不包含该方法(请参阅docs)。我认为更好的方法是拥有两个画布并使用 CSS 相对定位它们 - 请参阅 this simple fiddle
HTML
<div class="parent">
<div class="artcanvas">
<canvas id="artcanvas" ></canvas>
</div>
<div class="innerCanvas">
<canvas id="innerCanvas" ></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
【讨论】:
感谢您的帮助。不,在X时间点,如果我保存artcanvas
的状态,我错过了innerCanvas
的变化,我必须处理canvas的两个状态。想避免它。
好的。在那种情况下,我认为您需要更详细地解释为什么您需要两个单独的画布对象
假设我正在设计一件带有用户给定徽标和文字的 T 恤(他也可以选择型号)。所以我的 T 恤将在画布 1 和用户游戏区(我想让他有机会放置一些预定义的徽标和文本。否则他可能会将徽标放在他喜欢的任何地方。)成为用户可以放下东西的另一个画布。所以在任何时候,如果我保存一个主画布,内部画布也会保存,最后我会得到带有徽标/文本的 T 恤的最终输出。如果它们是分开的,我必须再次处理这两者可能会陷入混乱。希望它能解释一下。
我明白了。所以当你保存时,你想要生成什么?您可以对其进行进一步处理的图像或对象列表?
所以对于第一部分 - 在保存时,您可以将第二个画布序列化为图像,作为图像对象添加到第一个画布,然后保存。也许不漂亮,但它应该工作?至于结合JSON我想你只需要改变内部画布上每个对象的left和top属性?以上是关于在另一个画布中添加画布:obj.setCoords 不是函数(fabric js)的主要内容,如果未能解决你的问题,请参考以下文章