1、注意
- canvas只兼容 IE9 以上的浏览器
- canvas 有默认宽高 300x150
- canvas 如果用style设置宽高 会导致画布变形
- 所以通常使用行间样式 width height 来设置宽高
2、canvas绘制步骤
- 1、获取canvas标签
var canvas = document.getElementById
- 2、获取canvas工作环境(功能端口)
var ctx = canvas.getContext('2d');
- 3、开始绘制
ctx.beginPath();
- 4、设置画线的粗细(有默认值,可以不设置)
ctx.lineWidth = 5;
- 5、设置线的颜色(有默认值,默认为黑色)
ctx.strokeStyle = 'red';
- 6、确定起始点坐标
ctx.moveTo();
- 7、确定结束点坐标
ctx.lineTo();
- 8、结束绘制
ctx.closePath();
- 9、绘制图形
ctx.stroke();
3、绘制一个矩形
function Rect(width,x,y,bgcolor,line) {
this.width = width;
this.x = x;
this.y = y;
this.bgColor = bgColor;
this.line = line;
}
Rect.prototype.draw = function () {
ctx.beginPath();
//4、设置画线的粗细
ctx.lineWidth = this.line;
//5、线的颜色
ctx.strokeStyle = this.bgColor;
//6、确定起始点坐标
ctx.moveTo(this.x, this.y);
//7、结束点坐标
ctx.lineTo(this.x, this.y + this.width);
ctx.lineTo(this.x + this.width, this.y + this.width);
ctx.lineTo(this.x + this.width, this.y);
ctx.lineTo(this.x, this.y);
ctx.closePath();
//8、绘制图形
ctx.stroke();
}
//实例化
var r1 = new Rect();
r1.draw();
4、绘制一个三角形
//封装一个 三角形类
function Triangle(options) {
this.x1 = options.x1;
this.y1 = options.y1;
this.x2 = options.x2;
this.y2 = options.y2;
this.x3 = options.x3;
this.y3 = options.y3;
//线宽、颜色
this.color = options.color || '#007aff';
this.line = options.line || 2;
// this.draw();
}
Triangle.prototype.draw = function () {
ctx.beginPath();
ctx.lineWidth = this.line;
ctx.strokeStyle = this.color;
ctx.moveTo(this.x1, this.y1);
ctx.lineTo(this.x2, this.y2);
ctx.lineTo(this.x3, this.y3);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.closePath();
ctx.stroke();
}
5、绘制圆弧
- ctx.arc(x,y,r,begin,end,bool)
参数 |
参数表示的意义 |
x |
圆心 x 坐标 |
y |
圆心 y 坐标 |
r |
半径 |
begin |
起始点与0度夹角 |
end |
结束点与0度夹角 |
bool(布尔值) |
false 默认值 顺时针绘制、true 逆时针绘制 |
- 角度计算 : 1度 = Math.PI / 180
6、绘制扇形
//定义一个扇形类
function Circle(options) {
this.x = options.x;
this.y = options.y;
this.r = options.r;
//起始角度
this.begin = options.begin;
//结束
this.end = options.end;
this.color = options.color || '#007aff';
}
var deg = Math.PI / 180;
//给扇形类添加一个方法
Circle.prototype.draw = function () {
ctx.beginPath();
ctx.moveTo(this.x, this.y)
ctx.arc(this.x, this.y, this.r, this.begin * deg, this.end * deg - Math.PI / 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.lineWidth = 3;
ctx.closePath();
ctx.stroke();
}
//实例化
var y1 = new Circle({
x: 300,
y: 300,
r: 100,
begin: 0,
end: 360 * deg,
});
y1.draw();
//按照百分比绘制圆弧
function bai(n) {
n = 360 * n / 100;
var y2 = new Circle({
x: 450,
y: 450,
r: 100,
begin: -90,
end: n,
color: 'red',
});
y2.draw();
}
bai(50)
7、绘制饼状图方法
//封装饼状图
function createPie(options) {
var x = options.x;
var y = options.y;
var r = options.r;
var data = options.data;
var deg = Math.PI / 180;
//封装随机数
function randNum(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
//随机颜色
function randColor() {
var r = randNum(0, 255);
var g = randNum(0, 255);
var b = randNum(0, 255);
return `rgb(${r},${g},${b})`;
}
function Set(x, y, r, begin, end, color) {
this.x = x;
this.y = y;
this.r = r;
this.begin = begin;
this.end = end;
this.color = color || randColor();
}
Set.prototype.draw = function () {
ctx.beginPath();
ctx.moveTo(this.x, this.y)
ctx.arc(this.x, this.y, this.r, this.begin * deg, this.end * deg);
ctx.fillStyle = this.color;
ctx.fill();
ctx.lineWidth = 3;
ctx.closePath();
ctx.stroke();
}
var arr = data;
for (var i = 0; i < arr.length - 1; i++) {
var min_index = i;
for (var j = i + 1; j < arr.length; j++) {
if (arr[j].num < arr[min_index].num) {
min_index = j;
}
}
var min = arr[i];
arr[i] = arr[min_index];
arr[min_index] = min;
}
console.log(arr);
//计算总数
var sum = 0
for (var i = 0; i < arr.length; i++) {
sum += arr[i].num;
}
console.log(sum);
//计算比例
var begin = 0;
var end = 0;
for (var i = 0; i < arr.length; i++) {
end += arr[i].num / sum * 360;
console.log(end);
var s1 = new Set(400, 400, 200, begin, end);
s1.draw()
begin = end;
}
}
createPie({
x: 300,
y: 300,
r: 200,
data: [
{
type: '0-40',
num: 5,
color: "red",
},
{
type: '40-60',
num: 8,
color: "#ccc",
},
{
type: '60-80',
num: 12,
color: "blue",
},
{
type: '80-90',
num: 9,
color: "#ccc",
},
{
type: '90-100',
num: 6,
color: "blue",
},
]
})
// 计算文字 起点坐标公式
// textX= Math.cos(角度)*(半径+文字里饼状图的距离)+圆心坐标X
// textY= Math.sin(角度)*(半径+文字里饼状图的距离)+圆心坐标Y
8、绘制文字
- 1、文字字体必须设置,否则不会正常展示
ctx.font = "oblique 50px '微软雅黑'";
- 2、设置文字水平位置
ctx.textAline = 'right'
常用值 |
代表的意思 |
left |
起始点在文字的左边 |
right |
起始点在文字的右边 |
center |
起始点在文字的中间 |
- 设置文字纵向对齐方式
ctx.textBaseline = 'bottom';
常用值 |
代表的意思 |
alphabetic |
默认,根据字母基线对齐 |
top |
文字顶部对齐 |
middle |
文字中间对齐 |
bottom |
文字底部对齐 |
Hanging |
悬挂基线 |
- 3、实心文字
ctx.fillText('Hello Wold', 300, 200);
- 4、空心文字
ctx.strokeText('Hello Wold', 300, 300);
9、绘制贝塞尔曲线
- ctx.quadraticCurveTo(控制点X,控制点Y,结束点X,结束点Y)
- 绘制贝塞尔曲线需要三个点
- 第一个起始点 moveTo(起始点X,起始点Y)
- 第二个点 控制点 贝塞尔曲线的前两个参数 就是控制点的x、y
- 第三个点 结束点 贝塞尔曲线的后两个参数
//鼠标移动的方法
canvas.onmousemove = function (e) {
//获取鼠标坐标 ,将鼠标坐标点,当作贝塞尔曲线的控制点
var mx = e.offsetX;
var my = e.offsetY;
canvas.width = canvas.width;
box()
//绘制曲线
ctx.beginPath();
ctx.lineWidth = 5;
ctx.strokeStyle = '#007aff';
ctx.moveTo(400, 400);
ctx.quadraticCurveTo(mx, my, 700, 400)
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = '#000';
ctx.moveTo(400, 400);
ctx.lineTo(700, 400)
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.moveTo(400, 400);
ctx.lineTo(mx, my)
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = 'orange';
ctx.moveTo(700, 400);
ctx.lineTo(mx, my)
ctx.closePath();
ctx.stroke();
}
function box() {
//先计算需要多少格子
var num = 20;
var n = canvas.width / num;
console.log(canvas.width);
var m = canvas.height / num;
ctx.beginPath();
ctx.strokeStyle = '#ccc';
var x = 0;
var y = 0;
for (var i = 0; i < m; i++) {
for (var j = 0; j < n; j++) {
ctx.strokeRect(x, y, num, num);
x += num;
}
y += num;
x = 0;
}
ctx.stroke();
}
10、帧频率(浏览器每次渲染的频率)
- requestAnimationFrame
- 帧频率实现的原理是 递归
- 只有在展示的时候,才会执行,页面切换到后台,自动停止,降低了浏览器压力
//时间轴
var timer = 0;
function move(){
timer++
//计时器效果
requestAnimationFrame(move);
//定时器效果
if (timer == 500) {
alert('帧频率已停止')
//清除帧频率
cancelAnimationFrame(z)
}
}
move();
11、平移
- ctx.translate(x,y)
- 移动的不是画出来的图形
- 而是坐标原点 (0,0)点
- 所以每次必须 先平移后绘制
12、保存和恢复坐标原点
- 保存当前坐标系设置 存档
ctx.save();
- 移动结束之后,将移动了的坐标系 恢复
restore 永远恢复最新一次的 存档
ctx.restore();
13、旋转
function deg(n){ return n * (Math.PI / 180); }
14、绘制钟表
var ctx = canvas.getContext('2d');
canvas.width = window.innerWidth - 50;
canvas.height = window.innerHeight - 50;
//封装随机数
function randNum(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
//随机颜色
function randColor() {
var r = randNum(0, 255);
var g = randNum(0, 255);
var b = randNum(0, 255);
return `rgb(${r},${g},${b})`;
}
//封装一个钟表类
function Clock() {
this.r = 200;
//时分秒针的颜色
this.hc = randColor();
this.mc = randColor();
this.sc = randColor();
}
//度数的方法
function deg(n) {
return n * (Math.PI / 180);
}
Clock.prototype.draw = function () {
ctx.save()
ctx.beginPath();
//绘制表盘
ctx.arc(400, 300, this.r, 0, deg(360))
// ctx.arc(400, 300, 10, 0, deg(360))
ctx.lineWidth = 4;
ctx.closePath()
ctx.stroke();
//圆点
ctx.beginPath();
//绘制表盘
ctx.fillStyle = 'red';
ctx.fill();
ctx.arc(400, 300, 5, 0, deg(360))
ctx.closePath()
ctx.stroke();
//绘制刻度
var long = this.r / 6;
var middle = this.r / 9;
var short = this.r / 12;
// console.log(long,short);
//先平移坐标系 到圆点
ctx.translate(400, 300);
//绘制表盘
for (var i = 0; i < 60; i++) {
ctx.save();
ctx.rotate(deg(6 * i))
ctx.beginPath();
var l = 0;
if (i % 5 == 0 && i % 15 != 0) {
l = this.r - middle;
ctx.lineWidth = 3;
} else if (i % 15 == 0) {
l = this.r - long;
ctx.lineWidth = 4;
} else {
l = this.r - short;
ctx.lineWidth = 2;
}
ctx.moveTo(l, 0);
ctx.lineTo(this.r, 0);
ctx.closePath();
ctx.stroke()
ctx.restore()
}
//计算时分秒旋转角度
var date = new Date();
//当前系统时间 时分秒
var h = date.getHours();
var m = date.getMinutes();
var s = date.getSeconds();
var ms = date.getUTCMilliseconds();
var timer = date.getTime();
/*
1min 60000ms
1h 3600000ms
1d 86400000ms
12h 43200000ms
注意 :中国时区差八小时,所以要加上 八小时的毫秒数
*/
//加 中国时区
var h = (timer % 86400000 + 1000 * 60 * 60 * 8) * 720 / 86400000;
var m = timer % 3600000 * 360 / 3600000;
var s = timer % 60000 * 360 / 60000;
// console.log(ms);
ctx.rotate(deg(270))
//绘制时针
ctx.save();
ctx.rotate(deg(h))
ctx.beginPath();
ctx.lineWidth = 5;
ctx.strokeStyle = this.hc;
ctx.moveTo(0, 0);
ctx.lineTo(this.r / 2.5, 0);
ctx.stroke();
ctx.restore();
//绘制分针
ctx.save();
ctx.rotate(deg(m))
ctx.beginPath();
ctx.lineWidth = 4;
ctx.strokeStyle = this.mc;
ctx.moveTo(0, 0);
ctx.lineTo(this.r / 1.6, 0)
ctx.stroke()
ctx.restore();
//绘制秒针
ctx.save();
ctx.rotate(deg(s))
ctx.beginPath();
ctx.lineWidth = 2
ctx.strokeStyle = this.sc;
ctx.moveTo(0, 0);
ctx.lineTo(this.r / 1.25, 0)
ctx.stroke()
ctx.restore();
ctx.restore();
}
var c1 = new Clock();
function run(){
canvas.width = canvas.width
c1.draw();
// console.log(c1);
requestAnimationFrame(run)
}
run()
15、绘制图片
- ctx.drawImage(img,x,y,w,h);
参数 |
参数代表的意思 |
img |
DOM图片对象 |
x |
图片左上角 x 坐标 |
y |
图片左上角 y 坐标 |
w |
图片的宽 |
h |
图片的高 |
var img = new Image();
img.src = './shark1.png';
ctx.drawImage(this, x,y,w,h)
}
- 图片的裁剪
ctx.drawImage(img,cx,cy,cw,ch,x,y,w,h);
参数 |
参数代表的意思 |
img |
DOM图片对象 |
cx |
裁剪起点x |
cy |
裁剪起点y |
cw |
裁剪宽度 以原图大小为参照物 |
ch |
裁剪高度 以原图大小为参照物 |
x |
图片左上角 x 坐标 |
y |
图片左上角 y 坐标 |
w |
图片的宽 |
h |
图片的高 |
网友评论