How to open react canvas in a new window using react portal?

Viewed 29

I want to make a whiteboard. The whiteboard will open in a new window. I am using react portal to open the whiteboard in a new window. All are working fine. But drawing in canvas does not work. Don't understand what I am doing wrong.Please help!!

I have shared my code below which I tried so far.

Menu.tsx

export default function Menu(props: { buttonClassName?: string }) {
  const isMobile = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'));
  const [aboutOpen, setAboutOpen] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const [settingsOpen, setSettingsOpen] = useState(false);
  const { setIsBackgroundSelectionOpen } = useVideoContext();
  const [showWindowPortal, setWindowPortal] = useState(false);
  const Toggle=()=>setWindowPortal(!showWindowPortal);

  const anchorRef = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    window.addEventListener('beforeunload', () => {
      setWindowPortal(false);

    });
  });

  function toogleWhiteboardPortal(e: any) {
    setWindowPortal(e.target.value);
  };

   function closeWhiteboardPortal (e:any) {
    setWindowPortal(e.target.value);
  };
  

  return (
    <>
     
      <MenuContainer
        open={menuOpen}
        onClose={() => setMenuOpen(isOpen => !isOpen)}
        anchorEl={anchorRef.current}
        anchorOrigin={{
          vertical: 'top',
          horizontal: 'left',
        }}
        transformOrigin={{
          vertical: isMobile ? -55 : 'bottom',
          horizontal: 'center',
        }}
      >           
        <MenuItem
          onClick={() => {
            Toggle();
          }}
        >
          <Typography variant="body1">Whiteboard</Typography>
        </MenuItem>
      </MenuContainer>          
      {showWindowPortal ? <Whiteboard 
      
      /> : null}
    </>
  );
}

Whiteboard.tsx

const useStyles = makeStyles({
  canvascover: {
    opacity: '1',
  },
});

export default function Whiteboard(props) {
  const classes = useStyles();
  const [isDrawing, setIsDrawing] = useState(false);
  const [color, setColor] = useState('#3B3B3B');
  const [size, setSize] = useState('3');
  const canvasRef = useRef(null);
  const ctx = useRef(null);
  const timeout = useRef(null);
  const [cursor, setCursor] = useState('default');
  const [container, setContainer] = useState(null);
  const newWindow = useRef(null);
  

   useEffect(() => {
     // Create container element on client-side
     setContainer(document.createElement('div'));
   }, []);

  useEffect(() => {
    // When container is ready
    if (container) {

      //Create window
      newWindow.current = window.open('', '', 'width=600,height=400,left=200,top=200');
      // // Append container
      // setContainer(document.createElement('div'));
      newWindow.current.document.title = 'Whiteboard';
      newWindow.current.document.body.appendChild(container);

      // Save reference to window for cleanup
      const curWindow = newWindow.current;

      const canvas = canvasRef.current;
      ctx.current = canvas.getContext('2d');

      //Resizing
      canvas.height = window.innerHeight;
      canvas.width = window.innerWidth;

      //Load from locastorage
      const canvasimg = localStorage.getItem('canvasimg');
      if (canvasimg) {
        var image = new Image();
        ctx.current = canvas.getContext('2d');
        image.onload = function() {
          ctx.current.drawImage(image, 0, 0);
          setIsDrawing(false);
        };
        image.src = canvasimg;
      }

      // // Return cleanup function
      return () => curWindow.close();
    }
  }, [container]);

  const startPosition = ({ nativeEvent }) => {
    setIsDrawing(true);
    draw(nativeEvent);
  };

  const finishedPosition = () => {
    setIsDrawing(false);
    ctx.current.beginPath();
  };

  const draw = ({ nativeEvent }) => {
    console.log('entr');
    if (!isDrawing) {
      return;
    }
    const canvas = canvasRef.current;
    ctx.current = canvas.getContext('2d');
    ctx.current.lineWidth = size;
    ctx.current.lineCap = 'round';
    ctx.current.strokeStyle = color;

    ctx.current.lineTo(nativeEvent.clientX, nativeEvent.clientY);
    ctx.current.stroke();
    ctx.current.beginPath();
    ctx.current.moveTo(nativeEvent.clientX, nativeEvent.clientY);

    if (timeout.current !== undefined) clearTimeout(timeout.current);
    timeout.current = setTimeout(function() {
      var base64ImageData = canvas.toDataURL('image/png');
      localStorage.setItem('canvasimg', base64ImageData);
    }, 400);
  };

  const clearCanvas = () => {
    localStorage.removeItem('canvasimg');
    const canvas = canvasRef.current;
    const context = canvas.getContext('2d');
    context.fillStyle = 'white';
    context.fillRect(0, 0, canvas.width, canvas.height);

    //Passing clear screen
    if (timeout.current !== undefined) clearTimeout(timeout.current);
    timeout.current = setTimeout(function() {
      var base64ImageData = canvas.toDataURL('image/png');
      localStorage.setItem('canvasimg', base64ImageData);
    }, 400);
  };

  const getPen = () => {
    setCursor('default');
    setSize('3');
    setColor('#3B3B3B');
  };

  const eraseCanvas = () => {
    setCursor('grab');
    setSize('20');
    setColor('#FFFFFF');
    $('#circularcursor').show();
    $(document).ready(function() {
      $(document).on('mousemove', function(e) {
        $('#circularcursor').css({
          left: e.pageX,
          top: e.pageY,
        });
      });
    });

    if (!isDrawing) {
      return;
    }
  };

  return (
    container &&
    createPortal(
      <>
        <div className="canvas-btn">
          <button onClick={getPen} className="btn-width">
            Pencil
          </button>
          <div className="btn-width">
            <input type="color" value={color} onChange={e => setColor(e.target.value)} />
          </div>
          <div>
            <select className="btn-width" value={size} onChange={e => setSize(e.target.value)}>
              <option> 1 </option>
              <option> 3 </option>
              <option> 5 </option>
              <option> 10 </option>
              <option> 15 </option>
              <option> 20 </option>
              <option> 25 </option>
              <option> 30 </option>
            </select>
          </div>
          <button
            onClick={() => {
              clearCanvas();
            }}
            className="btn-width"
          >
            Clear
          </button>
          <div>
            <button
              onClick={() => {
                eraseCanvas();
              }}
              className="btn-width"
            >
              Erase
            </button>
          </div>
        </div>
        <canvas
          style={{ cursor: cursor }}
          onMouseDown={startPosition}
          onMouseUp={finishedPosition}
          onMouseMove={draw}
          ref={canvasRef}
          className={classes.canvascover}
        />
      </>,
      container
    )
  );
}
0 Answers
Related