Проблема с использованием холста в React - PullRequest
0 голосов
/ 20 июня 2020
• 1000

const canvasOptions = () => {
  const canvas = canvasRef.current;
  const ctx = canvas.getContext("2d");

  // Start position of drawing
  const startPosition = (e) => {
    setIsPainting(true);
    drawCanvas(e);
  };

  // Finished position of drawing
  const finishedPosition = () => {
    setIsPainting(false);
    ctx.beginPath();
  };

  const drawCanvas = (e) => {
    if (!isPainting) return;
    ctx.lineWidth = 10;
    ctx.lineCap = "round";
    ctx.strokeStyle = "red";
    ctx.lineTo(e.clientX, e.clientY);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(e.clientX, e.clientY);
    console.log('drawing')
  };

  canvas.addEventListener("mousedown", (e) => {
    startPosition(e);
  });

  canvas.addEventListener("mouseup", () => {
    finishedPosition();
  });

  canvas.addEventListener("mousemove", (e) => {
    drawCanvas(e);
  });
};

useEffect(() => {
  canvasOptions();
}, [isPainting]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

1 Ответ

0 голосов
/ 20 июня 2020

вот ваша проблема:

  const startPosition = (e) => {
    setIsPainting(true);
    drawCanvas(e);
  };

вы запускаете обновление состояния setIsPainting, а затем сразу запускаете drawCanvas, которое ретранслирует состояние рисования. и реагировать на состояние обновления асинхронно, поэтому при drawCanvas fire:

 const drawCanvas = (e) => {
    if (!isPainting) return;
    ctx.lineWidth = 10;
    ctx.lineCap = "round";
    ctx.strokeStyle = "red";
    ctx.lineTo(e.clientX, e.clientY);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(e.clientX, e.clientY);
    console.log('drawing')
  };

isPainting будет ложным, поэтому функция вернется.

для решения этой проблемы попробуйте добавить запуск drawCanavs в useEffect hook или componentDidUpdate для класса Component, например:

useEffect(()=>{
drawCanvas(startPosition)
,[isPainting]}

этот эффект сработает, когда isPainting изменение состояния + вам нужно добавить дополнительное состояние для сохранения startPosition или события щелчка.

отредактировано: окончательный код:

const MyCanavas = ()=>{
canvasRef = useRef();
const [isPainting,setIsPainting] = useState({painting:false,startPostion:null})

 const startPosition = (e) => {
const event = e
    setIsPainting({painting:true,startPostion:event});
  };
  const drawCanvas = (e) => {
    if (!isPainting.painting) return;
    const ctx = canvasRef.current.getContext("2d");
    ctx.lineWidth = 10;
    ctx.lineCap = "round";
    ctx.strokeStyle = "red";
    ctx.lineTo(e.clientX, e.clientY);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(e.clientX, e.clientY);
    console.log('drawing')
  };
  // Finished position of drawing
  const finishedPosition = () => {
    const ctx = canvasRef.current.getContext("2d");
    setIsPainting({painting:false,startPostion:null});
    ctx.beginPath();
  };

useEffect(()=>{
const canvas = canvasRef.current
  canvas.addEventListener("mousedown", (e) => {
    startPosition(e);
  });

  canvas.addEventListener("mouseup", () => {
    finishedPosition();
  });

  canvas.addEventListener("mousemove", (e) => {
    drawCanvas(e);
  });
return ()=>{
canvas.removeEventListener("mousedown")
canvas.removeEventListener("mouseup")
canvas.removeEventListener("mousemove") // clean up 
}

},[])

useEffect(()=>{
drawCanvas(isPainting.startPosition)
},[isPainting] 

return <Canvas ref={canvasRef}/>
}
...