目录
0x05 使用Canvas 交互 和 isPointInPath
0x00 阴影
ctx.shadowColor 阴影颜色
ctx.shadowOffsetX 阴影的位移值
ctx.shadowOffsetY
ctx.shadowBlur 阴影的模糊距离
效果:
代码:
var canvas = document.getElementById('canvas');
canvas.width=document.body.clientWidth;
canvas.height=document.body.clientHeight;
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#058';
ctx.shadowColor = "gray";
ctx.shadowOffsetX = 20;
ctx.shadowOffsetY = 20;
ctx.shadowBlur = 5;
ctx.fillRect(200,200,400,400);
0x01 globalAlpha
设置全局透明度
globalAlpha = 1(default)
案例:
效果:
代码:
var canvas = document.getElementById('canvas');
canvas.width=document.body.clientWidth;
canvas.height=document.body.clientHeight;
var ctx = canvas.getContext('2d');
ctx.globalAlpha = 0.7;
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);
ctx.fillStyle = "rgba("+R+","+G+","+B+")";
ctx.beginPath();
ctx.arc(Math.random()*canvas.width,Math.random()*canvas.height,Math.random()*100,0,2*Math.PI);
ctx.fill();
ctx.closePath();
}
0x02 globalCompositeOperation
globalCompositeOperation = "source-over" (default)
设置图像发生重叠时的效果
source-over 表示后绘制的图形 覆盖之前绘制的图形
destination-over 表示之前绘制的图形 覆盖 之后绘制的图形
案例:
效果:
代码:
window.onload = function(){
draw('source-over');
var a = document.getElementsByTagName('a');
for(var i =0;i<a.length;i++){
a[i].onclick = function(){
draw(this.text);
}
}
}
function draw(text){
var canvas = document.getElementById('canvas');
canvas.width=1200;
canvas.height=650;
var ctx = canvas.getContext('2d');
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.font = '40px solid Arial';
ctx.textAlign ='center';
ctx.textBaseline = "middle";
ctx.fillStyle = '#058';
ctx.fillText(text,canvas.width/2,canvas.height/2);
ctx.fillStyle='#058';
ctx.fillRect(100,100,200,200);
ctx.globalCompositeOperation=text.trim();
ctx.fillStyle ='green';
ctx.beginPath();
ctx.moveTo(200,200);
ctx.lineTo(100,300);
ctx.lineTo(400,300);
ctx.closePath();
ctx.fill();
}
0x03 clip
ctx.clip() 将之前规划的路径所构成的封闭图形 作为 绘制环境 (默认情况下绘制环境是整个画布)
效果:
代码:
window.onload = function(){
var canvas = document.getElementById('canvas');
canvas.width = 1024;
canvas.height = 689;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'black';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
ctx.arc(canvas.width/2,canvas.height/2,100,0,Math.PI*2);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.clip();
ctx.font='100px blod Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#058';
ctx.fillText("DataBank",canvas.width/2,canvas.height/2);
}
探照灯效果:
代码:
var canvas = document.getElementById('canvas');
canvas.width = 1024;
canvas.height = 689;
var searchLight={
x:canvas.width/2,
y:canvas.height/2,
r:100,
vx:Math.random()*10+10,
vy:Math.random()*10+10
}
var ctx = canvas.getContext('2d');
setInterval(function(){
render(ctx);
update(ctx);
},50);
function render(ctx){
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.save();
ctx.beginPath();
ctx.fillStyle = 'black';
ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.beginPath();
ctx.arc(searchLight.x,searchLight.y,100,0,Math.PI*2);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.clip();
ctx.font='100px blod Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#058';
ctx.fillText("DataBank",ctx.canvas.width/2,ctx.canvas.height/2-100);
ctx.fillText("DataBank",ctx.canvas.width/2,ctx.canvas.height/2);
ctx.fillText("DataBank",ctx.canvas.width/2,ctx.canvas.height/2+100);
ctx.fillText("DataBank",ctx.canvas.width/2,ctx.canvas.height/2+200);
ctx.restore();
}
function update(ctx){
searchLight.x += searchLight.vx;
searchLight.y += searchLight.vy;
console.log(searchLight);
// 下边缘碰撞检测
if(searchLight.y >= ctx.canvas.height - searchLight.r){
searchLight.y = ctx.canvas.height - searchLight.r;
searchLight.vy = -searchLight.vy*0.5;//每次反弹都会损失能量
}
if(searchLight.y <= 0 +searchLight.r){
searchLight.y = 0+searchLight.r;
searchLight.vy = -searchLight.vy;
}
if(searchLight.x <= 0+searchLight.r){
searchLight.x = 0+searchLight.r;
searchLight.vx = -searchLight.vx;
}
if(searchLight.x >= ctx.canvas.width-searchLight.r){
searchLight.x = ctx.canvas.width-searchLight.r;
searchLight.vx = - searchLight.vx;
}
}
0x04 非零环绕原则
如何判断一块区域在多边形的内侧还是外侧呢?
可以将顺时针箭头规定为1,逆时针箭头规定为-1。
如果从该区域向外引出一条射线,存在穿过的箭头总和为0的情况,则该区域在外侧
否则,该区域在内侧
典型应用:剪纸效果
也就是如果我们绘制两个圆弧,一个圆弧顺时针,一个圆弧逆时针,两个圆弧构成一个封闭图形,那么canvas便会根据非零环绕原则判定封闭图形的内侧和外侧。
效果:
代码:
var canvas = document.getElementById('canvas');
canvas.width = 1024;
canvas.height = 689;
var ctx = canvas.getContext('2d');
ctx.arc(canvas.width/2,canvas.height/2,100,0,Math.PI *2,true);
ctx.arc(canvas.width/2,canvas.height/2,50,0,Math.PI *2,false);
ctx.shadowColor = 'grey';
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
ctx.shadowBlur =10;
ctx.fillStyle = '#058';
ctx.fill();
0x05 使用Canvas 交互 和 isPointInPath
ctx.clearRect(x,y,width,height);
清空一个矩形区域
ctx.isPointInPath(x,y)
点击检测函数
(x,y) 组成了一个点的坐标,该函数判断该点是否在当前所规划的路径内
案例:
点击小球换色
<!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>
<style>
#canvas{
border:1px solid black;
position:absolute;
left:50%;
top:50%;
transform: translate(-50%,-50%);
}
</style>
</head>
<body>
<canvas id='canvas'></canvas>
</body>
<script>
var canvas = document.getElementById('canvas');
canvas.width = 1024;
canvas.height = 689;
var ctx = canvas.getContext('2d');
var balls = [];
window.onload = function(){
for(var i =0;i<10;i++){
var ball ={
x:Math.random() * canvas.width,
y:Math.random() * canvas.height,
r:Math.random() * 100,
color:'#058'
};
balls[i] = ball;
ctx.beginPath();
ctx.arc(ball.x,ball.y,ball.r,0,2* Math.PI);
ctx.fillStyle = ball.color;
ctx.fill();
}
canvas.addEventListener('mouseup',detect);
}
function detect(event){
// 标准的获得鼠标在canvas中的位置的方法,记住
//getBoundingClientRect是一个js函数,并不会canvas提供的接口,该函数用于获取一个dom对象的盒子模型(包围框)的相关属性
var x = event.clientX - canvas.getBoundingClientRect().left;
var y = event.clientY - canvas.getBoundingClientRect().top;
for(var i=0;i<balls.length;i++){
ctx.beginPath();
//注意要先规划路径,然后才能判断鼠标当前是否在路径内
ctx.arc(balls[i].x,balls[i].y,balls[i].r,0,Math.PI * 2);
if(ctx.isPointInPath(x,y)){
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var color = "rgb("+r+","+g+","+b+")";
ctx.fillStyle = color;
ctx.fill();
}
}
}
</script>
</html>
点击小球运动
<!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>
<style>
html,body{
height:100%;
}
</style>
</head>
<body>
<canvas id='canvas'></canvas>
</body>
<script>
var canvas = document.getElementById('canvas');
canvas.width=document.body.clientWidth;
canvas.height=document.body.clientHeight;
var ctx = canvas.getContext('2d');
window.onload = function(){
canvas.addEventListener('click',detect);
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,
flag:0
}
balls.push(ball);
}
setInterval(function(){
render(ctx);
update(ctx);
},50)
}
function detect(event){
var x = event.clientX - canvas.getBoundingClientRect().left;
var y = event.clientY - canvas.getBoundingClientRect().top;
for(var i=0;i<balls.length;i++){
ctx.beginPath();
ctx.arc(balls[i].x,balls[i].y,balls[i].r,0,Math.PI * 2);
if(ctx.isPointInPath(x,y)){
balls[i].flag = (balls[i].flag ==1)?0:1;
}
}
}
function render(ctx){
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
// console.log(ctx.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++){
if(balls[i].flag == 1 ){
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>