-1

Here is my issue : I a have a class of objects defined by a certain amount of attributes and methodes among which :

  • A "type" attribute that resumes to text or image
  • A drawObject methode that will either draw (canvas drawImage function) the object on a canvas if it is an image or "write" the object on the same canvas if it is a text (canvas fillText function).

On the canvas a I can draw/writ any amount of those objects that are stored in an array.

My problem is I am trying to have those objects drawn in a given order so that the overlaping is consistent to the order of the objects in the array.

to do so, I am parsing all objects in the array in the following manner :

function drawer(obj) {
    return new Promise((resolve) => {
            let objToDraw = obj.drawObject();
            resolve(objToDraw);
    })
}

async function drawObjects() {
    for (const obj of pageObjects) {
        await drawer(obj);
    }
}

drawObjects();

My expectation was that the "for of" loop would only go from one iteration to the next if the drawObject function would have finished it's work including the drawing on the canvas. But all "text" objects are always drawn before the images and even the images are sometimes drawn in an unexpected order.

Here are the drawObject, wrapText (called by drawObject) methods :

drawObject() {
        if (this.type == "image")
        {
            var drawTheImg = new Image();
            drawTheImg.src = this.destImg
            drawTheImg.onload = function () {
                showCtx.save();
                showCtx.drawImage(drawTheImg, this.sx, this.sy, swidth, sheight, this.dx, this.dy, this.dwidth, this.dheight);
                showAlbumCtx.restore();
}.bind(this)
        } else {
            showAlbumCtx.save();
            showAlbumCtx.fillStyle = this.fontColor;
            showAlbumCtx.textBaseline = "top";
            this.wrapText((this.dy + this.textLineHeight));
            showAlbumCtx.restore();
        }
    }

    wrapText(y) {
        var words = this.containedText.split(' ');
        var line = '';
        showAlbumCtx.save();

        if (this.txtJustification === "right") {
            var x = (this.dx + this.textPadding) + (this.dwidth - this.textPadding);
        } else if (this.txtJustification === "center") {
            var x = (this.dx + this.textPadding) + ((this.dwidth - this.textPadding) / 2);
        } else {
            x = (this.dx + this.textPadding);
        }

        for(var n = 0; n < words.length; n++) {
            var testLine = line + words[n] + ' ';
            var metrics = showAlbumCtx.measureText(testLine);
            var testWidth = metrics.width;
            if (n > 0 && words[n - 1].match(/\n/g)) {
                showAlbumCtx.fillText(line, x, y);
                line = words[n] + ' ';
                y += this.textLineHeight;
            } else if (testWidth > this.textMaxWidth && n > 0) {
                showAlbumCtx.fillText(line, x, y);
                line = words[n] + ' ';
                y += this.textLineHeight;
            } else {
                line = testLine;
            }
        }

        showAlbumCtx.fillText(line, x, y);
        showAlbumCtx.restore();
    }

Thank you for any advice you could provide

phduc
  • 19
  • 6
  • 3
    Your `drawObject` methods needs to return a promise (that is resolved when the image was loaded and drawn). Just calling `drawObject` inside a `new Promise` doesn't cut it - you immediately resolve the promise with the return value `undefined`. – Bergi May 24 '21 at 13:24
  • Can be useful: https://stackoverflow.com/q/46399223/3702797 – Kaiido May 24 '21 at 13:31
  • 2
    But really the best is to first load your assets, and then start drawing. Having to wait for your assets when you already started drawing means that the "unfinished" drawing may be visible. – Kaiido May 24 '21 at 13:47

1 Answers1

-1

In case anybody needs the answer the issue was fixed in my case by using Bergi's advice and making the drawObject return a Promise.

phduc
  • 19
  • 6