1.canvas绘图
通过HTML5的canvas API捕获鼠标或触摸轨迹,实时绘制签名,支持自定义线条样式、颜色和动画效果,生成的签名可以直接转换为图片或矢量数据。但是需要自行处理平滑算法和兼容性问题,移动端触摸事件处理较复杂
html
<div class="signature-container">
<canvas id="signatureCanvas" width="400" height="200"></canvas>
<div class="signature-actions">
<button id="clearBtn">清除签名</button>
<button id="saveBtn">保存签名</button>
</div>
<input type="hidden" id="signatureInput" name="signature">
</div>
javascript
// 获取DOM元素
const canvas = document.getElementById('signatureCanvas');
const ctx = canvas.getContext('2d');
const clearBtn = document.getElementById('clearBtn');
const saveBtn = document.getElementById('saveBtn');
const signatureInput = document.getElementById('signatureInput');
// 初始化画布
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
// 鼠标/触摸事件变量
let isDrawing = false;
let lastX = 0;
let lastY = 0;
// 开始绘制
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('touchstart', handleTouch);
// 绘制过程
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('touchmove', handleTouchMove);
// 结束绘制
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
canvas.addEventListener('touchend', stopDrawing);
// 清除画布
clearBtn.addEventListener('click', clearCanvas);
// 保存签名
saveBtn.addEventListener('click', saveSignature);
function startDrawing(e) {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
}
function handleTouch(e) {
e.preventDefault();
const touch = e.touches[0];
const mouseEvent = {
offsetX: touch.clientX - canvas.getBoundingClientRect().left,
offsetY: touch.clientY - canvas.getBoundingClientRect().top
};
startDrawing(mouseEvent);
}
function draw(e) {
if (!isDrawing) return;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
}
function handleTouchMove(e) {
e.preventDefault();
const touch = e.touches[0];
const mouseEvent = {
offsetX: touch.clientX - canvas.getBoundingClientRect().left,
offsetY: touch.clientY - canvas.getBoundingClientRect().top
};
draw(mouseEvent);
}
function stopDrawing() {
isDrawing = false;
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
signatureInput.value = '';
}
function saveSignature() {
const dataURL = canvas.toDataURL('image/png');
signatureInput.value = dataURL;
// 可以在这里添加提交表单或AJAX上传的逻辑
}
css
.signature-container {
border: 1px solid #ccc;
padding: 10px;
margin: 10px 0;
}
#signatureCanvas {
border: 1px solid #000;
background-color: #fff;
}
.signature-actions {
margin-top: 10px;
}
button {
padding: 5px 10px;
margin-right: 5px;
}
2.SVG路径绘制
使用SVG的<path>元素记录签名轨迹,生成矢量图
优点:生成的签名是矢量图,可无损缩放;支持复杂的动画和交换效果;文件体积小,便于存储和传输;
缺点:路径数据结构较复杂,需手动维护;性能可能低于canvas对于大规模绘制
javascript
<svg id="signatureSvg" width="400" height="200" style="border: 1px solid #ccc;"></svg>
<button id="clearSvgBtn">清空</button>
<script>
const svg = document.getElementById('signatureSvg');
let currentPath = null;
let isDrawing = false;
function startDrawing(e) {
isDrawing = true;
const pt = svg.createSVGPoint();
pt.x = e.clientX;
pt.y = e.clientY;
const svgPoint = pt.matrixTransform(svg.getScreenCTM().inverse());
currentPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
currentPath.setAttribute('d', `M ${svgPoint.x} ${svgPoint.y}`);
currentPath.setAttribute('stroke', '#333');
currentPath.setAttribute('stroke-width', '2');
currentPath.setAttribute('fill', 'none');
currentPath.setAttribute('stroke-linecap', 'round');
svg.appendChild(currentPath);
}
function draw(e) {
if (!isDrawing || !currentPath) return;
const pt = svg.createSVGPoint();
pt.x = e.clientX;
pt.y = e.clientY;
const svgPoint = pt.matrixTransform(svg.getScreenCTM().inverse());
const pathData = currentPath.getAttribute('d');
currentPath.setAttribute('d', `${pathData} L ${svgPoint.x} ${svgPoint.y}`);
}
function stopDrawing() {
isDrawing = false;
currentPath = null;
}
// 绑定事件(与Canvas类似)
svg.addEventListener('mousedown', startDrawing);
window.addEventListener('mousemove', draw);
window.addEventListener('mouseup', stopDrawing);
document.getElementById('clearSvgBtn').addEventListener('click', () => {
while (svg.firstChild) {
svg.removeChild(svg.firstChild);
}
});
</script>
3.第三方库(signature pad)
javascript
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.5/dist/signature_pad.umd.min.js"></script>
<canvas id="signaturePad" style="border: 1px solid #000;"></canvas>
<script>
const canvas = document.getElementById('signaturePad');
const signaturePad = new SignaturePad(canvas);
document.getElementById('clearBtn').addEventListener('click', () => {
signaturePad.clear();
});
document.getElementById('saveBtn').addEventListener('click', () => {
const dataURL = signaturePad.toDataURL();
// 处理签名数据
});
</script>
4.表单输入模拟签名
使用文本输入或选择预设签名图片,适用于对签名要求不高的场景
javascript
<!-- 文本输入方式 -->
<label>请输入您的签名:</label>
<input type="text" id="signatureText">
<button onclick="generateSignature()">生成签名</button>
<div id="generatedSignature"></div>
<script>
function generateSignature() {
const text = document.getElementById('signatureText').value;
document.getElementById('generatedSignature').innerText = text;
// 可结合字体样式模拟手写效果
}
</script>