* 🚀 Draw Command ready for connect [Rebase]
* revert schema changes
* fix & replace Button with theme button
* fix UI
* add test cases
* fix travis issue
* on image upload enable send button
* revert schema.db changes
* revert UI changes
* fix suggestions
* Update app/javascript/chat/draw/index.jsx
Co-authored-by: Nick Taylor <nick@iamdeveloper.com>
* update test cases
* remove commented code
* Trigger Travis CI
Co-authored-by: Narender Singh <narender2031@gmail.com>
Co-authored-by: Nick Taylor <nick@iamdeveloper.com>
186 lines
4.8 KiB
JavaScript
186 lines
4.8 KiB
JavaScript
import { h } from 'preact';
|
|
import { useRef, useEffect, useState } from 'preact/hooks';
|
|
import PropTypes from 'prop-types';
|
|
import { chatDrawPalettes } from '../../utilities/Constants';
|
|
import { Button } from '@crayons';
|
|
|
|
/**
|
|
* Draw function is wrapped in this component
|
|
*
|
|
* @example
|
|
* <Draw
|
|
* sendCanvasImage={sendCanvasImage}
|
|
* />
|
|
*
|
|
*
|
|
* @param {object} props
|
|
* @param {function} props.sendCanvasImage
|
|
*/
|
|
function Draw({ sendCanvasImage }) {
|
|
const canvasRef = useRef(null);
|
|
const [isDrawing, setIsDrawing] = useState(false);
|
|
const [drawColor, setDrawColor] = useState('#F58F8E');
|
|
const [coordinates, setCoordinates] = useState({});
|
|
const [sendButtonDisabled, setSendButtonDisabled] = useState(true);
|
|
const prevCoordinates = usePrevious(coordinates);
|
|
|
|
const handleCanvasSend = () => {
|
|
const canvas = canvasRef.current;
|
|
canvas.toBlob((blob) => {
|
|
sendCanvasImage(new File([blob], 'draw.png'));
|
|
});
|
|
};
|
|
|
|
const handleMouseDown = (e) => {
|
|
setCoordinates({ x: e.offsetX, y: e.offsetY });
|
|
setIsDrawing(true);
|
|
};
|
|
|
|
const handleImageDrop = (e) => {
|
|
e.preventDefault();
|
|
if (!canvasRef.current) {
|
|
return;
|
|
}
|
|
const canvas = canvasRef.current;
|
|
const context = canvas.getContext('2d');
|
|
canvas.classList.remove('opacity-25');
|
|
|
|
const { files } = e.dataTransfer;
|
|
const img = new Image();
|
|
img.src = URL.createObjectURL(files[0]);
|
|
|
|
img.onload = () => {
|
|
const scale = Math.min(
|
|
canvas.width / img.width,
|
|
canvas.height / img.height,
|
|
);
|
|
setSendButtonDisabled(false);
|
|
const x = canvas.width / 2 - (img.width / 2) * scale;
|
|
const y = canvas.height / 2 - (img.height / 2) * scale;
|
|
context.drawImage(img, x, y, img.width * scale, img.height * scale);
|
|
};
|
|
};
|
|
|
|
const handleClearCanvas = () => {
|
|
setSendButtonDisabled(true);
|
|
if (!canvasRef.current) {
|
|
return;
|
|
}
|
|
const context = canvasRef.current.getContext('2d');
|
|
context.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
};
|
|
|
|
const handleDragHover = (e) => {
|
|
e.preventDefault();
|
|
|
|
canvasRef.current.classList.add('opacity-25');
|
|
};
|
|
|
|
const handleChangeColor = (e) => {
|
|
setDrawColor(e.target.style.backgroundColor);
|
|
};
|
|
|
|
const handleDragExit = (e) => {
|
|
e.preventDefault();
|
|
canvasRef.current.classList.remove('opacity-25');
|
|
canvasRef.current.classList.add('opacity-100');
|
|
};
|
|
|
|
const handleMouseMove = (e) => {
|
|
if (isDrawing) {
|
|
setSendButtonDisabled(false);
|
|
setCoordinates({ x: e.offsetX, y: e.offsetY });
|
|
}
|
|
};
|
|
|
|
const handleMouseUp = () => {
|
|
setCoordinates({});
|
|
setIsDrawing(false);
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!canvasRef.current) {
|
|
return;
|
|
}
|
|
|
|
const context = canvasRef.current.getContext('2d');
|
|
|
|
if (isDrawing) {
|
|
context.beginPath();
|
|
context.strokeStyle = drawColor;
|
|
context.lineWidth = 2;
|
|
context.moveTo(prevCoordinates.x, prevCoordinates.y);
|
|
context.lineTo(coordinates.x, coordinates.y);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
}, [drawColor, isDrawing, coordinates, prevCoordinates]);
|
|
|
|
return (
|
|
<div className="p-4 grid gap-2 crayons-card mb-4 connect-draw">
|
|
<div className="mb-1 draw-title">
|
|
<h2>Connect Draw</h2>
|
|
<div className="connect-draw__colors">
|
|
{chatDrawPalettes.map((color) => (
|
|
<button
|
|
className="connect-draw__color"
|
|
onClick={handleChangeColor}
|
|
style={`background-color: ${color}`}
|
|
title={`Change color to ${color}`}
|
|
key={color}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<div
|
|
aria-hidden
|
|
className="connect-draw__draw-area"
|
|
onMouseUp={handleMouseUp}
|
|
>
|
|
<canvas
|
|
className="connect-draw__draw"
|
|
ref={canvasRef}
|
|
onMouseDown={handleMouseDown}
|
|
onMouseMove={handleMouseMove}
|
|
onDrop={handleImageDrop}
|
|
onDragOver={handleDragHover}
|
|
onDragExit={handleDragExit}
|
|
height="600"
|
|
width="400"
|
|
/>
|
|
<div className="connect-draw__actions">
|
|
<Button
|
|
onClick={handleClearCanvas}
|
|
title="Clear the canvas."
|
|
type="button"
|
|
size="s"
|
|
variant="secondary"
|
|
>
|
|
Clear
|
|
</Button>
|
|
<Button
|
|
onClick={handleCanvasSend}
|
|
title="Send the canvas."
|
|
disabled={sendButtonDisabled}
|
|
>
|
|
Send
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function usePrevious(value) {
|
|
const ref = useRef();
|
|
useEffect(() => {
|
|
ref.current = value;
|
|
}, [value]);
|
|
|
|
return ref.current;
|
|
}
|
|
Draw.propTypes = {
|
|
sendCanvasImage: PropTypes.func.isRequired,
|
|
};
|
|
|
|
export default Draw;
|