目录
0x00 在Canvas中使用其他HMTL 元素
canvas本身并不是透明的,默认背景色为白色。
如果将一个html标签,放在了canvas标签之前,即便是我们对该标签进行了绝对定位,那么该标签也有可能被canvas遮挡住
建议将浮动在canvas之上的标签放在canvas之后。
同时也可以通过z-index属性来调整不同的div在z轴方向的先后顺序
案例:
效果:
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
<style>
#canvas-wrapper{
position: absolute;;
top:50%;
left:50%;
transform: translate(-50%,-50%);
width:1024px;
height:650px;
}
#controller{
position:absolute;
top:30px;
left:30px;
width:200px;
border-radius:10px;
padding:15px;
background: rgba(0,85,116,0.7);
color:#fff;
}
.btn-black{
background:black;
}
.btn-white{
background:white;
}
</style>
</head>
<body>
<div id='canvas-wrapper'>
<canvas id='canvas'></canvas>
<div id="controller">
<h4>Canvas 控制面板</h4>
<a href="javascript:;" id='canvas-btn' class='btn btn-danger'>停止运动</a>
<a href="javascript:;" id='black-color-btn' class='btn btn-black'> </a>
<a href="javascript:;" id='white-color-btn' class='btn btn-white'> </a>
</div>
</div>
</body>
<script>
var themeColor = 'white';
var isMoving = true;
window.onload = function(){
var canvas = document.getElementById('canvas');
canvas.width=1024;
canvas.height=650;
var ctx = canvas.getContext('2d');
ctx.globalAlpha = 1;
ctx.globalCompositeOperation='xor';
balls = [];
for(var i=0;i<100;i++){
var R = Math.floor(Math.random()*255);
var G = Math.floor(Math.random()*255);
var B = Math.floor(Math.random()*255);
var color = "rgba("+R+","+G+","+B+")";
var ball = {
x:Math.random()*canvas.width,
y:Math.random()*canvas.height,
r:Math.random()*100,
vx:Math.random()*20,
vy:Math.random()*20,
c:color
}
balls.push(ball);
}
setInterval(function(){
render(ctx);
if(isMoving){
update(ctx);
}
},50)
document.getElementById('canvas-btn').onclick = function(){
if(isMoving){
isMoving = false;
this.text = "开始运动";
}else{
isMoving = true;
this.text = "停止运动";
}
return false;
}
document.getElementById('white-color-btn').onclick = function(){
themeColor = "white";
return false;
}
document.getElementById('black-color-btn').onclick = function(){
themeColor = "black";
return false;
}
}
function render(ctx){
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
// console.log(ctx.canvas.height);
if(themeColor == "black"){
ctx.fillStyle = "black";
ctx.fillRect(0,0,canvas.width,canvas.height);
}
for(var i=0;i<balls.length;i++){
ctx.beginPath();
ctx.fillStyle = balls[i].c;
ctx.arc(balls[i].x,balls[i].y,balls[i].r,0,Math.PI * 2);
ctx.closePath();
ctx.fill();
}
}
function update(ctx){
for(var i =0;i<balls.length;i++){
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
// 碰撞检测
// 下边缘碰撞检测
if(balls[i].y >= ctx.canvas.height - balls[i].r){
balls[i].y = ctx.canvas.height - balls[i].r;
balls[i].vy = -balls[i].vy*0.5;//每次反弹都会损失能量
}
if(balls[i].y <= 0 +balls[i].r){
balls[i].y = 0+balls[i].r;
balls[i].vy = -balls[i].vy;
}
if(balls[i].x <= 0+balls[i].r){
balls[i].x = 0+balls[i].r;
balls[i].vx = -balls[i].vx;
}
if(balls[i].x >= ctx.canvas.width-balls[i].r){
balls[i].x = ctx.canvas.width-balls[i].r;
balls[i].vx = - balls[i].vx;
}
}
}
</script>
</html>
0x01 扩展Canvas的context对象
我们可以将我们自己写的函数添加给
CanvasRenderingContext.prototype,使之成为ctx的一个接口
CanvasRenderingContext 就是我们获取的context对象,所以我们需要将函数中的ctx 全部修改为this
代码:
window.onload=function(){
var canvas = document.getElementById('canvas');
canvas.width = document.body.clientWidth;
canvas.height =document.body.clientHeight;
var ctx = canvas.getContext('2d');
/**
* 规划弯月的路径
*
*/
CanvasRenderingContext2D.prototype.pathMoon=function(d){
this.beginPath();
this.arc(0,0,1,0.5*Math.PI,1.5*Math.PI,true);
this.moveTo(0,-1);
this.quadraticCurveTo(1.2,0,0,1);
this.closePath();
}
/**
* 绘制一轮填充的弯月
* @ d 控制点坐标的横坐标值
* @ x,y 弯月的位置
* @ R 弯月的半径
* @ rot 旋转角度 角度值
* @ fillColor 可选
*/
CanvasRenderingContext2D.prototype.fillMoon = function(d,x,y,R,rot,fillColor){
this.save();
this.translate(x,y);
this.rotate(rot * Math.PI / 180);
this.scale(R,R);
this.pathMoon(d);
this.fillStyle = fillColor || "#fb5";
this.fill();
this.restore();
}
//黑夜
var skyStyle = ctx.createLinearGradient(0,0,0,canvas.height);
skyStyle.addColorStop(0.0,'black');
skyStyle.addColorStop(1.0,'#035');
ctx.fillStyle = skyStyle;
ctx.fillRect(0,0,canvas.width,canvas.height);
//200个星星
for(var i=0;i<40;i++){
var r = Math.random() * 5 + 2; //2 - 7之间的随机值
var x = Math.random() * canvas.width;
var y = Math.random() * canvas.height / 3;
var rot = Math.random() * 360;
drawStar(ctx,r,x,y,rot);
}
//绘制月亮
ctx.fillMoon(2,900,200,100,30);
//绘制绿地
drawLand(ctx);
}
/**
* 产生一个标准星星的路径
* 一个位于(0,0)点 外圆半径为1,内圆半径为0.5的星星
*
*/
function starPath(ctx){
var R = 1;
var r = 0.5 * R;
var rot =0;
var x = 0;
var y =0;
ctx.beginPath();
for(var i=0;i<5;i++){
// 大圆半径为300 ,平移400px
ctx.lineTo(
Math.cos((18 +i*72 - rot)*Math.PI/180)*R + x,
-Math.sin((18 +i*72 - rot )*Math.PI/180)*R + y
);
//小圆半径为150,平移400px;
ctx.lineTo(
Math.cos((54 +i*72 - rot)*Math.PI/180)*r +x,
-Math.sin((54 +i*72 - rot)*Math.PI/180)*r +y
);
}
ctx.closePath();
}
/**
* 绘制一个五角星
* ctx 上下文
* r 小圆半径
* x x轴方向上的平移
* y y轴方向上的平移
* rot 顺时针旋转角度
*/
function drawStar( ctx,r,x,y,rot){
ctx.save();
//因为 我们左上角坐标是0,0,所以scale不会改变左上角的坐标
ctx.translate(x,y);
ctx.rotate(rot * Math.PI/180);
ctx.scale(r,r);
starPath(ctx);
ctx.lineJoin = 'round';
ctx.fillStyle = '#fb3';
ctx.strokeStyle = '#fd5';
ctx.fill();
ctx.restore();
}
// 计算两点间的距离
function dis(x1,y1,x2,y2){
return Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
function drawLand(ctx){
ctx.save();
ctx.beginPath();
ctx.moveTo(0,600);
ctx.bezierCurveTo(540,400,660,800,document.body.clientWidth,600);
ctx.lineTo(document.body.clientWidth,document.body.clientHeight);
ctx.lineTo(0,document.body.clientHeight);
ctx.closePath();
var landStyle = ctx.createLinearGradient(0,800,0,0);
landStyle.addColorStop(0.0,'#030');
landStyle.addColorStop(1.0,'#580');
ctx.fillStyle=landStyle;
ctx.fill();
ctx.restore();
}
0x02 Canvas与浏览器兼容性
通过if(ctx.函数名) 可以判断浏览器是否支持该函数