HTML5 canvas自适应手机屏幕大小的一种解决方案

一、最终效果

为了不浪费大家时间,先展示最终效果,看看是不是大家需要的解决方案:

完整项目地址:https://github.com/zxf20180725/canvas_auto-adapted

标准分辨率:

其他分辨率的适配情况:

二、需求

1.canvas的内容能全部展示在屏幕上

2.尽量能保证图像不变形

3.绘制的文字也能自适应

三、解决方案

1.我们需要指定一个标准分辨率gameWgameH

2.我们需要获取屏幕的实际分辨率:

screenW=document.documentElement.clientWidth

screenH=document.documentElement.clientHeight

3.把canvas的宽高设置为屏幕一样大

4.计算屏幕宽度与标准宽度的比值:

kW=screenW/gameW

5.适配之后的绘图区高度可能小于屏幕高度,所以会出现黑边。那么我们需要计算黑边的高度:

dY = (screenH - gameH * kW) / 2;    //黑色区域的高度(紫色区域顶部与屏幕顶部的距离)

注意,当dY小于0时,绘图区会超出屏幕范围,这时就需要压缩绘图区高度(这时,画面会有所变形,也是不可避免的事):

    //我们先根据宽度比例适配
    let dY = (screenH - gameH * kW) / 2;    //黑色区域的高度(紫色区域顶部与屏幕顶部的距离)
    //当dY小于0时,我们不得不把画面给纵向压缩了。不然部分内容就会到屏幕外面去了
    if (dY<0){
        dY=0;
        kH=screenH/gameH;
    }

    let scaleH = kW;    //高度缩放率,默认以宽度比例
    if (kH!==1){
        scaleH=kH;
    }

最后,还有一个重要的问题,字体大小的自适应。我想到的最简单的方法就是使用双缓冲机制,我们绘图、绘制文字都在另一个缓冲canvas上进行,最后根据scaleH进行缩放,把缓冲canvas的内容绘制到屏幕canvas上。

四、完整代码

完整项目地址:https://github.com/zxf20180725/canvas_auto-adapted

核心代码:

    let canvas = document.getElementById("main");
    let ctx = canvas.getContext("2d");
    let screenW = document.documentElement.clientWidth;     //屏幕宽度
    let screenH = document.documentElement.clientHeight;    //屏幕高度
    let gameW = 640, gameH = 1280;   //标准分辨率,也就是你开发时的分辨率 TODO:这里可以自行修改

    let kW = screenW / gameW;       //屏幕宽度与标准宽度的比值
    let kH = 1;                   //屏幕高度与标准高度的比值

    //我们先根据宽度比例适配
    let dY = (screenH - gameH * kW) / 2;    //黑色区域的高度(紫色区域顶部与屏幕顶部的距离)
    //当dY小于0时,我们不得不把画面给纵向压缩了。不然部分内容就会到屏幕外面去了
    if (dY < 0) {
        dY = 0;
        kH = screenH / gameH;
    }

    let scaleH = kW;    //高度缩放率,默认以宽度比例
    if (kH !== 1) {
        scaleH = kH;
    }

    //设置canvas的绝对大小与屏幕一致
    canvas.width = screenW;
    canvas.height = screenH;

    //缓冲区
    let canvasBuffer = document.createElement("canvas");
    let ctxBuffer = canvasBuffer.getContext("2d");
    //缓冲区使用标准分辨率
    canvasBuffer.width = gameW;
    canvasBuffer.height = gameH;

    let timer = setInterval(mainLoop, 32);      //60FPS
    let testImg = NewImage('./test.png', 200, 250); //测试图片

    //游戏主循环
    function mainLoop() {
        drawFillRect(ctx, '#000', 0, 0, canvas.width, canvas.height);   //给canvas刷上一层黑色背景~
        drawFillRect(ctxBuffer, '#FF00FF', 0, 0, gameW, gameH);     //给游戏区域刷上一层紫色背景~
        drawText(ctxBuffer, '#FFF', 25, '窗口width:' + screenW, 0, 0);
        drawText(ctxBuffer, '#FFF', 25, '窗口height:' + screenH, 0, 30);
        drawText(ctxBuffer, '#FFF', 25, 'kW:' + kW, 0, 60);
        drawText(ctxBuffer, '#FFF', 25, 'kH:' + kH, 0, 90);
        drawText(ctxBuffer, '#FFF', 25, 'dY:' + dY, 0, 120);

        drawSrcImg(ctxBuffer, testImg, 100, 100);
        drawText(ctxBuffer, '#000', 32, '柳逐霓', 150, 350);

        drawSrcImg(ctxBuffer, testImg, 270, 100);
        drawText(ctxBuffer, '#000', 32, '柳逐霓', 320, 350);

        drawSrcImg(ctxBuffer, testImg, 530, 100);
        drawText(ctxBuffer, '#000', 32, '柳逐霓', 580, 350);

        drawSrcImg(ctxBuffer, testImg, 100, 400);
        drawText(ctxBuffer, '#000', 32, '柳逐霓', 150, 650);

        drawSrcImg(ctxBuffer, testImg, 100, 700);
        drawText(ctxBuffer, '#000', 32, '柳逐霓', 150, 950);

        drawSrcImg(ctxBuffer, testImg, 100, 1000);
        drawText(ctxBuffer, '#000', 32, '柳逐霓', 150, 1250);

        //双缓冲
        ctx.drawImage(canvasBuffer, 0, 0, gameW, gameH, 0, dY, screenW, gameH * scaleH);
    }
发布了40 篇原创文章 · 获赞 99 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_39687901/article/details/104071957