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
)
);
}