canvas 最早由Apple引入WebKit,用于Mac OS X 的 Dashboard,后来又在Safari和Google Chrome被实现。 基于 Gecko 1.8的浏览器,比如 Firefox 1.5, 同样支持这个元素。 <canvas> 元素是WhatWG Web applications 1.0规范的一部分,也包含于HTML 5中。
canvas初体验:
<!--1.准备画布-->
<!--1.1 画布是白色的 而且默认300*150-->
<!--1.2 设置画布的大小---------最好在标签里设置,在样式表设置会变粗(相当于将画布拉伸至设置的宽高度) -->
<canvas width="600" height="400" ></canvas>
<!--2.准备绘制工具-->
<!--3.利用工具绘图-->
<script>
/*1.获取元素*/
var myCanvas = document.querySelector('canvas');
/*2.获取上下文 绘制工具箱---这里称为画笔 */
/*是否有3d? 暂时没有*/
var ctx = myCanvas.getContext('2d'); /*web gl(一种网页3D技术) 绘制3d效果的网页技术*/
/*3.移动画笔*/
ctx.moveTo(100,100);
/*4.绘制直线 (轨迹,绘制路径)*/
ctx.lineTo(200,100);
/*5.描边*/
ctx.stroke();
</script>
/*关于线条的问题*/ | |
/*1.默认的宽度是多少 1px*/ 效果是2px | |
/*2.默认的颜色是什么 黑色*/ 效果是灰色 | |
/*产生原因 对齐的点是线的中心位置 会把线分成两个0.5px 显示的是会不饱和增加宽度*/ | |
/*解决方案 前后移动0.5px */ |
修改画笔描边颜色、宽度:
ctx.strokeStyle = 'blue';
ctx.lineWidth = 10;
为画笔开启新路径(新的画笔-----默认的画笔样式):为画笔设置新的样式需要用到这个方法
ctx.beginPath();
关闭新路径(画笔自动封闭-------将未封闭的开口给封闭上)
ctx.closePath();
描边和填充:(产生效果必选其一)
/*1.描边*/
ctx.stroke();
/*2.填充*/
ctx.fill();
修改填充颜色:
ctx.fillStyle = 'red';
颜色填充规则:非零环绕填充规则
设置画笔样式:
-
lineWidth 线宽,默认1px
-
lineCap 线末端类型:(butt默认)、round(末端为半圆)、square
-
lineJoin 相交线的拐点 miter(默认)、round(拐角为圆弧)、bevel
-
strokeStyle 线的颜色
-
fillStyle 填充颜色
-
setLineDash([n, m, ...]) 设置虚线(虚线长度为npx,mpx。。。。)
-
getLineDash() 获取虚线宽度集合
-
lineDashOffset 设置虚线偏移量(负值向右偏移)
面向对象的方式绘制折线图:
<canvas width="600" height="400"></canvas>
<script>
/*1.构造函数*/
var LineChart = function (ctx) {
/*获取绘图工具*/
this.ctx = ctx || document.querySelector('canvas').getContext('2d');
/*画布的大小*/
this.canvasWidth = this.ctx.canvas.width;
this.canvasHeight = this.ctx.canvas.height;
/*网格的大小*/
this.gridSize = 10;
/*坐标系的间距*/
this.space = 20;
/*坐标原点*/
this.x0 = this.space;
this.y0 = this.canvasHeight - this.space;
/*箭头的大小*/
this.arrowSize = 10;
/*绘制点*/
this.dottedSize = 6;
/*点的坐标 和数据有关系 数据可视化*/
}
/*2.行为方法*/
LineChart.prototype.init = function (data) {
this.drawGrid();
this.drawAxis();
this.drawDotted(data);
};
/*绘制网格*/
LineChart.prototype.drawGrid = function () {
/*x方向的线*/
var xLineTotal = Math.floor(this.canvasHeight / this.gridSize);
this.ctx.strokeStyle = '#eee';
for (var i = 0; i <= xLineTotal; i++) {
this.ctx.beginPath();
this.ctx.moveTo(0, i * this.gridSize - 0.5);
this.ctx.lineTo(this.canvasWidth, i * this.gridSize - 0.5);
this.ctx.stroke();
}
/*y方向的线*/
var yLineTotal = Math.floor(this.canvasWidth / this.gridSize);
for (var i = 0; i <= yLineTotal; i++) {
this.ctx.beginPath();
this.ctx.moveTo(i * this.gridSize - 0.5, 0);
this.ctx.lineTo(i * this.gridSize - 0.5, this.canvasHeight);
this.ctx.stroke();
}
};
/*绘制坐标系*/
LineChart.prototype.drawAxis = function () {
/*X轴*/
this.ctx.beginPath();
this.ctx.strokeStyle = '#000';
this.ctx.moveTo(this.x0, this.y0);
this.ctx.lineTo(this.canvasWidth - this.space, this.y0);
this.ctx.lineTo(this.canvasWidth - this.space - this.arrowSize, this.y0 + this.arrowSize / 2);
this.ctx.lineTo(this.canvasWidth - this.space - this.arrowSize, this.y0 - this.arrowSize / 2);
this.ctx.lineTo(this.canvasWidth - this.space, this.y0);
this.ctx.stroke();
this.ctx.fill();
/*Y轴*/
this.ctx.beginPath();
this.ctx.strokeStyle = '#000';
this.ctx.moveTo(this.x0, this.y0);
this.ctx.lineTo(this.space, this.space);
this.ctx.lineTo(this.space + this.arrowSize / 2, this.space + this.arrowSize);
this.ctx.lineTo(this.space - this.arrowSize / 2, this.space + this.arrowSize);
this.ctx.lineTo(this.space, this.space);
this.ctx.stroke();
this.ctx.fill();
};
/*绘制所有点*/
LineChart.prototype.drawDotted = function (data) {
/*1.数据的坐标 需要转换 canvas坐标*/
/*2.再进行点的绘制*/
/*3.把线连起来*/
var that = this;
/*记录当前坐标*/
var prevCanvasX = 0;
var prevCanvasY = 0;
data.forEach(function (item, i) {
/* x = 原点的坐标 + 数据的坐标 */
/* y = 原点的坐标 - 数据的坐标 */
var canvasX = that.x0 + item.x;
var canvasY = that.y0 - item.y;
/*绘制点*/
that.ctx.beginPath();
that.ctx.moveTo(canvasX - that.dottedSize / 2, canvasY - that.dottedSize / 2);
that.ctx.lineTo(canvasX + that.dottedSize / 2, canvasY - that.dottedSize / 2);
that.ctx.lineTo(canvasX + that.dottedSize / 2, canvasY + that.dottedSize / 2);
that.ctx.lineTo(canvasX - that.dottedSize / 2, canvasY + that.dottedSize / 2);
that.ctx.closePath();
that.ctx.fill();
/*点的连线*/
/*当时第一个点的时候 起点是 x0 y0*/
/*当时不是第一个点的时候 起点是 上一个点*/
if(i == 0){
that.ctx.beginPath();
that.ctx.moveTo(that.x0,that.y0);
that.ctx.lineTo(canvasX,canvasY);
that.ctx.stroke();
}else{
/*上一个点*/
that.ctx.beginPath();
that.ctx.moveTo(prevCanvasX,prevCanvasY);
that.ctx.lineTo(canvasX,canvasY);
that.ctx.stroke();
}
/*记录当前的坐标,下一次要用*/
prevCanvasX = canvasX;
prevCanvasY = canvasY;
});
};
/*3.初始化*/
var data = [
{
x: 100,
y: 120
},
{
x: 200,
y: 160
},
{
x: 300,
y: 240
},
{
x: 400,
y: 120
},
{
x: 500,
y: 80
}
];
var lineChart = new LineChart();
lineChart.init(data);
</script>
进阶:
不使用API,使用数学方程来绘制图:
<canvas width="600" height="400"></canvas>
<script>
var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');
/*1.体验曲线的绘制*/
/*2.线是由点构成的*/
/*3.曲线可以由数学公式得来*/
/*公式:y = x/2 */
/*公式:y = (x + 2) ^2 */
/*公式:y = sin(x) */
for(var i = 1 ; i < 600 ; i ++){
var x = i;
//var y = x/2;
//var y = Math.pow(x/10-30,2);
var y = 50*Math.sin(x/10) + 100;
ctx.lineTo(x,y);
}
ctx.stroke();
</script>
线性渐变
var linearGradient = ctx.createLinearGradient(100,100,500,400);
linearGradient.addColorStop(0,'pink');
//linearGradient.addColorStop(0.5,'red');
linearGradient.addColorStop(1,'blue');
ctx.fillStyle = linearGradient;
ctx.fillRect(100,100,400,100);
/*pink---->blue*/
/*回想线性渐变---->要素 方向 起始颜色 结束颜色 */
/*通过两个点的坐标可以控制 渐变方向*/
矩形绘制
-
rect(x,y,w,h) 没有独立路径
-
strokeRect(x,y,w,h) 有独立路径,不影响别的绘制
-
fillRect(x,y,w,h) 有独立路径,不影响别的绘制
-
clearRect(x,y,w,h) 擦除矩形区域
圆弧绘制
-
弧度概念
-
arc()
-
x 圆心横坐标
-
y 圆心纵坐标
-
r 半径
-
startAngle 开始角度
-
endAngle 结束角度
-
anticlockwise 是否逆时针方向绘制(默认false表示顺时针;true表示逆时针)
-
<canvas width="600" height="400"></canvas>
<script>
var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');
/*绘制圆弧*/
/*确定圆心 坐标 x y*/
/*确定圆半径 r */
/*确定起始绘制的位置和结束绘制的位置 确定弧的长度和位置 startAngle endAngle 弧度*/
/*取得绘制的方向 direction 默认是顺时针 false 逆时针 true */
/*在中心位置画一个半径150px的圆弧左下角*/
var w = ctx.canvas.width;
var h = ctx.canvas.height;
ctx.arc(w/2,h/2,150,Math.PI/2,Math.PI,true);
ctx.stroke();
</script>
绘制文本
-
ctx.font = '微软雅黑' 设置字体
-
strokeText()
-
fillText(text,x,y,maxWidth)
-
text 要绘制的文本
-
x,y 文本绘制的坐标(文本左下角)
-
maxWidth 设置文本最大宽度,可选参数
-
-
ctx.textAlign文本水平对齐方式,相对绘制坐标来说的
-
left
-
center
-
right
-
start 默认
-
end
-
-
ctx.direction属性css(rtl ltr) start和end于此相关
-
如果是ltr,start和left表现一致
-
如果是rtl,start和right表现一致
-
-
ctx.textBaseline 设置基线(垂直对齐方式 )
-
top 文本的基线处于文本的正上方,并且有一段距离
-
middle 文本的基线处于文本的正中间
-
bottom 文本的基线处于文本的证下方,并且有一段距离
-
hanging 文本的基线处于文本的正上方,并且和文本粘合
-
alphabetic 默认值,基线处于文本的下方,并且穿过文字
-
ideographic 和bottom相似,但是不一样
-
-
measureText() 获取文本宽度obj.width
想想饼图如何绘制----------------------------------------------------------------------------------------------
综合案例:绘制饼状图
<canvas width="600" height="400"></canvas>
<script>
/*var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');*/
/*1.绘制饼状态图*/
/*1.1 根据数据绘制一个饼图*/
/*1.2 绘制标题 从扇形的弧中心伸出一条线在画一条横线在横线的上面写上文字标题*/
/*1.3 在画布的左上角 绘制说明 一个和扇形一样颜色的矩形 旁边就是文字说明*/
var PieChart = function (ctx) {
/*绘制工具*/
this.ctx = ctx || document.querySelector('canvas').getContext('2d');
/*绘制饼图的中心*/
this.w = this.ctx.canvas.width;
this.h = this.ctx.canvas.height;
/*圆心*/
this.x0 = this.w / 2 + 60;
this.y0 = this.h / 2;
/*半径*/
this.radius = 150;
/*伸出去的线的长度*/
this.outLine = 20;
/*说明的矩形大小*/
this.rectW = 30;
this.rectH = 16;
this.space = 20;
}
PieChart.prototype.init = function (data) {
/*1.准备数据*/
this.drawPie(data);
};
PieChart.prototype.drawPie = function (data) {
var that = this;
/*1.转化弧度*/
var angleList = this.transformAngle(data);
/*2.绘制饼图*/
var startAngle = 0;
angleList.forEach(function (item, i) {
/*当前的结束弧度要等于下一次的起始弧度*/
var endAngle = startAngle + item.angle;
that.ctx.beginPath();
that.ctx.moveTo(that.x0, that.y0);
that.ctx.arc(that.x0, that.y0, that.radius, startAngle, endAngle);
var color = that.ctx.fillStyle = that.getRandomColor();
that.ctx.fill();
/*下一次要使用当前的这一次的结束角度*/
/*绘制标题*/
that.drawTitle(startAngle, item.angle, color , item.title);
/*绘制说明*/
that.drawDesc(i,item.title);
startAngle = endAngle;
});
};
PieChart.prototype.drawTitle = function (startAngle, angle ,color , title) {
/*1.确定伸出去的线 通过圆心点 通过伸出去的点 确定这个线*/
/*2.确定伸出去的点 需要确定伸出去的线的长度*/
/*3.固定伸出去的线的长度*/
/*4.计算这个点的坐标*/
/*5.需要根据角度和斜边的长度*/
/*5.1 使用弧度 当前扇形的起始弧度 + 对应的弧度的一半 */
/*5.2 半径+伸出去的长度 */
/*5.3 outX = x0 + cos(angle) * ( r + outLine)*/
/*5.3 outY = y0 + sin(angle) * ( r + outLine)*/
/*斜边*/
var edge = this.radius + this.outLine;
/*x轴方向的直角边*/
var edgeX = Math.cos(startAngle + angle / 2) * edge;
/*y轴方向的直角边*/
var edgeY = Math.sin(startAngle + angle / 2) * edge;
/*计算出去的点坐标*/
var outX = this.x0 + edgeX;
var outY = this.y0 + edgeY;
this.ctx.beginPath();
this.ctx.moveTo(this.x0, this.y0);
this.ctx.lineTo(outX, outY);
this.ctx.strokeStyle = color;
/*画文字和下划线*/
/*线的方向怎么判断 伸出去的点在X0的左边 线的方向就是左边*/
/*线的方向怎么判断 伸出去的点在X0的右边 线的方向就是右边*/
/*结束的点坐标 和文字大小*/
this.ctx.font = '14px Microsoft YaHei';
var textWidth = this.ctx.measureText(title).width ;
if(outX > this.x0){
/*右*/
this.ctx.lineTo(outX + textWidth,outY);
this.ctx.textAlign = 'left';
}else{
/*左*/
this.ctx.lineTo(outX - textWidth,outY);
this.ctx.textAlign = 'right';
}
this.ctx.stroke();
this.ctx.textBaseline = 'bottom';
this.ctx.fillText(title,outX,outY);
};
PieChart.prototype.drawDesc = function (index,title) {
/*绘制说明*/
/*矩形的大小*/
/*距离上和左边的间距*/
/*矩形之间的间距*/
this.ctx.fillRect(this.space,this.space + index * (this.rectH + 10),this.rectW,this.rectH);
/*绘制文字*/
this.ctx.beginPath();
this.ctx.textAlign = 'left';
this.ctx.textBaseline = 'top';
this.ctx.font = '12px Microsoft YaHei';
this.ctx.fillText(title,this.space + this.rectW + 10 , this.space + index * (this.rectH + 10));
};
PieChart.prototype.transformAngle = function (data) {
/*返回的数据内容包含弧度的*/
var total = 0;
data.forEach(function (item, i) {
total += item.num;
});
/*计算弧度 并且追加到当前的对象内容*/
data.forEach(function (item, i) {
var angle = item.num / total * Math.PI * 2;
item.angle = angle;
});
return data;
};
PieChart.prototype.getRandomColor = function () {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
return 'rgb(' + r + ',' + g + ',' + b + ')';
};
var data = [
{
title: '15-20岁',
num: 6
},
{
title: '20-25岁',
num: 30
},
{
title: '25-30岁',
num: 10
},
{
title: '30以上',
num: 8
}
];
var pieChart = new PieChart();
pieChart.init(data);
</script>
做动画
绘制图片
-
drawImage()
-
三个参数drawImage(img,x,y)
-
img 图片对象、canvas对象、video对象
-
x,y 图片绘制的左上角
-
-
五个参数drawImage(img,x,y,w,h)
-
img 图片对象、canvas对象、video对象
-
x,y 图片绘制的左上角
-
w,h 图片绘制尺寸设置(图片缩放,不是截取)
-
-
九个参数drawImage(img,x,y,w,h,x1,y1,w1,h1)
-
img 图片对象、canvas对象、video对象
-
x,y,w,h 图片中的一个矩形区域
-
x1,y1,w1,h1 画布中的一个矩形区域
-
-
序列帧动画
-
绘制精灵图
-
动起来
-
控制边界
-
键盘控制
案例:行走的Boss:
<canvas width="600" height="400"></canvas>
<script>
var Person = function (ctx) {
/*绘制工具*/
this.ctx = ctx || document.querySelector('canvas').getContext('2d');
/*图片路径*/
this.src = 'image/04.png';
/*画布的大小*/
this.canvasWidth = this.ctx.canvas.width;
this.canvasHeight = this.ctx.canvas.height;
/*行走相关参数*/
this.stepSzie = 10;
/* 0 前 1 左 2 右 3 后 和图片的行数包含的图片对应上*/
this.direction = 0;
/*x轴方向的偏移步数*/
this.stepX = 0;
/*y轴方向的偏移步数*/
this.stepY = 0;
/*初始化方法*/
this.init();
};
Person.prototype.init = function () {
var that = this;
/*1.加载图片*/
this.loadImage(function (image) {
/*图片的大小*/
that.imageWidth = image.width;
that.imageHeight = image.height;
/*人物的大小*/
that.personWidth = that.imageWidth / 4;
that.personHeight = that.imageHeight / 4;
/*绘制图片的起点*/
that.x0 = that.canvasWidth / 2 - that.personWidth / 2;
that.y0 = that.canvasHeight / 2 - that.personHeight / 2;
/*2.默认绘制在中心位置正面朝外*/
that.ctx.drawImage(image,
0,0,
that.personWidth,that.personHeight,
that.x0,that.y0,
that.personWidth,that.personHeight);
/*3.能通过方向键去控制人物行走*/
that.index = 0;
document.onkeydown = function (e) {
if(e.keyCode == 40){
that.direction = 0;
that.stepY ++;
that.drawImage(image);
/*前*/
}else if(e.keyCode == 37){
that.direction = 1;
that.stepX --;
that.drawImage(image);
/*左*/
}else if(e.keyCode == 39){
that.direction = 2;
that.stepX ++;
that.drawImage(image);
/*右*/
}else if(e.keyCode == 38){
that.direction = 3;
that.stepY --;
that.drawImage(image);
/*后*/
}
}
});
}
/*加载图片*/
Person.prototype.loadImage = function (callback) {
var image = new Image();
image.onload = function () {
callback && callback(image);
};
image.src = this.src;
};
/*绘制图片*/
Person.prototype.drawImage = function (image) {
this.index ++;
/*清除画布*/
this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight);
/*绘图*/
/*在精灵图上的定位 x 索引*/
/*在精灵图上的定位 y 方向*/
this.ctx.drawImage(image,
this.index * this.personWidth,this.direction * this.personHeight,
this.personWidth,this.personHeight,
this.x0 + this.stepX * this.stepSzie ,this.y0 + this.stepY * this.stepSzie,
this.personWidth,this.personHeight);
/*如果索引超出了 变成0*/
if(this.index >= 3){
this.index = 0;
}
};
new Person();
</script>
坐标变换
-
平移 移动画布的原点
-
translate(x,y) 参数表示移动目标点的坐标(将坐标原点移动至(x, y))
-
-
缩放
-
scale(x,y) 参数表示宽高的缩放比例(坐标轴的缩放,x轴,y轴)
-
-
旋转
-
rotate(angle) 参数表示旋转角度(画布旋转)
-