绘制高清晰度HTML canvas适配不同移动设备
最近在做项目的时候,需要把文字以图片形式在前端显示出来,发现canvas这个好东西。但是在手机端显示的时候总是很模糊,查找资料发现是devicePixelRatio惹的祸
下面是做的简单测试,先贴代码:
<script type="text/javascript"> var canvas = document.createElement("canvas"); canvas.width = 414; var ctx = canvas.getContext("2d"); ctx.font = "30px Arial"; ctx.fillText("Low DPI Text", 10, 40); document.body.appendChild(canvas); var HiDPIcanvas = document.createElement("canvas"); HiDPIcanvas.width = 414 * window.devicePixelRatio; HiDPIcanvas.style.width = 414; var HiDPIctx = HiDPIcanvas.getContext("2d"); HiDPIctx.scale(window.devicePixelRatio,window.devicePixelRatio); HiDPIctx.font = "30px Arial"; HiDPIctx.fillText("High DPI Text", 10, 40); document.body.appendChild(HiDPIcanvas); </script>
Chrome开发模式下,可以看出前者是正常的,而后者“太”清晰了,因为电脑屏幕一般devicePixelRatio都是1,没有影响
而在手机上显示就不同了,iPhone 6sp下,后者正常,而前者其实有些模糊了,iPhone 6sp的devicePixelRatio为3
文字转成图片(解决中英文混杂字符串如何按字节截断问题)
由于canvas的fillText方法不支持自动换行,所以需要手动截断字符串,找好canvas的X和Y坐标位置后,像画画一样把文字画上去。
代码如下,(自定义字节长度进行截断,不截断数字)
1 // Create HiDPI canvas based on custom ratio or device pixel ratio 2 function createCanvas(str, pixelRatio) { 3 var w = window.screen.width * 0.935; // 0.935 is the canvas' width proportion 4 if (!pixelRatio) { pixelRatio = window.devicePixelRatio || 1; } 5 var can = document.createElement("canvas"); 6 can.width = w * pixelRatio; 7 can.style.width = w + "px"; 8 return drawImage(str, can, pixelRatio); 9 } 10 11 // Draw text on HTML canvas 12 function drawImage(text, canvas, pixelRatio) { 13 var ratio = window.screen.width / 414; // Fit with iPhone 6sp as the standard 14 var rowLength = 39; // Byte length of canvas row 15 var k = 0; // rowLength counter 16 var fontSize = 20 * ratio; 17 18 // adjust canvas height according to text byte length 19 var h = (function (text) { 20 var strLength = 0; // text byte length 21 for (var j = 0; j < text.length; j++) { 22 if (text.charCodeAt(j) > 255) { 23 strLength += 2; 24 } else { 25 strLength++; 26 } 27 } 28 return (strLength / rowLength + 1) * (fontSize*1.3); 29 })(text); 30 canvas.height = h * pixelRatio; 31 canvas.style.height = h + "px"; 32 canvas.getContext("2d").scale(pixelRatio,pixelRatio); 33 34 var ctx = canvas.getContext("2d"); 35 ctx.font = fontSize + "px Arial"; 36 var x = 10 * ratio; // X axis position of canvas 37 var y = 20 * ratio; // Y axis position of canvas 38 39 for (var j = 0; j < text.length; j++) { 40 if (k == rowLength || k == rowLength - 1) { 41 // move forward when you encounter numbers 42 while (text.charCodeAt(j - 1) >= 48 && text.charCodeAt(j - 1) <= 57) { 43 j--; 44 } 45 text = text.substr(0, j) + "<br>" + text.substr(j); 46 k = 0; // truncate for next line 47 j += 4; // plus the "<br>" length 48 } 49 // plus 2 bytes when you encounter chinese character 50 if (text.charCodeAt(j) > 255) { 51 k += 2; 52 } else { 53 k++; 54 } 55 } 56 var textArray = text.split("<br>"); // truncate text to array 57 // Fill text on canvas 58 for (var j = 0; j < textArray.length; j++) { 59 ctx.fillText(textArray[j], x, y); 60 y += 25 * ratio; 61 } 62 return canvas; 63 }
参考:(这篇文章写得很好,可以看看,不过需要注意提到的backingStorePixelRatio已经弃用)
www.html5rocks.com/en/tutorials/canvas/hidpi/
https://stackoverflow.com/questions/15661339/how-do-i-fix-blurry-text-in-my-html5-canvas
https://stackoverflow.com/questions/24332639/why-context2d-backingstorepixelratio-deprecated