如果不能设置canvasElm.style.width,那么如何实现canvas绘制的移动端适配

因为canvas是基于像素的绘图,我们在pc端封装的canvas绘制方法如果想直接迁移至移动端并实现移动端适配,可以使用如下思路:

使用transformscale对画布进行缩放,缩放比例的计算并不难,思路就是canvas(像素大小)占手机dip的比例等于设计稿上canvas占设计稿的比例,并且移动设备上canvas的像素大小可以用pc端的canvas大小✖️缩放比例来表示,即:

pc端canvas图像宽度(像素大小) * 缩放比例 / 移动设备的dip宽度 === 设计稿上canvas部分的宽度 / 设计稿宽度
pc端canvas图像宽度(像素大小) * 缩放比例 / 移动设备的dip宽度 === 设计稿上canvas部分的宽度 / 设计稿宽度
pc端canvas图像宽度(像素大小) * 缩放比例 / 移动设备的dip宽度 === 设计稿上canvas部分的宽度 / 设计稿宽度

综上可得适配方法adaptMobile

/**
* @param {number} designWidth: 设计稿上的canvas宽度
* @param {number} width: 设计稿的宽度
* @param {Element} canvasElm: canvas元素
*/
function adaptMobile(designWidth, width, canvasElm) {
const ratio = designWidth / width; // 目标canvas占屏幕的宽度比例
const screenPx = screen.width; // 当前设备的宽度dip像素数
const canvasWidth = parseInt(canvasElm.style.width); // canvas的宽度
canvasElm.style.transformOrigin = '0 0';
canvasElm.style.transform = `scale(${ratio * screenPx / canvasWidth})`;
}
/**
 * @param {number} designWidth: 设计稿上的canvas宽度
 * @param {number} width: 设计稿的宽度
 * @param {Element} canvasElm: canvas元素
 */
function adaptMobile(designWidth, width, canvasElm) {
  const ratio = designWidth / width; // 目标canvas占屏幕的宽度比例
  const screenPx = screen.width; // 当前设备的宽度dip像素数
  const canvasWidth = parseInt(canvasElm.style.width); // canvas的宽度
  canvasElm.style.transformOrigin = '0 0';
  canvasElm.style.transform = `scale(${ratio * screenPx / canvasWidth})`;
}
/** * @param {number} designWidth: 设计稿上的canvas宽度 * @param {number} width: 设计稿的宽度 * @param {Element} canvasElm: canvas元素 */ function adaptMobile(designWidth, width, canvasElm) {  const ratio = designWidth / width; // 目标canvas占屏幕的宽度比例  const screenPx = screen.width; // 当前设备的宽度dip像素数  const canvasWidth = parseInt(canvasElm.style.width); // canvas的宽度  canvasElm.style.transformOrigin = '0 0';  canvasElm.style.transform = `scale(${ratio * screenPx / canvasWidth})`; }

canvasElm即用pc端的绘制方法所绘制的画布,但当前还存在一个问题,因为pc端绘制时canvas的像素大小(宽度)可能超出移动设备的dip宽度,虽然经过transform缩放后画布已经完全在手机屏幕之内,但是熟悉浏览器渲染原理的朋友肯定知道,transform是在渲染的最后一步完成的,不参与render tree的构建以及布局绘制等等前面的逻辑,所以这就导致移动端出现滚动条。

解决方案很简单:给canvas的dom元素外面套一个空<div>,给这个div设置一个overflow: hidden即可解决。

综上我们就完成了pc端绘制的canvas图像无痛迁移到移动端实现适配的流程。

给个demo,如下adaptMobile(375, 750, canvasElm);即等价于让canvas元素width: 50vw,可以切换不同型号的移动设备感受:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.canvas-container {
overflow: hidden;
}
</style>
</head>
<body>
<div class="canvas-container">
<canvas id="canvasElm"></canvas>
</div>
<script>
const canvas = document.getElementById('canvasElm');
canvasElm.width = 300;
canvasElm.height = 300;
canvasElm.style.width = 500 + 'px';
canvasElm.style.border = `1px solid red`;
const ctx = canvasElm.getContext('2d');
ctx.fillStyle = 'pink';
ctx.fillRect(0, 0, 150, 150);
/**
* @param {number} designWidth: 设计稿上的canvas宽度
* @param {number} width: 设计稿的宽度
* @param {Element} canvasElm: canvas元素
*/
function adaptMobile(designWidth, width, canvasElm) {
const ratio = designWidth / width; // 目标canvas占屏幕的宽度比例
const screenPx = screen.width; // 当前设备的宽度dip像素数
const canvasWidth = parseInt(canvasElm.style.width); // canvas的宽度
canvasElm.style.transformOrigin = '0 0';
canvasElm.style.transform = `scale(${ratio * screenPx / canvasWidth})`;
}
adaptMobile(375, 750, canvasElm);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .canvas-container {
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <div class="canvas-container">
      <canvas id="canvasElm"></canvas>
    </div>
    <script>
      const canvas = document.getElementById('canvasElm');
      canvasElm.width = 300;
      canvasElm.height = 300;
      canvasElm.style.width = 500 + 'px';
      canvasElm.style.border = `1px solid red`;
      const ctx = canvasElm.getContext('2d');
      ctx.fillStyle = 'pink';
      ctx.fillRect(0, 0, 150, 150);
      /**
       * @param {number} designWidth: 设计稿上的canvas宽度
       * @param {number} width: 设计稿的宽度
       * @param {Element} canvasElm: canvas元素
       */
      function adaptMobile(designWidth, width, canvasElm) {
        const ratio = designWidth / width; // 目标canvas占屏幕的宽度比例
        const screenPx = screen.width; // 当前设备的宽度dip像素数
        const canvasWidth = parseInt(canvasElm.style.width); // canvas的宽度
        canvasElm.style.transformOrigin = '0 0';
        canvasElm.style.transform = `scale(${ratio * screenPx / canvasWidth})`;
      }
      adaptMobile(375, 750, canvasElm);
    </script>
  </body>
</html>
<!DOCTYPE html> <html lang="en">  <head>    <meta charset="UTF-8" />    <meta http-equiv="X-UA-Compatible" content="IE=edge" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <title>Document</title>    <style>      .canvas-container {        overflow: hidden;     }    </style>  </head>  <body>    <div class="canvas-container">      <canvas id="canvasElm"></canvas>    </div>    <script>      const canvas = document.getElementById('canvasElm');      canvasElm.width = 300;      canvasElm.height = 300;      canvasElm.style.width = 500 + 'px';      canvasElm.style.border = `1px solid red`;      const ctx = canvasElm.getContext('2d');      ctx.fillStyle = 'pink';      ctx.fillRect(0, 0, 150, 150);      /**       * @param {number} designWidth: 设计稿上的canvas宽度       * @param {number} width: 设计稿的宽度       * @param {Element} canvasElm: canvas元素       */      function adaptMobile(designWidth, width, canvasElm) {        const ratio = designWidth / width; // 目标canvas占屏幕的宽度比例        const screenPx = screen.width; // 当前设备的宽度dip像素数        const canvasWidth = parseInt(canvasElm.style.width); // canvas的宽度        canvasElm.style.transformOrigin = '0 0';        canvasElm.style.transform = `scale(${ratio * screenPx / canvasWidth})`;     }      adaptMobile(375, 750, canvasElm);    </script>  </body> </html>

plus:这里有人反应过来会问,为啥不直接设置canvas元素宽度为50vw,因为canvas只支持通过canvasElm.style.width来设置像素大小hh。

并且这里还有个可能让你迷惑的点就是,为啥不直接操作canvasElm.style.width完成移动端适配,也就是说计算移动设备上应该要画多少像素,完全没问题,但是业务场景所需,可以理解为我们业务中pc端的绘制方法内包含了对canvasElm.style.width的设置,并且这个方法相当于一个黑盒,我们无法操作。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYjqPLlz' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片