使用
要使用<canvas>
元素,必须先设置其width
和height
属性,指定可以绘图的区域大小。开始和结束标签中的内容是后备信息,如果浏览器不支持<canvas>
元素,就会显示这些信息。使用toDataURL()
方法,可以导出在<canvas>
元素上绘制的图像。这个方法接受一个参数,即图像的MIME
类型格式
<canvas id="drawing" width=" 200" height="200">A drawing of something.</canvas>
<script>
var drawing = document.getElementById("drawing");
//确定浏览器支持<canvas>元素
if (drawing.getContext){
// 取得2D上下文对象
var context = drawing.getContext("2d");
//取得图像的数据URI
var imgURI = drawing.toDataURL("image/png");
//显示图像
var image = document.createElement("img");
image.src = imgURI;
document.body.appendChild(image);
}
</script>
绘制
1. 填充和描边
//确定浏览器支持<canvas>元素
if (drawing.getContext){
var context = drawing.getContext("2d");
context.strokeStyle = "red"; // 描边
context.fillStyle = "#0000ff"; // 填充
}
之后所有涉及描边和填充的操作都将使用这两个样式,直至重新设置这两个值。这两个属性的值也可以是渐变对象或模式对象。上下文对象还有以下属性来设置描边线条样式,lineWidth
设置线宽;lineCap
控制线条末端形状,("butt"
平头、"round"
圆头或"square"
方头);lineJoin
控制相交方式样式("round"
圆交、"bevel"
斜交或"miter"
斜接)
2. 绘制矩形
fillRect()
、strokeRect()
和clearRect()
。这三个方法都能接收4个参数:矩形的x坐标、矩形的y坐标、矩形宽度和矩形高度。这些参数的单位都是像素。
if (drawing.getContext){
var context = drawing.getContext("2d");
//绘制红色填充矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制半透明的蓝色描边矩形
context.strokeStyle = "rgba(0,0,255,0.5)"; // 也可以使用 rgb ,hsl ,hsla
context.strokeRect(30, 30, 50, 50);
}
clearRect()
方法用于清除画布上的矩形区域。
3. 绘制路径
要绘制路径,首先必须调用beginPath()
方法,表示要开始绘制新路径。然后,再通过调用下列方法来实际地绘制路径。
arc(x, y, r, sAngle, eAngle, counterclockwise)
:画圆;xy
圆心坐标、半径、开始弧度、结束弧度、是否逆时针(false
为顺时针,可选)-
arcTo(x1, y1, x2, y2, radius)
:从上一点开始绘制一条弧线,到(x2,y2)
为止,并且以给定的半径radius
穿过(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)
:这个方法绘制的是矩形路径,而不是strokeRect()
和fillRect()
所绘制的独立的形状。
创建路径后,如果是绘制连接路径起点的条线,可以调用closePath()
;也可以调用fill()
方法进行路径填充(应用fillStyle
样式);也可以调用stroke()
方法进行路径描边(应用strokeStyle
样式),也可以调用clip()
方法在路径上创建一个剪切区域。
var drawing = document.getElementById("drawing");
//确定浏览器支持<canvas>元素
if (drawing.getContext){
var context = drawing.getContext("2d");
//开始路径
context.beginPath();
//绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
//绘制内圆 移动到内圆圆边上,以免产生不必要的线条
// moveTo 只移动游标,不画线。
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
//绘制分针
context.moveTo(100, 100);
context.lineTo(100, 15);
//绘制时针
context.moveTo(100, 100);
context.lineTo(35, 100);
//描边路径
context.stroke();
}
4. 绘制文本
fillText()
和strokeText()
,这两个方法都可以接收4个参数:要绘制的文本字符串、x坐标
、y坐标
和可选的最大像素宽度(也就是文本的最大像素宽度,调用时如果传入的字符串大于最大宽度,则绘制的文本字符的高度正确,但宽度会收缩以适应最大宽度)。这两个方法都以下列3个属性为基础且3个属性都有默认值。
-
font
:表示文本样式、大小及字体;默认值"10px sans-serif"
。context.font = "bold 14px Arial";
-
textAlign
:表示文本对齐方式。可能的值有"start"
、"end"
、"left"
、"right"
和"center"
。建议使用"start"
和"end"
,不要使用"left"
和"right"
,因为前两者的意思更稳。默认值"start"
-
textBaseline
:表示文本的基线。可能的值有"top"
、"hanging"
、"middle"
、"alphabetic"
、"ideographic"
和"bottom"
。默认值"alphabetic"
其中关于textAlign
属性,设置为center
,则以参数坐标画与y
轴的平行线,以该线作为字体分布的中间线;设置为start
则是以该线作为文本左端的位置。关于textBaseline
,设置为top
,则以参数坐标画与x轴的平行线,以该线作为字体分布的顶端;设置为alphabetic
,则是以该线作为字母书写线。
measureText()
方法利用font
、textAlign
和textBaseline
的当前值计算指定文本的大小。这个方法接收一个参数,即要绘制的文本,返回绘制完该文本需要多大的width
值。
// 假设你想在一个140 像素宽的矩形区域中绘制文本Hello world!
var fontSize = 100;
context.font = fontSize + "px Arial";
while(context.measureText("Hello world!").width > 140){
fontSize-=2;
context.font = fontSize + "px Arial";
}
// 以100px递减 直到找到合适的fontSize绘制文本以适配140px
5. 变换
rotate(angle)
:围绕原点(0,0)
旋转图像angle
弧度。scale(scaleX, scaleY)
:缩放图像,在x
方向乘以scaleX
,在y
方向乘以scaleY
。scaleX
和scaleY
的默认值都是1.0
。translate(x, y)
:将坐标原点移动到(x,y)
。执行这个变换之后,坐标(0,0)
会变成之前由(x,y)
表示的点。transform(a, b, c, d, e, f)
:修改变换矩阵,a,d
代表缩放的值,默认为1
;e,f
代表平移的值,默认为0
;b,c
代表倾斜的值,默认为0
。即默认``transform(1, 0, 0, 1, 0, 0)`
// 如果第一个正方形要旋转45°并且放大两倍,位移到(100,100)
var context = drawing.getContext("2d");
var deg = Math.PI/180;
context.fillRect(200,0,50,50)
// 变化前的正方形显示在(200,0),宽高50
ctx.setTransform(1,0,0,1,0,0);
ctx.beginPath();
context.transform(2,0,0,2,0,0);
context.transform(Math.cos(45*deg),Math.sin(45*deg),-Math.sin(45*deg),Math.cos(45*deg),100,100);
ctx.fillRect(200,0,50,50);
// 变换后的正方形 宽高100,与x轴平行线相交45度 ,左上角坐标(300,100)
// 或者直接context.transform(2*Math.cos(deg*45),2*Math.sin(deg*45),-2*Math.sin(deg*45),2*Math.cos(deg*45),0,0);
// 记忆点CS-SC
-
setTransform(a, b, c, d, e, f)
:将变换矩阵重置为默认状态,然后再调用transform()
。
无论是刚才执行的变换,还是fillStyle
、strokeStyle
等属性,都会在当前上下文中一直有效,除非再对上下文进行什么修改。可以调用save()
方法保存当时的样式设置,这个设置都会进入一个栈结构,得以妥善保管。然后可以对上下文进行其他修改。等想要回到之前保存的设置时,可以调用restore(
)方法,在保存设置的栈结构中向前返回一级,恢复之前的状态。连续调用save()
可以把更多设置保存到栈结构中,之后再连续调用restore()
则可以一级一级返回。
context.fillStyle = "red";
context.save();
context.fillStyle = "green";
context.translate(100, 100);
context.save();
context.fillStyle = "blue";
// 执行此行代码之前 100,100 green。
// 执行时平移已经完成 执行后只修改了颜色 所以变成 100,100 blue
context.fillRect(0, 0, 100, 200);
//从点(100,100)开始绘制蓝色矩形
context.restore();
// 这次释放 blue被保存的green 替换 。变成100,100 green
context.fillRect(10, 10, 100, 200);
//从点(110,110)开始绘制绿色矩形
context.restore();
// 这次释放 变换就被取消了 释放之后 100,100,green 变成 red
context.fillRect(0, 0, 100, 200); //从点(0,0)开始绘制红色矩形
save()
方法保存的只是对绘图上下文的设置和变换,不会保存绘图上下文的内容。
6. 绘制图像
如果你想把一幅图像绘制到画布上,可以使用drawImage()
方法,该可以使用三种不同的参数组合。
var image = document.images[0];
context.drawImage(image, 10, 10);
// img元素 绘制图像的起点坐标 (与图片大小一致)
context.drawImage(image, 50, 10, 20, 30);
// img元素 绘制图像的起点坐标 目标宽高 (大小取决于后两个参数)
context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60);
// img元素 源图片-->坐标x,y,width,height, 画在哪-->坐标,宽高
// 可以理解为(从源图片的哪一点作为左上角截出一个多大的矩形画在画布的哪一点 以多大的宽高展示)
第一个参数除了能穿img
元素外,也可以传另一个canvas
元素,这样就可以把另一个画布内容绘制到当前画布上。
对画布的操作结果,可以使用canvas
对象的toDataURL()
方法获得,但是图片不能来自其他域,否则会抛出错误。
7.阴影
2D 上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。
-
shadowColor
:用CSS
颜色格式表示的阴影颜色,默认为黑色。 -
shadowOffsetX
:形状或路径x
轴方向的阴影偏移量,默认为0。 -
shadowOffsetY
:形状或路径y
轴方向的阴影偏移量,默认为0。 -
shadowBlur
:模糊的像素数,默认0,即不模糊。
var context = drawing.getContext("2d");
//设置阴影
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = "rgba(0, 0, 0, 0.5)";
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制蓝色矩形
context.fillStyle = "rgba(0,0,255,1)";
context.fillRect(30, 30, 50, 50);
// 红上蓝下 拥有相同的阴影
8.渐变
createLinearGradient()
创建线性渐变,接收4 个参数:起点的x 坐标、起点的y 坐标、终点的x 坐标、终点的y 坐标。创建了渐变对象后,下一步就是使用addColorStop()
方法来指定色标。这个方法接收两个参数:色标位置和CSS
颜色值。色标位置是一个0(开始的颜色)到1(结束的颜色)之间的数字。
var gradient = context.createLinearGradient(30, 30, 70, 70);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
// 连线两点:(30,30)和(70,70),以此为对角线取一个矩形范围,从white到black开始渐变
// 然后就可以把fillStyle 或strokeStyle 设置为这个对象,从而使用渐变来绘制形状或描边:
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制渐变矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);
// 渐变的范围在x轴30~70,y轴30~70组成的矩形
// 所以绘制渐变矩形的起点坐标 所以要看到全部的渐变效果 绘制的起点坐标要设置为(30,30)
确保渐变与形状对齐非常重要,有时候可以考虑使用函数来确保坐标合适。
function createRectLinearGradient(context, x, y, width, height){
return context.createLinearGradient(x, y, x+width, y+height);
}
// 此时只需要考虑在画布的哪个地方创建一个多大的范围的渐变就可以了
// 显示全部渐变范围的终点坐标已经被计算出来
createRadialGradient()
创建径向渐变。这个方法接收6 个参数,对应着两个圆的圆心和半径。如果想从某个形状的中心点开始创建一个向外扩散的径向渐变效果,就要将两个圆定义为同心圆。如果把一个圆形开口定义得比另一个小很多,那这个圆桶就变成了圆锥
体,而通过移动每个圆形开口的位置,就可达到像旋转这个圆锥体一样的效果。
var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制渐变矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);
9.模式
模式其实就是重复的图像, 可以用来填充或描边图形。要创建一个新模式, 可以调用createPattern()
方法并传入两个参数:一个HTML <img>
元素和一个表示如何重复图像的字符串。其中,第二个参数的值与CSS
的background-repeat
属性值相同,包括"repeat"
、"repeat-x"
、"repeat-y"
和"no-repeat"
。
var image = document.images[0],
pattern = context.createPattern(image, "repeat");
//绘制矩形
context.fillStyle = pattern;
context.fillRect(10, 10, 150, 150);
模式与渐变一样,都是从画布的原点(0,0)
开始的。将填充样式(fillStyle
)设置为模式对象。即图片在画布上,从画布的原点(0,0)
开始平铺的重复,调用fillRect(10, 10, 150, 150)
,相当于在坐标(10,10)
处开了一个150
宽高的视口去看到被平铺的图像,实际上重复是发生在整个画布上的。
10.使用图像数据
可以通过getImageData()
取得画布原始图像数据。这个方法接收4个参数:要取得其数据的画面区域的x 和y 坐标以及该区域的像素宽度和高度。
var imageData = context.getImageData(10, 5, 50, 50);
这里返回的对象是ImageData
的实例。每个ImageData
对象都有三个属性:width
、height
和data
。其中data
属性是一个数组,保存着图像中每一个像素的数据。(数组的每4项都代表1px
的rgba
四个值,这些值都是0~255
之间,这些值也可以被修改)
11. 合成
-
globalAlpha
和globalCompositionOperation
globalAlpha
是一个介于0 和1 之间的值(包括0 和1),用于指定所有绘制的透明度。默认值为0。context.globalAlpha = 0.5;
globalCompositionOperation
表示后绘制的图形怎样与先绘制的图形结合。
-
source-over
(默认值):后绘制的图形位于先绘制的图形上方。 -
source-in
:后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明。 -
source-out
:后绘制的图形与先绘制的图形不重叠的部分可见,先绘制的图形完全透明。 -
source-atop
:后绘制的图形与先绘制的图形重叠的部分可见,先绘制图形不受影响。 -
destination-over
:后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见。 -
destination-in
:后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明。 -
destination-out
:后绘制的图形擦除与先绘制的图形重叠的部分。 -
destination-atop
:后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明。 -
lighter
:后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮。 -
copy
:后绘制的图形完全替代与之重叠的先绘制图形。 -
xor
:后绘制的图形与先绘制的图形重叠的部分执行“异或”操作。