今日目标:
(1)使用Canvas绘制路径和图像 —— 重点&难点
(2)使用第三方绘图工具 —— Chart.js,掌握
1.使用Canvas绘制路径(Path)
提示:Canvas中的路径概念与Photoshop中钢笔工具类似的。路径本身是不可见的,有三个用途:描边、填充(闭合)、裁剪(闭合)
Canavs中与路径绘制相关方法:
ctx.beginPath() //开始一条新路径
ctx.closePath() //闭合路径,让最后一个锚点自动连接到第一个锚点
ctx.moveTo(x, y) //移动到指定点
ctx.lineTo(x,y) //从当前点到指定点绘制直线路径
ctx.arc() //绘制拱形路径
ctx.ellipse() //绘制椭圆路径
ctx.bezierCurveTo() //绘制贝塞尔曲线路径
----------------------------------------------
ctx.stroke()
ctx.fill()
ctx.clip()
练习:
(1)使用直线路径绘制坐标轴
<body>
<canvas id="c3" width="600" height="400"></canvas>
<script>
var ctx = c3.getContext('2d');
//绘制x轴
ctx.beginPath();
ctx.moveTo(50,350);//坐标轴原点
ctx.lineTo(550,350);//最右侧点
ctx.lineTo(550-20,350-20);
ctx.lineTo(550,350);//最右侧点
ctx.lineTo(550-20,350+20);
ctx.lineWidth = 5;
ctx.strokeStyle = '#a00';
//ctx.lineJoin = 'bevel';//修改折线拐点处的样式 斜面
ctx.lineJoin = 'round';//修改折线拐点处的样式 圆角
//ctx.lineJoin = 'miter';//修改折线拐点处的样式 尖角
ctx.stroke();
//绘制Y轴
ctx.beginPath();//注意此处
ctx.moveTo(50-20,50+20);
ctx.lineTo(50,50);
ctx.lineTo(50+50,50+20);
ctx.moveTo(50,50);
ctx.lineTo(50,350);
ctx.strokeStyle = '#0f0';
ctx.stroke();
</script>
</body>
(2)使用圆拱+定时器绘制可以前进的进度条
<body>
<h3>绘制路径——圆拱</h3>
<canvas id="c3" width="600" height="400"></canvas>
<script>
var ctx = c3.getContext('2d');
//绘制灰色的圆环
ctx.beginPath();
ctx.arc(300,200,100, 0, 2*Math.PI);
ctx.strokeStyle = '#aaa';
ctx.lineWidth = 15;
ctx.stroke();
//绘制变色的进度环
var start = -Math.PI/2;
var deg = 0; //进度环前进的角度
var timer = setInterval(function(){
ctx.beginPath(); //注意此处!
deg += 5;
ctx.arc(300,200,100,start, start+deg*Math.PI/180);
ctx.strokeStyle = '#f00';
ctx.stroke();
},100);
</script>
</body>
(3)创建一个函数:openMouth(),在画布上绘制如下的图形:
(4)创建一个函数:closeMouth(),在画布上绘制如下的图形:
(5)使用定时器,不停的调用openMouth()和closeMouth()
<style>
body {
text-align: center;
}
canvas {
background: #f0f0f0;
}
</style>
</head>
<body>
<h3>绘制路径——圆拱</h3>
<canvas id="c3" width="600" height="400"></canvas>
<script>
var ctx = c3.getContext('2d');
//openMouth();
//吃豆人张嘴
function openMouth(){
//外围轮廓:半圆环 + 斜线到圆心 + 闭合
ctx.beginPath();
ctx.arc(300,200,100,Math.PI/4, 7*Math.PI/4);
ctx.lineTo(300,200);
ctx.closePath();
ctx.fillStyle = '#fea';
ctx.fill();
ctx.stroke();
//眼睛的外框
ctx.beginPath();
ctx.arc(300,150,25, 0, 2*Math.PI);
ctx.stroke();
ctx.fillStyle = '#38f';
ctx.fill();
//两个眼神光
ctx.beginPath();
ctx.arc(315, 140, 5, 0, 2*Math.PI);
ctx.arc(305, 130, 3, 0, 2*Math.PI);
ctx.fillStyle = '#fff';
ctx.fill();
}
//closeMouth();
//吃豆人闭嘴
function closeMouth(){
//外围轮廓:圆环 + 直线到圆心
ctx.beginPath();
ctx.arc(300,200,100,0, 2*Math.PI);
ctx.lineTo(300,200);
ctx.fillStyle = '#fea';
ctx.fill();
ctx.stroke();
//眼睛的外框
ctx.beginPath();
ctx.arc(300,150,25, 0, 2*Math.PI);
ctx.stroke();
ctx.fillStyle = '#38f';
ctx.fill();
//两个眼神光
ctx.beginPath();
ctx.arc(315, 140, 5, 0, 2*Math.PI);
ctx.arc(305, 130, 3, 0, 2*Math.PI);
ctx.fillStyle = '#fff';
ctx.fill();
}
var isOpen = true; //是否处于张嘴状态
setInterval(function(){
//清除已有内容
ctx.clearRect(0,0,600,400);
if(isOpen){
closeMouth();
isOpen = false;
}else {
openMouth();
isOpen = true;
}
}, 500);
</script>
</body>
2.使用Canvas绘制图像
提示:图片的定位点在图片的左上角。客户端JS必须等待图片加载完成才能开始绘制。
var img = new Image();
img.src = 'x.jpg';
img.onload = function(){
//图片已经加载完成了
ctx.drawImage(img, x, y) //使用默认的宽高
ctx.drawImage(img, x, y, w, h)
}
练习:
(1)在画布的四个角各绘制一个小飞机
(2)在画布的中央绘制一个2倍标准大小的飞机
(3)*绘制一个可以随着鼠标而移动的小飞机,提示需要使用mousemove
注意:Canvas绘图中,只有一个HTML元素——canvas!!其它图形图像都不是元素,不能绑定事件函数!!
(4)*绘制一个可以左右移动的小飞机
(5)**绘制一个可以在画布范围内走斜线移动的小飞机——碰到画布的任何一个边缘,立即反弹
<canvas id="c1" width="600" height="400"></canvas>
<script>
//(1)在画布的四个角各绘制一个小飞机
var ctx = c1.getContext('2d');
var p3 = new Image();
p3.src = 'img/p3.png';
p3.onload = function () {
//console.log(p3.width+'哈哈哈哈哈'+p3.height);200 100
//左上角飞机
ctx.drawImage(p3,0,0);
//左下角飞机
ctx.drawImage(p3,0,400-p3.height);
//右上角飞机
ctx.drawImage(p3,600-p3.width,0);
//右下角飞机
ctx.drawImage(p3,600-p3.width,400-p3.height);
//(2)在画布的中央绘制一个2倍标准大小的飞机
ctx.drawImage(p3, 300-200,200-100, 200*2, 100*2);
(3)*绘制一个可以随着鼠标而移动的小飞机,提示需要使用mousemove
c1.onmouseover = function (e) {
var x = e.offsetX;//事件相对于事件源的坐标
var y = e.offsetY;
ctx.clearRect(0,0,600,400);
ctx.drawImage(p3,x-p3.width/2,y-p3.height/2);
}
//(4)*绘制一个可以左右移动的小飞机
//碰撞弹回算法
var x=0;
var xDirection = 1;//移动的方向1、-1
var y=0;
setInterval(function () {
ctx.clearRect(0,0,600,400);
x+=5*xDirection;
ctx.drawImage(p3,x,y);
if(x>=(600-200)){ xDirection = -1}//已到最右侧
else if(x<=0) { xDirection = 1}
},41)
//(5)**绘制一个可以在画布范围内走斜线移动的小飞机——碰到画布的任何一个边缘,立即反弹
//碰撞弹回算法
var x=0;
var xDirection = 1;//移动的方向1、-1
var yDirection = 1;//移动的方向1、-1
var y=0;
setInterval(function () {
ctx.clearRect(0,0,600,400);
x+=5*xDirection;
y+=5*yDirection;
ctx.drawImage(p3,x,y);
if(x>=(600-200)){ xDirection = -1}//已到最右侧
else if(x<=0) { xDirection = 1}
if(y>=(400-100)){ yDirection = -1}//已到最右侧
else if(y<=0) { yDirection = 1}
},41)
}
</script>
小结:Canvas绘图可以绘制的内容: (1)矩形: ctx.fillRect() ctx.strokeRect() ctx.clearRect() (2)文本: ctx.fillText() ctx.strokeText() ctx.measureText() (3)路径 - 描边/填充/裁剪 ctx.beginPath() ctx.closePath() ctx.moveTo() ctx.lineTo() ctx.arc() ctx.stroke() ctx.fill() ctx.clip() (4)图像: ctx.drawImage() (5) |
3.绘图上下文的状态改变和恢复 —— 难点&晦涩
var ctx = canvas.getContext('2d');
//可以将绘图上下文对象(即画笔对象)进行变形(transform)——与对Canvas施加CSS Transform样式不同,绘图上下文的变形只影响当前绘制的图形图像内容
ctx.translate(x,y) //坐标轴原点平移到指定点,所有点的坐标都发生改变
ctx.rotate(deg) //画笔旋转,则内容旋转,轴点在坐标轴原点
ctx.scale() //画笔缩放
====================
ctx.save() //保存绘图上下文(画笔)当前的变形数据
ctx.restore() //恢复最近一次保存的画笔的变形相关的状态
练习:***有点坑——绘制四个小飞机,各在画布的一个角在绕着自己的中心在旋转。
<h3>绘制路径——四个旋转的飞机</h3>
<canvas id="c8" width="600" height="400"></canvas>
<script>
var ctx = c8.getContext('2d');
var p3 = new Image();
p3.src = "img/p3.png";
p3.onload = function(){
var deg = 0; //飞机旋转的角度
setInterval(function(){
ctx.clearRect(0, 0, 600,400);
deg+=5;
//绘制左上角的小飞机
ctx.save(); //保存画笔当前的变形状态
ctx.translate(200/2, 100/2);//原点平移
ctx.rotate(deg*Math.PI/180);//旋转画笔
ctx.drawImage(p3,-200/2, -100/2); //绘图
ctx.restore(); //恢复到上一次的保存的变形状态
//绘制此飞机对画笔的修改最终全部恢复原样
//绘制右上角的小飞机
ctx.save();
ctx.translate(600-200/2, 100/2);//原点平移
ctx.rotate(deg*Math.PI/180);
ctx.drawImage(p3,-200/2, -100/2);
ctx.restore();
//此飞机对画笔的修改最终全部恢复原样 17:16
//绘制左下角的小飞机
ctx.translate(200/2, 400-100/2);//原点平移
ctx.rotate(deg*Math.PI/180); //旋转画笔
ctx.drawImage(p3,-200/2, -100/2); //绘图
ctx.rotate(-deg*Math.PI/180); //逆向旋转
ctx.translate(-200/2, -(400-100/2)); //原点恢复
//此飞机对画笔的修改最终全部恢复原样
},50)
}
</script>
</body>
项目中Canvas技术的主要用途:
(1)绘制统计图
(2)小游戏
(3)绘图板
(4)动态的背景(带交互带动画)
4.使用第三方统计图绘制工具——Chart.js——重点在于自学过程
提示:第三方的绘图工具非常多!直接百度“JS绘图工具”!
第三方工具的使用步骤:
(1)打开官网,看工具介绍
http://www.chartjs.org/
Simple yet flexible JavaScript charting for designers & developers。一款开源的、提供了8中图表的、基于Canvas、响应式图表绘制工具库。
(2)参考DEMO,编写示例程序
new Chart(canvasId, {
type: 'bar', //图表的类型,共8中
data: { }, //图表必需的数据
options: { } //可选项
});
(3)查看API Document,实现自己的项目需求
参考手册中的示例代码
<h3>第三方绘图功能——Chart.js的使用</h3>
<canvas id="c15" width="600" height="400">
</canvas>
<script src="js/Chart.js"></script>
<script>
new Chart(c15,{
type: 'bar', //总共有8中,见手册
data: {
labels: ['部门1','部门2','部门3','部门4','部门5','部门6'], //X轴说明文字
datasets: [
{
label: '年度销售总结',
data: [400,300,500,200,450,480]
}
]
},
options: {
responsive: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>