今天用前面做过的小画家相似功能,来完成一个可以在文件上面签名的功能~
当然也会有新的东西可以玩。
我们将文件签名分成三个步骤
<div className="App">
<h1>步骤一</h1>
<h3>绘制签名档</h3>
<SignBox></SignBox>
<h1>步骤二</h1>
<h3>上传文件</h3>
<UploadFile></UploadFile>
<h1>步骤三</h1>
<h3>合并输出</h3>
<Output></Output>
</div>
今天先教学 绘制签名档
及 上传文件
的部分
根据以前的操作,相信已经对 mouse 的事件滚瓜烂熟了,
这里就不赘述罗。
code
import React, { useEffect, useRef, useState } from "react";
import getTouchPos from "../../utils/getTouchPos";
import getMousePos from "../../utils/getMousePos";
import { useAtom } from "jotai";
import { signAtom } from "../../data";
const canvasSize = 500;
const SignFile = () => {
const canvasRef = useRef(null);
const [canvas, setCanvas] = useState(null);
const [ctx, setCtx] = useState(null);
const [src, setSrc] = useState(null);
const [drawing, setDrawing] = useState(false);
const [_, setSignData] = useAtom(signAtom);
useEffect(() => {
const c = canvasRef.current;
setCanvas(c);
if (c) setCtx(c.getContext("2d"));
}, [canvasRef]);
/** 开始 */
const handleTouchStart = (event) => {
setDrawing(true);
const touchPos = getTouchPos(canvas, event);
ctx.beginPath(touchPos.x, touchPos.y);
ctx.moveTo(touchPos.x, touchPos.y);
event.preventDefault();
};
const handleMouseDown = (event) => {
setDrawing(true);
const mousePos = getMousePos(canvas, event);
ctx.beginPath();
ctx.moveTo(mousePos.x, mousePos.y);
event.preventDefault();
};
/** 移动 */
const handleTouchMove = (event) => {
if (!drawing) return;
const touchPos = getTouchPos(canvas, event);
ctx.lineWidth = 2;
ctx.lineCap = "round"; // 绘制圆形的结束线帽
ctx.lineJoin = "round"; // 两条线条交汇时,建立圆形边角
ctx.shadowBlur = 1; // 边缘模糊,防止直线边缘出现锯齿
ctx.shadowColor = "black"; // 边缘颜色
ctx.lineTo(touchPos.x, touchPos.y);
ctx.stroke();
};
const handleMouseMove = (event) => {
if (!drawing) return;
const mousePos = getMousePos(canvas, event);
ctx.lineWidth = 2;
ctx.lineCap = "round"; // 绘制圆形的结束线帽
ctx.lineJoin = "round"; // 两条线条交汇时,建立圆形边角
ctx.shadowBlur = 1; // 边缘模糊,防止直线边缘出现锯齿
ctx.shadowColor = "black"; // 边缘颜色
ctx.lineTo(mousePos.x, mousePos.y);
ctx.stroke();
};
/** 结束 */
const handleTouchEnd = (event) => {
setDrawing(false);
};
const handleMouseUp = (event) => {
setDrawing(false);
};
/** 清除 */
const handleClear = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
/** 转图片 */
const handleConvertToImage = () => {
const image = canvas.toDataURL();
setSignData(image);
setSrc(image);
};
return (
<div>
<canvas
style={{ background: "#EEE" }}
ref={canvasRef}
width={canvasSize}
height={canvasSize}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
></canvas>
<div>
<button onClick={handleClear}>清除</button>
<button onClick={handleConvertToImage}>转图</button>
</div>
{src && (
<img
src={src}
alt="signImage"
style={{ color: "#FFF", border: "none" }}
/>
)}
</div>
);
};
export default SignFile;
补充一下,这次跨组件都用 jotai
,想要用 recoil
之类的都是可行的。
迅速的就完成画签名啦,而且同时支援滑鼠
与触控
事件。
做文件签名当然也需要文件的支持啦,这段是本篇章的重点!
我们需要学习新的lib pdfjs
,迅速地让他帮我们做到 pdf to canvas
至於怎麽使用,就请大家去翻翻文档吧
import React, { useEffect, useRef, useState } from "react";
import getScaledDim from "../../utils/getScaledDim";
import { useAtom } from "jotai";
import { bgFileAtom } from "../../data";
import { pdfjs } from "react-pdf";
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
const canvasSize = 500;
const UploadFile = () => {
const canvasRef = useRef(null);
const [canvas, setCanvas] = useState(null);
const [ctx, setCtx] = useState(null);
const [src, setSrc] = useState(null);
const [bgFileData, setBgFileData] = useAtom(bgFileAtom);
useEffect(() => {
const c = canvasRef.current;
setCanvas(c);
if (c) setCtx(c.getContext("2d"));
}, [canvasRef]);
/** image */
const handleUploadImage = (event) => {
const f = event.target.files[0];
const ctx = canvasRef.current.getContext("2d");
const img = new Image();
img.onload = function () {
const scaled = getScaledDim(img, canvasSize, canvasSize);
// scale canvas to image
ctx.width = scaled.width;
ctx.height = scaled.height;
// draw image
ctx.drawImage(img, 0, 0, ctx.width, ctx.height);
};
img.src = URL.createObjectURL(f);
};
/** pdf */
const handleUploadPdf = (event) => {
const file = event.target.files[0];
if (file.type === "application/pdf") {
let fileReader = new FileReader();
fileReader.onload = function () {
const pdfData = new Uint8Array(this.result);
// Using DocumentInitParameters object to load binary data.
const loadingTask = pdfjs.getDocument({ data: pdfData });
loadingTask.promise.then(
function (pdf) {
console.log("PDF loaded");
// Fetch the first page
const pageNumber = 1;
pdf.getPage(pageNumber).then(function (page) {
console.log("Page loaded");
const scale = 1.5;
const viewport = page.getViewport({ scale: scale });
// Prepare canvas using PDF page dimensions
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render PDF page into canvas context
const renderContext = {
canvasContext: ctx,
viewport: viewport
};
const renderTask = page.render(renderContext);
renderTask.promise.then(function () {
console.log("Page rendered");
});
});
},
function (reason) {
// PDF loading error
console.error(reason);
}
);
};
fileReader.readAsArrayBuffer(file);
}
};
const handleConvertToImage = () => {
const image = canvas.toDataURL();
setBgFileData(image);
setSrc(image);
};
return (
<div>
<div style={{ marginBottom: `1rem` }}>
上传 Image:
<input type="file" onChange={handleUploadImage} />
</div>
<div>
上传 PDF:
<input accept=".pdf" type="file" onChange={handleUploadPdf} />
</div>
<canvas ref={canvasRef} width={canvasSize} height={canvasSize}></canvas>
<button onClick={handleConvertToImage}>转图</button>
<img src={src} alt="imagePdf" />
</div>
);
};
export default UploadFile;
// https://mozilla.github.io/pdf.js/examples/index.html#interactive-examples
这样材料就算是准备好了,明天来准备合并吧!!
>>: 30-28 之 DDD 战术篇1 - Entity 与 Value Object
DAY22 用 Azure Machine Learning SDK 建立环境 我们在前面图形化介面...
DAY 5提到暂存器如何查找,还有开启时钟才能对GPIO口操作,我补充一下昨天没贴到的暂存器地图,在...
正文 如果还没有看Day28的话,建议可以先回去看,不然接下来可能搞不清楚状况。 延续昨天的内容,我...
昨天抱病撰文,终於在本机端将单笔资料透过ORM的方法,成功将新增的订单资料更新到Heroku Pos...
数位 I/O 视窗当然是要有数位讯号相关功能啦。 数位 I/O 功能 在 Supported Mod...