前端实现电子签名(web、移动端)通用组件(canvas实现)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas></canvas>
<div>
<button onclick="cancel()">取消</button>
<button onclick="save()">保存</button>
</div>
</body>
<script>
// 配置内容
const config = {
width: 400, // 宽度
height: 200, // 高度
lineWidth: 5, // 线宽
strokeStyle: 'red', // 线条颜色
lineCap: 'round', // 设置线条两端圆角
lineJoin: 'round', // 线条交汇处圆角
} // 获取canvas 实例
const canvas = document.querySelector('canvas')
// 设置宽高
canvas.width = config.width
canvas.height = config.height
// 设置一个边框
canvas.style.border = '1px solid #000'
// 创建上下文
const ctx = canvas.getContext('2d') // 设置填充背景色
ctx.fillStyle = 'transparent'
// 绘制填充矩形
ctx.fillRect(
0, // x 轴起始绘制位置
0, // y 轴起始绘制位置
config.width, // 宽度
config.height // 高度
); // 保存上次绘制的 坐标及偏移量
const client = {
offsetX: 0, // 偏移量
offsetY: 0,
endX: 0, // 坐标
endY: 0
} // 判断是否为移动端
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent)) // 初始化
const init = event => {
// 获取偏移量及坐标
const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event // 修改上次的偏移量及坐标
client.offsetX = offsetX
client.offsetY = offsetY
client.endX = pageX
client.endY = pageY // 清除以上一次 beginPath 之后的所有路径,进行绘制
ctx.beginPath()
// 根据配置文件设置相应配置
ctx.lineWidth = config.lineWidth
ctx.strokeStyle = config.strokeStyle
ctx.lineCap = config.lineCap
ctx.lineJoin = config.lineJoin
// 设置画线起始点位
ctx.moveTo(client.endX, client.endY)
// 监听 鼠标移动或手势移动
window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
}
// 绘制
const draw = event => {
// 获取当前坐标点位
const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
// 修改最后一次绘制的坐标点
client.endX = pageX
client.endY = pageY // 根据坐标点位移动添加线条
ctx.lineTo(pageX , pageY ) // 绘制
ctx.stroke()
}
// 结束绘制
const cloaseDraw = () => {
// 结束绘制
ctx.closePath()
// 移除鼠标移动或手势移动监听器
window.removeEventListener("mousemove", draw)
}
// 创建鼠标/手势按下监听器
window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init)
// 创建鼠标/手势 弹起/离开 监听器
window.addEventListener(mobileStatus ? "touchend" :"mouseup", cloaseDraw) // 取消-清空画布
const cancel = () => {
// 清空当前画布上的所有绘制内容
ctx.clearRect(0, 0, config.width, config.height)
}
// 保存-将画布内容保存为图片
const save = () => {
// 将canvas上的内容转成blob流
canvas.toBlob(blob => {
// 获取当前时间并转成字符串,用来当做文件名
const date = Date.now().toString()
// 创建一个 a 标签
const a = document.createElement('a')
// 设置 a 标签的下载文件名
a.download = `${date}.png`
// 设置 a 标签的跳转路径为 文件流地址
a.href = URL.createObjectURL(blob)
// 手动触发 a 标签的点击事件
a.click()
// 移除 a 标签
a.remove()
})
}
</script>
</html>
前端实现电子签名(web、移动端)通用组件(canvas实现)的更多相关文章
- 饿了么基于Vue2.0的通用组件开发之路(分享会记录)
Element:一套通用组件库的开发之路 Element 是由饿了么UED设计.饿了么大前端开发的一套基于 Vue 2.0 的桌面端组件库.今天我们要分享的就是开发 Element 的一些心得. 官网 ...
- 前端文摘:Web 开发模式演变历史和趋势
今天的<前端文摘>给大家分享一篇玉伯的文章.文章详细介绍了 Web 开发的四种常用模式以及未来可能成为流行趋势的 Node 全栈开发模式,相信你看了以后一定会有收获. 您可能感兴趣的相关文 ...
- Web服务端软件的服务品质概要
软件品质概述 提供同样功能.产品和服务的服务者中, 竞争力来自功能的多样化和服务品质的差异化, 无论是个体.企业还是国家. 这里的服务指功能.产品的实现程度和处理能力,以及研发/客服提供的技术支持程度 ...
- Vue2.0的通用组件
饿了么基于Vue2.0的通用组件开发之路(分享会记录) Element:一套通用组件库的开发之路 Element 是由饿了么UED设计.饿了么大前端开发的一套基于 Vue 2.0 的桌面端组件库. ...
- JS前端图形化插件之利器Gojs组件(php中文网)
JS前端图形化插件之利器Gojs组件(php中文网) 一.总结 一句话总结:php中文网我可以好好走一波 二.JS前端图形化插件之利器Gojs组件 参考: JS前端图形化插件之利器Gojs组件-js教 ...
- 关于如何提高Web服务端并发效率的异步编程技术
最近我研究技术的一个重点是java的多线程开发,在我早期学习java的时候,很多书上把java的多线程开发标榜为简单易用,这个简单易用是以C语言作为参照的,不过我也没有使用过C语言开发过多线程,我只知 ...
- HT for Web的HTML5树组件延迟加载技术实现
HT for Web的HTML5树组件有延迟加载的功能,这个功能对于那些需要从服务器读取具有层级依赖关系数据时非常有用,需要获取数据的时候再向服务器发起请求,这样可减轻服务器压力,同时也减少了浏览器的 ...
- Openstack的web管理端相关
openstack的web管理端技术方面要关注的问题. 同步?异步 先说浏览器的同步和异步,我们知道的浏览器可以使用ajax实现异步请求,就是浏览器在请求数据的时候,我们管理员还能对浏览器就行其他操作 ...
- 从web移动端布局到react native布局
在web移动端通常会有这样的需求,实现上中下三栏布局(上下导航栏位置固定,中间部分内容超出可滚动),如下图所示: 实现方法如下: HTML结构: <div class='container'&g ...
- 【译】编写支持SSR的通用组件指南
原文来自:https://blog.lichter.io/posts/the-guide-to-write-universal-ssr-ready-vue-compon?utm_campaign=Vu ...
随机推荐
- [Codeforces Round #794 (Div. 2)] D. Linguistics
我是什么东西艹艹艹 <我离正解只差个sort> 首先,观察字符串,可以发现:若存在形似\(AA--BB\)或\(BB--AA\)等有两个相同的字符挨在一起的情况,则我们在它们中间放一块隔板 ...
- 创建型模式 - 抽象工厂模式AbstractFactory
学习而来,代码是自己敲的.也有些自己的理解在里边,有问题希望大家指出. 模式的定义与特点 抽象工厂模式.是一种为访问类提供一个创建一组相关或相关一类对象的接口,且访问类无需指定所要的产品的具体类,就能 ...
- JDK8 四大核心函数式接口及扩展接口总结
前言 Java8的四大函数式接口及相关的扩展接口在日常使用中的频率也是非常多的,包括自己定义的函数式接口,在JDK1.8之前,我们定义的方法都是用来接收参数,然后自己根据参数传递实现逻辑.在1.8之后 ...
- pycharm设置python头文件模版
钢铁知识库,一个学习python爬虫.数据分析的知识库.人生苦短,快用python. 使用pycharm创建python文件时候,有时候需要自动生成想要的文件头,如何生成呢? 只需要以下几步: 在fi ...
- vue学习笔记(八)---- vue中的实例属性(wacth和computed的使用)
一.watch属性的使用 1.传统方式实现双向数据改变监听事件(姓名拼接案例) <div id="app"> 姓: <input type="text& ...
- Selenium Webdriver驱动自管理
Webdriver驱动自管理 背景 在selenium自动化中,驱动和浏览器有一定的对应关系,以最常见的chrome和firefox为例. chrome 要求比较严格. 比如在地址栏输入chrome: ...
- undefined会变为null吗?
echarts 会将 series data中的数据并不是你想的那样简单 我们很多小伙伴都使用过echarts. 然后 series:[{ data:[] }] 中的数据可能并没有我们想的那样简单 为 ...
- Solon2 开发之容器,八、动态代理的本质
在 Java 里动态代理,主要分:接口动态代理 和 类动态代理.因为它的代理类都是动态创建的,所以名字里会带上"动态". 官网的有些地方叫"代理",也有些地方叫 ...
- spring源码写注释
转:https://blog.csdn.net/z_c8819/article/details/105258015 1.从GitHub上下载spring项目 https://github.com/sp ...
- concurrent.futures之ThreadPoolExecutor python线程池代码实现方法
from concurrent.futures import ThreadPoolExecutor def main(i): print(i) THREAD_NUM = 20 # 线程数 with T ...