需求一:用canvas生成一张图片,用户长按可保存,效果图:
看效果图可以看出,这里面涉及到了几个功能点:
如何适配手机屏幕 / 文字如何居中 / 如何生成二维码 / 如何在加载图片后绘制 / canvas脏画布问题
下面就一个个来解决这些问题。
移动端大小适配(有问题):
getInitialState:function(){return{cvsWidth:window._rem *9.375,cvsHeight:window._rem *12};},
文字居中显示
CanvasRenderingContext2D.measureText():可以测量字体的宽度
ctx.fillText("测试",(this.state.cvsWidth - ctx.measureText("测试").width)/2,startY);
二维码的生成
思路是,先生成canvas二维码,再将canvas转成图片,然后画到canvas中。
letQR =require("arale-qrcode");letqrObject =newQR({render:"canvas",text:"https://weixiao.qq.com",size: WindowRem*1.875
});letqrcodeSrc = qrObject.toDataURL("image/png",1.0);
这里使用了一个生成二维码的库arale-qrcode,地址:https://github.com/aralejs/qrcode
图片的加载
在用canvas绘制图片过程中会遇到一个问题是,当canvas在画这张图片的时候,实际上这张图片还没有加载完成。结果当canvas转化成图片的时候画出来的是一张空白图片。针对这个问题,可以这样解决:
if(img.complete || img.complete === undefined) {ctx.drawImage(img,startX,startY,imgSize,imgSize);}else{ img.onload =()=>{ctx.drawImage(img,startX,startY,imgSize,imgSize);};}
toDataURL的跨域问题
在canvas中,不在本站域名中的图片默认只可读不可写,也就是说,你可以将一张非本站点图片画到canvas中,但你无法使用toBlob(),toDataURL() 或 getImageData() 方法,否则会报错。
这就很麻烦,因为图片中有cdn的图片,还有从微信拉过来的头像图片。
网络中的方法是:
img.setAttribute("crossorigin","anonymous");
可是我试了一下没有用,可能是服务端阻止了图片的拉取。
于是换了一种解决方案,将图片转化成base64,解决了。
需求二:画一张统计饼图,带动画和点击,效果图:
canvas动画
MDN上给出了用canvas绘制动画的基本思路,简单来说就是,画一帧,擦除画布,再画下一帧,再擦除...
如果你是画那种一直在动的动画,像时钟、太阳系这种,可以引用 window.requestAnimationFrame()方法。
如果是画一段,然后停止的话,可以用setInterval方法:
cvsFrame:function(){ let_this =this,speed =0; letdrawProcess = setInterval(function(){ _this.state.ctx.clearRect(0,0, _this.state.cvs.width, _this.state.cvs.height);_this.doCanvas(speed);if(speed >=100) { clearInterval(drawProcess);}speed +=2; },10);},
canvas点击事件
要点击canvas并出现一些效果,主要就是获取鼠标点击的位置。
在移动端可绑定的点击事件有onTouchStart和onTouchEnd,
当绑定onTouchStart时,获取鼠标位置的方式是:
lettouch = e.touches[0], mx = touch.clientX , my = touch.clientY ;
当绑定onTouchEnd时,获取鼠标位置的方式是:
e.changedTouches
P.s:移动端无法用onClick绑定事件的e.clintX、e.screenX、e.layerX获取鼠标位置,这些只适合PC端用。在PC端用e.clintX、e.screenX、e.layerX时,有浏览器兼容问题,layerX是Firefox的特有属性。用错的话会undefined的。