<canvas id="tutorial" width="300" height="300"></canvas>
<canvas>你的浏览器不支持 canvas,请升级你的浏览器。</canvas>
<canvas><img src="./icon.png" alt=""></canvas>
var canvas = document.getElementById('tutorial');
//获得 2d 上下文对象
var ctx = canvas.getContext('2d');
function draw(){
let canvas = document.getElementById('tutorial');
if(!canvas.getContext) return;
let ctx = canvas.getContext("2d");
//开始代码
}
Canvas 绘制图形的基础,就是它自身的栅格 (grid) 对应着坐标空间。
Canvas 左上角的位置,坐标为 (0, 0);
fillRect:绘制一个填充的矩形。
strokeRect:绘制一个矩形的边框。
clearRect:清除指定的矩形区域。
ctx.fillRect(10, 10, 100, 50); // 绘制矩形,填充的默认颜色为黑色。
ctx.strokeRect(10, 70, 100, 50); // 绘制矩形边框
ctx.clearRect(15, 15, 50, 25); // 清除指定矩形区域
问题:ctx.clearRect 和 清空整个画布的区别?
图形的基本元素是路径。
绘制一个路径的步骤:
新建一条路径,路径一旦创建成功,图形绘制命令会被指向到路径上生成路径。
把画笔指向固定的坐标(x, y),相当于设置路径的起始点。
闭合路径后,图形绘制命令又会重新指向到上下文中。
通过线条来绘制图形轮廓。
通过填充路径的内容区域生成实心的图形。
绘制线段,从某个点绘制到当前的点(x, y)。
以(x, y) 为圆心,以r 为半径,从 startAngle 弧度开始到endAngle弧度结束。anticlosewise 是布尔值,true 表示逆时针,false 表示顺时针(默认是顺时针)。
根据给定的控制点和半径画一段圆弧,最后再以直线连接两个控制点。
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(300, 300);
ctx.stroke();
注意,stroke方法,是给边框着色。而fill方法,是给图形填充颜色。
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(200, 50);
ctx.lineTo(125, 120);
ctx.closePath();
ctx.stroke();// stroke就是绘制边框,fill就是绘制实心图形。
tips:Canvas绘制图形的时候,需要一定的数学功底。
ctx.beginPath();
ctx.arc(100, 100, 100, 0, Math.PI/2, false);
ctx.stroke();
ctx.closePath 的本质就是,就是把画笔的起点和终点连接起来。
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.arcTo(200, 50, 200, 200, 100);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(10, 200);
let cp1x = 40,cp1y = 100;// 控制点
let x = 200, y = 200;// 结束点。
ctx.quadraticCurveTo(cp1x, cp1y, x, y);
ctx.stroke();
cp1x, cp1y:控制点1的坐标。
cp2x, cp2y:控制点2的坐标。
x,y:结束点坐标。
fillStyle = color,设置图形的填充颜色。
strokeStyle = color,设置图形轮廓的颜色。
ctx.strokeStyle = 'red';
ctx.quadraticCurveTo(cp1x, cp1y, x, y);
ctx.stroke();
ctx.lineWidth
ctx.beginPath();
ctx.moveTo(10, 200);
ctx.lineTo(200, 200);
ctx.lineWidth = 10;
ctx.stroke();
ctx.lineCap
有三个值:butt(方形)、round(圆形)、square(方形、但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域)
ctx.beginPath();
ctx.moveTo(10, 200);
ctx.lineTo(200, 200);
ctx.lineWidth = 10;
ctx.lineCap = 'round';
ctx.stroke();
ctx.lineJoin
共有 3 个值 round, bevel 和 miter:
round 通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。 圆角的半径是线段的宽度。
bevel 在相连部分的末端填充一个额外的以三角形为底的区域, 每个部分都有各自独立的矩形拐角。
miter(默认) 通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。
ctx.setLineDash
setLineDash 方法接受一个数组,来指定线段与间隙的交替;
ctx.lineDashOffset
lineDashOffset属性设置起始偏移量。
ctx.setLineDash([20, 5]); // [实线长度, 间隙长度]
fillText(text, x, y [, maxWidth])
strokeText(text, x, y [, maxWidth])
ctx.lineWidth = 1;
ctx.font = "20px sans-serif";
ctx.strokeText('我是中国人', 20, 100);
let img = new Image();
img.src = 'https://www.runoob.com/wp-content/uploads/2018/12/2255709523-5b74dd8eb033e_articlex.png';
img.onload = function () {
ctx.drawImage(img, 10, 10, 200, 200);
}
绘制图片,可以放大,也可以缩小。
问?能不能做图片的等比压缩?
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
第一个参数和其它的是相同的,都是一个图像或者另一个 canvas 的引用。
前 4 个是定义图像源的切片位置和大小,后 4 个则是定义切片的目标显示位置和大小。
let img = new Image();
img.src = 'https://www.runoob.com/wp-content/uploads/2018/12/2255709523-5b74dd8eb033e_articlex.png';
img.onload = function () {
ctx.drawImage(img, 10, 10, 200, 200);
ctx.drawImage(img, 10, 10, 200, 200, 220, 220, 200, 200);
}
Canvas 在绘制的过程中,如果我们想保存某个状态的绘图,使用 save() 方法。
如果想恢复到上一个状态,可以使用 restore() 方法。
save() 方法,把 Canvas 的状态,存入一个栈中。类似数组的 push() 方法。
restore() 方法,把存入到栈中的 Canvas 状态释放出来。类似数组的 pop() 方法。
一个绘画状态包括:
let canvas = document.getElementById('myCanvas');
let ctx = canvas.getContext('2d');
ctx.fillRect(10, 10, 100, 100);
ctx.save();
// save 保存的是fillStyle状态的值。
ctx.fillStyle = 'red';
ctx.fillRect(120, 10, 100, 100);
ctx.save();
ctx.restore(); // fillStyle = 'red';
ctx.fillRect(330, 10, 100, 100);
ctx.restore(); // fillStyle = 默认值;
ctx.fillRect(330, 120, 100, 100);
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
旋转的中心是坐标原点。
ctx.translate(250, 250);
ctx.rotate(Math.PI/180 * 45);
ctx.fillStyle = 'red';
ctx.scale(2, 2);
ctx.fillRect(0, 0, 100, 100);
表示缩放,x代表x轴上的缩放比例,y代表y轴上的缩放比例。
ctx.translate(250, 250);
ctx.rotate(Math.PI/180 * 45);
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 100, 100);
ctx.scale(2, 2);
ctx.strokeRect(0, 0, 100, 100);
globalCompositeOperation:表示合成,有以下几个值:
source-over,这是默认设置,新图像会覆盖在原有图像。
source-in,仅仅会出现新图像与原来图像重叠的部分,其他区域都变成透明的。(包括其他的老图像区域也会透明)
source-out,仅仅显示新图像与老图像没有重叠的部分,其余部分全部透明。(老图像也不显示)
source-atop,新图像仅仅显示与老图像重叠区域。老图像仍然可以显示。
destination-over,新图像会在老图像的下面。
destination-in,仅仅新老图像重叠部分的老图像被显示,其他区域全部透明。
lighter,新老图像都显示,但是重叠区域的颜色做加处理。
darken,保留重叠部分最黑的像素。(每个颜色位进行比较,得到最小的)
lighten,保证重叠部分最量的像素。(每个颜色位进行比较,得到最大的)
xor,重叠部分会变成透明。
copy,只有新图像会被保留,其余的全部被清除(边透明)
ctx.fillRect(0, 0, 200, 200);
ctx.globalCompositeOperation = "source-over"; //全局合成操作
ctx.fillStyle = "red";
ctx.fillRect(100, 100, 200, 200);
clip()
把已经创建的路径转换成裁剪路径。
裁剪路径的作用是遮罩。只显示裁剪路径内的区域,裁剪路径外的区域会被隐藏。
动画在Canvas中的本质,就是不断的重新绘制。
setInterval
setTimeout
requestAnimationFrame
原生的实现方式:
let canvas = document.getElementById('myCanvas');
let ctx = canvas.getContext('2d');
canvas.width = 140;
canvas.height = 140;
ctx.fillStyle = "pink";
ctx.fillRect(20, 20, 100,100);
let imageUrl = canvas.toDataURL('image/png');
img.src = imageUrl;
另外,Canvas2image,是一个把 Canvas 转化为 img 的库。
html2canvas,是一个把HTML网页,转化为Canvas的js库。
import html2canvas from 'html2canvas';
import canvas2image from 'canvas2image';
let box = document.getElementById("box"); //生成的DOM元素
var img = document.getElementById("img"); //需要展示的图片
//生成canvas
html2canvas(box).then(function(canvas) {
//生成图片
let url = canvas2image.saveAsPNG(canvas,true).getAttribute('src');
img.src = url;
});
当前业界比较流行的使用场景