javascriptreactjsfabricjsfabric

Fabric.js and react, sendBackward and bringForward are being reported as not functions, despite other fabric options/ functions working


This is a React/ Fabric.js test I'm trying in order to figure out what I'm doing wrong with moving objects in the stack. The canvas inits and the red and blue boxes are there, they can be manipulated using the gizmo, and preserveObjectStacking is working, however, both bringForward and sendBackward report that there is no such function, these are canvas functions, yes? They are in the documentation, but they always error with "* is not a function" Any help would be much appreciated.

import React, { useEffect, useRef, useState } from 'react';
import { Canvas, Rect } from 'fabric';

const FabricCanvasTest = () => {
  const canvasRef = useRef(null);
  const [canvas, setCanvas] = useState(null);
  const [activeObject, setActiveObject] = useState(null);

  useEffect(() => {
    const initCanvas = new Canvas(canvasRef.current, {
      width: 400,
      height: 400,
      backgroundColor: '#f0f0f0',
      preserveObjectStacking: true,
    });

    const redSquare = new Rect({
      left: 50,
      top: 50,
      fill: 'red',
      width: 100,
      height: 100
    });

    const blueSquare = new Rect({
      left: 200,
      top: 200,
      fill: 'blue',
      width: 100,
      height: 100
    });

    initCanvas.add(redSquare, blueSquare);
    setCanvas(initCanvas);

    initCanvas.on('selection:created', (e) => setActiveObject(e.selected[0]));
    initCanvas.on('selection:updated', (e) => setActiveObject(e.selected[0]));
    initCanvas.on('selection:cleared', () => setActiveObject(null));

    return () => {
      initCanvas.dispose();
    };
  }, []);

  const bringForward = () => {
    if (activeObject) {
      activeObject.bringForward();
      canvas.renderAll();
    }
  };

  const sendBackward = () => {
    if (activeObject) {
      activeObject.sendBackwards();
      canvas.renderAll();
    }
  };

  return (
    <div>
      <canvas ref={canvasRef} />
      <div>
        <button onClick={bringForward} disabled={!activeObject}>Bring Forward</button>
        <button onClick={sendBackward} disabled={!activeObject}>Send Backward</button>
      </div>
      <p>
        {activeObject
          ? `Selected: ${activeObject.fill} square`
          : 'No object selected'}
      </p>
    </div>
  );
};

export default FabricCanvasTest;

Solution

  • I am not sure why the official API document for 'fabric.js' is not consistent with the actual interface it implemented. There are some functions that I used, you may take a try:

     const bringForward = () => {
          if (activeObject) {
          // bring to topmost
          // canvas.bringObjectToFront(activeObject)
          canvas.bringObjectForward(activeObject, true);
          canvas.renderAll();
        }
      };
    
    const sendBackward = () => {
        if (activeObject) {
          // send to bottom 
          // canvas.sendObjectBackwards(activeObject)
          canvas.sendObjectToBack(activeObject, true);
          canvas.renderAll();
        }
      };