模糊原因
首先, 需要理解 canvas 的展示机制.
<canvas id="map" width="375" height="667"></canvas>
我绘制了一张 375px 的 canvas,iphone6 的宽度也是 375px,ok,canvas 铺满了整个屏幕.
那么 canvas 的大小就是 375px,canvas 类似于图片, 一张 375px 的图片, 我们就把它当做是图片来看就好了. 我, 尖沙咀段坤说的.
如果遇到了屏幕宽度 400px 的手机, 那么图片会 拉伸, canvas 也会拉伸, 拉伸则必然会模糊.
那么 iphone6 确实是 375px 宽度的手机, 还是会出现模糊问题, 为什么呢? 手机端会存在高清屏的问题. 也就是我们说的 2 倍屏或者 3 倍屏, 也叫作屏幕的 DPI. 高清屏在绘制界面时, 会把 2px 的宽度渲染成 1px, 也就达到了高清的效果. 也就是说, 我们在高清屏下看到的 375px 其实是 750 个像素点绘制出来的, canvas 其实是 375px 被拉伸到了 750px 再展示出来的, 拉伸则必然会模糊.
好了, 模糊的原因知道了, 其实就是高清屏所带来的麻烦, 怎么解决呢?
解决方法
如果是 2 倍屏, 我们把设计图上 375px 的 canvas 画成 750px 不就解决了?
设置 canvas 样式
这里我们不写 width 和 height, 而直接写 style. 把它看成是图片, 我们先不管图片原宽高是多少, 不管拉伸还是压缩, 直接让他铺满整个屏幕. style 里写的宽高不是图片的原宽高, 也就是 style 里写的宽高并不是 canvas 的真实宽高
<canvas id="map" style="width: 375px;height:330px;"></canvas>
设置 canvas 宽高
上面的 style 并不是 canvas 的真实宽高, 那么我们如何设置它的宽高呢?
普通屏, 2 倍屏, 3 倍屏如果分别适配?
- <canvas id="map" style="width: 375px;height:330px;"></canvas>
- <script>
- let canvas = document.querySelector('#map');
- // 获取到屏幕倒是是几倍屏.
- let getPixelRatio = function(context) {
- var backingStore = context.backingStorePixelRatio ||
- context.webkitBackingStorePixelRatio ||
- context.mozBackingStorePixelRatio ||
- context.msBackingStorePixelRatio ||
- context.oBackingStorePixelRatio ||
- context.backingStorePixelRatio || 1;
- return (Windows.devicePixelRatio || 1) / backingStore;
- };
- // iphone6 下得到是 2
- const pixelRatio = getPixelRatio(canvas);
- // 设置 canvas 的真实宽高
- canvas.width = pixelRatio * canvas.offsetWidth; // 想当于 2 * 375 = 750
- canvas.height = pixelRatio * canvas.offsetHeight;
- </script>
那么 canvas 的宽高就变成了下图这样, 750 宽度的 canvas, 如果你是 2 倍屏我就刚好能够适应!!!
设置后的宽高
开始画点
比如, 375 的设计图上, 有一个半径为 2px 的圆点, 点的位置是 x:100,y:100.
那么我们现在 canvas 的宽度是 750, 宽高变成了之前的 2 倍. 为了视觉上位置保持不变, 我们画点的位置就应该是 x:100*pixelRatio,y:100*pixelRatio.
完整代码如下:
- <canvas id="map" style="width: 375px;height:330px;"></canvas>
- <script>
- let canvas = document.querySelector('#map');
- // 获取到屏幕倒是是几倍屏.
- let getPixelRatio = function(context) {
- var backingStore = context.backingStorePixelRatio ||
- context.webkitBackingStorePixelRatio ||
- context.mozBackingStorePixelRatio ||
- context.msBackingStorePixelRatio ||
- context.oBackingStorePixelRatio ||
- context.backingStorePixelRatio || 1;
- return (Windows.devicePixelRatio || 1) / backingStore;
- };
- // iphone6 下得到是 2
- const pixelRatio = getPixelRatio(canvas);
- // 设置 canvas 的真实宽高
- canvas.width = pixelRatio * canvas.offsetWidth; // 想当于 2 * 375 = 750
- canvas.height = pixelRatio * canvas.offsetHeight;
- // 开始画点
- let ctx = canvas.getContext("2d");
- ctx.beginPath();
- // 375 设计图上的位置和尺寸都应该 * pixelRatio 因为我们现在的 canvas 是 750
- ctx.arc(100*pixelRatio, 100*pixelRatio, 2*pixelRatio, 0, 2 * Math.PI);
- ctx.fillStyle = "#fff";
- ctx.fill();
- ctx.closePath();
- // ... 你的其他代码
- </script>
来源: http://www.jianshu.com/p/7c76667662f1