// 预加载图片 & 跨域设置
const imgs = ['avatar.png', 'bg_screenshot.jpg', 'container.png']
const imgEls = {}
let loadCount = 0
const imgLoad = (callback) => {
loadCount ++
if (loadCount === imgs.length) callback()
const preloadImg = (callback) => {
imgs.forEach((imgUrl) => {
let img = document.createElement('img')
img.crossOrigin = 'Anonymous'
img.onload = ()=>{
imgEls[imgUrl] = img
imgLoad(callback)
img.src = './img/' + imgUrl
// 使用
preloadImg(() => {
console.log('img loaded!')
注意:img.crossOrigin = 'Annoymous
只是将该图片请求设置为一个跨域请求,这个时候,如果服务器没有设置合适的CORS,浏览器会提示图片加载失败,因此这里需要后端配合设置:Access-Control-Allow-Origin:*
。
3.3.2 高清图 & 位置适配
高清图这个概念和两倍图、三倍图的概念一样,不理解的同学可以去搜索一下。举个例子,iPhone6下window.devicePixelRatio = 2
, 而window.innerWidth = 375
,因此需要给750px
宽的视觉稿才能在手机上看到和视觉稿一样的效果。而iPhoneX是三倍图,因此需要375 * 3
的背景图,但是视觉设计师一般只会给二倍图,所以这个时候在iPhoneX下图片显示没有视觉稿那么清晰,如果对视觉有要求,还需要设计师给三倍图(除非是矢量图,我们可以自由缩放)。
理解了高清图之后,我们截屏的canvas大小就可以计算出来了,和高清图一样,在window.devicePixelRatio = 2
的设备上,我们会将canvas设置成window.innerWidth
的两倍,最后生成的图片就相当于是两倍图,能在该设备清晰显示。
在canvas大小已知的基础上,我们就可以从视觉稿中量出绘制元素的宽度,left,top信息,直接缩放绘制到canvas上了。
const scale = window.innerWidth / 750 * window.devicePixelRatio
const ratio = 1.7
const width = 750 * scale
const height = width * ratio
screenshotCanvas = document.createElement('canvas')
screenshotCanvas.width = width
screenshotCanvas.height = height
const ctx = screenshotCanvas.getContext('2d')
ctx.drawImage(imgEls['container.png'], (750 - 643) / 2 * scale, 184 * scale, 634 * scale, 843 * scale )
复制代码
3.3.3 圆形头像绘制
微信后台给到的用户头像都是方形的,如果需要绘制圆形头像,可以先设置头像圆形区域,裁剪后进行绘制,这个时候只有在圆形区域的内容才会被绘制进去,然后恢复ctx设置(ctx.save() / ctx.restore()
)继续绘制别的内容即可。
ctx.save()
const avatarR = 103 * scale / 2
ctx.arc(540 * scale + avatarR, 244 * scale + avatarR, avatarR, 0, Math.PI * 2, false)
ctx.clip()
ctx.drawImage(imgEls['avatar.png'], 540 * scale, 244 * scale, 103 * scale, 103 * scale )
ctx.restore()
复制代码
3.3.4 绘制文字 & 适配大小
文字大小我们经常用rem
来适配,但是canvas绘制只支持px
单位,因此需要我们自己计算,其实和上面的高清图一样,等比缩放即可:
const getFont = (size) => {
return size * scale + 'px serif'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.font = getFont(26)
复制代码
看上面的注释大家应该也看到了,关于字体的垂直位置设置有个坑,字体绘制的时候,默认是顶部对齐的,但是不同浏览器顶部对齐的表现不同,因此改用垂直居中。假设原来的top是400,字体高度为100,那设置ctx.textBaseline = 'middle'
后,绘制字体的y位置就是400 + 100 / 2 = 450
。
参考:Canvas文字绘制top位置不一致问题
5 End
截图分享需求,大都是绘制图片、分享文案和用户信息,很多时候并不需要出动html2canvas这种“重型武器”,了解如何做适配和查阅绘制相关的api,你也可以轻松实现截图需求。
前方还有很多问题等着我们去解决,例如文字绘制怎么局部高亮、自动换行和自动省略等等,下一篇博客见,同时期待与大家共同成长。
附:demo源码
写完后发现系统相关推荐的一篇文章讲截图(主要用了html2canvas)讲得比较全面,这里引用一下,大家可以结合起来学习:
《高质量前端快照方案:来自页面的「自拍」》