Добавление холста внутри другого холста: obj.setCoords не является функцией (fabric js)

Начните с использования 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

введите описание изображения здесь

Может кто-то указать на ошибку в моих кодах?

Ответ 1

После прохождения обсуждений и интернет-решений на данный момент я использую Fabric Rectangle в качестве клипера и устанавливаю его границы, чтобы пользователь мог сбрасывать/играть с помощью этого конкретного клипера.

Пунктирный красный (изображение ниже) - это мой клипер, и теперь я могу связать выпадение, а ниже - код для добавления изображения с клипером.

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/

Так что я остаюсь с этим решением на данный момент, и я действительно чувствую, что это хаки и грязные. Ищете другие чистые решения.

Ответ 2

Насколько я знаю, вы не можете добавить холст к другому холсту - вы получаете эту ошибку, поскольку он пытается вызвать setCoords() для объекта, который вы добавили, но в этом случае это другой холст и ткань .Canvas не содержит этого метода (см. docs). Я думаю, что лучший подход состоял бы в том, чтобы иметь два холста и относить их относительно с помощью CSS - см. эта простая скрипка

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 для всех объектов на обеих полотнах

Ответ 3

У меня нет понимания, почему вы хотите сделать это, но чтобы поместить холст внутри другого холста, у вас есть один простой способ:

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

Затем, в зависимости от того, что вы хотите сделать, вам могут потребоваться дополнительные настройки, но это должно работать из коробки.

Ответ 4

Не создавайте холст

Большинство объектов в ткани (из моего ограниченного опыта) в какой-то момент преобразуются в холст. Создание дополнительного холста ткани для управления группой объектов является бессмысленным, поскольку вы просто добавляете служебные и имитирующие ткани, созданные в объекте групп.

Объекты ткани в основном представляют собой обертки холлов DOM.

В следующем примере показано, как ткань использует холст для хранения содержимого группы. Демо создает группу и добавляет ее к холсту ткани, затем получает холст групп и добавляет его в 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 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>

Ответ 5

innerCanvas.setCoords(); - функция, но она вам нужна только после того, как вы установили координаты. Или более точно, установите эти четыре элемента:

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