0

I try to draw various products from an array on the canvas. Now I succeed to a certain extent. But if I want to output the variable "articleNumber", the product images "oImg" change, but not the text. This text will probably be overwritten with every new drawing and at the end all texts are identical with the last one in the array. It is probably related to the "var text". Can any of you help me to solve this problem easily? I'm relatively unfamiliar with the subject and therefore don't really know what to look for.

for (var i = 0; i < allproducts.length; i++) {
  // Product image
  var articleNumber = allproducts[i];

  fabric.Image.fromURL('img/products/' + articleNumber + '.png', function(oImg) {
      oImg.scaleToHeight(fullHeight/10)
          .set('originX', 'center')
          .set('left', Math.floor(Math.random() * fullWidth))
          .set('top', Math.floor(Math.random() * (fullHeight - 200)))

    // Article Number
    var text = new fabric.Text('  '+ allproducts[i] + '  ', {
        left: oImg.left,
        top: oImg.top + fullHeight/10 + 2,
        originX: 'center', 
        fontSize: 9,
        fontFamily: 'Helvetica',
        textAlign: 'center',
        backgroundColor: 'white'
    });

    // Grouped Article number and Product Image
    var product = new fabric.Group([oImg, text], {
        hasControls: false,
    });

    // Add Product to Canvas
    canvas.add(product);
});
}

Regards, Reden G.

1 Answers1

0

There is a very simple fix to your problem and that's to use let instead of var to declare i within your for statement.

for (let i = 0; i < allproducts.length; i++) {  
  // ...
}

The problem was that within all of your callbacks to fromURL, the value of i was stuck at the last value it had when the for loop completed. This is because when you declare the i variable with var, its scope is not just within the for loop, but throughout the containing function. There is thus only one i variable which is shared by all your callbacks, and since they all run after the loop is completed, they get the last value that i had. If you put a console.log within your callback, you will find this to be the case.

When you use let, on the other hand, a new i variable is created for every iteration of the for loop. This is because let has block scope and the for loop is a block. Thus each callback has its own unique and correct value of i.

There's a discussion of the differences between let and var here

Here is a working version of your code:

const allproducts = [1, 2, 3, 4];

var canvas = new fabric.Canvas('foo');

for (let i = 0; i < allproducts.length; i++) {
  // Product image
  var articleNumber = allproducts[i];

  const fullHeight = 1000;
  const fullWidth = 500;

  const imageUrl = 'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcRlkStdmho9qfM4ofmV4lSVRV_MPmrxPu1f1Q&usqp=CAU';

  fabric.Image.fromURL(imageUrl, function(oImg) {

    oImg.scaleToHeight(fullHeight / 10)
      .set('originX', 'center')
      .set('left', Math.floor(Math.random() * fullWidth))
      .set('top', Math.floor(Math.random() * (fullHeight - 200)))

    // Article Number
    var text = new fabric.Text('  ' + allproducts[i] + '  ', {
      left: oImg.left,
      top: oImg.top + fullHeight / 10 + 2,
      originX: 'center',
      fontSize: 9,
      fontFamily: 'Helvetica',
      textAlign: 'center',
      backgroundColor: 'white'
    });

    // Grouped Article number and Product Image
    var product = new fabric.Group([oImg, text], {
      hasControls: false,
    });

    // Add Product to Canvas
    canvas.add(product);
  });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>
<canvas id="foo" width="1200" height="1200"></canvas>
Richard Hunter
  • 1,933
  • 2
  • 15
  • 22