🌸Author Echo Pan
备忘:proto
canvas
是HTML5
提供的用于展示绘图效果的标签。
canvas
是一个矩形画布,可以用JS
绘图,它本身没有画图功能。
Echarts
、d3.js
、three.js
、higncharts
canvas
默认大小为 300px * 150px,可以自定义大小:
<canvas width="600" height="400"></canvas>
注意,canvas
可以用CSS来定义大小,区别是html中设置的是画布,而css中设置的是框架,绘图时图片会伸缩来适应该框架大小。而且当css尺寸比例和画布不一样时,图像就会扭曲拉伸。
<canvas>
起初是空白的,它公开了一个或多个渲染上下文用来绘制和处理展示的内容,我们的教学基于2D渲染上下文,其他当然还有WebGL
使用了基于OpenGL ES
的3D上下文。
脚本要先找到上下文才能绘制,canvas
提供一个getContext()
方法,用来获取渲染上下文和绘图功能。getContext()
可以接受一个参数,即上下文类型。对于2D图像而言,可以使用CanvasRenderingContext2D
接口,获取方法:
var canvas = document.getElementById('tutorial');
var ctx = canvas.getContext('2d');
<!DOCTYPE html>
<html>
<head>
<title>Canvas tutorial</title>
<script type="text/javascript">
function draw(){
var canvas = document.getElementById('tutorial');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
}
}
</script>
<style type="text/css">
canvas { border: 1px solid black; }
</style>
</head>
<body onload="draw();">
<canvas id="tutorial" width="150" height="150"></canvas>
</body>
</html>
说明:写的script
代码可以放在body
尾部,这样加载网页时会自动加载;也可以放在head
或其他任意位置,这样就需要给功能代码套一个函数function
,然后在html
标签中使用onload="函数"
或在script
中用window.onload=函数
调用。
canvas
支持绘制矩形和路径。
fillRect(x,y,width,height);//填充矩形
strokeRect(x,y,width,height);//矩形边框
clearRect(x,y,width,height);//清除矩形区域(透明),橡皮擦功能
这三个函数使用后会自动绘制,与后面的路径函数(Path function)有所区别。
如果使用的是rect()
函数的话,则需要手动设置fill
还是stroke
。
步骤:
新建一条路径,将图形绘制命令指向该路径。在绘制路径的时候,会有一个路径列表记录子路径,即一个beginPath()
下的所有路径。而当重新开始一个beginPath()
时,会清空之前保存的记录,无论是否stroke()
或者fill()
。
闭合路径,将图形绘制命令重新指向上下文。不是必需的。
该命令会尝试连接当前点和起始点,使图形闭合,如果已经是闭合图形或只有一个点则不作操作。但是该命令不会重建一条新路径,它与beginPath()
没有关系。
当调用fill()
时,未闭合形状自动闭合,但是stroke()
不会。
注意,beginPath和closePath不是必须的。
canvas里的beginPath和closePath 理解beginPath和closePath
stroke()
通过线条绘制图形轮廓,将路径列表中的子路径全部绘出。
fill()
通过填充路径内容生成实心的图形。
moveTo(x,y)
移动画笔到指定的x和y坐标上,设置路径起点。
lineTo(x,y)
绘制直线,从当前位置到x和y坐标上。
// 填充三角形
ctx.beginPath();
ctx.moveTo(25, 25);
ctx.lineTo(105, 25);
ctx.lineTo(25, 105);
ctx.fill();
// 描边三角形
ctx.beginPath();
ctx.moveTo(125, 125);
ctx.lineTo(125, 45);
ctx.lineTo(45, 125);
ctx.closePath();
ctx.stroke();
使用arc()
方法绘制圆或圆弧。
语法:
arc(x, y, radius, startAngle, endAngle <, anticlockwise>);
//x,y:确定圆心位置
//radius:半径长度
//startAngle:起点,按x轴方向算,单位弧度
//endAngle:终点
//anticlockwise:可选,true逆时针,false默认顺时针
因为采用弧度制,所以表达的时候可以这么写Math.PI*2
。
简单画个圆:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();//开始路径
ctx.arc(75, 75, 50, 0, 2 * Math.PI);//圆
ctx.stroke();//绘制路径
如果要绘制扇形,可以使用两种方法,一种是moveTo
到圆心,然后绘制圆弧,最后闭合路径;另一种方法是先画圆弧,然后lineTo
到圆心,最后闭合路径。
使用贝塞尔曲线绘制路径。语法:
//确定起始点
moveTo(x,y);
//二次贝塞尔曲线,第一个坐标为控制点,第二个坐标为结束点
quadraticCurveTo(cp1x, cp1y, x, y);
//三次贝塞尔曲线,依次为控制点1,控制点2,结束点
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
fillStyle
修改填充颜色。语法:
// 这些 fillStyle 的值均为 '橙色'
ctx.fillStyle = "orange";
ctx.fillStyle = "#FFA500";
ctx.fillStyle = "rgb(255,165,0)";
ctx.fillStyle = "rgba(255,165,0,1)";
strokeStyle
修改描边颜色,用法与fillStyle
类似。
可以通过globalAlpha
或者rgba
来设置透明度。
lineWidth
线条宽度注意当线条宽度没有完全占据像素格子时,带来的模糊渲染问题。
lineCap
线条末端样式线段末端样式,包括三种:
butt
,末端平齐,默认round
末端是为1/2线宽的半圆square
末端是高度为1/2线宽的方块lineJoin
线条与线条接合处样式线段连接处样式,拿折线举例:
miter
连接处向外延伸(尖角),默认round
磨圆连接处(圆角),圆半径等于线宽bevel
平角//起点和终点,表示一条线段,类似于PS里的渐变工具
var lg=ctx.createLinearGradient(x1,y1,x2,y2);
y1 和 y2 决定了渐变存在的范围
x1 和 x2 决定了渐变的方向
首先设置颜色样式,并把该颜色设置为当前颜色:
//addColorStop(position, color);
//position介于0.0-1.0,颜色相对位置
lg.addColorStop(0,"white");//在起始位置为白色
lg.addColorStop(0.5,"black");//在中间位置为黑色
ctx.fillStyle=lg;
注意,设置的颜色位置相对于画布是固定的,当画上图形的时候,与图形重叠部分的该颜色会显示出来。实际上,这里的画图仅相当于解除透明的作用,真正的图形是设置的颜色。
//绘出图形,图形所在区域会显示设置的渐变色
ctx.fillRect(50,50,50,50);
实际使用中存在的问题:设置的是两个坐标点,不是长宽;没有理解x和y实际决定了什么,x是方向,y是范围。
//圆1:原点+半径,圆2:原点+半径
var rg=ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
//举例
var rg=ctx.createRadialGradient(75,75,10,75,75,50);
rg.addColorStop(0,"pink");//0是圆1边缘
rg.addColorStop(0.8,"purple")//0-1之间的参数为过渡
rg.addColorStop(1,"yellow");//1是圆2边缘
ctx.fillStyle=rg;//将样式改为rg
ctx.fillRect(0,0,150,150);//显示设置的样式
setLineDash
定制虚线样式:
//指定线段与间隙,奇数位线段,偶数位间隙
ctx.setLineDash([4,2,10,6]);
lineDashOffest
设置起始偏移量,默认为0。
var ptrn=ctx.createPattern(image, type);
//image可以是image对象或者另一个canvas对象
//Type的值包括repeat,repeat-x,repeat-y,no-repeat
//例子
var img = new Image();
img.src = 'someimage.png';
var ptrn = ctx.createPattern(img,'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 150, 150);
shadowOffsetX
x轴偏移shadowOffsetY
y轴偏移shadowBlur
模糊度shadowColor
阴影颜色ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 2;
ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
ctx.fill("nonzero")
默认值,完全填充ctx.fill("evenodd")
重叠部分透明通过ctx.font=""
设置字体样式,和在css中设置类似。
其他的属性设置还包括:
textAlign
值包括start
,end
,left
,right
,center
textBaseline
值包括alphabetic
,top
,,haning
,bottom
,middle
等direction
值包括ltr
,rtl
,inherit
fillText
fillText(text,x,y[,maxWidth]);
//例子
ctx.font = "48px serif";
ctx.fillText("Hello world", 10, 50);
strokeText
strokeText(text,x,y[,maxWidth]);
measureText
var measureText=ctx.measureText('文本内容');//获取测量对象
var width=measureText.width;//获取宽度属性
关于第一次测出的宽度和第二次不一致的问题,是因为宽度是根据字体大小来计算的,需要把measureText
放到font
后面。
图片源可以是:
Image()
函数构造对象或<img>
元素<video>
元素中的一帧<canvas>
元素举例:
var img=new Image();//创建image对象,用于加载图像缓存
img.onload=function(){
context.drawImage(img,69,50);
};
img.src="image url";
drawImage(image,x,y);
//x,y是起始坐标
drawImage(image,x,y,width,height);
//width和height为缩放大小
drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHight);
//dx和dy是必须参数,绘制起始坐标
//dw和wh是绘制宽高,允许缩放图像
//sx和sy是裁切起始点(相对源而言)
//sw和sh是裁切宽高
绘制流程:前四个参数先对源图像进行裁切,然后通过后四个参数把裁切后的图像绘制在画布上,也就是说,裁切参数是相对图像源而言的,绘制参数是相对画布而言的,缩放针对的是裁切后的新图。