You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在网页中实现iPad用户可通过手指/手写笔记笔记的功能

网页端iPad手写/触控笔记功能实现修正方案

原代码核心问题

  • 未阻止触摸默认行为,iPad操作时页面会滚动,干扰绘图
  • 坐标计算未适配设备像素比,高分辨率屏幕下绘图模糊
  • 未支持手写笔压力感应,无法实现自然的粗细变化书写效果
  • 未限制单点触控,多点操作会导致绘图异常
  • Canvas尺寸固定,未适配容器宽度

修正后的完整代码

HTML

<div class="container">
  <div class="row form-section centered-content" style="background-color:lavender;">
    <div class="col-md-12">
      <div class="canvas-container">
        <canvas id="signatureCanvas"></canvas>
      </div>
      <button type="button" class="btn btn-secondary mt-2" onclick="clearCanvas()">清除笔记</button>
    </div>
  </div>
</div>

CSS

.canvas-container {
  border: 1px solid #ccc;
  width: 100%;
  overflow: hidden;
  height: 300px; /* 可按需调整高度 */
}

#signatureCanvas {
  width: 100%;
  height: 100%;
  background-color: white;
}

JavaScript

let painting = false;
let lastX = 0;
let lastY = 0;

const canvas = document.getElementById('signatureCanvas');
const ctx = canvas.getContext('2d');

// 初始化Canvas,适配设备像素比与容器尺寸
function initCanvas() {
  const container = canvas.parentElement;
  const rect = container.getBoundingClientRect();
  const dpr = window.devicePixelRatio || 1;

  // 设置Canvas实际像素尺寸(解决模糊问题)
  canvas.width = rect.width * dpr;
  canvas.height = rect.height * dpr;
  // 设置显示尺寸
  canvas.style.width = `${rect.width}px`;
  canvas.style.height = `${rect.height}px`;

  // 缩放绘图上下文,匹配设备像素比
  ctx.scale(dpr, dpr);
  ctx.lineCap = 'round';
  ctx.lineJoin = 'round';
}

// 获取触摸/鼠标的精准坐标与压力值
function getEventCoords(e) {
  const rect = canvas.getBoundingClientRect();
  const dpr = window.devicePixelRatio || 1;
  let x, y, pressure = 1;

  if (e.type.includes('touch')) {
    // 仅取第一个触摸点,避免多点干扰
    const touch = e.touches[0];
    x = touch.clientX - rect.left;
    y = touch.clientY - rect.top;
    // 读取手写笔压力(Safari原生支持force属性)
    pressure = touch.force || 1;
  } else {
    x = e.clientX - rect.left;
    y = e.clientY - rect.top;
    // 鼠标模拟压力,按下时生效
    pressure = e.buttons === 1 ? 1 : 0;
  }

  return {
    x: x * dpr,
    y: y * dpr,
    pressure: Math.min(pressure, 1) // 限制压力值在0-1区间
  };
}

function startPosition(e) {
  e.preventDefault(); // 阻止触摸默认行为(如页面滚动)
  painting = true;
  const coords = getEventCoords(e);
  lastX = coords.x;
  lastY = coords.y;
  draw(e);
}

function finishedPosition() {
  painting = false;
  ctx.beginPath();
}

function draw(e) {
  if (!painting) return;
  e.preventDefault();

  const coords = getEventCoords(e);
  // 根据压力动态调整线条粗细
  ctx.lineWidth = coords.pressure * 4 + 1;

  // 绘制连续平滑线条
  ctx.beginPath();
  ctx.moveTo(lastX, lastY);
  ctx.lineTo(coords.x, coords.y);
  ctx.stroke();

  lastX = coords.x;
  lastY = coords.y;
}

function clearCanvas() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}

// 绑定事件监听
canvas.addEventListener('mousedown', startPosition);
canvas.addEventListener('mouseup', finishedPosition);
canvas.addEventListener('mouseout', finishedPosition);
canvas.addEventListener('mousemove', draw);

canvas.addEventListener('touchstart', startPosition);
canvas.addEventListener('touchend', finishedPosition);
canvas.addEventListener('touchcancel', finishedPosition);
canvas.addEventListener('touchmove', draw);

// 窗口大小变化时重新初始化Canvas
window.addEventListener('resize', initCanvas);
// 页面加载完成后初始化
window.addEventListener('load', initCanvas);

关键优化点说明

  • 触摸行为拦截:通过e.preventDefault()阻止iPad页面滚动、缩放等默认行为,确保绘图操作不受干扰
  • 高分辨率适配:利用设备像素比调整Canvas实际尺寸,解决iPad视网膜屏幕下绘图模糊问题
  • 手写笔压力支持:读取触摸事件的force属性,实现类似真实纸笔的粗细变化书写效果
  • 单点触控限制:仅处理第一个触摸点,避免多手指操作导致的绘图异常
  • 响应式布局:Canvas尺寸随容器自动调整,适配不同屏幕宽度
  • 流畅度提升:记录上一次绘图坐标,绘制连续线条,优化书写流畅感

内容的提问来源于stack exchange,提问作者Testa Maxima

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:52:53