欢迎光临散文网 会员登陆 & 注册

canvas旋转移动的矩阵换算模板

2023-02-25 22:03 作者:无我Code  | 我要投稿



 前言

前段时间  需要在小程序上面做一个功能,类似于fabricJS库的canvas编辑效果,但是小程序没有Windows对象,所以需要魔改fabricJS  ,后来又打算自己模仿一个类似的, 但是遇到一个问题,就是图片在设置旋转以后,画布就变得很奇怪,移动图片就发生XY轴偏差的问题,后来参阅资料发现需要用到一个矩阵换算的公式,进过长时间的专研,最后发现一个大佬的帖子有个类似的例子,谢谢大佬。


例子URL  canvas 中的变换矩阵


> https://juejin.cn/post/6844904063121752077




直接看代码


<!DOCTYPE html>

<html>


<head>

    <meta charset="UTF-8">

    <title>canvas矩阵换算</title>

    <style>

        #canvas {

            border: 1px solid red;

        }

    </style>

</head>


<body>

    <canvas des="渲染画布" id="canvas"></canvas>

    <button des="旋转画布按钮" id="rotateBtn">旋转</button>

    <p des="渲染当前鼠标的X" id="x"></p>

    <p des="渲染当前鼠标的Y" id="y"></p>

    <p des="渲染当前旋转的角度" id="rotate"></p>

</body>

<script>

    var img = new Image()// 创建一个图片dom

    img.src = './1.png' // 引入图片路径

    img.width = 290// 设置图片宽度

    img.height = 440// 设置图片高度

    canvasWidth = 1200// 设置画布宽度

    canvasHeight = 900// 设置画布高度

    let rotate = 0// 设置一个旋转角度

    let x = 100// 设置X值的初始值

    let y = 20// 设置Y值的初始值

    let rotateArr = []// 设置一个旋转角度数组

    var canvas = document.getElementById('canvas')// 获取画布dom节点

    var rotateBtn = document.getElementById('rotateBtn')// 旋转按钮

    var xEl = document.getElementById('x')// 当前渲染X值的标签

    var yEl = document.getElementById('y')// 当前渲染Y值的标签

    var rotateEl = document.getElementById('rotate') // 当前渲染旋转角度的标签

    canvas.width = canvasWidth // 画布宽度赋值

    canvas.height = canvasHeight// 画布高度赋值

    var ctx = canvas.getContext("2d") // 获取画布上下文

    let move = false // 是否移动

    const nextRotateSize = 5// 下一次旋转的角度


    // 创建一个矩阵数组

    let m = [1, 0, 0, 1, x, y]

    // 插入旋转角度数值 0-360度

    for (let i = 0; i < 360; i++) {

        rotateArr.push(i)

    }

    // 插入一个0的值 让数组的查找的索引从新值指向0

    rotateArr.push(0)

    // 当浏览器引入图片资源的时候  渲染图片

    img.onload = function () {

        imageRender()

    }

    /**

     * @description 图片渲染

     */

    function imageRender() {

        clearCanvas(ctx, 0, 0, canvasWidth, canvasHeight)  // 清空画布

        ctx.fillRect(m[4], m[5], img.width, img.height); // 绘制一个矩形

        ctx.drawImage(img, m[4], m[5], img.width, img.height) // 绘制图片

        setXY() // 渲染 当前X、Y、rotate的值大小到页面中

    }

    // 点击旋转

    rotateBtn.onclick = function () {

        const index = rotateArr.indexOf(rotate) // 查找当前选择角度的索引

        rotate = rotateArr[index + nextRotateSize]// 赋值新的旋转角度

        // a:水平方向的缩放

        // b:水平方向的倾斜偏移

        // c:竖直方向的倾斜偏移

        // d:竖直方向的缩放

        // dx:水平方向的移动

        // dy:竖直方向的移动

        //setTransform(a, b, c, d, x, y)

        /**

         * a c x

         * b d y

         * 0 0 1

         */

        let a = (rotate * Math.PI / 180); // 根据数学方法计算旋转角度的值

        let sin = Math.sin(a);// 计算sinθ值

        let cos = Math.cos(a);// 计算cosθ值

        m[0] = cos // 将计算的cosθ值赋值给矩阵0的索引  

        m[1] = sin // 将计算的sinθ值赋值给矩阵1的索引

        m[2] = -sin// 将计算的-sinθ值赋值给矩阵2的索引

        m[3] = cos // 将计算的cosθ值赋值给矩阵3的索引 

        clearCanvas(ctx, 0, 0, canvasWidth, canvasHeight)  // 清空画布

        drawCanvas(ctx)// 绘制画布

        setXY()  // 渲染 当前X、Y、rotate的值大小到页面中


    }


    // 移动图片  渲染画布

    function moveImage() {

        if (!move) return // 判断当前是否可以移动

        clearCanvas(ctx, 0, 0, canvasWidth, canvasHeight) // 清空画布

        drawCanvas(ctx) // 绘制画布

        setXY()

    }

    // 当鼠标按下时 可以移动

    canvas.onmousedown = () => {

        move = true

    }

    // 当鼠标抬起时  不可以移动

    canvas.onmouseup = () => {

        move = false

    }


    // 当鼠标移动时

    canvas.onmousemove = (event) => {

        if (!move) return // 判断当前是否可以移动

        m[4] = event.offsetX  // 将鼠标的X轴坐标赋值给矩阵4

        m[5] = event.offsetY //  将鼠标的Y周坐标赋值给矩阵5

        // console.log(m); 

        moveImage() // 调用渲染画布方法

    }

    /**

     * @description 清空画布

     * @param {Object} ctx 画布上下文

     * @param {Number} startX 清除画布的左上角X

     * @param {Number} startY 清除画布的左上角Y

     * @param {Number} endX 清除画布的右上角X

     * @param {Number} endY 清除画布的右上角Y

     */

    function clearCanvas(ctx, startX, startY, endX, endY) {

        ctx.clearRect(startX, startY, endX, endY)  // 清空画布

    }



    //  渲染 当前X、Y、rotate的值大小到页面中

    function setXY() {

        xEl.innerHTML = m[4]

        yEl.innerHTML = m[5]

        rotateEl.innerHTML = rotate

    }


    /**

     * @description 绘制画布

     * @param {Object} ctx 画布上下文

     */

    function drawCanvas(ctx) {

        ctx.save()// 保存当前画布的状态  入栈

        ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);// 根据矩阵参数  将画布移至指定的地点

        ctx.fillRect(0, 0, img.width, img.height);// 绘制一个矩形

        ctx.drawImage(img, 0, 0, img.width, img.height)// 绘制图片

        ctx.restore()// 退出当前画布的状态  返回上一次画布状态  出栈

    }



</script>


</html>









结语


目前国内的小程序canvas库基本上都是一些简单的案例,前端的路程依旧遥远。

无我code


canvas旋转移动的矩阵换算模板的评论 (共 条)

分享到微博请遵守国家法律