24
2021
06

canvas窗口自适应

问题描述

我们基于canvas做互动课件开发,本质上更接近游戏开发,而非前端(指DOM)开发。由于当前设备的分辨率种类太多,而且用户可以任意改变浏览器窗口尺寸,所以我们必须要做自适应。为了显示不变形,我们一定是进行等比缩放。

为什么要写这篇文章

自适应窗口或者分辨率的算法,网上有很多,而且类似于白鹭的引擎一般都提供自适应的算法,开发者不用自己去实现。但是,看似简单,其实还是有一些坑的,我把自己踩过的坑记录下来,避免自己,也避免他人重复踩坑。

问题分析

设计尺寸和显示尺寸

屏幕分辨率多种多样,甚至宽高比都不一样,我们不可能照着所有尺寸全部开发一遍,一般来说,我们会定义一个尺寸,设计人员基于这个尺寸来做设计,开发人员基于这个尺寸做开发,我们把这个尺寸叫设计尺寸

最终显示的时候,屏幕分辨率不同,窗口尺寸不一样,最终显示的大小并不会和设计尺寸一样,我们把这个最终显示的尺寸叫显示尺寸

自适应算法要做的,其实就是根据设计尺寸和显示尺寸的值对课件(游戏)整体进行缩放。

canvas的宽高

canvas有width、height属性,canvas的style中也有width、height属性,这两个属性有什么区别呢?

其实canvas的width和height就是我们的设计尺寸,style中的width和height就是我们的显示尺寸。

canvas的设计尺寸决定了在开发的时候可视区域有多少个像素点,比如获取可视区域的ImageData得到的数据的长度,WebGl中顶点着色器调用的次数。显示尺寸决定了最终渲染的大小。相当于先按照设计尺寸去计算,得到一张图片,然后再把整张图缩放到显示尺寸的大小,用于最终显示。

分析

我们现在有4个尺寸:canvas的设计尺寸、canvas的显示尺寸、课件的设计尺寸、课件的显示尺寸。

canvas的显示尺寸我们是可以确定的,课件的设计尺寸是提前定好的常量,课件的显示尺寸等于canvas的设计尺寸(这里我们做了简化,也可以不等,问题会变得更复杂)。

为了进一步简化,我们可以把问题分成相互独立的两步:课件内部的缩放、canvas的缩放。这样,我们可以保持其中一步缩放比例为1,只需要计算另外一步的缩放。

自适应算法要做的就是确定缩放比例,使得

  1. 最终显示效果为等比缩放。

  2. 设计尺寸范围内的要全部显示出来,并且宽和高方向至少有一个刚好全部显示。

自适应

假设canvas的设计尺寸为s0(w0, h0)、canvas的显示尺寸为s1(w1, h1)、课件的设计尺寸为s2(w2, h2)、课件的显示尺寸为s0(w0, h0)。

方法1-缩放canvas

保持课件内部不缩放,通过缩放canvas来实现自适应。

为了满足约束条件1,保持缩放比例,有

w1 / h1 = w0 / h0;

为了满足约束条件2,全部显示,且宽和高方向至少有一个刚好全部显示,有

w0 ≥ w2且h0 ≥ h2,且至少有一个等号成立。

w1、h1已知,w2、h2也已知。要求w0和h0。

w0 = (w1 / h1) * h0 ≥ w2;

=> h0 ≥ w2 * h1 / w1;

所以,有

h0 = max(w2 * h1 / w1, h2);

w0 = (w1 / h1) * h0;

方法2-缩放课件

保持canvas不缩放,通过缩放课件内部来实现自适应。

w0 = w1,h0 = h1,变成了已知量。

为了满足两个约束条件,有

w2 * s ≤ w0 且 h2 * s ≤ h0且至少有一个等号成立。

=> s ≤ w0 / w2 且 s ≤ h0 / h2

所以,有

s = min(w0 / w2, h0 / h2);

对比

方法1:

  • 优点:课件的开发和自适应完全分离。

  • 缺点:canvas的设计尺寸可能变得很大;canvas整体缩放显示效果不好。

方法2:

  • 优点:canvas的设计尺寸永远和显示尺寸一致;比canvas整体缩放显示效果好。

  • 缺点:自适应会影响课件开发(比如全局和本地坐标转换)。

总结

最初,我们选择的是方法1,但是我们遇到了两个问题:一个是在大分辨率的显示设备上,最终显示效果很差,图片很模糊;另一个是我们用到了shader,需要计算的顶点数量会永远大于等于实际显示的像素点数,影响性能,屏幕宽高比和设计尺寸差的很多的时候(比如设计尺寸是16:9,手机竖屏显示的情况)会更明显。所以,最终我们换成了方法2。


« 上一篇下一篇 »

相关文章:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。