目錄
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>