предисловие
Запишите процесс.
Шаблон соглашения
анализировать
Как показано на рисунке выше, все, что вам нужно сделать, это сделать блокнот для подписи, на котором вы можете писать.После написания нажмите «Готово», чтобы создать изображение, как показано выше, и поместите подписанное слово в указанное место.
Первой реакцией на это должно быть использование холста для рисования пути.
Ход моих мыслей таков:
Пишите по одному слову за раз, нажимайте на запись для каждого написанного слова и, наконец, сплайсинг, но, думая о проблеме взаимодействия с пользователем, я отказался от этой идеи.
Окончательная идея: вы можете написать много слов в одну строку, позволяя пользователям скользить по холсту и продолжать писать (потому что шаблон соглашения должен копировать абзац в конце).
Путь рисования холста - реализация функции подписи
<canvas id="canvas" style="top:0">您的手机不支持在线签署</canvas>
const canvasPaint = {};//定义一个全局对象,把canvas的各种状态存进去
canvasPaint.canvas = document.getElementById("canvas");
canvasPaint.ctx = document.getElementById("canvas").getContext("2d");
canvasPaint.ctx.lineCap = 'round';//让结束线帽呈现圆滑状
canvasPaint.ctx.lineJoin = 'round';//交汇时呈现圆滑状
canvasPaint.ctx.strokeWidth = 5;//描边宽度
canvasPaint.ctx.lineWidth = 5;//线条宽度
После инициализации холста нам нужно прослушивать скользящие события на холсте.
canvasPaint.canvas.addEventListener('touchstart', startEventHandler, {passive: false});
function startEventHandler(event) {
event.preventDefault();
canvasPaint.ctx.beginPath();//每次都是一个新路径,不写会和上个字的最后一笔连起来
canvasPaint.canvas.addEventListener('touchmove', moveEventHandler, {passive: false});
canvasPaint.canvas.addEventListener('touchend', endEventHandler, {passive: false});
}
passive: falseа такжеevent.preventDefault()Эти двое - идеальная пара.event.preventDefault()Не позволяйте поведению по умолчанию вызывать собственное раскрывающееся действие браузера при записи на холсте. Этоpassive: falseЯвляется ли новый атрибут, предложенный после версии Google 56, установленным наfalseПросто скажите браузеру, что у меня есть код, который блокирует поведение по умолчанию, сначала не проводите пальцем, вам нужно выполнить мойevent.preventDefault()Этот код, если установленtrue, браузер автоматически проигнорирует этот код, поэтому он не может предотвратить успех, по умолчаниюtrue, так вот одна из ям.
Продолжаем писать логику движущегося тире
function moveEventHandler(event) {
event.preventDefault();
var coverPos = canvasPaint.canvas.getBoundingClientRect();
canvasPaint.mouseX = event.clientX - coverPos.left;
canvasPaint.mouseY = event.clientY - coverPos.top;
if (canvasPaint.canPaint) {//后续为拖动画布功能设置的状态
canvasPaint.ctx.lineTo(//使用lineTo将移动过的坐标绘制成线
canvasPaint.mouseX,
canvasPaint.mouseY
);
canvasPaint.ctx.stroke();//绘制
}
}
function endEventHandler(event) {
event.preventDefault();
//抬起手指时取消move和end事件的监听
canvasPaint.canvas.removeEventListener('touchmove', moveEventHandler, false);
canvasPaint.canvas.removeEventListener('touchend', endEventHandler, false);
}
холст - функция очистки экрана
Эта функция относительно проста в одном предложении
function clearCanvas() {
canvasPaint.ctx.clearRect(0, 0, canvasPaint.canvas.width, canvasPaint.canvas.height);
}
Отправить функцию подписи
Сначала нужно преобразовать текст на канве в объект img, а затем с помощью drawImage отрисовать его в протокол
preLoadImg(['/assets/index/images/agree.jpg', canvasPaint.canvas.toDataURL()], result);
//agree.jpg为协议名,canvasPaint.canvas.toDataURL()就是签好的字转换为base64的结果
function preLoadImg(source, callBack, args) {
var pr = [];
source.forEach(url => {
var p = loadImage(url)
.then(function (img) {
return img;
})
.catch(function (err) {
console.log(err);
});
pr.push(p);
});
Promise.all(pr)
.then(function (imgArray) {
callBack(imgArray, args);
});
}
function loadImage(url) {
return new Promise((resolve, reject) => {
var img = new Image();
img.onload = function () {
resolve(img);
};
img.onerror = reject;
img.src = url;
});
}
Так как назначение img src является асинхронным, у нас должен быть полный объект изображения, поэтому мы используем упаковку обещаний, чтобы все наши изображения были преобразованы, а затем результат был передан в функцию обратного вызова (результат)
function result(imgArr) {
drawName(imgArr);
}
function drawName(imgArr) {
//绘制名字和底部的名字和日期
canvasPaint.canvas2 = document.getElementById('canvas2');
canvasPaint.context2 = canvasPaint.canvas2.getContext('2d');
canvasPaint.ratio = canvasPaint.canvas.height / canvasPaint.canvas.width; //计算画布比例
canvasPaint.context2.drawImage(imgArr[0], 0, 0, 500, 707);//img0是底图原协议
canvasPaint.context2.save();
canvasPaint.context2.translate(50, 190);
canvasPaint.context2.rotate(270 * Math.PI / 180);
canvasPaint.context2.drawImage(imgArr[1], 80, 50, 33, 33 * canvasPaint.ratio);//画反转后的名字
canvasPaint.context2.restore();
canvasPaint.context2.save();
canvasPaint.context2.translate(67, 723);//下方的字
canvasPaint.context2.rotate(270 * Math.PI / 180);
canvasPaint.context2.drawImage(imgArr[1], 80, 50, 33, 33 * canvasPaint.ratio);//画反转后的名字
canvasPaint.context2.restore();
canvasPaint.context2.save();
canvasPaint.context2.translate(400, 625);//下方的字
canvasPaint.context2.font = "11px 微软雅黑";
canvasPaint.context2.fillStyle = "#000";
canvasPaint.context2.textAlign = "center";
canvasPaint.context2.textBaseline = "middle";
var time = new Date().toLocaleString().split(' ')[0];
canvasPaint.context2.fillText(time, 0, 0);
canvasPaint.context2.restore();
prevDrawStatement();
}
Самое главное здесь — понять методы поворота и перевода холста, чтобы текст можно было поворачивать под любым углом и размещать в любом положении.
Длинный почерк — перетаскивание холста
После того, как вышеприведенная подпись завершена, мы фактически использовали другой холст для синтеза текста и исходного соглашения.Теперь нам нужно выполнить функцию бесконечного перетаскивания, что на самом деле очень просто.
Перед этим нам нужно очистить предыдущий холст
function prevDrawStatement() {
clearCanvas();//清除画布
canvasPaint.finish.innerHTML = "提交抄写";
canvasPaint.pencilBtn.style.display = 'block';
canvasPaint.secondState.style.display = 'block';
canvasPaint.tips.innerHTML = "(最后一步)请抄写屏幕上方引号内的确认语句";
canvasPaint.tips.style.color = 'red';
setTimeout(function () {
canvasPaint.tips.style.color = '#666';
}, 2000);
state = STATEMENT;//开始写句子
}
В правом верхнем углу есть функция мобильной панели для подписи. Здесь реализовано перемещение влево и вправо. Соответствующий код выглядит следующим образом.
function togglePencil() {
if (canvasPaint.canPaint) {
canvasPaint.canPaint = false;
canvasPaint.pencilBtn.innerText = "使用签字笔";
//不能签字时应该把开始写字事件去掉,同时加上document事件
canvasPaint.canvas.removeEventListener('touchstart', startEventHandler, false);
document.addEventListener('touchstart', documentStartEventHandler, {passive: false});
} else {
canvasPaint.canPaint = true;
canvasPaint.pencilBtn.innerText = "移动签字板";
//能签字时应该把开始写字事件绑定上去,同时去掉document事件
canvasPaint.canvas.addEventListener('touchstart', startEventHandler, {passive: false});
document.removeEventListener('touchstart', documentStartEventHandler, false);
}
}
function documentStartEventHandler(event) {
event.preventDefault();
canvasPaint.y = event.clientY;
canvasPaint.top = parseFloat(canvasPaint.canvas.style.top);//画板距离顶部的值
document.addEventListener('touchmove', documentMoveEventHandler, {passive: false});
document.addEventListener('touchend', documentEndEventHandler, {passive: false});
}
function documentMoveEventHandler(event) {
event.preventDefault();
canvasPaint.newY = event.clientY - canvasPaint.y;
if (!canvasPaint.canPaint) {
canvasPaint.canvas.style.top = canvasPaint.newY + canvasPaint.top + 'px';
if (parseFloat(canvasPaint.canvas.style.top) > 0) {//限制边界
canvasPaint.canvas.style.top = 0 + 'px';
}
}
}
function documentEndEventHandler(event) {
event.preventDefault();
}
Синтезируйте длинные предложения в протокол и покажите итоговую картинку
После нажатия кнопки отправки транскрипции выполняется следующая функция
function statementDraw(imgArr) {
canvasPaint.context2.save();
canvasPaint.context2.translate(52, 690);
canvasPaint.context2.rotate(270 * Math.PI / 180);
canvasPaint.context2.drawImage(imgArr[0], 80, 50, 33, 33 * canvasPaint.ratio);//画反转后的名字
canvasPaint.context2.restore();
console.log(canvasPaint.canvas2.toDataURL());
document.getElementById('resultImg').setAttribute('src', canvasPaint.canvas2.toDataURL());
document.getElementById('resultImg').style.position = 'absolute';
document.getElementById('resultImg').style.left = 0;
document.getElementById('resultImg').style.top = 0;
document.getElementById('resultImg').st = 50;
Эпилог
В конце концов, это стало желаемым результатом.Еще много деталей нужно исправить.Код также можно использовать повторно во многих местах.Заинтересованные друзья могут общаться друг с другом.
Код в статье является основным, а остальные базовые опущены, надеюсь кому-то из друзей он поможет.
Демонстрация исходного кода
Чтобы всем было легче учиться, добавьте, наконец, адрес github.