画布上的签名无法在手机上使用

问题描述 投票:0回答:1

我的脚本在桌面上运行良好,但在移动设备上运行不佳。 该脚本的工作原理如下:

  1. 用户单击按钮
  2. 单击按钮打开模态框
  3. 用户在位于模式内部的画布内签名。

在桌面上,它运行良好。但不适用于移动设备。

你能帮我改正我的代码吗?

这是页面:http://p4547.phpnet.org/velos/modal/

我已经添加了 touchstart、touchmove 和 touchend 功能,但是不起作用。

这是我的代码:

"use strict";
class Signature {
    constructor() {
        this.color = "#000000";
        this.sign = false;
        this.begin_sign = false;
        this.width_line = 5;
        this.canvas = document.getElementById('canvas');
        this.offsetLeft = this.canvas.offsetLeft;
        this.offsetTop = this.canvas.offsetTop;
        this.context = canvas.getContext('2d');
        this.context.lineJoin = 'round'; // jointure arrondie
        this.context.lineCap = 'round'; // extrémité arrondie
        this.whenActionDown();
        this.whenActionUp();
        this.whenActionMove();
        this.createSignature();
        this.clearCanvas();
        this.resetCanvas();
    }
    // Mise à jour de la position de la souris car c'est dans une modal
    updateMousePosition(mX, mY) {
    let rect = this.canvas.getBoundingClientRect();
    let scaleX = this.canvas.width / rect.width;
    let scaleY = this.canvas.height / rect.height;
    this.cursorX = (mX - rect.left) * scaleX;
    this.cursorY = (mY - rect.top) * scaleY;
}

    actionDown(e) {
        this.sign = true;
        this.updateMousePosition(e.clientX, e.clientY);
    }

    actionUp() {
        this.sign = false;
        this.begin_sign = false;
    }

    actionMove(e) {
        if (this.sign) {
            this.updateMousePosition(e.clientX, e.clientY);
            this.createSignature();
        }
    }


    // La signature commence lorsqu'on clique sur la souris :
    whenActionDown() {
        document.addEventListener("mousedown", this.actionDown.bind(this));
      document.addEventListener("touchstart", this.actionDown.bind(this));
    }

    // Relâchement du clic. On arrête la signature :
    whenActionUp() {
        document.addEventListener("mouseup", this.actionUp.bind(this));
      document.addEventListener("touchend", this.actionUp.bind(this));
    }

    // Mouvement de la souris sur le canvas :
    whenActionMove() {
        this.canvas.addEventListener('mousemove', this.actionMove.bind(this));
        this.canvas.addEventListener('touchmove', this.actionMove.bind(this));
    }

    // Fonction qui permet la création de la signature :
    createSignature() {
        // Si c'est le début, la signature démarre :
        if (!this.begin_sign) {
            // Placement du curseur pour la première fois :
            this.context.beginPath();
            this.context.moveTo(this.cursorX, this.cursorY);
            this.begin_sign = true;
        }
        // Sinon on signe :
        else {
            this.context.lineTo(this.cursorX, this.cursorY);
            this.context.strokeStyle = this.color;
            this.context.lineWidth = this.width_line;
            this.context.stroke();
        }
    }
    // Nettoyage du Canvas :
    clearCanvas() {
        this.context.clearRect(0, 0, this.canvas.offsetWidth, this.canvas.offsetHeight);
    }
    // Reset :
    resetCanvas() {
        document.getElementById("reset").addEventListener("click", () => {
            this.clearCanvas();
        })
    }
}
// Instanciation de la Signature :
document.addEventListener("DOMContentLoaded", event => {
    new Signature();
});

请注意:我还是一个初学者,我已经在Google上搜索了解决方案,但没有成功。

javascript class html5-canvas touch-event
1个回答
0
投票

要解决签名脚本在桌面上运行而不是在移动设备上运行的问题,您需要关注两个关键事项:

  1. 跨设备一致的画布缩放:确保画布正确缩放而不改变线条粗细。
  2. 正确的触摸事件处理:在移动设备上正确翻译触摸事件。

解决方案:统一画布缩放和触摸事件处理

此解决方案将确保画布在不同设备上均匀缩放,并且触摸事件正确转换到画布,避免线条粗细或光标未对齐的任何问题。

代码调整 这是脚本的改进版本,其中包括画布缩放和触摸事件处理的修复:

    "use strict";
    
    class Signature {
        constructor() {
            this.color = "#000000";
            this.sign = false;
            this.begin_sign = false;
            this.width_line = 5;
    
            // Set up the canvas and context
            this.canvas = document.getElementById('canvas');
            this.context = this.canvas.getContext('2d');
            this.context.lineJoin = 'round';
            this.context.lineCap = 'round';
    
            // Resize the canvas for uniform behavior across devices
            this.resizeCanvas();
    
            // Set up event listeners
            this.whenActionDown();
            this.whenActionUp();
            this.whenActionMove();
            this.resetCanvas();
            
            // Ensure the canvas resizes properly when the window is resized
            window.addEventListener('resize', this.resizeCanvas.bind(this));
        }
    
        // Resize the canvas without applying devicePixelRatio
        resizeCanvas() {
            const rect = this.canvas.getBoundingClientRect();
            this.canvas.width = rect.width;
            this.canvas.height = rect.height;
            this.clearCanvas(); // Clear the canvas after resizing
        }
    
        // Update cursor position with adjusted coordinates
        updateMousePosition(mX, mY) {
            const rect = this.canvas.getBoundingClientRect();
            const scaleX = this.canvas.width / rect.width;
            const scaleY = this.canvas.height / rect.height;
    
            this.cursorX = (mX - rect.left) * scaleX;
            this.cursorY = (mY - rect.top) * scaleY;
        }
    
        actionDown(e) {
            this.sign = true;
            const clientX = e.touches ? e.touches[0].clientX : e.clientX;
            const clientY = e.touches ? e.touches[0].clientY : e.clientY;
            this.updateMousePosition(clientX, clientY);
        }
    
        actionUp() {
            this.sign = false;
            this.begin_sign = false;
        }
    
        actionMove(e) {
            if (this.sign) {
                const clientX = e.touches ? e.touches[0].clientX : e.clientX;
                const clientY = e.touches ? e.touches[0].clientY : e.clientY;
                this.updateMousePosition(clientX, clientY);
                this.createSignature();
            }
        }
    
        whenActionDown() {
            this.canvas.addEventListener("mousedown", this.actionDown.bind(this));
            this.canvas.addEventListener("touchstart", this.actionDown.bind(this), { passive: false });
        }
    
        whenActionUp() {
            document.addEventListener("mouseup", this.actionUp.bind(this));
            document.addEventListener("touchend", this.actionUp.bind(this));
        }
    
        whenActionMove() {
            this.canvas.addEventListener('mousemove', this.actionMove.bind(this));
            this.canvas.addEventListener('touchmove', this.actionMove.bind(this), { passive: false });
        }
    
        createSignature() {
            if (!this.begin_sign) {
                this.context.beginPath();
                this.context.moveTo(this.cursorX, this.cursorY);
                this.begin_sign = true;
            } else {
                this.context.lineTo(this.cursorX, this.cursorY);
                this.context.strokeStyle = this.color;
                this.context.lineWidth = this.width_line;
                this.context.stroke();
            }
        }

    clearCanvas() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }

    resetCanvas() {
        document.getElementById("reset").addEventListener("click", () => {
            this.clearCanvas();
        });
    }
}

// Initialize the Signature class after the content loads
document.addEventListener("DOMContentLoaded", () => {
    new Signature();
});

变更说明

  1. 无 devicePixelRatio 的画布缩放:

    • resizeCanvas 方法根据其可见大小(getBoundingClientRect)设置画布大小。这确保画布出现
      跨设备相同,无需依赖 devicePixelRatio,这
      可能会导致不同的线条粗细。
  2. 鼠标和触摸事件的 clientX 和 clientY 处理:

    • clientX 和 clientY 属性有条件地从触摸事件的 e.touches[0] 派生,确保在移动设备上正确解释触摸坐标。
  3. 为触摸事件添加{passive: false}:

    • 将 { Passive: false } 添加到 touchstart 和 touchmove 可以防止签名时的默认滚动行为,从而提高移动设备上的可用性。

结果

此解决方案应为您在桌面和移动设备上提供一致的画布行为,具有统一的线条粗细和正确对齐的触摸输入。如果这解决了您的问题,请告诉我!

© www.soinside.com 2019 - 2024. All rights reserved.