Canvas是HTML5新增的元素,用于在网页上绘制图形,它由Apple在Safari1.3Web浏览器中引入,之所以对HTML扩展的原因在于,HTML在Safari中的绘图能力能为MacOSX桌面的Dashboard组件所使用,并且Apple也希望有一种方式可以在Dashboard中支持脚本化的图形。Firefox1.5和Opera9这两个浏览器也紧随Safari的引领,开始支持Canvas。
现在,Canvas标签已经是HTML5最伟大的改进之一,因为它可以让我们在不使用图片的情况下实现网页的图形设计。它就像一块画布,本身没有绘制能力,但却把绘制API展现给客户端JavaScript,我们借助JavaScript的支持,在画布范围内尽情发挥,达到想要的效果。
技术选型
这个功能无论是Canvas、SVG或是Flash,都可以实现,但是我们为什么选择了Canvas呢?
首先,由于功能上我们需要支持移动平台,所以Flash我们就可以直接弃掉,它在移动端方面并没有得到友好的支持,但Canvas和SVG都具有很好的跨平台能力,我们如何抉择,下面我们来对比一下。
两者各有自己的擅长领域,基于以上,我们选择了Canvas来实现签字功能。
下面,我们来看一下实现效果。
创建画布
首先,我们需要判断浏览器是否支持Canvas:
{isCanvasSupported(this.canvas=canvas)}height={canvasHeight}width={canvasWidth}>:对不起,当前浏览器暂不支持此功能!}我们知道,每个Canvas节点都有一个对应的context对象,我们可以通过Canvas对象的getContext()方法,直接把量字符串“2d”作为唯一的参数传递给它来获取。接下来,我们通过ref获取Canvas元素,再通过getContext()方法得到一个画布上绘图的环境。
绘制
首先绘制开始路径:
cxt.beginPath();然后设置当前线条的宽度:
cxt.lineWidth=5;设置线条的颜色:
cxt.moveTo(0,0);cxt.lineTo(150,0);//绘制已定义的路径cxt.stroke()
但是,我们发现绘制的线条比较生硬
这时,我们可以通过lineCap改变线条末端线帽的样式,为每个末端添加圆形线帽,减少线条的生硬感
同时,我们还可以通过设置lineJoin,指定条线交汇时为圆形边角
但我们又发现,绘制的线条有明显的锯齿,此时我们就需要借助Canvas为我们提供的绘制元素阴影的功能来模糊边缘出现的锯齿,因为有阴影,所以我们可以适当改变lineWidth值
是不是变得圆润很多,到这里,我们绘制线路的方法已经准备完事,接下来我们来看一下怎么监听画布事件来实现连贯执行绘制吧!
监听画布事件
因为我们需要同时兼容PC端和移动端,所以我们需要事先需要判断一下对应执行的事件
this.canvas.addEventListener(this.events[0],startEventHandler,false);在startEventHandler函数中监听events[1]和events[2]事件
this.canvas.addEventListener(events[1],moveEventHandler,false);this.canvas.addEventListener(events[2],endEventHandler,false);重点来了,我们核心的内容就是计算、描绘划过的路径
moveEventHandler(event:any):void{event.preventDefault();const{ctx,isSupportTouch}=this.state;constevt=isSupportTouchevent.touches[0]:event;constcoverPos=this.canvas.getBoundingClientRect();constmouseX=evt.clientX-coverPos.left;constmouseY=evt.clientY-coverPos.top;cxt.lineTo(mouseX,mouseY);cxt.stroke();}了解Canvas的知道,Canvas画布为我们提供了一个用来作图的平面空间,该空间的每个点都有自己的坐标,x表示横坐标,y表示竖坐标。原点(0,0)位于图像左上角,x轴的正向是原点向右,y轴的正向是原点向下。
于是我们通过getBoundingClientRect()方法获得页面Canvas元素相对浏览器视窗的位置左边和顶部的像素距离,再利用clientX,clientY事件属性返回当事件被触发时鼠标指针向对于浏览器页面的水平和垂直坐标,最后通过lineTo和stroke来绘制路径。
同时,我们要记得在events[2]事件执行之后,移除events[1]、events[2]事件,否则会造成一直绘制。
endEventHandler(event:any):void{event.preventDefault();const{events,moveEventHandler,endEventHandler}=this.state;this.canvas.removeEventListener(events[1],moveEventHandler,false);this.canvas.removeEventListener(events[2],endEventHandler,false);}如此反复循环上述事件操作,我们的签字功能就基本实现了。
重新绘制
签字过程中,签错或是签的过于潦草是必不可免的,所以我们需要支持清空签字的功能,这时,我们利用Canvas的clearRect()方法就可以帮助我们清除画布区域内容。
cxt.clearRect(0,0,canvasWidth,canvasHeight);图片处理
绘制之后我们还没完事,我们还需要把绘制的签名上传保存。这时,我们可以利用toDataURL()方法将Canvas转化成一般的图像文件形式。
通常我们直接执行以操作就能转化成dataURI,然后再利用ajax请求上传就完事了。
说道html2canvas,顺便给大家一个绕坑提示,它在一些低版本浏览器截出来的图片是空白的,原因是使用了flex布局,而html2canvas并不支持-webkit-flex或-webkit-box,所以无法将HTML生成Canvas,从而导致了截出一张白屏。