1.补充一个数组的map方法:
/*
* map方法定义在Array.prototype上,所以所有的数组都可以访问
* 语法:数组.map( 回调函数 )
* 作用:接收回调函数的返回值,共同构成一个新数组返回。
* */
var arr = [1,2,3,4,5];
var newArr = arr.map( function( val, i, arr ) {
return val * 5 - i;
});
console.log( newArr );
2.canvas是基于状态:
/*
* canvas是基于状态:
* strokeStyle = 'red';
* strokeStyle = 'blue';
* 主要strokeStyle变化了,那么接下来所有和描边相关的绘制方法都会受到影响。
* */
例如:
<canvas id="cvs" width="500" height="500"></canvas>
<script>
var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d');
ctx.strokeStyle = 'blue';
ctx.strokeRect(10,10,50,50);
// ctx.strokeStyle = 'red'; 屏蔽这一句,两个矩形框颜色都是blue,打开后第二个变为red
ctx.strokeRect(50,50,50,50);
</script>
3.在画布上画好内容后,使用toDataURL方法可把画布内容转化为base64编码格式的图片,可以尝试使用打印的内容替换canvas标签看下效果
// 把画布的内容转换为base64编码格式的图片
console.log(cvs.toDataURL( 'image/png' ));
/*·
* base64编码图片的应用:
* 如果一个网站中有少量的小图片,可以考虑直接使用base64编码。
* */
4.画弧形
最主要是理解ctx.arc中起始角度和终止角度在哪里,是顺时针还是逆时针
<canvas id="cvs" width="500" height="500"></canvas>
<script>
var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d');
/*
* 画弧( 画的是路径 )
* ctx.arc( 圆心x轴坐标,圆心y轴坐标,半径, 起点弧度,结束点弧度,是否逆时针画(可选) )
* arc方法内部会先从路径结束点到弧的起点画一条路径线。
* 起点弧度、结束点弧度以及弧度的方向共同决定了弧的大小。
* */
// 把角度转换为弧度
function angleToRadian( angle ) {
return Math.PI / 180 * angle;
}
// 顺时针画一段弧 看清楚哪里是90度 哪里是270度 顺时针哦 别搞错了!!!
ctx.arc( 100, 100, 30, angleToRadian( 90 ), angleToRadian( 270 ),false );
ctx.stroke();
// 逆时针画一段弧
ctx.beginPath();
ctx.arc( 200, 100, 30, angleToRadian( 90 ), angleToRadian( 270 ), true );
ctx.stroke();
// 一个圆
ctx.beginPath();
ctx.arc( 300, 100, 30, angleToRadian( 90 ), angleToRadian( 360 ) );
ctx.stroke();
/*
* 画扇形:
* 1、先设置路径起点为圆心
* 2、画弧
* 3、闭合路径
* */
ctx.beginPath();
ctx.moveTo( 250, 250 ); //默认是顺时针
ctx.arc( 250, 250, 90, angleToRadian( 45 ), angleToRadian( 180 ) );
ctx.closePath();
ctx.stroke();
</script>
5.求一组数中的最大值,用call和apply的方法(为下面讲解做铺垫…)
var numMax = Math.max(2,3,4,6,8,9);
// 用call方法
var num = Math.max.call(null,(2,3,4,6,8,9));
// 用apply的方法
var numArr = [2,3,4,6,8,9];
var num = Math.max.apply(null,numArr);
console.log(num);
6.在canvas上画空心字,实心字,以及各自的参考点
<canvas id="cvs" width="500" height="500"></canvas>
<script>
var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d');
/*
* 设置文字的属性
* ctx.font = 和css语法一样。
* 注意:这里设置字体大小时必须带单位,单位支持css的所有表示方式。
* 注意:单独设置字体大小不会生效,必须要加一个额外属性样式。
* */
ctx.font = '2rem 微软雅黑';
/*
* 绘制描边文字:
* ctx.strokeText( 文字, 参考x轴坐标,参考y轴坐标,限制文字的最大长度(可选) )
* */
ctx.strokeText( '我是空心字体strokeText', 100, 100 );
/*
* 绘制填充文字:
* ctx.fillText( 文字, 参考x轴坐标,参考y轴坐标,限制文字的最大长度(可选) )
* */
ctx.fillText( '我是实心字fillText', 100, 200 );
// 绘制空心文字的参考点
ctx.beginPath();
ctx.arc( 100, 100, 4, 0, Math.PI * 2 );
ctx.stroke();
// 绘制实心文字的参考点
ctx.beginPath();
ctx.arc( 100, 200, 4, 0, Math.PI * 2 );
ctx.fill();
</script>
7.canvas上字的参考点和基线共同决定了字的位置
<canvas id="cvs" width="500" height="500"></canvas>
<script>
var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d');
ctx.font = '2rem 微软雅黑';
/*
* 设置文字的水平对其方式:
* ctx.textAlign = 'left || start' 、 'right || end' 、 'center'
* 默认值为start。
* */
/*
* 设置文字的垂直对其方式:
* ctx.textBaseline = 'top' 、'bottom'、'middle'、'alphabetic'、'hanging'、'ideographic'
* 默认值为alphabetic。
* */
// 以参考点为坐标轴(0,0)画x,y轴,x轴即为基线
//textAlign表示参考点在字的哪一侧(左中右)
ctx.textAlign = 'left';
//textBaseline表示基线在字的哪一侧(上中下)
ctx.textBaseline = 'bottom';
ctx.fillText( '位置取决于参考点和基线', 100, 200 );
// 绘制文字的参考点
ctx.beginPath();
ctx.arc( 100, 200, 4, 0, Math.PI * 2 );
ctx.fill();
</script>
8.如何用正弦余弦函数来求圆上某一点的坐标?
我们在正常的坐标系中是向右为x正向,向上为y正方向,角度时逆时针转的。
在我们的画布上,角度时顺指针转的,向右是0度,是X轴正方向,垂直向下是90度,是Y轴正方法,所以公式依然适用。
假设圆心的坐标为(a,b),那么圆的方程是(x-a)^2+(y-b)^2=r^2
根据方程可以求出圆上的各点坐标,已知角度m,圆上点的坐标分别是:(r*cosm+a,r*sinm+b)
9.有了上面那么多铺垫,我们来画一个饼状图,形状如下:
pie_chart.js
(function( w ) {
// 把角度转换为弧度
function angleToRadian( angle ) {
return Math.PI / 180 * angle;
}
// 混入式继承
function extend( o1, o2 ) {
for ( var key in o2 ) {
// 只有o2自己的属性才会copy到o1身上
if ( o2.hasOwnProperty( key ) ) {
o1[ key ] = o2[ key ];
}
}
}
/*
* constrcutor { Pipe } 饼图构造函数
* param { x: number } 圆心x轴坐标
* param { y: number } 圆心y轴坐标
* param { r: number } 圆半径
* param { data: Array } 绘制饼图所需的数据
* */
function Pipe( x, y, r, data ) {
this.x = x;
this.y = y;
this.r = r;
this.data = data;
// 一组颜色
this.colors = [ 'orange', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'peru', 'pink' ];
}
// 给原型扩充方法
extend( Pipe.prototype, {
// 绘制饼图
draw: function() {
// 在外面保存一下this
var self = this;
// 数据的总和
var num = 0;
this.data.forEach( function( obj ) {
num += obj.val;
});
// 一个数据值所占用的角度
var baseAngle = 360 / num;
// 假设一开始就绘制了一个起始为0,结束为0的扇形
var startAngle = 0,
endAngle = 0,
lineAngle = 0,
lineX, lineY;
// 画扇形
this.data.forEach( function( obj, i ) {
// 每次进来,计算当前扇形的起始角度和结束角度
// 下一个扇形的起始角度,是当前扇形的结束角度
startAngle = endAngle;
// 这个结束角度 = 上一个扇形的结束角度 + 当前数值所对应的角度
endAngle = endAngle + baseAngle * obj.val;
// 求扇形中间线的角度
lineAngle = startAngle + baseAngle * obj.val / 2;
/*
* 根据中间线的角度,求中间的线的x和y坐标:
* x = 圆心x + r * Math.cos( angleToRadian( pointAngle ) )
* y = 圆心y + r * Math.sin( angleToRadian( pointAngle ) )
* */
lineX = self.x + ( self.r + 20 ) * Math.cos( angleToRadian( lineAngle ) );
lineY = self.y + ( self.r + 20 ) * Math.sin( angleToRadian( lineAngle ) );
// 画每一个扇形
ctx.beginPath();
ctx.moveTo( self.x, self.y );
ctx.arc( self.x, self.y, self.r, angleToRadian( startAngle ), angleToRadian( endAngle ) );
ctx.closePath();
ctx.fillStyle = self.colors[ i ];
ctx.fill();
// 画每一个扇形的平分线
ctx.beginPath();
ctx.moveTo( self.x, self.y );
ctx.lineTo( lineX, lineY );
ctx.strokeStyle = self.colors[ i ];
ctx.stroke();
// 绘制文字
ctx.textBaseline = 'center';
if ( lineAngle >= 90 && lineAngle <= 270 ) {
ctx.textAlign = 'right';
}else {
ctx.textAlign = 'left';
}
ctx.fillText( obj.msg, lineX, lineY );
});
}
} );
// 把构造函数暴露到全局
w.Pipe = Pipe;
}( window ));
<canvas id="cvs" width="500" height="500"></canvas>
<script src="pie_chart.js"></script>
<script>
var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d');
// [ 10, 30, 50, 60, 20 ]
var pipe = new Pipe( 200, 200, 80, [
{
val: 10,
msg: '手机震动'
},
{
val: 30,
msg: '有人在敲门'
},
{
val: 50,
msg: 'TA好像喜欢我'
},
{
val: 50,
msg: '忙完这事就轻松了'
},
{
val: 50,
msg: '这次考试还可以'
},
{
val: 90,
msg: '今晚早点睡觉'
},
] );
pipe.draw();
</script>