1

I'm trying to implement a canvas on in my React project, essentially I need to be able to style text (font color, style, size) on top of an image. I have created a simple form for the styling attributes and the text to be entered.

When the user changes values within the form, I want the canvas to update the text accordingly and reflect the new text/style changes. Currently, i'm using useEffect with a blank array to trigger the writeFunction(). fontFamily, fontSize, colorCode, textA are all states that get changed when the user makes changes to the form.

I have tried changing the dependency array of the useEffect() to thefontFamily, fontSize, colorCode, textA but that has not worked successfully.

useEffect(() => {
    // dynamically assign the width and height to canvas
    const canvasEle = canvas.current;
    canvasEle.width = canvasEle.clientWidth;
    canvasEle.height = canvasEle.clientHeight;

    // get context of the canvas
    ctx = canvasEle.getContext("2d");
  }, []);

  useEffect(() => {
    writeText({
      text: textA,
      x: 350,
      y: 100,
    });
  }, []);

const writeText = (info) => {
const { text, x, y } = info;
    var imageObj = new Image();
    imageObj.onload = function () {
      ctx.drawImage(imageObj, 10, 10);
      ctx.beginPath();
      ctx.font = fontSize + "px " + fontFamily;
      ctx.textAlign = textAlign;
      ctx.textBaseline = "top";
      ctx.fillStyle = colorCode; 
      ctx.fillText(text, x, y);
      ctx.stroke();
    };
    imageObj.src = imageAddress; //imageAddress is a predetermined URL
    imageObj.width = "600px";
    imageObj.height = "550px";
  };

Here's what my form looks like:

<Form>
          <Form.Group className="mb-3" controlId="formBasicEmail">
            <Form.Label>Text 1</Form.Label>
            <Form.Control
              type="text"
              placeholder="Enter Text"
              onChange={(e) => setTextA(e.target.value)}
              value={textA}
            />
          </Form.Group>
          <Form.Group className="mb-3" controlId="formBasicEmail">
            <Form.Label>Font Size</Form.Label>
            <Form.Control
              type="text"
              placeholder="Enter Font Size"
              onChange={(e) => {setsize(e.target.value)
              console.log(e.target.value,'sizein114')}}
              value={size}
            />
          </Form.Group>
          <Form.Group className="mt-3" controlId="formBasicEmail">
            <Form.Label>Font Style</Form.Label>
            <Form.Control
              type="text"
              placeholder="Enter Font Style"
              onChange={(e) => setfamily(e.target.value)}
              value={family}
            />
          </Form.Group>
          <Form.Group className="mt-3" controlId="formBasicEmail">
            <Form.Label>Font Color</Form.Label>
            <Form.Control
              type="color"
              placeholder="Enter Font Color"
              onChange={(e) => setcolorCode(e.target.value)}
              defaultValue="#fffff"
            />
          </Form.Group>
</Form>

Update: This is the error I get when I pass the dependency array [fontFamily, fontSize, colorCode, textA] Dependency array error

Update: useState code

function App() {
  const canvas = useRef();
  let ctx = null;
  const [fontSize, setFontSize] = useState("28");
  const [fontFamily, setFontFamily] = useState("Calibri");
  const [colorCode, setcolorCode] = useState("red");
  const [textAlign, settextAlign] = useState("center");
  const [textA, setTextA] = useState("Title Here");
Fahad K
  • 11
  • 3

1 Answers1

0

If you put state values in the useEffect subscription array (e.g. [textA, size, family]), the effect function should run each time those values change. Make sure you use the right variables (you mention fontFamily but in your Form it says family).

If this doesn't work, omit the subscription array as a test – the effect should now run on all updates. Make sure the onload fires, too. If that does not work please include the useState code so we get the whole picture.

Ti Hausmann
  • 926
  • 8
  • 21
  • I've attached a screenshot of the error I get when I add the useEffect subscription array, and also the useState code. When the useEffect subscription array is blank, it only fires the `writeText` once during the initial render, changing the font/text values does not seem to call the `writeText` function. – Fahad K Feb 10 '22 at 04:14
  • @FahadK blank array means run once on mount, no array means run on every update. I think the dependencies are fine and the issue is your `let ctx` – React does not remember this value between renders. Use canvas.current.getContext() each time or put ctx in a store. Related/possible Duplicate: https://stackoverflow.com/a/56156394/860205 – Ti Hausmann Feb 10 '22 at 14:46