1. 程式人生 > 其它 >react-hooks實現簡單的繪圖、簽名功能

react-hooks實現簡單的繪圖、簽名功能

使用creat-react-app簡單搭建一個react-hooks專案

 return(<Fragment>
      <canvas
        ref={canvasRef}
        width={window.innerWidth}
        height={window.innerHeight}
      />
      <div className='SSS' onClick={clearCanvas}>清除</div>
 </Fragment>)

建立一個canvas繪圖區域

import React, { Fragment } from 'react'
const HOOK_SVG = 'm129.03125 63.3125c0-34.914062-28.941406-63.3125-64.519531-63.3125-35.574219 0-64.511719 28.398438-64.511719 63.3125 0 29.488281 20.671875 54.246094 48.511719 61.261719v162.898437c0 53.222656 44.222656 96.527344 98.585937 96.527344h10.316406c54.363282 0 98.585938-43.304688 98.585938-96.527344v-95.640625c0-7.070312-4.640625-13.304687-11.414062-15.328125-6.769532-2.015625-14.082032.625-17.960938 6.535156l-42.328125 64.425782c-4.847656 7.390625-2.800781 17.3125 4.582031 22.167968 7.386719 4.832032 17.304688 2.792969 22.160156-4.585937l12.960938-19.71875v42.144531c0 35.582032-29.863281 64.527344-66.585938 64.527344h-10.316406c-36.714844 0-66.585937-28.945312-66.585937-64.527344v-162.898437c27.847656-7.015625 48.519531-31.773438 48.519531-61.261719zm-97.03125 0c0-17.265625 14.585938-31.3125 32.511719-31.3125 17.929687 0 32.511719 14.046875 32.511719 31.3125 0 17.261719-14.582032 31.3125-32.511719 31.3125-17.925781 0-32.511719-14.050781-32.511719-31.3125zm0 0'
const HOOK_PATH = new Path2D(HOOK_SVG)
const SCALE = 0.3
const OFFSET = 80
function draw(
  ctx: {
    fillStyle: string; shadowColor: string; shadowBlur: number;
    save: () => void; scale:
    (arg0: number, arg1: number) => void;
    translate: (arg0: number, arg1: number) => void;
    fill: (arg0: Path2D) => void; restore: () => void
  },
  location: { x: any; y: any }) {

  ctx.fillStyle = 'deepskyblue'
  ctx.shadowColor = 'dodgerblue'
  ctx.shadowBlur = 20;
  ctx.save()
  ctx.scale(SCALE, SCALE)

  ctx.translate(location.x / SCALE - OFFSET, location.y / SCALE - OFFSET)
  ctx.fill(HOOK_PATH)
  ctx.restore()
}

function App() {
  const canvasRef = React.useRef<any>(null);
  let [Flag, setFlat] = React.useState(false)
  React.useEffect(() => {
    const canvas = canvasRef.current
    const ctx = canvas.getContext('2d')
    ctx.fillStyle = 'white';
    ctx.fillRect(10, 10, window.innerWidth, window.innerHeight);
    // 畫圖
    ctx.beginPath();
    ctx.moveTo(75, 50);
    ctx.lineTo(100, 75);
    ctx.lineTo(100, 25);
    ctx.lineWidth = '1';
    ctx.fillStyle = 'pink';
    ctx.fill();


  })
  const writing = (
    beginX: number,
    beginY: number,
    stopX: number,
    stopY: number,
    ctx: { beginPath: () => void; globalAlpha: number; lineWidth: number; strokeStyle: string; moveTo: (arg0: any, arg1: any) => void; lineTo: (arg0: any, arg1: any) => void; closePath: () => void; stroke: () => void },
  ) => {
    ctx.beginPath()  // 開啟一條新路徑
    ctx.globalAlpha = 1  // 設定圖片的透明度
    ctx.lineWidth = 3  // 設定線寬
    ctx.strokeStyle = 'pink'  // 設定路徑顏色
    ctx.moveTo(beginX, beginY)  // 從(beginX, beginY)這個座標點開始畫圖
    ctx.lineTo(stopX, stopY)  // 定義從(beginX, beginY)到(stopX, stopY)的線條(該方法不會建立線條)
    ctx.closePath()  // 建立該條路徑
    ctx.stroke()  // 實際地繪製出通過 moveTo() 和 lineTo() 方法定義的路徑。預設顏色是黑色。
  }
  React.useEffect(() => {
    let beginX: number; let beginY: number
    const canvas = canvasRef.current
    const ctx = canvas.getContext('2d')
    ctx.fillStyle = '#fff'
    ctx.fillRect(0, 0, canvas.width, canvas.height)
    console.log(ctx, 'canvas');

    // pc端 和 移動端事件
    canvas.addEventListener('click', function (event: { preventDefault: () => void; clientX: number; clientY: number }) {
      event.preventDefault() // 阻止在canvas畫布上簽名的時候頁面跟著滾動
      beginX = event.clientX
      beginY = event.clientY
      setFlat(true)


      ctx.fillStyle = 'deepskyblue'
      ctx.shadowColor = 'dodgerblue'
      ctx.shadowBlur = 20;
      ctx.save()
      ctx.scale(SCALE, SCALE)

      ctx.translate(event.clientX / SCALE - OFFSET, event.clientY / SCALE - OFFSET)
      ctx.fill(HOOK_PATH)
      ctx.restore()
    })
    canvas.addEventListener('mousemove', (event: { preventDefault: () => void; clientX: number; clientY: number }) => {
      event.preventDefault() // 阻止在canvas畫布上簽名的時候頁面跟著滾動

      if (Flag === false) {
        return
      }
      const stopX = event.clientX - canvas.offsetLeft
      const stopY = event.clientY - canvas.offsetTop
      writing(beginX, beginY, stopX, stopY, ctx)
      beginX = stopX // 這一步很關鍵,需要不斷更新起點,否則畫出來的是射線簇
      beginY = stopY
    })

    canvas.addEventListener('mouseleave', function (event: { preventDefault: () => void; }) {
      event.preventDefault() // 阻止在canvas畫布上簽名的時候頁面跟著滾動
    })
    canvas.addEventListener('touchstart', function (event: { preventDefault: () => void; touches: { clientX: number; pageY: any }[] }) {
      event.preventDefault() // 阻止在canvas畫布上簽名的時候頁面跟著滾動
      beginX = event.touches[0].clientX
      beginY = event.touches[0].pageY
    })
    canvas.addEventListener('touchmove', (event: { preventDefault: () => void; touches: any[]; clientX: number; pageY: number }) => {
      event.preventDefault() // 阻止在canvas畫布上簽名的時候頁面跟著滾動
      event = event.touches[0]
      const stopX = event.clientX - canvas.offsetLeft
      const stopY = event.pageY - canvas.offsetTop
      writing(beginX, beginY, stopX, stopY, ctx)
      beginX = stopX // 這一步很關鍵,需要不斷更新起點,否則畫出來的是射線簇
      beginY = stopY
    })
  })

  function clearCanvas() {   // 清除畫圖 ,重新畫布 ,或者設定白色背景色
    const canvas = canvasRef.current
    const ctx = canvas.getContext('2d')
    ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
  }