Что я пробовал:
- Добавил прослушиватели событий касания вручную с помощью { пассивного: false
- Установил touchAction: 'none' на холсте
- Вызов PreventDefault() и stopPropagation() для всех событий касания.
- Использовано useRef для состояния рисования, чтобы избежать устаревших замыканий.
- Удалена функция скрытия переполнения из родительских контейнеров.
- Настроено правильное масштабирование соотношения пикселей устройства.
События мыши работают на настольных компьютерах, но события касания ничего не делают на мобильных устройствах. Холст вообще не реагирует на прикосновения пальцев.
Среда:
- React 18.
- Тестирование в iOS Safari и Chrome на Android.
- Настольный Chrome работает нормально.
Код: Выделить всё
const SignatureCanvas = () => {
const canvasRef = React.useRef(null);
const containerRef = React.useRef(null);
const isDrawingRef = React.useRef(false);
// Initialize canvas with device pixel ratio
const initializeCanvas = React.useCallback(() => {
if (canvasRef.current && containerRef.current) {
const canvas = canvasRef.current;
const container = containerRef.current;
const rect = container.getBoundingClientRect();
const dpr = window.devicePixelRatio || 1;
canvas.width = rect.width * dpr;
canvas.height = 200 * dpr;
canvas.style.width = `${rect.width}px`;
canvas.style.height = `200px`;
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr);
ctx.lineWidth = 2;
ctx.lineCap = 'round';
ctx.strokeStyle = '#000';
}
}, []);
React.useEffect(() => {
initializeCanvas();
}, [initializeCanvas]);
// Attach touch listeners with { passive: false }
React.useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const touchStartHandler = (e) => startDrawing(e);
const touchMoveHandler = (e) => draw(e);
const touchEndHandler = (e) => stopDrawing(e);
canvas.addEventListener('touchstart', touchStartHandler, { passive: false });
canvas.addEventListener('touchmove', touchMoveHandler, { passive: false });
canvas.addEventListener('touchend', touchEndHandler, { passive: false });
return () => {
canvas.removeEventListener('touchstart', touchStartHandler);
canvas.removeEventListener('touchmove', touchMoveHandler);
canvas.removeEventListener('touchend', touchEndHandler);
};
}, []);
const getCoordinates = (e) => {
const canvas = canvasRef.current;
if (!canvas) return { x: 0, y: 0 };
const rect = canvas.getBoundingClientRect();
let clientX, clientY;
if (e.type.includes('touch')) {
const touch = e.touches[0] || e.changedTouches[0];
if (!touch) return { x: 0, y: 0 };
clientX = touch.clientX;
clientY = touch.clientY;
} else {
clientX = e.clientX;
clientY = e.clientY;
}
return {
x: clientX - rect.left,
y: clientY - rect.top
};
};
const startDrawing = (e) => {
if (e.type.includes('touch')) {
e.preventDefault();
e.stopPropagation();
}
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
const coords = getCoordinates(e);
ctx.beginPath();
ctx.moveTo(coords.x, coords.y);
isDrawingRef.current = true;
};
const draw = (e) => {
if (!isDrawingRef.current) return;
if (e.type.includes('touch')) {
e.preventDefault();
e.stopPropagation();
}
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
const coords = getCoordinates(e);
ctx.lineTo(coords.x, coords.y);
ctx.stroke();
};
const stopDrawing = (e) => {
if (e && e.type.includes('touch')) {
e.preventDefault();
}
isDrawingRef.current = false;
};
return (
);
};
Что мне не хватает? Почему события касания работают в консоли браузера (я вижу срабатывание touchstart), но холст не реагирует на попытки рисования на мобильных устройствах?
Есть ли лучший подход к обработке подписей холста, который надежно работает на всех устройствах?
Подробнее здесь: https://stackoverflow.com/questions/798 ... -despite-p
Мобильная версия