vue3 canvas 写字板的实现

447 阅读1分钟

效果预览

canvas.gif

具体实现

  • 首先创建canvas元素,并添加鼠标事件

     <canvas
          ref="canvasRef"
          :style="{
            width: canvasWidth + 'px',
            height: canvasHeight + 'px',
          }"
          @mousedown="($event) => handleMousedown($event)"
          @mousemove="($event) => handleMousemove($event)"
          @mouseup="handleMouseup()"
          @touchstart="($event) => handleMousedown($event)"
          @touchmove="($event) => handleMousemove($event)"
          @touchend="
            handleMouseup();
            mouseInCanvas = false;
          "
          @mouseleave="
            handleMouseup();
            mouseInCanvas = false;
          "
          @mouseenter="mouseInCanvas = true"
          @wheel="($event) => mousewheelListener($event)"
        ></canvas>
    
  • 初始化画布

    const initCanvas = () => {
        if (!canvasRef.value) return;
        ctx = canvasRef.value.getContext('2d');
        if (!ctx) return;
        canvasRef.value.width = options.width;
        canvasRef.value.height = options.height;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
      };
    
  • 处理鼠标移动事件

    const handleMousedown = (e: MouseEvent | TouchEvent) => {
        const [mouseX, mouseY] = getMouseOffsetPosition(e);
        const x = mouseX / widthScale.value;
        const y = mouseY / heightScale.value;
        isMouseDown = true;
        lastPos = { x, y };
        lastTime = new Date().getTime();
        if (!(e instanceof MouseEvent)) {
          mouse.value = { x: mouseX, y: mouseY };
          mouseInCanvas.value = true;
        }
      };
     const handleMousemove = (e: MouseEvent | TouchEvent) => {
        const [mouseX, mouseY] = getMouseOffsetPosition(e);
        const x = mouseX / widthScale.value;
        const y = mouseY / heightScale.value;
    ​
        mouse.value = { x: mouseX, y: mouseY };
    ​
        if (isMouseDown) handleMove(x, y);
      };
       const handleMove = (x: number, y: number) => {
        const time = new Date().getTime();
    ​
        if (options.model === 'pen') {
          const s = getDistance(x, y);
          const t = time - lastTime;
          const lineWidth = getLineWidth(s, t);
    ​
          draw(x, y, lineWidth);
          lastLineWidth = lineWidth;
        } else if (options.model === 'mark') draw(x, y, markSize.value);
        else erase(x, y);
    ​
        lastPos = { x, y };
        lastTime = new Date().getTime();
      };
      const handleMouseup = () => {
        if (!isMouseDown) return;
        isMouseDown = false;
      };
    
  • 绘制或清除笔迹

     const draw = (posX: number, posY: number, lineWidth: number) => {
        if (!ctx) return;
        const lastPosX = lastPos.x;
        const lastPosY = lastPos.y;
        ctx.lineWidth = lineWidth;
        ctx.strokeStyle = options.color;
        ctx.beginPath();
        ctx.moveTo(lastPosX, lastPosY);
        ctx.lineTo(posX, posY);
        ctx.stroke();
        ctx.closePath();
      };
    
  • 清空画布及修改绘制或清除

    const clearCanvas = () => {
        if (!ctx || !canvasRef.value) return;
        ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height);
      };
    ​
     const updateCtx = (model?: 'pen' | 'eraser' | 'mark') => {
        if (!ctx) return;
        if (model) {
          options.model = model;
        }
        if (options.model === 'mark') {
          ctx.globalCompositeOperation = 'xor';
          ctx.globalAlpha = 0.5;
        } else if (options.model === 'pen') {
          ctx.globalCompositeOperation = 'source-over';
          ctx.globalAlpha = 1;
        }
      };
    

完整代码 如果觉得文章对你有帮助,欢迎一键三连