html canvas 让物体随物体中心缩放

  在canvas的绘图api中旋转(rotate)与缩放(scale),如果直接调用的话是得不到想要的效果的,必须经过相应设置(偏移或其它)之后才能得到想要的效果。

  下面记录一下canvas中随物体中心缩放的处理。

 

  缩放的步骤:

    1.先执行缩放

    2.对画布进行偏移(translate):

      x: - (物体中心(x轴) * (x轴的缩放值 - 1)) / x轴的缩放值

      y: - (物体中心 (y轴) * (y轴的缩放值 - 1)) / y轴的缩放值

    3. 进行普通的绘图操作

  

 

具体实现:

html:

<canvas class="cv"></canvas>

javascript:

     let cv = document.querySelector('.cv'),
            ctx = cv.getContext('2d'),
            /*
            * @param Number sx 物体开始绘制的x点
            * @param Number sy 物体开始绘制的y点
            * @param Number width 物体开始绘制的宽
            * @param Number height 物体开始绘制的高
            */
            getCenter = (sx, sy, width, height) => { // 返回物体的中心点
                return {
                    x: sx + (width / 2),
                    y: sy + (height / 2)
                };
            },
            /*
            * 绘制图形
            */
            draw = () => {
                let arc_x = 150, // 圆心x轴
                    arc_y = 150, // 圆心y轴
                    arc_r = 20, // 圆半径
                    s = { // 缩放值
                        x: 2,
                        y: 2
                    },
                    arc_center = getCenter(arc_x - arc_r, arc_y - arc_r, 2 * arc_r, 2 * arc_r); // 圆心

                ctx.clearRect(0, 0, cv.width, cv.height);

                // 绘制圆
                ctx.save(); // 保存状态,以免影响其它物体
                ctx.scale(s.x, s.y); // 执行缩放
                ctx.translate(- (arc_center.x * (s.x - 1)) / s.x, - (arc_center.y * (s.y - 1)) / s.y); // 缩放后的差偏移回来
                ctx.beginPath(); // 开启路径
                ctx.arc(arc_x, arc_y, arc_r, 0, 2 * Math.PI); // 绘制圆
                ctx.closePath(); // 关闭路径
                ctx.stroke(); // 描边绘制
                ctx.restore();// 恢复状态
            };

        // 画布大小
        cv.width = 800;
        cv.height = 500;
        draw(); // 开始绘制缩放

 

其它物体(圆、矩形、直线)的缩放的完整实现:

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <canvas class="cv"></canvas>

    <script type="text/javascript">
        let cv = document.querySelector('.cv'),
            ctx = cv.getContext('2d'),
            sv = 0, // 缩放的增加值
            speed = 0.01, // 缩放增加速度
            /*
            * @param Number sx 物体开始绘制的x点
            * @param Number sy 物体开始绘制的y点
            * @param Number width 物体开始绘制的宽
            * @param Number height 物体开始绘制的高
            */
            getCenter = (sx, sy, width, height) => { // 返回物体的中心点
                return {
                    x: sx + (width / 2),
                    y: sy + (height / 2)
                };
            },
            /*
            * 绘制图形
            */
            draw = () => {
                let arc_x = 150, // 圆心x轴
                    arc_y = 150, // 圆心y轴
                    arc_r = 20, // 圆半径
                    rect_x = 300, // 矩形x轴
                    rect_y = 100,// 矩形y轴
                    rect_width = 50,// 矩形的宽
                    rect_height = 50,// 矩形的高
                    line_sx = 500, // 直线起点x轴
                    line_sy = 100, // 直线起点y轴
                    line_ex = 600, // 直线终点x轴
                    line_ey = 210, // 直线终点y轴
                    s = { // 缩放值
                        x: 1 + sv,
                        y: 1 + sv
                    },
                    arc_center = getCenter(arc_x - arc_r, arc_y - arc_r, 2 * arc_r, 2 * arc_r), // 圆心
                    rect_center = getCenter(rect_x, rect_y, rect_width, rect_height), // 矩形中心
                    line_center = getCenter(line_sx, line_sy, line_ex - line_sx, line_ey - line_sy); // 直线中心

                ctx.clearRect(0, 0, cv.width, cv.height);

                // 绘制圆
                ctx.save(); // 保存状态,以免影响其它物体
                ctx.scale(s.x, s.y); // 执行缩放
                ctx.translate(- (arc_center.x * (s.x - 1)) / s.x, - (arc_center.y * (s.y - 1)) / s.y); // 缩放后的差偏移回来
                ctx.beginPath(); // 开启路径
                ctx.arc(arc_x, arc_y, arc_r, 0, 2 * Math.PI); // 绘制圆
                ctx.closePath(); // 关闭路径
                ctx.stroke(); // 描边绘制
                ctx.restore();// 恢复状态

                // 绘制矩形
                ctx.save();
                ctx.scale(s.x, s.y);
                ctx.translate(- (rect_center.x * (s.x - 1)) / s.x, - (rect_center.y * (s.y - 1)) / s.y);
                ctx.beginPath();
                ctx.strokeRect(rect_x, rect_y, rect_width, rect_height);
                ctx.closePath();
                ctx.restore();

                // 绘制直线
                ctx.save();
                ctx.scale(s.x, s.y);
                ctx.translate(- (line_center.x * (s.x - 1)) / s.x, - (line_center.y * (s.y - 1)) / s.y);
                ctx.beginPath();
                ctx.moveTo(line_sx, line_sy);
                ctx.lineTo(line_ex, line_ey);
                ctx.closePath();
                ctx.stroke();
                // 绘制线的外框,以便明显线的缩放
                ctx.beginPath();
                ctx.strokeStyle = '#bbb';
                ctx.strokeRect(line_sx, line_sy, line_ex - line_sx, line_ey - line_sy);
                ctx.closePath();
                ctx.restore();

                sv += speed;

                if (sv <= 2) {
                    requestAnimationFrame(draw);
                }
            };

        // 画布大小
        cv.width = 800;
        cv.height = 500;

        window.requestAnimationFrame = window.requestAnimationFrame
                                        || window.webkitRequestAnimationFrame
                                        || window.mozRequestAnimationFrame
                                        || window.oRequestAnimationFrame
                                        || window.msRequestAnimationFrame
                                        || function (callback) {
                                            callback && setTimeout(callback, 1000 / 60);
                                        };
        draw(); // 开始绘制缩放
    </script>
</body>
</html>

 

posted @ 2019-11-01 17:04  nowtd  阅读(1086)  评论(0编辑  收藏  举报