web-dev-qa-db-fra.com

Ajout d'une toile à l'intérieur d'une autre toile: obj.setCoords n'est pas une fonction (fabric js)

Commencez à utiliser fabric.js et essayez d’ajouter une toile à l’intérieur d’une autre toile afin que la toile supérieure reste constante et que j’ajoute des objets à la toile intérieure. 

Voici l'extrait d'ajouter une toile à une autre toile.

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

et mon html ressemble à ceci 

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

Une fois ces éléments ajoutés avec succès, ce que je vais faire est d’ajouter les coordonnées au canevas intérieur, afin qu’il ressemble l’un à l’autre à l’utilisateur final. 

Cependant, couru dans l'erreur ci-dessous pour le code essayé 

    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

En regardant le message d'erreur, je suis juste allé à la ligne d'erreur et voici ce que j'ai trouvé dans la console chrome

 enter image description here

Est-ce que quelqu'un peut indiquer l'erreur dans mes codes?

Après avoir passé au travers de discussions et de solutions Internet, j'utilise Fabric Rectangle comme tondeuse et j'établis des limites qui permettent à l'utilisateur de jouer/jouer avec cette tondeuse en particulier.

En rouge pointillé ( image ci-dessous ) est ma tondeuse et maintenant je peux relier la chute et ci-dessous est le code pour ajouter une image avec une tondeuse.

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);

    });
}

 enter image description here

Maintenant, lors de l'ajout d'une image/couche au canevas, je lie cette image/couche/texte à la tondeuse que j'ai créée. 

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");

}

Et le ressemble, après restriction de limites,  enter image description here

Voici le violon que j'ai créé avec des URL d'image statique. 

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

Donc, je reste avec cette solution pour le moment et je sens vraiment que c'est hacky et sale. Vous recherchez d'autres solutions propres.

5
Suresh Atta

Autant que je sache, vous ne pouvez pas ajouter de zone de travail à une autre zone de travail - vous obtenez cette erreur car elle tente d'appeler setCoords () sur l'objet que vous avez ajouté, mais dans ce cas, il s'agit d'une autre zone de travail et d'un tissu. ne contient pas cette méthode (voir docs ). Je pense qu'une meilleure approche serait d'avoir deux toiles et de les positionner relativement en utilisant CSS - voir ce simple violon

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);
})

Pour gérer la sérialisation des objets, vous pouvez faire quelque chose comme ceci:

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);

Cela vous donnera alors le JSON pour tous les objets sur les deux toiles

3
John M

Je ne comprends pas pourquoi vous voulez faire cette chose, mais pour mettre une toile dans une autre toile, vous avez un moyen simple:

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

Ensuite, selon ce que vous souhaitez faire, vous aurez peut-être besoin d'ajustements supplémentaires, mais cela devrait fonctionner immédiatement.

2
AndreaBogazzi

Ne créez pas de toile

La plupart des objets en tissu (de mon expérience limitée) sont à un moment donné convertis en une toile. La création d'un canevas de tissu supplémentaire pour gérer un groupe d'objets n'a aucune utilité, car vous ne faites qu'ajouter une surcharge et imiter des tissus construits dans un objet de groupe.

Les objets Fabric sont essentiellement des wrappers de toiles DOM.

L'exemple suivant montre comment la matrice utilise un canevas pour stocker le contenu d'un groupe. La démo crée un groupe et l'ajoute au canevas du tissu, puis récupère le canevas du groupe et l'ajoute au DOM. En cliquant sur la toile du groupe, un cercle sera ajouté. Notez comment il se développe pour accueillir les nouveaux cercles.

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>

Utilisez un groupe plutôt qu'une nouvelle instance d'une toile de tissu.

Comme vous pouvez le voir, une toile est générée pour vous. Ajouter une autre toile de tissu (notez qu’une toile de tissu n’est pas la même chose qu’une toile DOM) ne fera qu’ajouter davantage de travail au tissu, qui a déjà beaucoup de travail à faire.

Il est préférable d’utiliser un groupe et d’avoir le contenu de l’autre objet de structure que vous souhaitez masquer. Cela contiendrait aussi son contenu dans un groupe.

Juste une image

Et pour ne pas dire un côté, un canevas DOM est une image et peut être utilisé par le tissu comme n'importe quelle autre image. Il est parfois préférable de faire le rendu directement sur le canevas plutôt que via un tissu afin d’éviter les surcoûts que le tissu doit utiliser.

Pour ajouter un canevas DOM à un tissu, ajoutez-le simplement en tant qu'image. La bordure et le texte ne sont pas des objets de structure et, mis à part le code à utiliser pour les rendre, ils n'utilisent ni mémoire, ni surcharge de ressources processeur si vous utilisiez un canevas de matrice et des objets.

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>

1
Blindman67

innerCanvas.setCoords(); est une fonction, mais vous en avez besoin seulement après avoir défini les coordonnées. Ou plus précisément, définissez ces quatre éléments:

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