canvas 2D绘图

熟悉html5的程序员们肯定都知道<canvas>元素,该元素是用来在页面中规定一块区域,然后由js在该区域内绘制图形。canvas支持2D绘图和名为WebGL的3D绘图。

<canvas>元素用法

<canvas id="draw" width="300" height="300">Your browser can't support canvas tag</canvas>

<canvas>元素需要通过width和height属性指定绘图区域大小。且标签中间的内容在浏览器不支持<canvas>元素时会显示。

JS绘图

要在这块画布上绘图,首先要通过getContext()方法取得绘图上下文。参数为“2d”,就可以取得2D上下文对象。

var myDraw = document.getElementById("draw");
if(myDraw.getContext) {
    var context = myDraw.getContext("2d");
    //更多代码
}

2D上下文的坐标原点(0,0)是<canvas>元素的左上角。x值越大表示越靠右,y值越大表示越靠下。

canvas画布坐标轴

2D上下文中两种基本绘图操作为填充和描边,可以通过fillStyle属性设置填充样式,通过strokeStyle属性设置描边样式,这两个属性的值可以是字符串、渐变对象或模式对象,默认值为“#000000”。如果为它们指定表示颜色的字符串值,可以使用CSS中指定颜色值的任何格式。

var myDraw = document.getElementById("draw");
if(myDraw.getContext) {
    var context = myDraw.getContext("2d");
    context.fillStyle = "#eeeeee";
    context.strokeStyle = "yellow";
}

渐变对象和模式对象,后面会讨论。
2D上下文可以绘制简单的2D图形,如矩形、路径和文本等。

绘制矩形

矩形是唯一一种可以直接在2D上下文中绘制的形状。与矩形有关的方法包括:fillRect()strokeRect()clearRect()。这三个方法都能接受4个参数:矩形左上角的X坐标、矩形左上角的Y坐标、矩形的宽度和矩形的高度。fillRect()方法填充指定矩形区域。填充的样式通过属性fillStyle设置。

var canvas = document.getElementById("draw");
if(canvas.getContext) {
    var context = canvas.getContext("2d");
    context.fillStyle = "#f361ee";
    context.fillRect(50, 50, 100, 100);
    context.fillStyle = "rgba(0, 0, 255, 0.5)";
    context.fillRect(100, 100, 100, 100);
}

fillRect()示例图

strokeRect()方法为指定的矩形描边,用法类似于fillRect(),且描边样式通过strokeStyle属性定义。clearRect()方法用于清除画布上的矩形区域,会将指定区域变透明。基于fillRect()的示例,在增加一行代码,便会产生有意思的效果。

context.clearRect(110, 110, 30, 30);
clearRect()示例图
绘制路径

2D上下文支持很多在画布上绘制路径的方法,通过这些路径可以创造出复杂的形状和线条。在绘制路径之前,首先必须调用beginPath()方法,表示要开始绘制新路径。绘制路径的方法包括:

  • arc(x, y, radius, startAngle, endAngle, counterclockwise),以(x, y)为圆心绘制一条弧线,radius表示弧形半径,startAngle和endAngle分别表示开始角度和结束角度,counterclockwise表示是否逆时针,值为false时表示顺时针;
  • arcTo(x1, y1, x2, y2, radius), 从上一点开始以给定的radius为半径绘制一条弧线,终点为(x2, y2),且穿过(x1, y1);
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y), 从上一点看是绘制一条曲线,到(x, y)为止,且(c1x, c1y) 和( c2x, c2y)为控制点;
  • lineTo(x, y) 从上一点开始绘制一条到(x, y)的直线;
  • moveTo(x, y) 将绘图游标移动到(x, y),不画线;
  • quadraticCurveTo(cx, cy, x, y) 从上一点开始绘制一条二次曲线, 到(x, y)为止,并且以(cx, cy)作为控制点;
  • rect(x, y, width, height) 从点(x, y)开始绘制一个矩形,宽度和高度分别由width和height指定。这个方法绘制的是矩形路径,而不是strokeRect()和fillRect()所绘制的形状;
    如果想绘制一条连接到起始点的路径,可以调用closePath()来形成封闭路径。如果想用fillStyle填充它,可调用fill()方法,也可调用stroke()方法对路径进行描边,描边样式有strokeStyle属性指定。
var canvas = document.getElementById("myCanvas");
if(canvas.getContext) {
    var context = canvas.getContext("2d");

    context.beginPath();

    context.arc(150, 150, 100, 0, 2 * Math.PI, false);

    context.moveTo(240, 150);
    context.arc(150, 150, 90, 0, 2 * Math.PI, false);

    context.moveTo(150, 150);
    context.lineTo(150, 80);

    context.moveTo(150, 150);
    context.lineTo(200, 150);

    context.stroke();
}
绘制文本

绘制文本主要有两个方法: fillText()strokeText()。这两个方法都能接受4个参数:要绘制的文本字符串、x坐标、y坐标和可选的最大像素宽度。文本的样式通过下面的属性指定:

  • font: 表示文本样式、大小及字体;
  • textAlign:表示文本对其方式;
  • textBaseline:表示文本的基线;
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 150, 70);

绘制文本示例

由于绘制文本比较复杂,特别是需要把文本控制在某一区域中时,2D上下文提供了辅助确定文本大小的方法measureText()。这个方法接受一个参数,即要绘制的文本,返回一个TextMetric对象,该对象有width属性。

绘制图像

2D上下文还支持绘制图像,可以调用drawImage()方法将一幅图像绘制到画布上。可使用下面3中方式调用drawImage()方法。

  • 绘制整个图像,且绘制到画布上的图像与原图像大小一致,需要传入的参数为:要绘制的图像,开始位置的x和y坐标。
    var image = document.images[0];
    context.drawImage(image, 10, 10)
  • 绘制整个图像,且用户定义绘制到画布上的图像尺寸,在上一种情况的基础上,再多传入两个参数,即绘制后图像的宽度和高度。
context.drawImage(image, 50, 10, 20, 30)
  • 绘制图像的指定区域到画布上,且用户定义绘制到画布上图像的大小,这种情况需要传入9个参数,分别为要绘制的图像、源图像的x坐标、源图像的y坐标、源图像的宽度、源图像的高度、目标图像的x坐标、目标图像的y坐标、目标图像的宽度、目标图像的高度。
context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60)

即从image图像上选取以(0, 10)为起点,长宽分别为50的矩形区域,并将这块区域的图像绘制到画布上,绘制后的图形的起点为(0, 100), 宽度为40, 长度为60。
也可以将另一个<canvas>元素作为drawImage()方法的第一个参数。

渐变和模式

前面提到,fillStylestrokeStyle的值可为渐变对象和模式对象。渐变分为两种:线性渐变和径向渐变。
可使用createLinearGradient()方法创建线性渐变,接收4个参数:起点的x坐标、起点的y坐标、终点的x坐标、终点的y坐标,并返回CanvasGradient对象的实例。它会创建一个指定大小的渐变。
创建渐变对象后,下一步就是调用渐变对象的addColorStop()方法指定渐变开始的颜色和渐变终止的颜色,色标位置的一个0到1之间的数字。

var gradient = context.createLinearGradient(50, 50, 250, 250);
gradient.addColorStop(0, "white");
gradient.addColorStop(0.5, "red");
gradient.addColorStop(1, "black");
context.fillStyle = gradient;
context.fillRect(50, 50, 200, 200);

使用渐变进行填充

可是使用createRadialGradient()方法创建径向渐变,该方法接受6个参数,前三个参数分别表示起点圆的圆心坐标和半径,后三个参数分别表示终点圆的圆心坐标和半径。

var gradient = context.createRadialGradient(150, 150, 50, 150, 150, 120);
gradient.addColorStop(0, "white");
gradient.addColorStop(0.5, "red");
gradient.addColorStop(1, "black");
context.fillStyle = gradient;
context.fillRect(30, 30, 240, 240);
径向渐变填充示例图

模式其实就是以何种方式重复图像,可使用createPattern()方法创建模式,参数为图像元素和表示图像重复方式的字符串,包括"repeat"、"repeat-x"、"repeat-y"和"no-repeat"。

阴影

2D上下文支持为图形或者路径设置阴影,涉及的属性值:

  • shadowColor:阴影颜色,默认为黑色;
  • shadowOffsetX:阴影在x轴方向的偏移量,默认为0;
  • shadowOffsetY:阴影在Y轴方向的偏移量,默认为0;
  • shadowBlur:模糊的像素数,默认为0,即不模糊;
context.shadowColor = "#000";
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 10;
context.fillStyle = "rgb(0, 0, 255)";
context.fillRect(100, 100, 100, 100);
阴影效果图

变换

2D绘制上下文支持各种基本的绘制变换,可旋转、缩放、移动坐标原点等,包括:

  • rotate(angle): 围绕原点旋转图像angle度。
  • scale(scaleX, scaleY):缩放图像,在x轴方向上缩放scaleX倍,在y轴方向上缩放scaleY倍。scaleX和scaleY默认值都是1.0;
  • translate(x, y):将坐标原点移动到(x, y);
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy):使用如下矩阵进行变换
m1_1     m1_2     dx
m2_1     m2_2     dy
0        0        1
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):现将变换矩阵设置为默认状态,然后再调用transform();
    以前面绘制表盘为例:
var canvas = document.getElementById("myCanvas");
if(canvas.getContext) {
    var context = canvas.getContext("2d");

    context.beginPath();

    context.arc(150, 150, 100, 0, 2 * Math.PI, false);

    context.moveTo(240, 150);
    context.arc(150, 150, 90, 0, 2 * Math.PI, false);

    context.translate(150, 150);

    context.moveTo(0, 0);
    context.lineTo(0, -70);

    context.moveTo(0, 0);
    context.lineTo(50, 0);

    context.stroke();
}

在进行重新设置填充、描边或变换后,如果想使用之前的某组属性与变换组合,可以在重置之前调用save()方法将这组属性和变换保存。有一个栈结构来保存这些记录,为先进后出。如果想回到之前保存的设置时,可以调用restore()方法。

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

推荐阅读更多精彩内容

  • 一:canvas简介 1.1什么是canvas? ①:canvas是HTML5提供的一种新标签 ②:HTML5 ...
    GreenHand1阅读 4,679评论 2 32
  • --绘图与滤镜全面解析 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益...
    韩七夏阅读 2,720评论 2 10
  • 本章内容 理解 元素 绘制简单的 2D 图形 使用 WebGL 绘制 3D 图形 这个元素负责在页面中设定一个区域...
    闷油瓶小张阅读 845评论 0 0
  • 一、canvas简介 1.1 什么是canvas?(了解) 是HTML5提供的一种新标签 Canvas是一个矩形区...
    Looog阅读 3,941评论 3 40
  • 科技发展到今天,我们再也不需要通过信件互通信息,而邮票也变成了一种收藏的艺术品。可你知道邮票是怎么来的吗? 发明邮...
    Easen的卡片写作人生阅读 374评论 2 1