canvas_canvastotempfilepath - CSDN
canvas 订阅
《canvas》是从2005年10月3日开始放映的24集日本动画,由F&C ZEXCS制作发行,讲述了拥有超人的绘画天分的男主角的故事。 展开全文
《canvas》是从2005年10月3日开始放映的24集日本动画,由F&C ZEXCS制作发行,讲述了拥有超人的绘画天分的男主角的故事。
信息
外文名
Canvas
制作·发行
F&C ZEXCS
放映日期
2005年10月3日
日文名
虹色のスケッチ
国    家
日本
总共集数
24
canvas剧情简介
拥有超人的绘画天分的男主角,却因某事故无法再次执起画笔,只能委身于某所大学,担任美术课的顾问。受男主角指导走向绘画之路的女主角,却因目睹双亲车祸身亡的现场,而在作画中无法使用红色。青梅竹马的女伴,可是高中时代的告白,却遭到男主角的拒绝,现在她又重新闯入了男主角的生活。 偶然的再会…… 三人之间,会发生什么?爱的前路,会走向哪里?
收起全文
精华内容
参与话题
  • web前端:Canvas 基础(一)

    万次阅读 多人点赞 2017-11-01 18:07:23
    web前端:Canvas 基础(一)

    0.前言

    最近忙里偷闲,来写写文章。

    ————-我是华丽的分割线————–

    终于把这篇文章写完了,关于本文,针对读者主要是之前从未接触过 Canvas的同学。当然,你要学 canvas 一定要有 JS 基础啦。

    其次就是,因为前前后后耽误了两天时间,可能在书写和描述中出现一些小的纰漏,请各位读者老爷见谅。

    最后,也希望这篇文章能够对迷茫的你产生一些帮助,感谢。

    1. canvas 简介


    1.1 canvas 是什么?

    是HTML5中重要的元素,和audio、video元素类似完全不需要任何外部插件就能够运行.

    Canvas中文翻译就是”画布”.它提供了强大的图形的处理功能(绘制,变换,像素处理…)。

    但是需要注意,canvas 元素本身并不绘制图形,它只是相当于一张空画布。

    如果开发者需要向 canvas 上绘制图形,则必须使用 JavaScript 脚本进行绘制。

    1.2 canvas 能够做什么?

    • 基础图形的绘制
    • 文字的绘制
    • 图形的变形和图片的合成
    • 图片和视频的处理
    • 动画的实现
    • 小游戏的制作

    1.3 支持的浏览器

    大多数现代浏览器都是支持Canvas的,比如 Firefox, safari, chrome, opera的最近版本以及IE9都支持.

     IE8及以下不支持HTML5,但是我们可以进行提示用户更新到最新的版本

    1.4 关于canvas 标签的基本概念

    在 HTML 页面上定义 canvas 元素与定义其他普通元素并无任何不同,它吃了可以指定 id, style ,class ,hidden 等通用属性之外,还可以设置 width 和 height 两个属性。

    为什么要特意去说这个呢?

    咱们在 章节 2.2 中详细去说明。

    除此之外,我们在网页中定义 canvas 元素之后,它只是一张空白的画布,想要在画布上绘画,一定要经过下面几步。

    1. 获取 canvas 元素对应的 DOM 对象,这必须是一个 canvas 对象
    2. 调用 canvas 对象的 getContext( ) 方法,该方法返回一个 canvasRenderingContext2D 对象,该对象可以绘制图形。
    3. 调用 canvasRenderingContext2D 对象的方法进行绘图。

    那么我们就来开始我们的canvas 实战,来看看 canvas 该如何会绘制图形。

    2.canvas 实战


    2.1 查看当前浏览器对 canvas 的支持情况

    我们在上面也说明了,我们的一些浏览器是不支持 canvas 的,这个时候我们应该怎么去做呢?

    这时候我们可以直接在 canvas 标签之间去书写内容,这么做的好处是当你的浏览器不支持 canvas 的时候,我们可以去展示标签之间的内容,具体如下。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <style type="text/css">
            html,body{
                margin: 0px;
            }
            canvas{
                background: #ccc;
            }
        </style>
    </head>
    <body>
        <canvas>
            我们在设置 canvas 之前需要首先监测用户电脑是否支持 canvas
        </canvas>
    </body>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    既然已经创建完成了具体的内容,那我们现在可以看见了么?

    我们虽然没有给定 canvas 的宽度和高度,但是实际上我们的canvas 在页面中是可见的

    需要注意,canvas 默认样式的宽度和高度 是 300px * 150px.

    即使我们不去设置具体的宽度和高度,它也是可以显示的。

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <meta charset="UTF-8">
     <title>Document</title>
     <style type="text/css">
      html,body{
       margin: 0px;
      }
      canvas{
       background: #ccc;
      }
     </style>
    </head>
    <body>
     <canvas>
      我们在设置 canvas 之前需要首先监测用户电脑是否支持 canvas
     </canvas>
    </body>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.png

    那我们该如何去修改画布的默认大小呢?

    2.2 修改 Canvas 的画布

    按照我们正常的思路来说,我们会直接去使用 canvas_1.style.width = "500px"; 来去修改我们的 canvas 的宽度,但是这样真的对么?

    答案当然是否定的,canvas 相当于是一张图片,如果我们设置 <canvas width="500" height="500">.

    这样写相当于图片的实际大小是 500 * 500.

    但是,假如我们这样去书写。

    <canvas style="width:500px;height:500px;">

    这样实际是把 canvas 默认的 300 * 150 的图片强行拉伸为 500px * 500px 了,所以这样会导致我们的内容被强行缩放,从而导致问题。

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <meta charset="UTF-8">
     <title>Document</title>
     <style type="text/css">
      html,body{
       margin: 0px;
      }
      canvas{
       background: #ccc;
      }
     </style>
    </head>
    <body>
     <canvas id="canvas_1">
      我们在设置 canvas 之前需要首先监测用户电脑是否支持 canvas
     </canvas>
    </body>
    <script type="text/javascript">
     var canvas_1 = document.getElementById("canvas_1");
     // 设置宽度和高度,但是这种写法会造成额外的问题
     // 画布会拉伸
     // canvas_1.style.width = "500px";
     // canvas_1.style.height = "500px";
    
     // 所以推荐写法
     // 1.使用内联样式表
     // 2.去使用点(.)
     canvas_1.width = "500"; //注意,不要加 px
     canvas_1.height = "500";
    
    </script>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2.3 获取绘制环境

    我们在上面已经设置了我们的画布的大小,但是存在一个问题。

    我们还没有找到我们的画布呀!~

    要是我们连具体的画布都没有,我们又该向哪里去绘画呢?

    实际上我们可以通过 var ctx = canvas_1.getContext("2d"); 来去获取到我们的绘制环境。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <canvas id="canvas_1" width="500" height="400" style="box-shadow: 0 0 20px black;">
            当前浏览器不支持 canvas
        </canvas>
    </body>
    <script type="text/javascript">
    
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
    
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
    
        // 打印一下,查看是否能够显示具体环境
        console.log(ctx);
    
    </script>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    假如打印成功,我们应该可以在浏览器中的 console 中查看到我们的画布具体信息。

    3.png

    但是请注意,getContext("2d"); 中一定是2d而不是2D,否则不会生效。

    2.4 绘制的坐标轴

    既然我们已经能够获取到我们具体的画布了,那我们是不是开始绘制了呀。

    先等等,我们首先先来分析一个问题,就是我们绘制图形的时候,以这个一个区域,我们应该从哪里开始,设置的数值又应该从哪里开始呢?这时候你就应该去想一想,是不是存在这么一个坐标轴,可以根据这个坐标轴来书写我们的数值呢?

    Paste_Image.png

    请注意,横轴向右是正,纵轴向下是正

    2.5 绘制直线

    我们既然要画一条直线,我们是不是至少应该有这么几个条件呢?

    • 线的起点
    • 线的终点
    • 线的颜色
    • 线的宽度

    所以我们接下来,就需要开始我们的代码书写了。

    我们该如何去进行绘制呢?

    我们需要一些工具,需要具体的方法。

    方法 说明
    beginPath() 开始定义路径
    closePath() 关闭前面定义的路径
    moveTo(float x,float y) 把 canvas 的当前路径的结束点移动到 x, y 对应的点
    lineTo(float x,float y) 把 canvas 的当前路径从当前结束点连接到 x , y 对应的点

    需要注意,moveTo 可以简单理解为,把当前绘制图像的起点设置为某一特定坐标,而 lineTo 则是将当前的起点和你想要设置的那个点之间连接起来。

    而 beginPath 是表示开始定义路径,不会产生特殊的效果。而 closePath 除了表示关闭当前定义的路径之外,还会有一个特殊的作用,就是可以将当前绘制图形的最后一个点和我们绘制图形开始的点进行连接,这一点咱们在章节2.6 中详细去看一下。当然,如果你只需要画一条线,不去加beginPath 和 closep 你的内容实际也是可以出来的,但是推荐加上。

    这个时候我们可以来运行一下,看看效果是否能够出来。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div>
            <canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
                当前浏览器不支持 canvas
            </canvas>
        </div>
    </body>
    <script type="text/javascript">
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
    
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
    
        // 打印一下,查看是否能够显示具体环境
        console.log(ctx);
    
        // 开始绘制
        ctx.beginPath();
    
        //设置绘制起点
        ctx.moveTo(0,0);
    
        //设置绘制下一个点
        ctx.lineTo(700,400);
    
        //结束绘制
        ctx.closePath();
    
    </script>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    发现了什么?我们的图形什么都没有出来呀,鹏哥你是不是坑我们呀?

    怎么可能,我那么帅气。

    效果没出来,只是因为 你已经把你的画笔的颜料,要画什么样的线条,全部都想好了,可是你往你的画布上绘画了么?

    没有对吧,所以咯,我们还需要有其他的方法去进行配合。

    - -
    fill() 填充 canvas 当前路径
    stroke() 填充 canvas 当前路径绘制边框

    这个时候我们添加上我们的 stroke() 之后,我们就发现我们的线条出现了。

    可是这条线一直是灰色的呀,好丑,我们想要自己去修改我们的线,该怎么做呢?

    - -
    fillStyle() 设置填充 canvas 路径所使用的填充风格
    strokeStyle() 设置绘制 canvas 路径的填充风格

    他们两个都支持三个属性值。

    1. 符合颜色格式的字符串值,表示使用纯色填充
    2. CanvasGradient,表明使用渐变填充
    3. CanvasPattern,表明使用位图填充

    这几个值,咱们在后续的课程中会去详细说明,在当前不去做更多阐述。

    除此之外,我们还可以设置一下线的宽度。

    - -
    lineWidth() 设置笔触线条的宽度

    这样我们就可以画出一些我们想要的线条的样式了。

    Paste_Image.png

    2.6 绘制三角形

    我们已经创建了这一条线段,那么我们平常开发中不会仅仅让你去绘制一条线吧,最起码我们需要会绘制出一个小的三角形吧。

    这时候我们就需要再去绘制两条线了。

    怎么去添加线呢?lineTo对吧。

    这个时候我们再去绘制一条线。

        //设置绘制起点
        ctx.moveTo(100,100);
    
        //设置绘制下一个点
        ctx.lineTo(700,400);
    
        //设置绘制下一个点
        ctx.lineTo(400,100);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这时候神奇的事情发生了,我们的三角形直接就出现了,可是我们仅仅绘制了两条线呀。

    Paste_Image.png

    这是因为,我们在绘制图形的时候,是不是设置了一个方法?

    还记得上面对 closePath 的描述么?

        //结束绘制
        ctx.closePath();
    • 1
    • 2

    这时因为当我们结束绘制的,电脑会自动将你设置的线段自动连接起来。

    Paste_Image.png

    这个时候我们应该有两个想法了。

    1. 我们可以用这个特性去做一个长方形或者多边形等。

    2. 我们需要给我们的方块内部设置一个颜色。

    那么我们首先来说一下,如何设置一个背景颜色。

    这时候我们需要使用填充。

        // 设置填充样式
        ctx.fillStyle = "green";
    
        // 填充当前视图
        ctx.fill();
    • 1
    • 2
    • 3
    • 4
    • 5

    这个时候我们就能看见,我们的背景颜色就已经成功填充了。

    Paste_Image.png

    当然,我的审美一直很特立独行,所以各位小伙伴也不要在意太多细节啦,科科。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div>
            <canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
                当前浏览器不支持 canvas
            </canvas>
        </div>
    </body>
    <script type="text/javascript">
    
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
    
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
    
        // 打印一下,查看是否能够显示具体环境
        console.log(ctx);
    
        // 开始绘制
        ctx.beginPath();
    
        //设置绘制起点
        ctx.moveTo(100,100);
    
        //设置绘制下一个点
        ctx.lineTo(700,400);
    
        //设置绘制下一个点
        ctx.lineTo(400,100);
    
        //设置绘制下一个点
        ctx.lineTo(600,500);
    
        //结束绘制
        ctx.closePath();
    
        //设置线的宽度
        ctx.lineWidth = 10;
    
        //设置绘制的样式
        ctx.strokeStyle = "red";
    
        //绘制点之间的线路
        ctx.stroke();
    
        // 设置填充样式
        ctx.fillStyle = "green";
    
        // 填充当前视图
        ctx.fill();
    
        // 注意:所有的绘制相应属性全部应该放在 closePath 之前
    
    </script>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    除此之外,还有一个需要注意的点,就是我们现在的图形是不是角度都是非常尖锐的?

    那我们是不是可以把这个效果修改一下,改的圆滑一点呢?

    这时候再来跟大家说另外一个属性。

    - -
    lineJoin 设置返回所创建边角的类型,当两条线交汇时。

    通过这个属性,我们就可以去修改我们图形的拐角的样式了,这个样式里面存在三个属性。需要注意一点,你去设置边角的样式,一定要设置在你的绘制矩形框之前,否则效果是不会出现的。

    - -
    bevel 创建斜角
    round 创建圆角
    miter 默认,创建尖角

    miter.png

    round.png

    bevel.png

    这时候我们的效果就已经全部出现了。

    那么大家可以去尝试制作一下下图的内容。

    Paste_Image.png

    2.7 绘制矩形

    不知道小伙伴们有没有将上面的内容成功设置出来呢?

    如果出来了,我们发现一个非常坑爹的情况,他喵的每设置一次都需要专门去计算这个内容的对应数值么?

    不能这么坑爹吧,所以这个时候我们要去学习另外一个方法。

    - -
    strokeRect(float x,float y,float width,float height) 绘制一个矩形边框
    fillRect(float x,float y,float width,float height) 填充一个矩形边框

    有了这两个方法,我们的矩形绘制就非常方便啦。

    那么我们来尝试一下。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div>
            <h2>绘制矩形</h2>
            <canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
                当前浏览器不支持 canvas
            </canvas>
        </div>
    </body>
    <script type="text/javascript">
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
    
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
    
        // 设置填充颜色
        ctx.fillStyle = '#f00';
        // 填充一个矩形
        ctx.fillRect(30,20,120,60);
    
        // 设置填充颜色
        ctx.fillStyle = '#ff0';
        // 填充一个矩形
        ctx.fillRect(80,60,120,60);
    
        // 设置填充颜色
        ctx.strokeStyle = '#00f';
        // 填充一个矩形
        ctx.strokeRect(30,130,120,60);
        // 设置线条宽度
        ctx.lineWidth = 20;
    
        // 设置线条宽度
        ctx.lineJoin = "round";
        // 设置填充颜色
        ctx.strokeStyle = '#0ff';
        // 填充一个矩形
        ctx.strokeRect(80,160,120,60);
    
    
        // 设置线条宽度
        ctx.lineJoin = "bevel";
        // 设置填充颜色
        ctx.strokeStyle = '#f0f';
        // 填充一个矩形
        ctx.strokeRect(130,190,120,60);
    
    
        ctx.storke();
    
    </script>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    Paste_Image.png

    2.8 绘制字符串

    我猜现在很多小伙伴都在想,我们可以绘制线条,可以绘制多边形,还可以绘制矩形了,那么接下来是不是要开始学习绘制圆形呢?

    当然不是,因为绘制圆形设计到的内容比较多,咱们放在下一篇文章中来书写。

    今天咱们就先来看一下,我们该如何去绘制我们的字符串。

    在绘制字符串之前同样需要跟大家说这么几个方法。

    - -
    fillText(String Text, float x, float y, [float maxWidth]) 填充字符串
    strokeText(String Text, float x, float y, [float maxWidth]) 绘制字符串边框

    同时我们既然设置了字符串的内容,我们是不是还需要去对我们字符串的对齐方式什么的去做一做设置呢?

    - -
    textAlign 设置绘制字符串的水平对齐方式(start、end、left、right、center等)
    textBaseAlign 设置绘制字符串的垂直对齐方式(top、hanging、middle、alphabetic、idecgraphic、bottom 等)

    了解了这些具体的方法,那我们再来看一下,我们该如何去设置我们的字符串内容。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div>
            <h2>绘制文字</h2>
            <canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
                当前浏览器不支持 canvas
            </canvas>
        </div>
    </body>
    <script type="text/javascript">
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
    
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
    
        ctx.fillStyle = '#00f';
        ctx.font = 'italic 50px 隶书';
        ctx.textBaseline = 'top';
    
        //填充字符串
        ctx.fillText('汪先生真是帅',0,0);
        ctx.strokeStyle = 'f0f';
        ctx.font = 'bold 45px 宋体';
    
        // 绘制字符串的边框
        ctx.strokeText('汪先生我爱你',0,50,200);
    
    </script>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35


    2.9 设置阴影

    我们在之前学习 HTML 的过程中,跟大家说过,我们的阴影可以简单分为两种,盒阴影和文字阴影,那在我们的画布中,是否也存在这么一个东西,能够为我们的文字去设置一个阴影呢?

    当然有,要不我也不会专门去提这个事情,对吧。

    我们学习设置阴影,同样要使用这么几个属性。

    - -
    shadowBlur 设置阴影的模糊程度。该值是一个浮点数,该数值越大,阴影的模糊程度也就越大。
    shadowColor 设置阴影的颜色。
    shadowOffsetX 设置阴影在 X 方向的偏移
    shadowOffsetY 设置阴影在 Y 方向的偏移

    那么我们接下来,一起来看看我们该如何去设置阴影。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div>
            <h2>绘制文字</h2>
            <canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
                当前浏览器不支持 canvas
            </canvas>
        </div>
    </body>
    <script type="text/javascript">
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
    
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
    
        // 设置阴影的模糊程度
        ctx.shadowBlur = 5.6;
    
        // 设置阴影的颜色
        ctx.shadowColor = '#222';
    
        // 设置阴影在 X,Y 方向的偏移
        ctx.shadowOffsetX = 10;
        ctx.shadowOffsetY = -6;
    
        ctx.fillStyle = '#00f';
        ctx.font = 'italic 50px 隶书';
        ctx.textBaseline = 'top';
    
        //填充字符串
        ctx.fillText('汪先生真是帅',0,0);
        ctx.strokeStyle = 'f0f';
        ctx.font = 'bold 45px 宋体';
    
        // 绘制字符串的边框
        ctx.strokeText('汪先生我爱你',0,50,200);
    
    </script>
    </html>
    展开全文
  • 学习HTML5 Canvas这一篇文章就够了

    万次阅读 多人点赞 2019-03-01 18:24:29
    一、canvas简介&amp;amp;lt;canvas&amp;amp;gt; 是 HTML5 新增的,一个可以使用脚本(通常为JavaScript)在其中绘制图像的 HTML 元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画,甚至可以进行...

    一、canvas简介

    <canvas>HTML5 新增的,一个可以使用脚本(通常为JavaScript)在其中绘制图像的 HTML 元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画,甚至可以进行实时视频处理和渲染。

    ​ 它最初由苹果内部使用自己MacOS X WebKit推出,供应用程序使用像仪表盘的构件和 Safari 浏览器使用。 后来,有人通过Gecko内核的浏览器 (尤其是MozillaFirefox),OperaChrome和超文本网络应用技术工作组建议为下一代的网络技术使用该元素。

    Canvas是由HTML代码配合高度和宽度属性而定义出的可绘制区域。JavaScript代码可以访问该区域,类似于其他通用的二维API,通过一套完整的绘图函数来动态生成图形。

    ​ Mozilla 程序从 Gecko 1.8 (Firefox 1.5)开始支持 <canvas>, Internet Explorer 从IE9开始<canvas> 。Chrome和Opera 9+ 也支持 <canvas>

    二、Canvas基本使用

    2.1 <canvas>元素

    <canvas id="tutorial" width="300" height="300"></canvas>
    

    <canvas>看起来和<img>标签一样,只是 <canvas> 只有两个可选的属性 width、heigth 属性,而没有 src、alt 属性。

    ​ 如果不给<canvas>设置widht、height属性时,则默认 width为300、height为150,单位都是px。也可以使用css属性来设置宽高,但是如宽高属性和初始比例不一致,他会出现扭曲。所以,建议永远不要使用css属性来设置<canvas>的宽高。

    ###替换内容

    ​ 由于某些较老的浏览器(尤其是IE9之前的IE浏览器)或者浏览器不支持HTML元素<canvas>,在这些浏览器上你应该总是能展示替代内容。

    ​ 支持<canvas>的浏览器会只渲染<canvas>标签,而忽略其中的替代内容。不支持 <canvas> 的浏览器则 会直接渲染替代内容。

    用文本替换:

    <canvas>
        你的浏览器不支持canvas,请升级你的浏览器
    </canvas>
    

    <img> 替换:

    <canvas>
        <img src="./美女.jpg" alt=""> 
    </canvas>
    

    结束标签</canvas>不可省

    <img>元素不同,<canvas>元素需要结束标签(</canvas>)。如果结束标签不存在,则文档的其余部分会被认为是替代内容,将不会显示出来。

    2.2 渲染上下文(Thre Rending Context)

    <canvas>会创建一个固定大小的画布,会公开一个或多个 渲染上下文(画笔),使用 渲染上下文来绘制和处理要展示的内容。

    ​ 我们重点研究 2D渲染上下文。 其他的上下文我们暂不研究,比如, WebGL使用了基于OpenGL ES的3D上下文 (“experimental-webgl”) 。

    var canvas = document.getElementById('tutorial');
    //获得 2d 上下文对象
    var ctx = canvas.getContext('2d');
    

    2.3 检测支持性

    var canvas = document.getElementById('tutorial');
    
    if (canvas.getContext){
      var ctx = canvas.getContext('2d');
      // drawing code here
    } else {
      // canvas-unsupported code here
    }
    

    2.4 代码模板

    <html>
    <head>
        <title>Canvas tutorial</title>
        <style type="text/css">
            canvas {
                border: 1px solid black;
            }
        </style>
    </head>
    <canvas id="tutorial" width="300" height="300"></canvas>
    </body>
    <script type="text/javascript">
        function draw(){
            var canvas = document.getElementById('tutorial');
            if(!canvas.getContext) return;
          	var ctx = canvas.getContext("2d");
          	//开始代码
            
        }
        draw();
    </script>
    </html>
    

    2.5 一个简单的例子

    绘制两个长方形。

    <html>
    <head>
        <title>Canvas tutorial</title>
        <style type="text/css">
            canvas {
                border: 1px solid black;
            }
        </style>
    </head>
    <canvas id="tutorial" width="300" height="300"></canvas>
    </body>
    <script type="text/javascript">
        function draw(){
            var canvas = document.getElementById('tutorial');
            if(!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            ctx.fillStyle = "rgb(200,0,0)";
          	//绘制矩形
            ctx.fillRect (10, 10, 55, 50);
    
            ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
            ctx.fillRect (30, 30, 55, 50);
        }
        draw();
    </script>
    </html>
    

    三、绘制形状

    3.1 栅格(grid)和坐标空间

    ​ 如下图所示,canvas元素默认被网格所覆盖。通常来说网格中的一个单元相当于canvas元素中的一像素。栅格的起点为左上角(坐标为(0,0))。所有元素的位置都相对于原点来定位。所以图中蓝色方形左上角的坐标为距离左边(X轴)x像素,距离上边(Y轴)y像素(坐标为(x,y))。

    ​ 后面我们会涉及到坐标原点的平移、网格的旋转以及缩放等。

    3.2 绘制矩形

    <canvas> 只支持一种原生的 图形绘制:矩形。所有其他图形都至少需要生成一种路径(path)。不过,我们拥有众多路径生成的方法让复杂图形的绘制成为了可能。

    canvast 提供了三种方法绘制矩形:

    1. fillRect(x, y, width, height)

      绘制一个填充的矩形

    2. strokeRect(x, y, width, height)

      绘制一个矩形的边框

    3. clearRect(x, y, widh, height)

      清除指定的矩形区域,然后这块区域会变的完全透明。

    说明:

    ​ 这3个方法具有相同的参数。

    x, y:指的是矩形的左上角的坐标。(相对于canvas的坐标原点)

    width, height:指的是绘制的矩形的宽和高。

    function draw(){
        var canvas = document.getElementById('tutorial');
        if(!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.fillRect(10, 10, 100, 50);  //绘制矩形,填充的默认颜色为黑色
        ctx.strokeRect(10, 70, 100, 50);  //绘制矩形边框
        
    }
    draw();
    

    ctx.clearRect(15, 15, 50, 25);
    

    

    四、绘制路径(path)

    ​ 图形的基本元素是路径。

    ​ 路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。

    ​ 一个路径,甚至一个子路径,都是闭合的。

    使用路径绘制图形需要一些额外的步骤:

    1. 创建路径起始点
    2. 调用绘制方法去绘制出路径
    3. 把路径封闭
    4. 一旦路径生成,通过描边或填充路径区域来渲染图形。

    下面是需要用到的方法:

    1. beginPath()

      新建一条路径,路径一旦创建成功,图形绘制命令被指向到路径上生成路径

    2. moveTo(x, y)

      把画笔移动到指定的坐标(x, y)。相当于设置路径的起始点坐标。

    3. closePath()

      闭合路径之后,图形绘制命令又重新指向到上下文中

    4. stroke()

      通过线条来绘制图形轮廓

    5. fill()

      通过填充路径的内容区域生成实心的图形

    4.1 绘制线段

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.beginPath(); //新建一条path
        ctx.moveTo(50, 50); //把画笔移动到指定的坐标
        ctx.lineTo(200, 50);  //绘制一条从当前位置到指定坐标(200, 50)的直线.
        //闭合路径。会拉一条从当前点到path起始点的直线。如果当前点与起始点重合,则什么都不做
        ctx.closePath();
        ctx.stroke(); //绘制路径。
    }
    draw();
    

    4.2 绘制三角形边框

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.moveTo(50, 50);
        ctx.lineTo(200, 50);
        ctx.lineTo(200, 200);
      	ctx.closePath(); //虽然我们只绘制了两条线段,但是closePath会closePath,仍然是一个3角形
        ctx.stroke(); //描边。stroke不会自动closePath()
    }
    draw();
    

    4.3 填充三角形

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.moveTo(50, 50);
        ctx.lineTo(200, 50);
        ctx.lineTo(200, 200);
       
        ctx.fill(); //填充闭合区域。如果path没有闭合,则fill()会自动闭合路径。
    }
    draw();
    

    4.4 绘制圆弧

    有两个方法可以绘制圆弧:

    1. arc(x, y, r, startAngle, endAngle, anticlockwise):

      (x, y)为圆心,以r为半径,从 startAngle弧度开始到endAngle弧度结束。anticlosewise是布尔值,true表示逆时针,false表示顺时针。(默认是顺时针)

      注意:

      1. 这里的度数都是弧度。
      2. 0弧度是指的x轴正方形
      radians=(Math.PI/180)*degrees   //角度转换成弧度
      
    2. arcTo(x1, y1, x2, y2, radius):

      根据给定的控制点和半径画一段圆弧,最后再以直线连接两个控制点。

    圆弧案例1:

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.arc(50, 50, 40, 0, Math.PI / 2, false);
        ctx.stroke();
    }
    draw();
    

    圆弧案例2:

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.arc(50, 50, 40, 0, Math.PI / 2, false);
        ctx.stroke();
    
        ctx.beginPath();
        ctx.arc(150, 50, 40, 0, -Math.PI / 2, true);
        ctx.closePath();
        ctx.stroke();
    
        ctx.beginPath();
        ctx.arc(50, 150, 40, -Math.PI / 2, Math.PI / 2, false);
        ctx.fill();
    
        ctx.beginPath();
        ctx.arc(150, 150, 40, 0, Math.PI, false);
        ctx.fill();
    
    }
    draw();
    

    圆弧案例3:

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.moveTo(50, 50);
      	//参数1、2:控制点1坐标   参数3、4:控制点2坐标  参数4:圆弧半径
        ctx.arcTo(200, 50, 200, 200, 100);
        ctx.lineTo(200, 200)
        ctx.stroke();
        
        ctx.beginPath();
        ctx.rect(50, 50, 10, 10);
        ctx.rect(200, 50, 10, 10)
        ctx.rect(200, 200, 10, 10)
        ctx.fill()
    }
    draw();
    

    arcTo方法的说明:

    ​ 这个方法可以这样理解。绘制的弧形是由两条切线所决定。

    ​ 第 1 条切线:起始点和控制点1决定的直线。

    ​ 第 2 条切线:控制点1 和控制点2决定的直线。

    其实绘制的圆弧就是与这两条直线相切的圆弧。

    4.5 绘制贝塞尔曲线

    4.5.1 什么是贝塞尔曲线

    ​ 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。

    ​ 一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。

    ​ 贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具如PhotoShop等。在Flash4中还没有完整的曲线工具,而在Flash5里面已经提供出贝塞尔曲线工具。

    ​ 贝塞尔曲线于1962,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau演算法开发,以稳定数值的方法求出贝兹曲线。

    一次贝塞尔曲线(线性贝塞尔曲线)

    ​ 一次贝塞尔曲线其实是一条直线。

    二次贝塞尔曲线

    三次贝塞尔曲线

    4.5.2 绘制贝塞尔曲线

    绘制二次贝塞尔曲线

    quadraticCurveTo(cp1x, cp1y, x, y):

    说明:

    ​ 参数1和2:控制点坐标

    ​ 参数3和4:结束点坐标

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.moveTo(10, 200); //起始点
        var cp1x = 40, cp1y = 100;  //控制点
        var x = 200, y = 200; // 结束点
        //绘制二次贝塞尔曲线
        ctx.quadraticCurveTo(cp1x, cp1y, x, y);
        ctx.stroke();
        
        ctx.beginPath();
        ctx.rect(10, 200, 10, 10);
        ctx.rect(cp1x, cp1y, 10, 10);
        ctx.rect(x, y, 10, 10);
        ctx.fill();
        
    }
    draw();
    

    绘制三次贝塞尔曲线

    bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

    说明:

    ​ 参数1和2:控制点1的坐标

    ​ 参数3和4:控制点2的坐标

    ​ 参数5和6:结束点的坐标

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.moveTo(40, 200); //起始点
        var cp1x = 20, cp1y = 100;  //控制点1
        var cp2x = 100, cp2y = 120;  //控制点2
        var x = 200, y = 200; // 结束点
        //绘制二次贝塞尔曲线
        ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
        ctx.stroke();
    
        ctx.beginPath();
        ctx.rect(40, 200, 10, 10);
        ctx.rect(cp1x, cp1y, 10, 10);
        ctx.rect(cp2x, cp2y, 10, 10);
        ctx.rect(x, y, 10, 10);
        ctx.fill();
    
    }
    draw();
    

    五、添加样式和颜色

    ​ 在前面的绘制矩形章节中,只用到了默认的线条和颜色。

    ​ 如果想要给图形上色,有两个重要的属性可以做到。

    1. fillStyle = color

      设置图形的填充颜色

    2. strokeStyle = color

      设置图形轮廓的颜色

    备注:

    1. `color` 可以是表示 `css` 颜色值的字符串、渐变对象或者图案对象。
    2. 默认情况下,线条和填充颜色都是黑色。
    3. 一旦您设置了 `strokeStyle` 或者 `fillStyle` 的值,那么这个新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,你需要重新设置 `fillStyle` 或 `strokeStyle` 的值。
    

    fillStyle

    function draw(){
      var canvas = document.getElementById('tutorial');
      if (!canvas.getContext) return;
      var ctx = canvas.getContext("2d");
      for (var i = 0; i < 6; i++){
        for (var j = 0; j < 6; j++){
          ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ',' +
            Math.floor(255 - 42.5 * j) + ',0)';
          ctx.fillRect(j * 50, i * 50, 50, 50);
        }
      }
    }
    draw();
    

    strokeStyle

    <script type="text/javascript">
        function draw(){
            var canvas = document.getElementById('tutorial');
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            for (var i = 0; i < 6; i++){
                for (var j = 0; j < 6; j++){
                    ctx.strokeStyle = `rgb(${randomInt(0, 255)},${randomInt(0, 255)},${randomInt(0, 255)})`;
                    ctx.strokeRect(j * 50, i * 50, 40, 40);
                }
            }
        }
        draw();
        /**
         作者:李振超      4 Jun 2017 12:12
         返回随机的 [from, to] 之间的整数(包括from,也包括to)
         */
        function randomInt(from, to){
            return parseInt(Math.random() * (to - from + 1) + from);
        }
    
    </script>
    

    Transparency(透明度)

    globalAlpha = transparencyValue

    ​ 这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。

    globalAlpha 属性在需要绘制大量拥有相同透明度的图形时候相当高效。不过,我认为使用rgba()设置透明度更加好一些。

    line style

    1. lineWidth = value

    线宽。只能是正值。默认是1.0

    起始点和终点的连线为中心,上下各占线宽的一半

    ctx.beginPath();
    ctx.moveTo(10, 10);
    ctx.lineTo(100, 10);
    ctx.lineWidth = 10;
    ctx.stroke();
    
    ctx.beginPath();
    ctx.moveTo(110, 10);
    ctx.lineTo(160, 10)
    ctx.lineWidth = 20;
    ctx.stroke()
    

    ###2. lineCap = type

    线条末端样式。

    共有3个值:

    1. butt:线段末端以方形结束

    2. round:线段末端以圆形结束

    3. square:线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。

      var lineCaps = ["butt", "round", "square"];
      
      for (var i = 0; i < 3; i++){
          ctx.beginPath();
          ctx.moveTo(20 + 30 * i, 30);
          ctx.lineTo(20 + 30 * i, 100);
          ctx.lineWidth = 20;
          ctx.lineCap = lineCaps[i];
          ctx.stroke();
      }
      
      ctx.beginPath();
      ctx.moveTo(0, 30);
      ctx.lineTo(300, 30);
      
      ctx.moveTo(0, 100);
      ctx.lineTo(300, 100)
      
      ctx.strokeStyle = "red";
      ctx.lineWidth = 1;
      ctx.stroke();
      

    3. lineJoin = type

    同一个path内,设定线条与线条间接合处的样式。

    共有3个值round, bevelmiter

    1. round

      通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。 圆角的半径是线段的宽度。

    2. bevel

      在相连部分的末端填充一个额外的以三角形为底的区域, 每个部分都有各自独立的矩形拐角。

    3. miter(默认)

      通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
    
        var lineJoin = ['round', 'bevel', 'miter'];
        ctx.lineWidth = 20;
    
        for (var i = 0; i < lineJoin.length; i++){
            ctx.lineJoin = lineJoin[i];
            ctx.beginPath();
            ctx.moveTo(50, 50 + i * 50);
            ctx.lineTo(100, 100 + i * 50);
            ctx.lineTo(150, 50 + i * 50);
            ctx.lineTo(200, 100 + i * 50);
            ctx.lineTo(250, 50 + i * 50);
            ctx.stroke();
        }
    
    }
    draw();
    

    4. 虚线

    setLineDash 方法和 lineDashOffset 属性来制定虚线样式. setLineDash 方法接受一个数组,来指定线段与间隙的交替;lineDashOffset属性设置起始偏移量.

    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        
        ctx.setLineDash([20, 5]);  // [实线长度, 间隙长度]
        ctx.lineDashOffset = -0;
        ctx.strokeRect(50, 50, 210, 210);
    }
    draw();
    

    备注:

    getLineDash():返回一个包含当前虚线样式,长度为非负偶数的数组。

    六、绘制文本

    绘制文本的两个方法

    canvas 提供了两种方法来渲染文本:

    1. fillText(text, x, y [, maxWidth])

      在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.

    2. strokeText(text, x, y [, maxWidth])

      在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的.

    var ctx;
    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        ctx = canvas.getContext("2d");
        ctx.font = "100px sans-serif"
        ctx.fillText("天若有情", 10, 100);
        ctx.strokeText("天若有情", 10, 200)
    }
    draw();
    

    给文本添加样式

    1. font = value

      当前我们用来绘制文本的样式。这个字符串使用和 CSS font属性相同的语法. 默认的字体是 10px sans-serif

    2. textAlign = value

      文本对齐选项. 可选的值包括:start, end, left, right or center. 默认值是 start

    3. textBaseline = value

      基线对齐选项,可选的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默认值是 alphabetic。

    4. direction = value

      文本方向。可能的值包括:ltr, rtl, inherit。默认值是 inherit。

    七、绘制图片

    ​ 我们也可以在canvas上直接绘制图片。

    7.1 由零开始创建图片

    创建<img>元素

    var img = new Image();   // 创建一个<img>元素
    img.src = 'myImage.png'; // 设置图片源地址
    

    脚本执行后图片开始装载

    绘制img

    //参数1:要绘制的img  参数2、3:绘制的img在canvas中的坐标
    ctx.drawImage(img,0,0); 
    

    注意:

    ​ 考虑到图片是从网络加载,如果 drawImage 的时候图片还没有完全加载完成,则什么都不做,个别浏览器会抛异常。所以我们应该保证在 img 绘制完成之后再 drawImage

    var img = new Image();   // 创建img元素
    img.onload = function(){
      ctx.drawImage(img, 0, 0)
    }
    img.src = 'myImage.png'; // 设置图片源地址
    

    7.2 绘制 img 标签元素中的图片

    img 可以 new 也可以来源于我们页面的 <img>标签

    <img src="./美女.jpg" alt="" width="300"><br>
    <canvas id="tutorial" width="600" height="400"></canvas>
    <script type="text/javascript">
        function draw(){
            var canvas = document.getElementById('tutorial');
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            var img = document.querySelector("img");
            ctx.drawImage(img, 0, 0);
        }
        document.querySelector("img").onclick = function (){
            draw();
        }
    
    </script>
    

    第一张图片就是页面中的<img>标签

    7.3 缩放图片

    drawImage() 也可以再添加两个参数:

    drawImage(image, x, y, width, height)

    ​ 这个方法多了2个参数:widthheight,这两个参数用来控制 当像canvas画入时应该缩放的大小。

    ctx.drawImage(img, 0, 0, 400, 200)
    

    7.4 切片(slice)

    drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

    ​ 第一个参数和其它的是相同的,都是一个图像或者另一个 canvas 的引用。

    其他8个参数:

    ​ 前4个是定义图像源的切片位置和大小,

    ​ 后4个则是定义切片的目标显示位置和大小。

    八、状态的保存和恢复

    Saving and restoring state是绘制复杂图形时必不可少的操作。

    save()和restore()

    saverestore 方法是用来保存和恢复 canvas 状态的,都没有参数。

    Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。

    1. 关于 save()

      Canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。一个绘画状态包括:

    • 当前应用的变形(即移动,旋转和缩放)

    • strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值

    • 当前的裁切路径(clipping path

      可以调用任意多次 save方法。(类似数组的push())

    1. 关于restore()

      每一次调用 restore 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。(类似数组的pop())

    var ctx;
    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
    
        ctx.fillRect(0, 0, 150, 150);   // 使用默认设置绘制一个矩形
        ctx.save();                  // 保存默认状态
    
        ctx.fillStyle = 'red'       // 在原有配置基础上对颜色做改变
        ctx.fillRect(15, 15, 120, 120); // 使用新的设置绘制一个矩形
    
        ctx.save();                  // 保存当前状态
        ctx.fillStyle = '#FFF'       // 再次改变颜色配置
        ctx.fillRect(30, 30, 90, 90);   // 使用新的配置绘制一个矩形
    
        ctx.restore();               // 重新加载之前的颜色状态
        ctx.fillRect(45, 45, 60, 60);   // 使用上一次的配置绘制一个矩形
    
        ctx.restore();               // 加载默认颜色配置
        ctx.fillRect(60, 60, 30, 30);   // 使用加载的配置绘制一个矩形
    }
    draw();
    

    九、变形

    9.1 translate

    translate(x, y)

    ​ 用来移动 canvas原点到指定的位置

    translate方法接受两个参数。x 是左右偏移量,y 是上下偏移量,如右图所示。

    在做变形之前先保存状态是一个良好的习惯。大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。又如果你是在一个循环中做位移但没有保存和恢复canvas 的状态,很可能到最后会发现怎么有些东西不见了,那是因为它很可能已经超出 canvas 范围以外了。

    ​ 注意:translate移动的是canvas的坐标原点。(坐标变换)

    var ctx;
    function draw(){
        var canvas = document.getElementById('tutorial1');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.save(); //保存坐原点平移之前的状态
        ctx.translate(100, 100);
        ctx.strokeRect(0, 0, 100, 100)
        ctx.restore(); //恢复到最初状态
        ctx.translate(220, 220);
        ctx.fillRect(0, 0, 100, 100)
    }
    draw();
    

    9.2 rotate

    rotate(angle)

    ​ 旋转坐标轴。

    ​ 这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。

    ​ 旋转的中心是坐标原点。

    var ctx;
    function draw(){
      var canvas = document.getElementById('tutorial1');
      if (!canvas.getContext) return;
      var ctx = canvas.getContext("2d");
    
      ctx.fillStyle = "red";
      ctx.save();
    
      ctx.translate(100, 100);
      ctx.rotate(Math.PI / 180 * 45);
      ctx.fillStyle = "blue";
      ctx.fillRect(0, 0, 100, 100);
      ctx.restore();
    
      ctx.save();
      ctx.translate(0, 0);
      ctx.fillRect(0, 0, 50, 50)
      ctx.restore();
    }
    draw();
    

    9.3 scale

    scale(x, y)

    ​ 我们用它来增减图形在 canvas 中的像素数目,对形状,位图进行缩小或者放大。

    scale方法接受两个参数。x,y分别是横轴和纵轴的缩放因子,它们都必须是正值。值比 1.0 小表示缩 小,比 1.0 大则表示放大,值为 1.0 时什么效果都没有。

    ​ 默认情况下,canvas 的 1 单位就是 1 个像素。举例说,如果我们设置缩放因子是 0.5,1 个单位就变成对应 0.5 个像素,这样绘制出来的形状就会是原先的一半。同理,设置为 2.0 时,1 个单位就对应变成了 2 像素,绘制的结果就是图形放大了 2 倍。

    9.4 transform(变形矩阵)

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

    a (m11)

    ​ Horizontal scaling.

    b (m12)

    ​ Horizontal skewing.

    c (m21)

    ​ Vertical skewing.

    d (m22)

    ​ Vertical scaling.

    e (dx)

    ​ Horizontal moving.

    f (dy)

    ​ Vertical moving.

    var ctx;
    function draw(){
        var canvas = document.getElementById('tutorial1');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.transform(1, 1, 0, 1, 0, 0);
        ctx.fillRect(0, 0, 100, 100);
    }
    draw();
    

    十、合成

    ​ 在前面的所有例子中、,我们总是将一个图形画在另一个之上,对于其他更多的情况,仅仅这样是远远不够的。比如,对合成的图形来说,绘制顺序会有限制。不过,我们可以利用 globalCompositeOperation 属性来改变这种状况。

    globalCompositeOperation = type

        var ctx;
        function draw(){
            var canvas = document.getElementById('tutorial1');
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            
            ctx.fillStyle = "blue";
            ctx.fillRect(0, 0, 200, 200);
    
            ctx.globalCompositeOperation = "source-over"; //全局合成操作
            ctx.fillStyle = "red";
            ctx.fillRect(100, 100, 200, 200);
        }
        draw();
    
    </script>
    

    注:下面的展示中,蓝色是原有的,红色是新的。

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

    ##1. source-over(default)

    这是默认设置,新图像会覆盖在原有图像。

    ##2. source-in

    仅仅会出现新图像与原来图像重叠的部分,其他区域都变成透明的。(包括其他的老图像区域也会透明)

    ##3. source-out

    仅仅显示新图像与老图像没有重叠的部分,其余部分全部透明。(老图像也不显示)

    ##4. source-atop

    新图像仅仅显示与老图像重叠区域。老图像仍然可以显示。

    ##5. destination-over

    新图像会在老图像的下面。

    ##6. destination-in

    仅仅新老图像重叠部分的老图像被显示,其他区域全部透明。

    ##7. destination-out

    仅仅老图像与新图像没有重叠的部分。 注意显示的是老图像的部分区域。

    ##8. destination-atop

    老图像仅仅仅仅显示重叠部分,新图像会显示在老图像的下面。

    ##9. lighter

    新老图像都显示,但是重叠区域的颜色做加处理

    ##10. darken

    保留重叠部分最黑的像素。(每个颜色位进行比较,得到最小的)

    blue: #0000ff

    red: #ff0000

    所以重叠部分的颜色:#000000

    ##11. lighten

    保证重叠部分最量的像素。(每个颜色位进行比较,得到最大的)

    blue: #0000ff

    red: #ff0000

    所以重叠部分的颜色:#ff00ff

    ##12. xor

    重叠部分会变成透明

    ##13. copy

    只有新图像会被保留,其余的全部被清除(边透明)

    #十一、裁剪路径

    clip()

    ​ 把已经创建的路径转换成裁剪路径。

    ​ 裁剪路径的作用是遮罩。只显示裁剪路径内的区域,裁剪路径外的区域会被隐藏。

    ​ 注意:clip()只能遮罩在这个方法调用之后绘制的图像,如果是clip()方法调用之前绘制的图像,则无法实现遮罩。

    var ctx;
    function draw(){
        var canvas = document.getElementById('tutorial1');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
    
        ctx.beginPath();
        ctx.arc(20,20, 100, 0, Math.PI * 2);
        ctx.clip();
        
        ctx.fillStyle = "pink";
        ctx.fillRect(20, 20, 100,100);
    }
    draw();
    

    十二、动画

    动画的基本步骤

    1. 清空canvas

      再绘制每一帧动画之前,需要清空所有。清空所有最简单的做法就是clearRect()方法

    2. 保存canvas状态

      如果在绘制的过程中会更改canvas的状态(颜色、移动了坐标原点等),又在绘制每一帧时都是原始状态的话,则最好保存下canvas的状态

    3. 绘制动画图形

      这一步才是真正的绘制动画帧

    4. 恢复canvas状态

      如果你前面保存了canvas状态,则应该在绘制完成一帧之后恢复canvas状态。

    控制动画

    我们可用通过canvas的方法或者自定义的方法把图像会知道到canvas上。正常情况,我们能看到绘制的结果是在脚本执行结束之后。例如,我们不可能在一个 for 循环内部完成动画。

    也就是,为了执行动画,我们需要一些可以定时执行重绘的方法。

    一般用到下面三个方法:

    1. setInterval()
    2. setTimeout()
    3. requestAnimationFrame()

    ##案例1:太阳系

    let sun;
    let earth;
    let moon;
    let ctx;
    function init(){
        sun = new Image();
        earth = new Image();
        moon = new Image();
        sun.src = "sun.png";
        earth.src = "earth.png";
        moon.src = "moon.png";
    
        let canvas = document.querySelector("#solar");
        ctx = canvas.getContext("2d");
    
        sun.onload = function (){
            draw()
        }
    
    }
    init();
    function draw(){
        ctx.clearRect(0, 0, 300, 300); //清空所有的内容
        /*绘制 太阳*/
        ctx.drawImage(sun, 0, 0, 300, 300);
    
        ctx.save();
        ctx.translate(150, 150);
    
        //绘制earth轨道
        ctx.beginPath();
        ctx.strokeStyle = "rgba(255,255,0,0.5)";
        ctx.arc(0, 0, 100, 0, 2 * Math.PI)
        ctx.stroke()
    
        let time = new Date();
        //绘制地球
        ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds())
        ctx.translate(100, 0);
        ctx.drawImage(earth, -12, -12)
    
        //绘制月球轨道
        ctx.beginPath();
        ctx.strokeStyle = "rgba(255,255,255,.3)";
        ctx.arc(0, 0, 40, 0, 2 * Math.PI);
        ctx.stroke();
    
        //绘制月球
        ctx.rotate(2 * Math.PI / 6 * time.getSeconds() + 2 * Math.PI / 6000 * time.getMilliseconds());
        ctx.translate(40, 0);
        ctx.drawImage(moon, -3.5, -3.5);
        ctx.restore();
    
        requestAnimationFrame(draw);
    }
    

    ##案例2:模拟时钟

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            body {
                padding: 0;
                margin: 0;
                background-color: rgba(0, 0, 0, 0.1)
            }
            
            canvas {
                display: block;
                margin: 200px auto;
            }
        </style>
    </head>
    <body>
    <canvas id="solar" width="300" height="300"></canvas>
    <script>
        init();
    
        function init(){
            let canvas = document.querySelector("#solar");
            let ctx = canvas.getContext("2d");
            draw(ctx);
        }
    
        function draw(ctx){
            requestAnimationFrame(function step(){
                drawDial(ctx); //绘制表盘
                drawAllHands(ctx); //绘制时分秒针
                requestAnimationFrame(step);
            });
        }
        /*绘制时分秒针*/
        function drawAllHands(ctx){
            let time = new Date();
    
            let s = time.getSeconds();
            let m = time.getMinutes();
            let h = time.getHours();
            
            let pi = Math.PI;
            let secondAngle = pi / 180 * 6 * s;  //计算出来s针的弧度
            let minuteAngle = pi / 180 * 6 * m + secondAngle / 60;  //计算出来分针的弧度
            let hourAngle = pi / 180 * 30 * h + minuteAngle / 12;  //计算出来时针的弧度
    
            drawHand(hourAngle, 60, 6, "red", ctx);  //绘制时针
            drawHand(minuteAngle, 106, 4, "green", ctx);  //绘制分针
            drawHand(secondAngle, 129, 2, "blue", ctx);  //绘制秒针
        }
        /*绘制时针、或分针、或秒针
         * 参数1:要绘制的针的角度
         * 参数2:要绘制的针的长度
         * 参数3:要绘制的针的宽度
         * 参数4:要绘制的针的颜色
         * 参数4:ctx
         * */
        function drawHand(angle, len, width, color, ctx){
            ctx.save();
            ctx.translate(150, 150); //把坐标轴的远点平移到原来的中心
            ctx.rotate(-Math.PI / 2 + angle);  //旋转坐标轴。 x轴就是针的角度
            ctx.beginPath();
            ctx.moveTo(-4, 0);
            ctx.lineTo(len, 0);  // 沿着x轴绘制针
            ctx.lineWidth = width;
            ctx.strokeStyle = color;
            ctx.lineCap = "round";
            ctx.stroke();
            ctx.closePath();
            ctx.restore();
        }
        
        /*绘制表盘*/
        function drawDial(ctx){
            let pi = Math.PI;
            
            ctx.clearRect(0, 0, 300, 300); //清除所有内容
            ctx.save();
    
            ctx.translate(150, 150); //一定坐标原点到原来的中心
            ctx.beginPath();
            ctx.arc(0, 0, 148, 0, 2 * pi); //绘制圆周
            ctx.stroke();
            ctx.closePath();
    
            for (let i = 0; i < 60; i++){//绘制刻度。
                ctx.save();
                ctx.rotate(-pi / 2 + i * pi / 30);  //旋转坐标轴。坐标轴x的正方形从 向上开始算起
                ctx.beginPath();
                ctx.moveTo(110, 0);
                ctx.lineTo(140, 0);
                ctx.lineWidth = i % 5 ? 2 : 4;
                ctx.strokeStyle = i % 5 ? "blue" : "red";
                ctx.stroke();
                ctx.closePath();
                ctx.restore();
            }
            ctx.restore();
        }
    </script>
    </body>
    </html>
    

    展开全文
  • 讲一讲 Canvas 究竟是个啥

    千次阅读 2016-12-19 17:57:36
    一个很重要的原因是,Canvas 的标准还没有完全确定,不适合大规模用在生产环境。但是,Canvas 的优点也是很明显的,例如在绘制含有大量元素的图表的时候,SVG 往往因为性能问题而无法胜任,例如我见过的一次技术分享...

    HTML5 的标准已经出来好久了,但是似乎其中的 Canvas 现在并没有在太多的地方用到。一个很重要的原因是,Canvas 的标准还没有完全确定,不适合大规模用在生产环境。但是,Canvas 的优点也是很明显的,例如在绘制含有大量元素的图表的时候,SVG 往往因为性能问题而无法胜任,例如我见过的一次技术分享会的抽奖环节,虽然效果比较炫,但因为每个头像都是 DOM,利用 CSS3 控制的动画,导致了性能非常低下。此外,随着硬件性能的提高,视频截图、图像处理等功能也逐渐可以在网页上实现了,大多数网站用的是 Flash,但是 Flash 在 Mac 电脑上性能不高,还需要学一些额外的知识。Canvas 则是直接使用 JavaScript 来进行绘图,对 Mac 友好,所以不失为 Flash 的一个继承者。

    使用 Canvas

    说了这么多,Canvas 究竟是个啥?

    英文中 Canvas 的意思是“画布”,不过这里说的 Canvas 是 HTML5 中新出的一个元素,开发者可以在上面绘制一系列图形。Canvas 在 HTML 文件中的写法很简单:

    <canvas id="canvas" width="宽度" height="高度"></canvas>
    

    其中 id 属性是所有 HTML 元素都可以用的,Canvas 自带的属性只有后面两个(分别控制宽度、高度),没有其它的了。至于兼容性,CanIUse 上面写了,基础的功能目前用户使用的 90% 的浏览器都支持,所以大部分情况下还是可以放心使用的。

    1

    注意,一定要使用 Canvas 自带的 width 和 height 属性,不要使用 CSS 来控制,因为 CSS 控制会导致 Canvas 变形。可以试着与 PhptpShop 对比一下,后者是改变“图像大小”,前者才是正确的改变“画布大小”。例如下图是三张图片的横向拼接:最左边的黑框中是大小为 50px * 50px 的原图;中间是改变了图像大小为 100px * 100px 的效果,图像变得模糊,但是对于图像本身来说坐标范围并没有变大;最右边才是正确的 100px * 100px 的 Canvas。

    2

    Canvas 绝大部分的绘图方法都与 <canvas> 标签无关,需要使用 JavaScript 对其进行操作,这就是所谓的 Canvas API。

    我们首先获取到这个元素:

    var canvas = document.getElementById('canvas');
    

    然后通过一个方法来获取可以调用一切 Canvas API 的入口:

    var ctx = canvas.getContext('2d');
    

    看到 2d 是不是很激动地联想到有没有 3d 呢?没有 3d 的写法,不过如果想要开启 3D 世界的大门,则可以写 canvas.getContext('webgl')。然而 WebGL 是基于 OpenGL ES 2.0 的一套标准,与本文是彻彻底底的两条路,因此这里就不讨论了。

    Canvas 中的基本概念

    坐标

    与数学上常见的笛卡尔坐标系不太相同,Canvas 的坐标系是计算机中常见的坐标系,它长这样:

    0

    画布的最左上角是 (0,0),往右 x 增大,往下 y 增大,而且 x 和 y 都是整数(就算在计算过程中不是整数,在绘制的时候也会当作整数处理),单位是像素。

    绘图

    带大家怀旧一下。不知道有多少同学小时候玩过 logo 语言,在里面你可以控制一只小海龟在一块板子上行走、画画、提笔、落笔。Canvas 中也一样,你需要控制一只画笔的移动和绘制。然而 Canvas 更高级一些,你可以直接利用一些函数来画图,不用去控制那只画笔的位置。

    Canvas 中的基本图形

    通过上文定义的 ctx 变量可以干许多有意思的事情,我们先看看如何绘制一些基本图形。

    线条

    我们指定画笔移动到某一点,然后告诉画笔需要从当前这一点画到另一点。我们可以让画笔多次移动、绘制,最后统一输出到屏幕上。例子如下:

    ctx.moveTo(10, 10);
    ctx.lineTo(150, 50);
    ctx.lineTo(10, 50);
    ctx.moveTo(10, 20);
    ctx.lineTo(40, 70);
    ctx.stroke();
    

    上面的代码中,lineTo 是产生线条用的函数,执行完之后画笔就移到了线条的终点。需要注意的是,线条此时并没有显示在屏幕上,必须调用 stroke 才会显示。这样设计是有道理的,因为向屏幕上输出内容需要耗费大量的资源,我们完全可以先攒够一波 lineTo,最后用 stroke 放一个大的。

    路径

    绘制路径非常简单,只需要先告诉 ctx 一声“我要开始画路径了”,然后通过各种方法(例如 lineTo)绘制路径。如果需要画一个封闭路径,那就最后告诉 ctx一声:“我画完了,你把它封闭起来吧。”当然,不要忘记利用 stroke 输出到屏幕上。

    一个简单的例子:

    ctx.beginPath();
    ctx.moveTo(10, 10);
    ctx.lineTo(150, 50);
    ctx.lineTo(10, 50);
    ctx.closePath();
    ctx.stroke();
    

    如果我不想只描绘路径线条,而是想填充整个路径呢?可以将最后一行的 stroke 改成 fill,这样就跟使用了画图中的油漆桶一样,封闭路径里面的内容就都被填充上颜色了:

    ctx.fill();
    

    弧 / 圆形

    绘制弧的函数参数比较多:

    ctx.arc(圆心 x 坐标, 圆心 y 坐标, 半径, 起始角度, 终止角度, 是否为逆时针);
    

    注意,在 Canvas 的坐标系中,角的一边是以圆心为中心的水平向右的直线。角度单位均为弧度。例如下图,确定了圆心、起始角度(图中标明的锐角)和终止角度(图中标明的钝角),方向为逆时针,于是就有了这么一个弧。如果方向为顺时针,那么就会是一个跟它互补的、非常非常大的弧……

    3

    所以如果转了 2π 圈之后,弧就成了圆形,因此也可以使用绘制弧的方式来绘制圆形:

    ctx.beginPath();
    ctx.arc(圆心 x 坐标, 圆心 y 坐标, 半径, 0, Math.PI * 2, true);
    ctx.closePath();
    

    最后一个参数随便填(当然也可以不填),因为不管是顺时针还是逆时针,转了 2π 圈之后都是一个圆。

    矩形

    如果只是想绘制一个横平竖直的矩形,可以使用下面的两个方法:

    // 只描边
    ctx.strokeRect(左上角 x 坐标, 左上角 y 坐标, 宽度, 高度);
    // 只填充
    ctx.fillRect(左上角 x 坐标, 左上角 y 坐标, 宽度, 高度);
    

    线条样式 / 填充样式

    之前绘制的所有图形都是黑色的,但是 Canvas 肯定不止这么一种颜色(不然标准的制定者会被喷的很惨)。事实上,Canvas 可以单独设置线条样式和填充样式,分别使用的是 strokeStyle 和 fillStyle。可能的值有三种:纯色、渐变、图像。既然线条样式与填充样式的使用方法相同,那么下面统一以填充样式为例。如果想设置线条样式,直接将所有的 fillStyle改成 strokeStyle 即可,里面的参数都不变。

    /* 纯色填充 */
    // 普通的颜色
    ctx.fillStyle = '#0000ff';
    // 带有透明度的颜色
    ctx.fillStyle = 'rgba(64, 0, 127, 0.5)';
    
    /* 渐变填充 */
    // 设置渐变的尺寸(参数分别为起始点的 x 和 y、终止点的 x 和 y)
    var gradient = ctx.createLinearGradient(0, 0, 170, 0);
    // 设置过渡色,第一个参数是渐变的位置,第二个参数是颜色
    gradient.addColorStop(0, 'magenta');
    gradient.addColorStop(0.5, 'blue');
    gradient.addColorStop(1.0, 'red');
    // 设置填充样式
    ctx.fillStyle = gradient;
    
    /* 图片填充 */
    // 创建图片
    var image = new Image;
    image.src = '/path/to/image.png';
    // 创建图片笔触,可以指定图片的平铺方式,这里是横向平铺
    var pattern = ctx.createPattern(image, 'repeat-x');
    // 设置笔触填充
    ctx.fillStyle = pattern;
    

    关于渐变,除了代码中提到的线性渐变以外,还有 createRadialGradient,也就是径向渐变。

    设置完填充样式之后,就可以使用 fill 来填充啦!如果设置的是线条样式,那么就可以使用 stroke 来描边。

    当然,对于线条样式,还有个额外的方法叫 lineWidth 可以用来控制线条的宽度。

    文字

    要想在画布上画文字,首先需要知道所使用的字体和字号:

    ctx.font = '30px Verdana';
    

    然后就可以通过 strokeText 或者 fillText 来对字体描边或者填充字体。

    ctx.strokeText("Hello Coding!", 23, 33);
    ctx.fillText("Hello Coding!", 23, 66);
    

    图片

    在 Canvas 中绘制图片有三种方法:

    // 指定绘制位置
    ctx.drawImage(image, x, y);
    // 指定绘制位置和图像宽高
    ctx.drawImage(image, x, y, width, height);
    // 指定剪裁区域、绘制位置和图像宽高
    ctx.drawImage(image, sx, sy, swidth, sheight, x, y, width, height);
    

    参数的含义依次如下:

    image:   要使用的 Image、Canvas 或 Video
    sx:      可选,开始剪切的 x 坐标
    sy:      可选,开始剪切的 y 坐标
    swidth:  可选,被剪切图像的宽度
    sheight: 可选,被剪切图像的高度
    x:       在画布上放置图像的 x 坐标
    y:       在画布上放置图像的 y 坐标
    width:   可选,要使用的图像的宽度
    height:  可选,要使用的图像的高度
    

    画布设置

    细心的同学可能会发现,刚才有些属性是直接对 ctx 变量做设置,例如 ctx.lineWidth,只要设置了它,那么后续画出来的线条全都是这么个宽度。

    其实,Canvas 的设置项还有许多,例如我们可以直接移动画布、旋转画布、设置全局的绘制透明度等等。这些设置还可以随时保存和恢复。

    要注意的一点是,所有已经画在画布上的东西,是已经定死了的,不管之后再次进行任何设置都不会再改变。这个很像 Windows 下的画图程序。

    废话不多说,直接上代码:

    // 移动画布,其实就是移动坐标系
    ctx.translate(往右移动的量, 往下移动的量);
    // 旋转画布,旋转中心为坐标系原点
    ctx.rotate(顺时针旋转的角度);
    // 以坐标系原点为中心缩放画布
    ctx.scale(横向放大倍数, 纵向放大倍数);
    // 设置绘制透明度,如果 fillStyle 等属性设置了透明度则会叠加
    ctx.globalAlpha(零到一的小数);
    // 设置全局组合操作
    ctx.globalCompositeOperation = 'lighter';
    // 保存当前设置
    ctx.save();
    // 恢复上次保存的设置
    ctx.restore();
    

    移动、旋转、缩放其实就是在控制绘图的坐标系,如果你在调用这三个方法的时候,脑子里时刻有一个带刻度的坐标系,效果会非常好。

    事实上,Canvas 的坐标变换遵循计算机图形学的知识:变换矩阵。简单来说,一个坐标可以看成是一个矩阵,坐标所对应的矩阵乘上变换矩阵就可以实现对坐标的变换。为了提升计算的效率,可以先计算出几种变换复合之后的变换矩阵,然后直接通过 transform 函数对当前坐标系进行变换,或者通过 setTransform 函数将坐标系重置为初始状态后再进行变换。至于变换矩阵的内容,对于本文来说就有些超纲了。

    全局组合操作有点像 PhotoShop 里面的“混合选项”,具体的实现方式还没有完全确定,目前常见浏览器都统一了的实现方式有:source-oversource-atopdestination-overdestination-outlighterxor。具体的行为可以看 Mozilla 官方文档,但是由于标准还未完全确定,因此其它浏览器不保证所有的行为都跟 Mozilla 的标准一致。一般来说,比较常见的是 source-over 和 lighter 两种,这两种的标准在浏览器界也算是无可争议的。

    至于保存和恢复设置就有点好玩了,首先需要了解一个叫“栈”的东西。

    栈是一个一维数组,规定只能从一个方向操作。栈一开始是空的,我们可以从这个方向往数组 push 元素,也只能从这个方向把最后一个元素(栈顶元素)pop 出来,除此以外没有任何多余的操作。当然,pop 的次数不能多于 push 的次数,因为 pop 到栈底的时候栈里就已经没有元素了,此时再 pop 是没有意义的。栈的用处有很多,例如括号匹配、表达式求值、深度优先搜索,甚至绝大部分语言的函数调用都要用到栈。

    每次我们调用 save 函数,实际上是将当前的全局设置 push 到了一个专门栈上,每次调用 restore 函数的时候将最后一次保存的内容 pop 出来并用它覆盖当前的全局设置,这样栈顶就是最近一次保存的内容了。保存和恢复在某些情况下很好用,例如我需要画一个歪着的图形,然后继续画正着的图形,这样就可以先调用 save,然后调用 rotate,画完图形之后再 restore 回来,继续画其它的图形。

    其实 Canvas 还有许多方法,例如 toDataURL 直接将当前画布上的内容转换为十六进制的 data-urlgetImageData直接将图像转换为 RGBA 数组以供图像处理算法使用,putImageData 将 RGBA 数组转换为图片显示在画布上等等。如果配上 JavaScript 的定时更新(最好用 requestAnimationFrame 而不是 setInterval),则可以产生动画效果。网上还有许多 Canvas 的库,可以让程序员更简便地基于 Canvas 编写属于自己的特效或功能。在这儿我想说一句话:大家的脑洞有多大,Canvas 的能力就有多强~

    转自:https://blog.coding.net/blog/what-is-canvas
    展开全文
  • HTML5Canvas绘图(上)

    千次阅读 2018-11-26 15:35:11
    1.Canvas绘制步骤 在html5页面中添加canvas元素,定义id属性值以便后面调用  &lt;canvas id="myCanvas" width="500" height="200"&gt;&lt;/canvas&gt; 使用id寻找...

    1.Canvas绘制步骤

    • 在html5页面中添加canvas元素,定义id属性值以便后面调用

               <canvas id="myCanvas" width="500" height="200"></canvas>

    • 使用id寻找页面中的canvas元素

              var c=document.getElementById("myCanvas");

    • 通过canvas元素的getContext方法来获取其上下文(Context),即创建context对象,以获取允许绘制的2D环境

              var context=c.getContext("2d");

    • 使用javascript脚本来进行绘制

             context.fillStyle="#ff0000";

             context.fillRect(50,25,100,50);

    <head>
    	<title></title>
    	<!--给画布设置一个样式-->
    	<style type="text/css">
    		#myCanvas{
    			border: 1px solid blue;
    		}
    	</style>
    	<script type="text/javascript">
    		window.onload=function(){
    			var canvas=document.getElementById("myCanvas");
    			var context=canvas.getContext("2d");
    			context.fillStyle="#ff0000";
    			context.fillRect(50,25,100,50);
    			//距离画布左边50,上边25,绘制的图形宽100,高50
    		}
    	</script>
    </head>
    <body>
        <canvas id="myCanvas" width="500" height="200"></canvas> 
    </body>

    运行结果:

     2.绘制直线相关方法及属性

    方法:

    • beginPath():定义绘制动作的开始
    • moveTo():绘制图形的起点位置
    • lineTo():绘制图形的重点位置
    • stroke():为所画的线赋予颜色,如没有指定,默认为黑色

    属性:

    • lineWidth:直线的宽度
    • strokeStvle:直线的颜色
    • 直线端点样式:用lineCap属性设定,包括三种样式,分别为butt,round,square
    <html>
    <title></title>
    	<style type="text/css">
    		#myCanvas{
    			border: 1px solid blue;
    			background-color: #77ffcc;
    		}
    	</style>
    	<script type="text/javascript">
    		window.onload=function(){
    			var canvas=document.getElementById("myCanvas");
    			var context=canvas.getContext("2d");
    			//绘制直线
    			context.beginPath();
    			context.moveTo(50,100);
    			context.lineTo(200,100);
    			context.lineWidth=10;
    			context.strokeStyle="#ff0000";
    			context.lineCap="round";
    			context.stroke();	
    		}
    	</script>
    </head>
    <body>
        <canvas id="myCanvas" width="500" height="200"></canvas> 
    </body>
    </html>

    3.绘制弧线和曲线  

              arcTo(x1,y1,x2,y2,radius) ;包含五个参数,(x1,y1)是端点1,(x2,y2)是端点2,radius是绘制的弧线的半径,此方法就是利用第一条线的终点、端点1、端点2组成的夹角,与夹角两边相切并以radius为半径画弧线,详情实例见下面代码。

    <html>
    <title></title>
    	<style type="text/css">
    		#myCanvas{
    			border: 1px solid blue;
    			background-color: #77ffcc;
    		}
    	</style>
    	<script type="text/javascript">
    		window.onload=function(){
    			var canvas=document.getElementById("myCanvas");
    			var context=canvas.getContext("2d");
    			//绘制弧线
    			context.beginPath();
    			context.moveTo(20,20);//第一条直线的起点
    			context.lineTo(100,20);//第一条直线的终点
    			//端点1:(150,20)端点2:(150,70)b半径:50;
    			context.arcTo(150,20,150,70,50);
    			context.lineTo(150,120);//第二条线的终点
    			context.stroke();	
    		}
    	</script>
    </head>
    <body>
        <canvas id="myCanvas" width="500" height="200"></canvas> 
    </body>

    •  arcTo():创建介于两个切线之间的弧/曲线
    • quadraticCurveTo():绘制二次曲线,每条二次曲线由上下文点、一个控制点和一个终止点来定义
    <html>
    	<style type="text/css">
    		#myCanvas{
    			border: 1px solid blue;
    			background-color: #77ffcc;
    		}
    	</style>
    	<script type="text/javascript">
    		window.onload=function(){
    			var canvas=document.getElementById("myCanvas");
    			var context=canvas.getContext("2d");
    			//绘制二次贝塞尔曲线
    			context.beginPath();
    			context.moveTo(200,100);//起始点
    			context.quadraticCurveTo(288,0,388,150);
    			context.lineWidth=5;
    			context.strokeStyle="pink";
    			context.stroke();	
    		}
    	</script>
    </head>
    <body>
        <canvas id="myCanvas" width="500" height="200"></canvas> 
    </body>
    </html>

     

    • bezierCurveTo():绘制贝塞尔曲线,每条贝塞尔曲线由上下文点、两个控制点和一个终止点来确定

     

    展开全文
  • Canvas简明教程(完整源码)

    千次阅读 2017-12-25 12:06:23
    博客停更大半年,趁着圣诞更新了个人主页,顺便推一篇很乱的文章上来哈哈哈哈哈哈哈!!! 主页效果:anxpp.com原文出处:http://blog.anxpp.com/index.php/archives/1094/原文...Canvas简明教程<canvas> 是 HTML5 新
  • canvas

    2019-12-19 17:51:41
    canvas本身没有绘制能力,必须使用脚本来完成实际的绘图任务 getContext():方法返回一个对象,该对象提供了用于在画布上绘图的方法和属性 <canvas id="canvas"></canvas> // 定义一个ID名为canvas的...
  • 《HTML5游戏开发的基本流程》 * 1. HTML5的简述 * 2. HTML5游戏开发所需的环境与工具 * 2.1. 开发环境 * 2.1.1. 浏览器 * 2.1.2. 开发语言 * 2.1.3. 开发平台 * 2.2.... * 2.2.1.... * 2.2.2....
  • canvas canvas是Android中自定义绘图中特别重要的一部分,如果你想画出想要的图形,canvas操作能帮你轻松许多。 canvas.save()和canvas.restore()  这两个方法是最先应该了解的,save方法是将现在的画布状态...
  • canvas绘图工具

    万次阅读 2019-08-22 10:14:31
    关于canvas绘图,在html页面上太方便了。为什么不用SVG呢?SVG大量的操作DOM元素你会发现网页的内存一下就达到几个G非常恐怖,更别说应用到移动端了。百度取了不少经,什么画板涂鸦只是小把戏缺乏实用性,灵活性。...
  • js设置canvas的宽高(动态设置canvas的宽高)

    万次阅读 多人点赞 2016-12-05 17:14:35
    1:设置canvas的宽高 2:在js中动态创建canvas
  • Android 清除canvas内容

    万次阅读 2014-02-14 13:44:15
    画新的东西之前需要先清除画布内容: ...canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 方法2 Paint paint = new Paint(); paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR)); canvas.d
  • [Canvas系列]Canvas画布系列教程

    千次阅读 2019-03-07 20:26:42
    canvas系列[Canvas系列]Canvas基本概念_01[Canvas系列]Canvas简单线条绘制_02[Canvas系列]Canvas填充与渐变_03[Canvas系列]Canvas绘制圆弧形状_04[Canvas系列]Canvas绘制曲线之ARCTO_05[Canvas系列]Canvas绘制...
  • 有如下的代码: canvas { position:absolute; height : 100%; width : 100%; } <canvas id="canvas" width="100%" height="100%"> </canvas> <script type
  • canvas的translate()方法的理解

    万次阅读 多人点赞 2011-11-22 19:18:27
    canvas.save();//锁画布(为了保存之前的画布状态) canvas.translate(10, 10);//把当前画布的原点移到(10,10),后面的操作都以(10,10)作为参照点,默认原点为(0,0) drawScene(canvas); canvas.restore();//把...
  • html5 canvas画布居中

    万次阅读 2016-03-23 17:55:56
    今天写一个demo的时候想把canvas的画布居中,一开始代码是这样的: 如图,设置了canvas的margin:0 auto;可是显示效果并不居中,如下图: 只有黑色的边框,怎么解决呢? 给canvas一个div,让div包裹canvas,...
  • 『教程』微信小游戏开发(教程+Demo+跳坑)canvas

    万次阅读 多人点赞 2017-12-29 14:59:36
    社区里有一群canvas爱好者,比jsh5css,安静的小智,jeffer等同学他们在canvas方面都有着自己的学习心得和见解。但是极乐叔发现在小程序开发学习过程中还是有很多小伙伴折戟在canvas上,为此我们在社区首页教程内...
  • WPF之路——Canvas布局(画布)

    万次阅读 2013-11-26 19:48:34
    Canvas为容器控件,用于定位 1.基本应用 可以把Canvas比作一个坐标系,所有的元素通过设置坐标来决定其在坐标系中的位置.这个坐标系的原点并不是在中央,而是位于它的左上角.见下图 元素设置坐标的方法共有四个:  ...
  • html5中svg,canvas和图片之间的相互转化

    万次阅读 热门讨论 2013-10-18 09:35:13
    最近有个需求,需要把网页转成pdf格式,
  • HTML5 Canvas鼠标与键盘事件

    万次阅读 多人点赞 2013-07-04 14:16:52
    演示HTML5 Canvas鼠标事件,获在Canvas对象上的取鼠标坐标,演示键盘事件 通过键盘控制Canvas上对象移动。
  • Canvas与Image互相转换

    万次阅读 2013-08-09 14:48:54
    JS Canvas与Image互相转换 原文地址: JavaScript Canvas Image Conversion 原文演示: JavaScript Canvas Image Conversion Demo 原文日期:2012年05月08日 翻译日期:2013年08月09日 在上周的Mozilla ...
1 2 3 4 5 ... 20
收藏数 240,975
精华内容 96,390
关键字:

canvas