>

1、当前上下文对象的移动、sbf282.com旋转、缩放配

- 编辑:澳门博发娱乐官网 -

1、当前上下文对象的移动、sbf282.com旋转、缩放配

图像翻转的实现

sbf282.com 1
上图所示“气泡”,宽为 160,高为 192,x 轴方向距离原点 172,y 轴方向距离原点 365,顺时针旋转 35 度。
要绘制该“气泡”,需要先将坐标系统平移(translate),翻转(scale),平移(translate),再旋转(rotate)。具体实现步骤如下:
sbf282.com 2
至此,实现了“气泡”的镜像翻转,但翻转后的“气泡”还需要旋转特定的角度,在方法一的基础上继续对坐标系统进行变换:
sbf282.com 3
以上操作中进行了两次平移(translate)操作,可以进行合并简化:
sbf282.com 4

/*
                    1、将当前的画布背景保存起来,context.save()
                    2、重置变换矩阵,context.setTransform(1,0,0,1,0,0);
                    3、编码转换角度的算法,angle = 90 * Math.PI / 180;使用PI单位
                      context.translate(x,y),因为旋转的整个画布对象
                    4、context.drawImage
                   
               */
               function rotate() {
                    ctx.save();
                    ctx.setTransform(1,0,0,1,0,0);
                    ctx.translate(0,0)
                    var angle = 90 * Math.PI / 180;
                    ctx.rotate(angle);
                    ctx.drawImage(img1,10,30);
                    ctx.restore();
               }

  图片的引入和调整(图片的变换就是画布的变换,不再介绍):

以 (dx,dy) 为基准点进行 (sx,sy)比例缩放:transform(sx, 0, 0, sy, dx(1-sx), dy(1-sy))

继续昨天的Canvas
变换:
会初始化矩阵
旋转: rotate(angle)//Math.PI/180*30 围绕原点旋转30度 这个不能直接 写度数 他是按照π来算的
缩放:scale(scaleX,scaleY)//1,2 x轴就是宽放大 不变1倍 , Y轴 就是高放大 原来的2倍(可写小数点)
平移:translate(x,y) 平移原点位置 x轴平移多少 y轴平移多少 原点从(0,0)变成(x,y)
复合:tansform(m1_1,m1_2,m2_1,m2_2,dx,dy)
默认值:setTransform(m1_1,m1_2,m2_1,m2_2,dx,dy) //变换矩阵重置为默认状态在调用transform
保存:save() //保存当前的状态 比如说原点在哪个位置什么角度 可以保存多次
复用:restore()//将save()保存的状态返回 调用一次返回上一个保存状态在调用一次在返回上上级保存的状态

小结

至此,小编的数学姿势又恢复到了高考水平。

  1. 图像旋转:
    • 基础变换法:
    JavaScript

    ctx.save() ctx.translate(x + width / 2, y + height / 2)
    ctx.rotate(angle * Math.PI / 180) ctx.drawImage(img, -width /
    2, -height / 2, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c32686a931313088-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32686a931313088-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32686a931313088-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32686a931313088-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32686a931313088-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c32686a931313088-1" class="crayon-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c32686a931313088-2" class="crayon-line crayon-striped-line">
    ctx.translate(x + width / 2,  y + height / 2)
    </div>
    <div id="crayon-5b8f33c32686a931313088-3" class="crayon-line">
    ctx.rotate(angle * Math.PI / 180)
    </div>
    <div id="crayon-5b8f33c32686a931313088-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width / 2,  -height / 2, width, height)
    </div>
    <div id="crayon-5b8f33c32686a931313088-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

-   矩阵变换法:  


    JavaScript

    ctx.save() var rad = angle * Math.PI/180 ctx.transform(
    Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x +
    width / 2, y + height / 2) ctx.drawImage(img, -width / 2,
    -height / 2, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c32686d570876064-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32686d570876064-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32686d570876064-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32686d570876064-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32686d570876064-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c32686d570876064-1" class="crayon-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c32686d570876064-2" class="crayon-line crayon-striped-line">
    var rad = angle * Math.PI/180
    </div>
    <div id="crayon-5b8f33c32686d570876064-3" class="crayon-line">
    ctx.transform( Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x + width / 2,  y + height / 2)
    </div>
    <div id="crayon-5b8f33c32686d570876064-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width / 2,  -height / 2, width, height)
    </div>
    <div id="crayon-5b8f33c32686d570876064-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
  1. 图像翻转:
    • 基础变换法:
    JavaScript

    // 方法一 ctx.save() ctx.translate(canvasWidth, 0) ctx.scale(-1,
    1) ctx.drawImage(img, canvasWidth-width-x, y, width, height)
    ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326870431697867-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326870431697867-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326870431697867-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326870431697867-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326870431697867-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326870431697867-6">
    6
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326870431697867-1" class="crayon-line">
    // 方法一
    </div>
    <div id="crayon-5b8f33c326870431697867-2" class="crayon-line crayon-striped-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326870431697867-3" class="crayon-line">
    ctx.translate(canvasWidth, 0)
    </div>
    <div id="crayon-5b8f33c326870431697867-4" class="crayon-line crayon-striped-line">
    ctx.scale(-1, 1)
    </div>
    <div id="crayon-5b8f33c326870431697867-5" class="crayon-line">
    ctx.drawImage(img, canvasWidth-width-x, y, width, height)
    </div>
    <div id="crayon-5b8f33c326870431697867-6" class="crayon-line crayon-striped-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>




    JavaScript

    // 方法二 ctx.save() ctx.scale(-1, 1) ctx.drawImage(img,
    -width-x, y, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326873786084115-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326873786084115-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326873786084115-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326873786084115-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326873786084115-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326873786084115-1" class="crayon-line">
    // 方法二
    </div>
    <div id="crayon-5b8f33c326873786084115-2" class="crayon-line crayon-striped-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326873786084115-3" class="crayon-line">
    ctx.scale(-1, 1)
    </div>
    <div id="crayon-5b8f33c326873786084115-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width-x, y, width, height)
    </div>
    <div id="crayon-5b8f33c326873786084115-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

-   矩阵变换法:  


    JavaScript

    // 方法一 ctx.save() ctx.transform(-1, 0, 0, 1, canvasWidth, 0)
    ctx.drawImage(img, canvasWidth-width-x, y, width, height)
    ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326877860333719-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326877860333719-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326877860333719-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326877860333719-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326877860333719-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326877860333719-1" class="crayon-line">
    // 方法一
    </div>
    <div id="crayon-5b8f33c326877860333719-2" class="crayon-line crayon-striped-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326877860333719-3" class="crayon-line">
    ctx.transform(-1, 0, 0, 1, canvasWidth, 0)
    </div>
    <div id="crayon-5b8f33c326877860333719-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, canvasWidth-width-x, y, width, height)
    </div>
    <div id="crayon-5b8f33c326877860333719-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>




    JavaScript

    // 方法二 ctx.save() ctx.transform(-1, 0, 0, 1, 0, 0)
    ctx.drawImage(img, -width-x, y, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c32687a381566637-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687a381566637-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687a381566637-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687a381566637-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687a381566637-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c32687a381566637-1" class="crayon-line">
    // 方法二
    </div>
    <div id="crayon-5b8f33c32687a381566637-2" class="crayon-line crayon-striped-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c32687a381566637-3" class="crayon-line">
    ctx.transform(-1, 0, 0, 1, 0, 0)
    </div>
    <div id="crayon-5b8f33c32687a381566637-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width-x, y, width, height)
    </div>
    <div id="crayon-5b8f33c32687a381566637-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

-   像素操作法:  


    JavaScript

    ctx.drawImage(img, x, y, width, height) var img_data =
    ctx.getImageData(x, y, width, height), i, i2, t, h =
    img_data.height, w = img_data.width, w_2 = w / 2; for (var dy
    = 0; dy &lt; h; dy ++) { for (var dx = 0; dx &lt; w_2; dx ++) {
    i = (dy &lt;&lt; 2) * w + (dx &lt;&lt; 2) i2 = ((dy + 1)
    &lt;&lt; 2) * w - ((dx + 1) &lt;&lt; 2) for (var p = 0; p &lt;
    4; p ++) { t = img_data.data[i + p] img_data.data[i + p] =
    img_data.data[i2 + p] img_data.data[i2 + p] = t } } }
    ctx.putImageData(img_data, x, y)

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-7">
    7
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-8">
    8
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-9">
    9
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-10">
    10
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-11">
    11
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-12">
    12
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-13">
    13
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-14">
    14
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-15">
    15
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-16">
    16
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-17">
    17
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-18">
    18
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c32687d641942026-1" class="crayon-line">
    ctx.drawImage(img, x, y, width, height)
    </div>
    <div id="crayon-5b8f33c32687d641942026-2" class="crayon-line crayon-striped-line">
    var img_data = ctx.getImageData(x, y, width, height),
    </div>
    <div id="crayon-5b8f33c32687d641942026-3" class="crayon-line">
        i, i2, t,
    </div>
    <div id="crayon-5b8f33c32687d641942026-4" class="crayon-line crayon-striped-line">
        h = img_data.height,
    </div>
    <div id="crayon-5b8f33c32687d641942026-5" class="crayon-line">
        w = img_data.width,
    </div>
    <div id="crayon-5b8f33c32687d641942026-6" class="crayon-line crayon-striped-line">
        w_2 = w / 2;
    </div>
    <div id="crayon-5b8f33c32687d641942026-7" class="crayon-line">
    for (var dy = 0; dy &lt; h; dy ++) {
    </div>
    <div id="crayon-5b8f33c32687d641942026-8" class="crayon-line crayon-striped-line">
        for (var dx = 0; dx &lt; w_2; dx ++) {
    </div>
    <div id="crayon-5b8f33c32687d641942026-9" class="crayon-line">
            i = (dy &lt;&lt; 2) * w + (dx &lt;&lt; 2)
    </div>
    <div id="crayon-5b8f33c32687d641942026-10" class="crayon-line crayon-striped-line">
            i2 = ((dy + 1) &lt;&lt; 2) * w - ((dx + 1) &lt;&lt; 2)
    </div>
    <div id="crayon-5b8f33c32687d641942026-11" class="crayon-line">
            for (var p = 0; p &lt; 4; p ++) {
    </div>
    <div id="crayon-5b8f33c32687d641942026-12" class="crayon-line crayon-striped-line">
                t = img_data.data[i + p]
    </div>
    <div id="crayon-5b8f33c32687d641942026-13" class="crayon-line">
                img_data.data[i + p] = img_data.data[i2 + p]
    </div>
    <div id="crayon-5b8f33c32687d641942026-14" class="crayon-line crayon-striped-line">
                img_data.data[i2 + p] = t
    </div>
    <div id="crayon-5b8f33c32687d641942026-15" class="crayon-line">
            }
    </div>
    <div id="crayon-5b8f33c32687d641942026-16" class="crayon-line crayon-striped-line">
        }
    </div>
    <div id="crayon-5b8f33c32687d641942026-17" class="crayon-line">
    }
    </div>
    <div id="crayon-5b8f33c32687d641942026-18" class="crayon-line crayon-striped-line">
    ctx.putImageData(img_data, x, y)
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
  1. 图像镜像对称(翻转+旋转):
    • 基础变换法:
    JavaScript

    ctx.save() ctx.scale(-1, 1) ctx.translate(-width/2-x,
    y+height/2) ctx.rotate(-angle * Math.PI / 180)
    ctx.drawImage(img, -width / 2, -height / 2, width, height)
    ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326880900901818-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326880900901818-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326880900901818-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326880900901818-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326880900901818-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326880900901818-6">
    6
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326880900901818-1" class="crayon-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326880900901818-2" class="crayon-line crayon-striped-line">
    ctx.scale(-1, 1)
    </div>
    <div id="crayon-5b8f33c326880900901818-3" class="crayon-line">
    ctx.translate(-width/2-x, y+height/2) 
    </div>
    <div id="crayon-5b8f33c326880900901818-4" class="crayon-line crayon-striped-line">
    ctx.rotate(-angle * Math.PI / 180)
    </div>
    <div id="crayon-5b8f33c326880900901818-5" class="crayon-line">
    ctx.drawImage(img, -width / 2,  -height / 2, width, height)
    </div>
    <div id="crayon-5b8f33c326880900901818-6" class="crayon-line crayon-striped-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

-   矩阵变换法:  


    JavaScript

    ctx.save() var k = Math.tan( (180-angle)/2 * Math.PI / 180 )
    var ux = 1 / Math.sqrt(1 + k * k) var uy = k / Math.sqrt(1 +
    k * k) ctx.transform( (2*ux*ux-1), 2*ux*uy, 2*ux*uy,
    (2*uy*uy-1), x + width/2, y + height/2 ) ctx.drawImage(img,
    -width/2, -height/2, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326883449167631-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326883449167631-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326883449167631-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326883449167631-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326883449167631-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326883449167631-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326883449167631-7">
    7
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326883449167631-1" class="crayon-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326883449167631-2" class="crayon-line crayon-striped-line">
    var k = Math.tan( (180-angle)/2 * Math.PI / 180 )
    </div>
    <div id="crayon-5b8f33c326883449167631-3" class="crayon-line">
    var ux = 1 / Math.sqrt(1 + k * k)
    </div>
    <div id="crayon-5b8f33c326883449167631-4" class="crayon-line crayon-striped-line">
    var uy = k / Math.sqrt(1 + k * k)
    </div>
    <div id="crayon-5b8f33c326883449167631-5" class="crayon-line">
    ctx.transform( (2*ux*ux-1), 2*ux*uy, 2*ux*uy, (2*uy*uy-1), x + width/2, y + height/2 )
    </div>
    <div id="crayon-5b8f33c326883449167631-6" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width/2, -height/2, width, height)
    </div>
    <div id="crayon-5b8f33c326883449167631-7" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

强大drawImage()方法可以完成一切需求

 

这个同样很简单,sx, sy 是缩放比例因子,缩放后新坐标系下任意一点 (x,y) 相当于原坐标系下的坐标为:

由于昨天写没有保存 今天就简写 哥哥很无语


像素操作实现图像翻转

除了坐标系统变换,canvas 的像素操作同样可以实现图像的翻转。首先需要了解下 getImageData() 方法(详细用法参见MDN)和 putImageData()(详细用法参见MDN)方法:

  1. getImageData()
    CanvasRenderingContext2D.getImageData() 返回一个 ImageData 对象,用来描述 canvas 区域隐含的像素数据,这个区域通过矩形表示,起始点为 (sx, sy)、宽为 sw、高为 sh。
JavaScript

ImageData ctx.getImageData(sx, sy, sw, sh);

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326860751214897-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326860751214897-1" class="crayon-line">
ImageData ctx.getImageData(sx, sy, sw, sh);
</div>
</div></td>
</tr>
</tbody>
</table>
  1. putImageData()
    CanvasRenderingContext2D.putImageData() 是 Canvas 2D API 将数据从已有的 ImageData 对象绘制到位图的方法。 如果提供了脏矩形,只能绘制矩形的像素。

JavaScript

void ctx.putImageData(imagedata, dx, dy); void ctx.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);

1
2
void ctx.putImageData(imagedata, dx, dy);
void ctx.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);

水平翻转实现:

JavaScript

// 绘制图像 ctx.drawImage(img, x, y, width, height) // 获取 img_data 数据 var img_data = ctx.getImageData(x, y, width, height), i, i2, t, h = img_data.height, w = img_data.width, w_2 = w / 2; // 将 img_data 的数据水平翻转 for (var dy = 0; dy < h; dy ++) { for (var dx = 0; dx < w_2; dx ++) { i = (dy << 2) * w + (dx << 2) i2 = ((dy

  • 1) << 2) * w - ((dx + 1) << 2) for (var p = 0; p < 4; p ++) { t = img_data.data[i + p] img_data.data[i + p] = img_data.data[i2 + p] img_data.data[i2 + p] = t } } } // 重绘水平翻转后的图片 ctx.putImageData(img_data, x, y)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 绘制图像
ctx.drawImage(img, x, y, width, height)
// 获取 img_data 数据
var img_data = ctx.getImageData(x, y, width, height),
    i, i2, t,
    h = img_data.height,
    w = img_data.width,
    w_2 = w / 2;
// 将 img_data 的数据水平翻转
for (var dy = 0; dy < h; dy ++) {
    for (var dx = 0; dx < w_2; dx ++) {
        i = (dy << 2) * w + (dx << 2)
        i2 = ((dy + 1) << 2) * w - ((dx + 1) << 2)
        for (var p = 0; p < 4; p ++) {
            t = img_data.data[i + p]
            img_data.data[i + p] = img_data.data[i2 + p]
            img_data.data[i2 + p] = t
        }
    }
}
// 重绘水平翻转后的图片
ctx.putImageData(img_data, x, y)

imagedata = context.createImageData(imagedata)

//imgData对象

从这个例子我们可以看出来,即使在这么简单的情况下,如果不移动坐标原点来直接计算旋转后的图形,也是比较困难的。


需求背景

从一个游戏需求说起:
sbf282.com 5

  1. 技术选型:canvas
    上图所展示的游戏场景,“可乐瓶”里有多个“气泡”,需要设置不同的动画效果,且涉及 deviceOrientation 的交互,需要有大量计算改变元素状态。从性能方面考虑,canvas 是不二的选择。
  2. 技术点:canvas 绘制图像
    通过对游戏场景的进一步分析,可见场景中的“气泡”元素形状都是相同的,且不规则,通过 canvas 直接绘制形状实现成本较高,因此需要在 canvas 上绘制图像。
  3. 技术点:canvas 图像旋转与翻转
    虽然“气泡”元素是相同的,可以使用相同的图像,但图像需要多个角度/多个方向展示,因此需要对图像进行相应的旋转与翻转(镜像),这也是本文所要介绍的重点。

后文代码以下图左侧绿框的“气泡”为示例,右侧展示了场景中用到的两个图像:
sbf282.com 6

 

  这是些常用的操作:













绘制图像drawImage()

可以操作图像
var img=doument.getElementByTagName("img")[0]
con.drawImage(img,10,10)
con.drawImage(img,10,10,w,h)

con.drawImage(imgs,0, 0, 100, 100,0,0,400,400) // imgs后的2个参数作为一组 :剪切的起点 剪切图像的宽高 剪切放置的位置 最后2个是显示的高宽

canvas 图像旋转与翻转姿势解锁

2017/05/26 · HTML5 · Canvas

原文出处: 凹凸实验室   

多图预警,数学不好可直接跳至文末小结。

     img.src = '';

//渐变(线性/放射性)

 

模式

con.createPattern()

图像旋转的实现

sbf282.com 7
上图所示“气泡”,宽为 160,高为 192,x 轴方向距离原点 512,y 轴方向距离原点 220,逆时针旋转 35 度。
要绘制该“气泡”,需要先将坐标系平移(translate),再旋转(rotate)。具体实现步骤如下:
sbf282.com 8

save() 方法与 restore() 方法:

  1. save() 方法用来保存 Canvas 状态的,没有参数。每一次调用 save() 方法,当前的状态就会被推入栈中保存起来。当前状态包括:
    • 当前应用的变形(移动/旋转/缩放)
    • strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值
    • 当前的裁切路径(clipping path)
  2. restore() 方法用来恢复 Canvas 状态,没有参数。每一次调用 restore() 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。
  3. 状态保存在栈中,可以嵌套使用 save() 与 restore()。

 

 

上面我们说某一刻的状态由那么多属性决定,我们要保存这一刻的状态就要把这些属性值一个一个都保存,恢复的时候在一个一个都设置回去,那也太麻烦了。确实是这样的,所以上下文对下提供了了两个简单的方法,对状态进行保存和恢复,他们是:

阴影

shadowColor="color"
shadowOffsetX=10
shadowOffsetY=10
shadowBlur=3
渐变createLineaGradient() //线性
ceateRadialGradient()//径向
使用图像数据
con.getImageData()//使用原图像的数据
合成
con.globalAlpha=.5 //全局透明度
con。gloalCompositionOperation=""上一个绘图和下一个重叠模式
注意:toDataURL()这个是canvas的对象 并不是 2d环境的对象

WebGL 3d的上下文 这不是一个w3c的标准

在 canvas 上绘制图像

在 canvas 上绘制图像,可以使用 drawImage() 方法,语法如下(详细用法参见 MDN):

JavaScript

void ctx.drawImage(image, dx, dy); void ctx.drawImage(image, dx, dy, dWidth, dHeight); void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

1
2
3
void ctx.drawImage(image, dx, dy);
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

需要注意的是,图像必须加载完毕,才能绘制到 canvas 上,否则会出现空白:

JavaScript

var img = new Image() img.src = 'xxxxxxx.png' img.onload = function() { // 绘制图像 ctx.drawImage(img, 512, 220, 160, 192); }

1
2
3
4
5
6
var img = new Image()
img.src = 'xxxxxxx.png'
img.onload = function() {
// 绘制图像
ctx.drawImage(img, 512, 220, 160, 192);
}

此时,便可以 canvas 上看到一个未旋转/翻转的“气泡”图像,如下图所示:
sbf282.com 9

imagedata.width,

ct.lineTo(x1,y1);

有一条线段 ,是 x 轴正向上的一小段

认识 canvas 坐标系

canvas 上图像的旋转和翻转,常见的做法是将 canvas 坐标系统进行变换。因此,我们需要先认识 canvas 坐标系统:
sbf282.com 10
由上图可得,canvas 2D 环境中坐标系统和 Web 的坐标系统是一致的,有以下几个特点:

  1. 坐标原点 (0,0) 在左上角
  2. X坐标向右方增长
  3. Y坐标向下方延伸

回到上述需求中,我们获取 canvas 对象并设置相应的宽高:

XHTML

<canvas id='myCanvas'></canvas>

1
<canvas id='myCanvas'></canvas>

JavaScript

// 获取 canvas 对象 var canvas = document.getElementById('myCanvas') canvas.width = 750 canvas.height = 1054 // 获取 canvas 2D 上下文对象 var ctx = canvas.getContext('2d')

1
2
3
4
5
6
// 获取 canvas 对象
var canvas = document.getElementById('myCanvas')
canvas.width = 750
canvas.height = 1054
// 获取 canvas 2D 上下文对象
var ctx = canvas.getContext('2d')

此时,canvas 的坐标系统如下图所示:
sbf282.com 11

//(dw , dh )截取大小

 

4、变形 transform(m11, m12, m21, m22, dx, dy)

canvas 坐标变换

接下来,我们再来了解 canvas 坐标的变换。上述需求仅涉及 2D 绘制上下文,因此仅介绍 2D 绘制上下文支持的各种变换:

  1. 平移 translate:
JavaScript

ctx.translate(x, y)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c32683b188872764-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c32683b188872764-1" class="crayon-line">
ctx.translate(x, y)
</div>
</div></td>
</tr>
</tbody>
</table>

translate() 方法接受两个参数。x 是左右偏移量,y 是上下偏移量。
  1. 旋转 rotate:
JavaScript

ctx.rotate(angle)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c32683e262081345-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c32683e262081345-1" class="crayon-line">
ctx.rotate(angle)
</div>
</div></td>
</tr>
</tbody>
</table>

rotate() 方法只接受一个参数。旋转的角度
angle,它是顺时针方向的,以弧度为单位的值。
  1. 缩放 scale:
JavaScript

ctx.scale(x, y)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326841695520558-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326841695520558-1" class="crayon-line">
ctx.scale(x, y)
</div>
</div></td>
</tr>
</tbody>
</table>

scale() 方法接受两个参数。x 和 y
分别是横轴和纵轴的缩放因子。其缩放因子默认是 1,如果比 1
小是缩小,如果比 1 大则放大。
  1. 变形 transform:
JavaScript

ctx.transform (a, b, c, d, e, f)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326844923845216-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326844923845216-1" class="crayon-line">
ctx.transform (a, b, c, d, e, f)
</div>
</div></td>
</tr>
</tbody>
</table>

transform() 方法是对当前坐标系进行矩阵变换。



JavaScript

ctx.setTransform (a, b, c, d, e, f)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326847245473351-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326847245473351-1" class="crayon-line">
ctx.setTransform (a, b, c, d, e, f)
</div>
</div></td>
</tr>
</tbody>
</table>

setTransform()
方法重置变形矩阵。先将当前的矩阵重置为单位矩阵(即默认的坐标系),再用相同的参数调用
transform() 方法设置矩阵。  
以上两个方法均接受六个参数,具体如下:
参数 含义
a 水平缩放绘图
b 水平倾斜绘图
c 垂直倾斜绘图
d 垂直缩放绘图
e 水平移动绘图
f 垂直移动绘图

context.putImageData(imagedata,dx,dy)

//重置样式

其实前面讲的移动、缩放、旋转都是变形的特例,transform 方法的六个参数组成了一个变形矩阵,如下

参考文章

  • 《W3cplus – CANVAS 系列》
  • 《html5 canvas.transform[转]》
  • 《html5 canvas 学习笔记》
  • 《在HTML5中翻转图片》

说明:本文讨论的 canvas 环境均为 2D 环境。若有更好的实现方式,欢迎留言告知。

2 赞 5 收藏 评论

sbf282.com 12

 

一、基本绘图

二、状态的保存与恢复

坐标系统的矩阵变换

前文介绍了 2D 绘制上下文变形(transform)变换,实际是直接修改变换的矩阵,它可以实现前面介绍的平移(translate)/旋转(rotate)/缩放( scale)变换,还可以实现切变/镜像反射变换等。矩阵计算遵循数学矩阵公式规则:
sbf282.com 13
由上公式可得:

x' = ax + cy + e y' = bx + dy + f

1
2
x' = ax + cy + e
y' = bx + dy + f

矩阵变换可实现以下变换效果:

  1. 平移 translate:
JavaScript

x' = 1x+0y+tx = x+tx y' = 0x+1y+ty = y+ty

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326850164003354-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326850164003354-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326850164003354-1" class="crayon-line">
x' = 1x+0y+tx = x+tx
</div>
<div id="crayon-5b8f33c326850164003354-2" class="crayon-line crayon-striped-line">
y' = 0x+1y+ty = y+ty
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_translate.png)
  1. 旋转 rotate:
JavaScript

x' = x*cosθ-y*sinθ+0 = x*cosθ-y*sinθ y' = x*sinθ+y*cosθ+0 =
x*sinθ+y*cosθ

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326853823296543-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326853823296543-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326853823296543-1" class="crayon-line">
x' = x*cosθ-y*sinθ+0 = x*cosθ-y*sinθ
</div>
<div id="crayon-5b8f33c326853823296543-2" class="crayon-line crayon-striped-line">
y' = x*sinθ+y*cosθ+0 = x*sinθ+y*cosθ
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_rotate.png)
  1. 缩放 scale:
JavaScript

x' = Sx*x+0y+0 = Sx*x y' = 0x+Sy*y+0 = Sy*y

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326856096178959-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326856096178959-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326856096178959-1" class="crayon-line">
x' = Sx*x+0y+0 = Sx*x
</div>
<div id="crayon-5b8f33c326856096178959-2" class="crayon-line crayon-striped-line">
y' = 0x+Sy*y+0 = Sy*y
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_scale.png)
  1. 切变
JavaScript

x' = x+y*tan(θx)+0 = x+y*tan(θx) y' = x*tan(θy)+y+0 =
x*tan(θy)+y

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326859970129213-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326859970129213-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326859970129213-1" class="crayon-line">
x' = x+y*tan(θx)+0 = x+y*tan(θx)
</div>
<div id="crayon-5b8f33c326859970129213-2" class="crayon-line crayon-striped-line">
y' = x*tan(θy)+y+0 = x*tan(θy)+y
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_skew.png)
  1. 镜像反射
JavaScript

// 定义(ux,uy)为直线(y=kx)方向的单位向量 ux=1/sqrt(1+k^2)
uy=k/sqrt(1+k^2) x' = (2*ux^2-1)*x+2*ux*uy*y y' =
2*ux*uy*x+(2*uy^2-1)*y

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c32685c751852723-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32685c751852723-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f33c32685c751852723-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32685c751852723-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f33c32685c751852723-5">
5
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c32685c751852723-1" class="crayon-line">
// 定义(ux,uy)为直线(y=kx)方向的单位向量
</div>
<div id="crayon-5b8f33c32685c751852723-2" class="crayon-line crayon-striped-line">
ux=1/sqrt(1+k^2)
</div>
<div id="crayon-5b8f33c32685c751852723-3" class="crayon-line">
uy=k/sqrt(1+k^2)
</div>
<div id="crayon-5b8f33c32685c751852723-4" class="crayon-line crayon-striped-line">
x' = (2*ux^2-1)*x+2*ux*uy*y
</div>
<div id="crayon-5b8f33c32685c751852723-5" class="crayon-line">
y' = 2*ux*uy*x+(2*uy^2-1)*y
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_flip.png)

结合上述公式,可推导出图像旋转和翻转的矩阵变换实现:

  1. 图像旋转:
    sbf282.com 14
  2. 图像翻转:
    sbf282.com 15
  3. 图像镜像反射(翻转+旋转):
    sbf282.com 16

Canvas图片API非常强大,有两个最基础的方法,一是展示图片,二是像素级的修改图片后再把它打印到画布上。

ct.putImageData(imgData,x,y)

上面这一系列配置决定了当前这一刻上下文对象的状态,其中移动、旋转、缩放、globalCompositeOperation(组合)、裁剪下面我们马上会讲到。

所以测试时,需要搭建一个web服务器

 

 

          ctx.drawImage(img,0,0)

var ct = $(#canvasId).get(0).getContext('2d');

    //==========================================
    //基准点变形类
    //==========================================
    function Transform(){
        //获取画布对象
        this.ctx = document.getElementById("canvas1").getContext("2d");
        //创建图像对象
        this.img=new Image();
        //指定图像源
        this.img.src=IMG_SRC;
        this.interval = null;
        //鼠标按钮状态
        this.pressed=false;
        this.init();
    }
    
    //初始化图形
    Transform.prototype.init=function(){
        //鼠标按钮状态
        this.pressed=false;
        //停止计时器
        if(this.interval) clearInterval(this.interval);
        //变化值
        this.delta = 0.06;
        //清空
        this.ctx.clearRect(0,0,250,300);
        //重绘
        this.paint();
    }
    
    //绘制图像
    Transform.prototype.paint=function(){
        var that=this;
        var img=this.img
        if(img.complete)
            that.ctx.drawImage(img,0,0);
        else 
            var interval = setInterval(function(){
                if(img.complete){
                    that.ctx.drawImage(img,0,0);
                    clearInterval(interval);
                }
            },300);
    }
    
    //鼠标按钮按下后,开始变形
    Transform.prototype.transform = function(){
        //获取基准点
        this.dx=event.offsetX;
        this.dy=event.offsetY;
        //获取基准点
        this.startx=event.offsetX;
        this.starty=event.offsetY;
        //初始缩放比例
        this.sc=1;
        //初旋转角度
        this.angle=0;
        
        var that=this;
        if(document.getElementById("r1").checked)
            //鼠标按钮状态
            this.pressed=true;
        else if(document.getElementById("r2").checked)
            this.interval = setInterval(function(){that.scale()},50);
        else if((document.getElementById("r3").checked))
            this.interval = setInterval(function(){that.rotate()},50);
        else 
            this.interval = setInterval(function(){that.scaleAndRotate()},50);
    }
    
    //移动
    Transform.prototype.translate = function(){
        this.ddx=event.offsetX-this.startx;
        this.ddy=event.offsetY-this.starty;
        if(this.pressed){
            //清空
            this.ctx.clearRect(0,0,250,300);
            //保存状态
            this.ctx.save();
            //平移
            this.ctx.translate(this.ddx,this.ddy);
            //重绘
            this.paint();
            //绘制基准点
            this.ctx.fillStyle="red";
            this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
            //恢复状态
            this.ctx.restore();
        }
    }

imagedata.height,

首先,定义2D渲染变量ct(这里用了Jquery库): var ct = $(#canvasId).get(0).getContext(2d); 以下是绘制各种基本图形的方法: 复制代码...

 

 

//设渐变的始终颜色

提示当你移动坐标原点之前,千万别忘了保存状态,当然,绘制完毕后也别放了恢复状态。

获取图像数据:

 

5、 在第 4 步的基础上,以 destination-over 方式绘制美女图像,这时候美女图像将会出现在第 4 步图形效果的下方,想象一下,正好是我们想要的效果吧?!

 

 

这样不是更简单、更直接吗?

//(sw , sh )目标大小(缩放)

 

下面的例子用了两种方法进行裁剪。第一种方法显示一来回移动的圆形裁剪区域,大体流程如下:

 

ct.transform(xScale,ySkew,xSkew,yScale,xTrans,yTrans)   

m11 m21 dx
m12 m22 dy
0 0 1

 

ct.drawImage(image,x,y,w,h)

改成

     }

  贝塞尔曲线绘制:

type 是下面 12 种字符串值之一:

 

ct.shadowOffsetX = 10;

三、变型

}

ct.beginPath();

2、改变圆心位置

imagedata = context.getImageData(sx,sy,sw,sh);

复制代码

1、移动:translate(dx,dy)

2、截取图片的一部分到画布上

ct.strokeText(txt,x,y);

<canvas id="canvas1" width="250" height="300" 
    onmousedown="trans.transform(event);"  
    onmouseup="trans.init(event);" 
    onmousemove="trans.translate(event);" 
    style="background-color:black">
    你的浏览器不支持 <canvas>标签,请使用 Chrome 浏览器 或者 FireFox 浏览器
</canvas><br/>
<input type="radio" name="r" id="r1" checked="checked">移动——在图像上按住鼠标并移动<br />
<input type="radio" name="r" id="r2">基准点缩放——在图像某点处按住鼠标<br />
<input type="radio" name="r"  id="r3">基准点旋转——在图像某点处按住鼠标<br />
<input type="radio" name="r"  id="r4">基准点缩放同时旋转——在图像某点处按住鼠标<br />

// 创建一个100x100的区域来存储像素信息

})

4、在新的圆心位置处以 XOR 方式绘制圆,这样和圆形重叠的部分将被擦除掉
这时候我们得到的图形效果是一个半透明的画布,上面有一块完全透明的圆形区域


 

    //缩放变形
    Transform.prototype.scale = function(){
        //清空
        this.ctx.clearRect(0,0,250,300);
        //改变缩放比例
        this.sc=this.sc - this.delta;
        if(this.sc<0.2 || this.sc>2) 
            this.delta = -this.delta;
        //保存状态
        this.ctx.save();
        //以 (dx,dy) 为基准点进行 (sx,sy)比例缩放:transform(sx, 0, 0, sy, dx(1-sx), dy(1-sy))
        this.ctx.transform(this.sc, 0, 0, this.sc, this.dx*(1-this.sc), this.dy*(1-this.sc))
        //用新的变形矩阵重绘
        this.paint();
        //绘制基准点
        this.ctx.fillStyle="red";
        this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
        //恢复状态
        this.ctx.restore();
    }
    
    //旋转变形
    Transform.prototype.rotate = function(){
        //清空
        this.ctx.clearRect(0,0,250,300);
        //改变缩放比例
        var PI = Math.PI;
        this.angle=this.angle + PI/60;
        //保存状态
        this.ctx.save();
        //以 (dx,dy) 为基准点旋转角度 A:transform(cosA, sinA, -sinA, cosA, dx(1-cosA) + dysinA, dy(1-cosA) - dxsinA)
        this.ctx.transform(Math.cos(this.angle), Math.sin(this.angle), 
                -Math.sin(this.angle), Math.cos(this.angle), 
                this.dx*(1-Math.cos(this.angle)) + this.dy*Math.sin(this.angle), 
                this.dy*(1-Math.cos(this.angle)) - this.dx*Math.sin(this.angle))
        //用新的变形矩阵重绘
        this.paint();
        //绘制基准点
        this.ctx.fillStyle="red";
        this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
        //恢复状态
        this.ctx.restore();
    }
    
    //即缩放又旋转变形,没有使用变形矩阵
    Transform.prototype.scaleAndRotate = function(){
        //清空
        this.ctx.clearRect(0,0,250,300);
        //改变缩放比例
        this.sc=this.sc - this.delta;
        if(this.sc<0.2 || this.sc>2) 
            this.delta = -this.delta;
        var PI = Math.PI;
        this.angle=this.angle + PI/60;
        //保存状态
        this.ctx.save();
        //先移动原点到基点
        this.ctx.translate(this.dx,this.dy);
        this.ctx.scale(this.sc,this.sc);
        this.ctx.rotate(this.angle);
        this.ctx.translate(-this.dx,-this.dy);
        //用新的变形矩阵重绘
        this.paint();
        //绘制基准点
        this.ctx.fillStyle="red";
        this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
        //恢复状态
        this.ctx.restore();
    }
    
    var trans = new Transform();
    
    //==========================================
    function Clip(){
        var canvas = document.getElementById("canvas3");
        this.ctx = canvas.getContext("2d");
        this.img=new Image();
        this.img.src=IMG_SRC;
        //移动方向
        this.delta=[3,3];
        //起始点
        this.pos_x = 225;
        this.pos_y = 120;
        //半径
        this.radius = 40;
        //画布的长和宽
        this.w = parseInt(canvas.getAttribute("width"));
        this.h = parseInt(canvas.getAttribute("height"));
    }
    
    Clip.prototype.draw1=function(){
        //碰撞检测
        if (this.pos_x < this.radius) {
            this.delta[0] = Math.random() % 4 + 5;
        } else if (this.pos_x > this.w - this.radius) {
            this.delta[0] = -(Math.random() % 4 + 5);
        }
        if (this.pos_y < this.radius) {
            this.delta[1] = Math.random() % 4 + 5;
        } else if (this.pos_y > this.h - this.radius) {
            this.delta[1] = -(Math.random() % 4 + 5);
        }
        this.pos_x += this.delta[0];
        this.pos_y += this.delta[1];

本文由胜博发-前端发布,转载请注明来源:1、当前上下文对象的移动、sbf282.com旋转、缩放配