五分钟学会 Canvas 基础(二)

请各位读者添加一下作者的微信公众号,以后有新的文章,将在微信公众号直接推送给各位,非常感谢。


0. 前言

相信各位小伙伴读了之前的文章,对 Canvas 基础已经有了一定的认识和了解,但是大家也一定记得我在上一篇文章留了一个小的坑。

就是我没有告诉大家该如何去绘制圆,之所以没有说是因为绘制圆实际上是因为 CanvasRenderingContext2D 对象只提供了两个绘制矩形的方法,并没有直接提供绘制圆,椭圆等几何图形的方法。为了在 Canvas 上绘制更复杂的方法,必须在 Canvas 上启用路径,借用路径来绘制图形。

那么我们现在就一起来看一看,该如何使用路径来绘制圆等图形吧。

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

下一篇文章预告, canvas 的各种图像特效。

另外,接下来一段时间,小编要享受一下假期,暂时不会给各位读者老爷更新啦,希望各位老爷耐心等待。

1.使用路径

在 Canvas 上使用路径,可按照下面的步骤进行。

  1. 调用 CanvasRenderingContext2D 对象的 beginPath()方法开始定义路径。
  2. 调用CanvasRenderingContext2D 的各种方法添加子路径。
  3. 调用CanvasRenderingContext2D 的 closePath 方法关闭路径。
  4. 调用CanvasRenderingContext2D 的fill()或 stroke()方法来填充路径或者绘制路径边框。

那我们明确了该如何去进行应该怎么去使用路径,那么我们接下来就来介绍一下 canvas 中添加子路径的方法。

- -
arc(float x,float y,float radius,float startAngle,float endAngle,boolean counterclockwise) 向 canvas 的当前路径上添加一段弧。绘制以 x , y 为圆心,radius 为半径,从 startAngle 角度开始,到 endAngle 角度结束的圆弧。startAngle 和 endAngle 以角度为单位。
arcTo(float x1,float x2,float y1,float y2,float radius) 向 canvas 的当前路径上添加一段弧。与上一个方法不同的地方只是定义弧的方式不同。
bezierCurveTo(float cpX1, float cpY1, float cpX2, float cpY2, float x, float y) 在当前路径上添加一段贝塞尔曲线
quadraticCurveTo(float cpX, float cpY,float x,float y) 向 canvas 当前路径添加一段二次贝塞尔曲线
rect(float x, float y,float width, float height) 向 canvas 的当前路径上添加一个矩形

方法就这些,但是参数就显得非常多了,咱们来一条条的来看看这些方法的具体使用吧。

1.1 绘制圆

首先我们来学习下如何绘制圆,首先明确,我们应该去使用 arc ( ) 方法,那么我们该如何去使用这个方法呢?

咱们,放“码”过来。

<!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");

    // 我们多去绘制几个圆形,使用下 for 循环
    for(var i = 0; i < 10 ; i++){
        // 开始定义路径
        ctx.beginPath();
        // 添加一段圆弧
        ctx.arc(i * 25,i * 25,(i + 1) * 8, 0, Math.PI * 2, true);
        // 关闭路径
        ctx.closePath();
        // 设置填充颜色
        ctx.fillStyle = 'rgba(255,0,255,'+ (10 - i) * 0.1 + ')';
        // 填充当前路径
        ctx.fill();
    }
</script>
</html>

最后实现效果如下:

Paste_Image.png

不知道小伙伴们是否看懂了上面的程序呢?

如果没看懂也无所谓,咱们就来一起说一说上面内容中的难点。

首先说一下,Math.PI 实际上指代的就是 π,换而言之也就是 180°,那么我们上面使用的角度是 Math.PI * 2,也就是绘制了一个圆形。

之后再说一下 arc(float x,float y,float radius,float startAngle,float endAngle,boolean counterclockwise)这个方法。

里面一共有 6 个参数,这六个参数实际上对应的是:

- -
float x 指定圆弧的圆心的 X 坐标
float y 指定圆弧的圆心的 Y 坐标
float radius 指定圆弧的半径
float startAngle 设置圆弧的开始角度
float endAngle 设置圆弧的结束角度
boolean counterclockwise 设置是否顺时针旋转

这样不知道大家对我们绘制圆是否清楚明白了呢?

如果有任何疑问请及时留言回复呦。

1.2 绘制圆角矩形

我们之前已经学习过绘制圆形,也学习过绘制矩形,甚至我们也可以通过 lineJoin 去对我们的元素的圆角去进行修改。

但是,固定的东西我们不需要,我们真正需要的是可以自定义,可以根据我们想要的效果能够随意订制的内容。

为了做到这个目的,我们还可以去使用 arcTo 来去绘制一段圆弧。

<!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">
    /*
        该方法负责绘制圆角矩形
        x1 , y2 : 圆角矩形左上角的坐标
        width,height:控制圆角矩形的宽度和高度
        radius:控制圆角矩形的四个圆角的半径
    */

    function creatRoundRect(ctx, x1, y1, width, height, radius){
        // 移动到左上角的开始点
        ctx.moveTo(x1 + radius, y1);
        // 添加一条连接开始点到右上角的线段
        ctx.lineTo(x1 + width - radius, y1);
        // 添加右上角的一段圆弧
        ctx.arcTo(x1 + width, y1, x1 + width, y1 + radius, radius);
        // 添加一条连接到右下角的线段
        ctx.lineTo(x1 + width, y1 + height - radius);
        // 添加右下角的一段圆弧
        ctx.arcTo(x1 + width, y1 + height, x1 + width - radius, y1 + height, radius);
        // 添加一条由右下角连接到左下角的线段
        ctx.lineTo(x1 + radius, y1 + height);
        // 添加左下的圆弧
        ctx.arcTo(x1, y1 + height, x1, y1 + height - radius,radius);
        // 添加一条由左下角连接到左上角的线段
        ctx.lineTo(x1, y1 + radius);
        // 添加一段圆弧
        ctx.arcTo(x1, y1, x1 + radius, y1, radius);
        ctx.closePath();
    }
    // 获取 canvas 元素对应的 DOM 对象
    var canvas_1 = document.getElementById("canvas_1");

    // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
    var ctx = canvas_1.getContext("2d");

    ctx.lineWidth = 3;
    creatRoundRect(ctx, 30, 30, 200, 100, 20);
    ctx.stroke();
</script>
</html>

注意,我在这里分别绘制了四条线和四个弧度角,并且让他们首尾相连,以此来达到绘制矩形框的作用。

其次就是专门去封装了一个函数,用于绘制圆角矩形,回头有需要的小伙伴可以直接自行粘贴呦。

Paste_Image.png

1.3 绘制多角形

不知道大家对之前绘制三角形是否还记得?

我们在绘制三角形的时候,主要是去使用 lineTo 和 moveTo 这两个方法,可是我们在生活中遇到的图形远远不止这么几种图形。

那么我们今天就来学习一下如何去绘制多角形。

<!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">
    /*
        该方法用于绘制多角形
            n:该参数通常设置为奇数,控制绘制 N 角星
            dx、dy:控制 N 角星的位置
            size:控制 N 角星的大小
    */
    function creatStar(context, n, dx, dy, size){
        // 开始创建路径
        context.beginPath();
        var dig = Math.PI / n * 4;
        context.moveTo(dx, y + dy);
        for(var i = 0; i <= n; i++){
            var x = Math.sin(i * dig);
            var y = Math.cos(i * dig);
            // 绘制从当前点连接到指定点的线条
            context.lineTo(x * size + dx, y * size + dy);
        }
        // 关闭路径
        context.closePath();
    }

    // 获取 canvas 元素对应的 DOM 对象
    var canvas_1 = document.getElementById("canvas_1");

    // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
    var ctx = canvas_1.getContext("2d");

    // 绘制三角星
    creatStar(ctx, 3, 60, 60, 50);
    ctx.fillStyle = '#f00';
    ctx.fill();
    // 绘制五角星
    creatStar(ctx, 5, 160, 60, 50);
    ctx.fillStyle = '#0f0';
    ctx.fill();
    // 绘制七角星
    creatStar(ctx, 7, 260, 60, 50);
    ctx.fillStyle = '#00f';
    ctx.fill();
    // 绘制九角星
    creatStar(ctx, 9, 360, 60, 50);
    ctx.fillStyle = '#f0f';
    ctx.fill();
</script>
</html>

可以看到我们又去封装了一个方法,专门用于绘制多角星,当然我们也可以在这个基础之上去继续拓展,这些就需要看小伙伴们的发挥啦。

Paste_Image.png

1.4 绘制曲线

还记得我们在一开始的时候我们学习了五个方法,除了现在已经学习的绘制圆和绘制圆角矩形,是不是还有一些奇奇怪怪的方法?

那么我们现在就开始来学习这些方法。

首先先来学习一下,添加贝塞尔曲线。

- -
bezierCurveTo(float cpX1, float cpY1, float cpX2, float cpY2, float x, float y) 在当前路径上添加一段贝塞尔曲线
quadraticCurveTo(float cpX, float cpY,float x,float y) 向 canvas 当前路径添加一段二次贝塞尔曲线

首先来看看第一个方法,第一个方法中实际上有四个点需要注意。

Paste_Image.png

他们分别是

  • 左下角的开始点
  • 粉红色的第一个控制点(锚点)
  • 藏青色的第二个控制点(锚点)
  • 右上角的结束点

而方法中 cpX1 和 cpY1 则是控制第一个控制点的坐标,

后面的 cpX2 和 cpY2 则是控制第二个控制点的坐标。

而二次贝塞尔曲线又是怎么回事呢?

Paste_Image.png

和正常贝塞尔不同,二次曲线只需要三个点:

  • 左下角的开始点
  • 藏青色的控制点
  • 右上角的结束点

方法中的 cpX 和 cpY 则是去设置控制点的坐标。

那么我们来一起试一试,该如何去绘制一个个花朵。

<!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">
    /*
        该方法负责绘制花朵
            n:该参数控制花朵的花瓣数
            dx,dy:控制花朵的位置
            size:控制花朵的大小
            length:控制花瓣的长度
    */
    function creatFlower(context, n, dx, dy, size, length){
        // 开始创建路径
        context.beginPath();
        context.moveTo(dx, dy + size);
        var dig = 2 * Math.PI / n;
        for(var i = 1; i < n + 1; i++){
            // 计算控制点的坐标
            var ctrlX = Math.sin((i - 0.5) * dig) * length + dx;
            var ctrlY = Math.cos((i - 0.5) * dig) * length + dy;
            // 计算结束点的坐标
            var x = Math.sin(i * dig) * size + dx;
            var y = Math.cos(i * dig) * size + dy;
            // 绘制二次曲线
            context.quadraticCurveTo(ctrlX, ctrlY, x, y);
        }
        context.closePath();
    }
    // 获取 canvas 元素对应的 DOM 对象
    var canvas_1 = document.getElementById("canvas_1");
    // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
    var ctx = canvas_1.getContext("2d");
    // 绘制五瓣的花朵
    creatFlower(ctx, 5, 70, 100, 30, 80);
    ctx.fillStyle = "#f00";
    ctx.fill();
    // 绘制六瓣的花朵
    creatFlower(ctx, 6, 220, 100, 30, 80);
    ctx.fillStyle = "#ff0";
    ctx.fill();
    // 绘制七瓣的花朵
    creatFlower(ctx, 7, 370, 100, 30, 80);
    ctx.fillStyle = "#f0f";
    ctx.fill();
</script>
</html>
Paste_Image.png

1.5 绘制位图

一直到现在我们讲了如何去绘制线,三角形,多角星,矩形,圆,花朵,圆角矩形等各种图形。

但是除了这些基础图形之外,我们还可以去绘制“位图”,让一张图片绘制在我们的画布之上。

那我们怎么来做呢?

我们既然想将我们的图片载入到我们的画布中,怎么做呢?我们先来差混构建一个 Image 对象。

var image = new Image();
image.src = "lipeng.png";

需要注意两点,

  • 我们的程序只是创建,加载图片,所以调用 image 时无需传入宽度和高度,这样创建的 image 将会与 src 属性指定的图片保持相同的宽度和高度。
  • src 加载图片是进行异步加载,如果图片数据太大,或者直接来自于网络,当我们网速较慢的时候,会发现我们的图片绘制会非常慢,导致影响用户使用。我们可以使用 onload 去保证我们一定是在图片加载完成后再绘制。
var image = new Image();
image.src = "lipeng.png";
image.onload =  function(){
  //绘制图片
}

学习了如何去加载图片,我们就可以向我们的画布中添加图片了么?

没有方法你怎么去添加图片呀,魂淡。

我们还要学习添加图片的方法,这里跟大家说三种方法。

- -
drawImage(Image image, float x, float y) 把 image 绘制在 x, y 处。该方法不会对图片做任何缩放处理,绘制处理的图片保持原来的大小
drawImage(Image image, float x, float y, float width, float height) 把 image 绘制在 x, y 处。该方法会对图片进行缩放,绘制出来的宽度为 width,高度为 height。
drawImage(Image image, integer sx, integer sy, integer sw, integer sh, float dx, float dy,float dw, float dh) 该方法将会从 image 上“挖出”一块绘制到画布上。其中 sx, sy 两个参数控制从原图片上的哪一个位置开始挖去, sw, sh 两个参数控制从原图片挖球的宽度和高度;dx, dy 两个参数控制把挖取的图片绘制到画布上的哪个位置,而 dw, dh 则控制对绘制图片进行缩放,绘制出来的宽度是 dw, 高度 dh

我们知道了方法,那就来一起学习下,该如何用代码来实现吧。

<!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");

    // 创建 image 对象
    var image = new Image();
    // 创建 image 对象装载图片
    image.src = "lipeng.png";
    // 当图片加载完成后触发该函数
    image.onload = function(){
        // 保持原大小绘制图片
        ctx.drawImage(image, 20, 10);
        // 绘制图片的时候进行缩放
        ctx.drawImage(image, 600, 10, 76, 110);
        // 从原图中挖去一块,放大三倍后绘制在 canvas 上
        var sd = 50;
        var sh = 50;
        /*
        参数说明
            Image image, integer sx, integer sy, integer sw, integer sh, float dx, float dy,float dw, float dh

            sx, sy 两个参数控制从原图片上的哪一个位置开始挖去,
            sw, sh 两个参数控制从原图片挖球的宽度和高度;
            dx, dy 两个参数控制把挖取的图片绘制到画布上的哪个位置,而
            dw, dh 则控制对绘制图片进行缩放,绘制出来的宽度是 dw, 高度 dh
        */
        ctx.drawImage(image, 230, 220,sd, sh, 765, 10, sd * 3, sh * 3);
    }
</script>
</html>

结果如下:

Paste_Image.png

怎么样,是不是觉得瞬间高大上了呢?赶快学起来啦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容

  • 一:canvas简介 1.1什么是canvas? ①:canvas是HTML5提供的一种新标签 ②:HTML5 ...
    GreenHand1阅读 4,598评论 2 32
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,472评论 25 707
  • 前言 自定义View是Android开发者必须了解的基础;而Canvas类的使用在自定义View绘制中发挥着非常重...
    Carson带你学安卓阅读 27,020评论 7 218
  • (简书-打赏)美篇打赏入袋里,昨晚没眠看简书。点点看看乱翻看,看见打赏二百六。默默勤耕不理事,点点耕耘树艺成。人生...
    甘朝武阅读 446评论 0 0
  • 开一个“果书”:有健康的果蔬汁;营养的简装书;一个信箱可以收取你的烦恼,它们也会得到用心的反馈;男店主热爱音乐,每...
    小小小小小猴子阅读 108评论 0 0