0

ok, so, I have a functional component which renders 2 images in a Canvas with some text input from the user. I'm noticing that the 2nd image often doesn't render or say disappears from the Canvas.

I've a small editor which allows user to select fonts, font sizes, text color and font style like Bold and Italics .. these font properties are reflected in the Canvas text.

Below is my code ...

const handleDraw = (
    msg,
    fontSize,
    selectedFont,
    textColor,
    boldStyle,
    italicStyle,
    underlineStyle
  ) => {
    const img = document.getElementById("cardImage");
    const canvas = canvasRef.current;
    const context = canvas.getContext("2d");
    var factor = Math.max(canvas.width / img.width, canvas.height / img.height);
    const image = new Image();
    const logoImage = new Image();

    console.log(
      "Drawing image....handleDraw was called card content is ",
      imageContent
    );

    image.src = imageContent;
    logoImage.src = logo;
    canvas.width = image.width + 1200;
    canvas.height = image.height + 500;

    context.drawImage(image, 0, 0, img.width + 150, img.height - 20);
    image.onerror = function(err) {
      console.log("card image error : ", err);
    };
    
    //below line FAILS to draw an image
    context.drawImage(logoImage, img.width + 200, 0, 250, 100);

    logoImage.onerror = function(err) {
      console.log("Logo Image error ", err);
    };
    context.font =
      (boldStyle ? "bold " : "normal ") +
      (italicStyle ? " italic " : " ") +
      fontSize +
      "px " +
      selectedFont;
    console.log("context.font ",context.font)
    context.fillStyle = textColor;
    

    drawText(context, 400, 40, msg, img.width + 160,
      img.height / 6)

    
    
  };

function drawText(context, maxWidth, lineHeight, text, x, y) {
  
    // Split the text into an array of lines
    const lines = text.split("\n");
  
    // Loop through the lines and split into smaller chunks if necessary
    const newLines = [];
    for (const line of lines) {
      let words = line.split(" ");
      let currentLine = words[0];
      for (let i = 1; i < words.length; i++) {
        const width = context.measureText(currentLine + " " + words[i]).width;
        if (width > maxWidth) {
          newLines.push(currentLine);
          currentLine = words[i];
        } else {
          currentLine += " " + words[i];
        }
      }
      newLines.push(currentLine);
    }
  
    // Render the new array of lines on the canvas
    
    for (const line of newLines) {
      context.fillText(line, x, y);
      y += lineHeight;
    }
  }
Dev
  • 177
  • 1
  • 5
  • 15
  • One possible reason for the second image not rendering correctly could be that the image file is not loaded before trying to draw it on the Canvas. You can use the `onload` event of the `Image` object to ensure that the image is loaded before trying to draw it on the Canvas. – Arun B S Mar 22 '23 at 05:01
  • I don't see any React in this question. Your functions are just functions, not function components. Is there code missing from your question? – Andy Mar 22 '23 at 05:12
  • @ArunBS Image initially shows up at times but when based on user actions like selecting BOLD text format, changing fonts etc, the image disappears and later when you keep changing font properties or type in the text in a multiline text field, the image comes back. – Dev Mar 22 '23 at 05:21
  • @Andy this code is a part of a React functional component. The rest of the code uses Material UI based multiline text element which allows user to enter\update text. this text should get populated on Canvas in the font user has chosen. I thought those HTML elements were of no relevance to my issue. Let me see if I can add more code to my original question as SO reported an error earlier when I tried to post a lot of code indicating I was posting all code and not enough message to explain my issue. – Dev Mar 22 '23 at 05:22
  • @ArunBS please note, the image is a static file .. not some external image via URL. – Dev Mar 22 '23 at 05:27
  • Hi @ArunBS i think your solution worked.. just changed the code to ... and it renders it every time logoImage.onload = () => { context.drawImage(logoImage, img.width + 200, 0, 250, 100); } – Dev Mar 22 '23 at 05:32
  • @ArunBS while the solution works, it keeps flickering images as user either types text in the multiline text edit or when they change font properties as the canvas need to be redrawn to reflect those changes in a real time. May be I guess I have to live with it. – Dev Mar 22 '23 at 06:00
  • Don't load a new image at each stroke. Load your assets once, at the initialization of your app, and store the Image objects somewhere accessible to every call of your function. – Kaiido Mar 22 '23 at 08:35

0 Answers0