<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>圆形扩散</title>
<style>
body {
overflow: hidden;
background: #000;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script type="text/javascript">
var oAnim=document.getElementById('canvas');
var context = oAnim.getContext("2d");
var radius=0
function drawCircle(){
context.beginPath();
render(radius);
context.arc(50,50,radius,0,Math.PI * 2);
context.closePath();
context.lineWidth=2;
context.strokeStyle='rgba(250,250,50,1)';
context.stroke();
radius +=0.5;//每帧半径增加0.5
if(radius > 20){
radius=0;
}
}
function render(x) {
//默认值为source-over,覆盖原图上面,效果像z-index:999<br>
var prev = context.globalCompositeOperation;
//<br><br> //只显示canvas上原图像的重叠部分<br>
context.globalCompositeOperation = 'destination-in';
//<br><br> //设置主canvas的绘制透明度,圆圈中间的浅黄色部分<br>
context.globalAlpha = 0.95;
//<br> <br> //这一步目的是将canvas上的图像变的透明<br>
context.fillRect(0,0,40*x,40*x);
//<br><br> //在原图像上重叠新图像<br>
context.globalCompositeOperation = prev
//;<br> //下面代用的drawcricle方法,圆圈覆盖在正方形上
};
//在主canvas上画新圆
setInterval(function(){
drawCircle();
},20);
</script>
</html>
参考:https://www.cnblogs.com/anxiaoyu/p/6672187.html
canvas 雨滴效果
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>rain</title>
</head>
<body>
<canvas id="canvas" style="position: absolute; height: 100%; width:100%;"></canvas>
<script>
window.onload=main;
function getRgb(r,g,b){
return "rgb("+ r+","+g+","+b+")";
}
function main(){
//drop来存放溅射的雨滴
var dropList=[];
//重力因素,保持溅射的雨滴不会飞远
var gravity=0.8;
//保存雨滴
var linelist=[];
var canvasEl = document.getElementById('canvas');
var ctx = canvasEl.getContext('2d');
//鼠标的开始点为
var mousePos = [0, 0];
var backgroundColor = '#000';
canvasEl.width=canvasEl.clientWidth;
canvasEl.height=canvasEl.clientHeight;
var speedx=0;
var maxspeedx=0;
//当改变浏览器窗口大小时
window.onresize=function () {
canvasEl.width=canvasEl.clientWidth;
canvasEl.height=canvasEl.clientHeight;
}
//当鼠标移动时,获取坐标
window.onmousemove=function (e) {
mousePos[0]=e.clientX;
mousePos[1]=e.clientY;
//最大速度-1到1个屏幕
maxspeedx=(e.clientX-canvasEl.clientWidth/2)/(canvasEl.clientWidth/2);
}
//给单个雨滴加属性
function createLine(e){
//长度在12.5-37.5之间
var temp= 0.25*( 50+Math.random()*100);
//速度在16.5-50.5之间
var myline={
speed:5.5*(Math.random()*6+3),
die:false,
posx:e,
posy:-200,
h:temp,
//颜色在
color:(getRgb(Math.floor(temp*255/75),Math.floor(temp*255/75),Math.floor(temp*255/75)))
};
//添加到数组中
linelist.push(myline);
}
update();
//生产小雨滴
function createDrop(x,y){
var mydrop={
die:false,
//溅射x坐标
posx:x,
//溅射的y坐标
posy:y,
//随机生成一个x轴速度
vx:(Math.random()-0.5)*8,
//随机生成一个y轴速度
vy:Math.random()*(-6)-3,
radius:Math.random()*1.5+1
};
return mydrop;
}
//溅射效果
function madedrops(x,y){
//溅射的雨滴数为5-10滴
var maxi=Math.floor(Math.random()*5+5);
for(var i=0;i<maxi;i++){
dropList.push(createDrop(x,y));
}
}
function update() {
//循环遍历小雨滴,显示溅射的雨滴,移除超出范围的雨滴
if(dropList.length>0){
dropList.forEach(function (e) {
//小雨滴的x轴速度=随机速度+雨滴初始速度
e.vx=e.vx+(speedx)/2;
//小雨滴的新坐标
e.posx=e.posx+e.vx;
//小雨滴的y轴速度=随机速度+重力
e.vy=e.vy+gravity;
e.posy=e.posy+e.vy;
//雨滴超出屏幕高度,则消失
if(e.posy>canvasEl.clientHeight){
e.die=true;
}
});
}
//移除超出范围的雨滴
for(var i=dropList.length-1;i>=0;i--){
if(dropList[i].die){
dropList.splice(i,1);
}
}
//鼠标的位置控制雨的速度
//当鼠标在中间maxspeedx为0,不倾斜,速度不加快
speedx=speedx+(maxspeedx-speedx)/50;
if(Math.random()>0){
//雨滴的出生点的X轴坐标在-0.5到1.5倍的屏幕,这样雨滴倾斜的时候,最角落也会有雨滴
createLine(Math.random()*1.5*canvasEl.width -Math.random()*0.5*canvasEl.width);
createLine(Math.random()*1.5*canvasEl.width -Math.random()*0.5*canvasEl.width);
createLine(Math.random()*1.5*canvasEl.width -Math.random()*0.5*canvasEl.width);
}
//雨滴到达近地面时,近地面(1到0.8的屏幕高度)
var mydeadline=canvasEl.clientHeight- Math.random()*canvasEl.clientHeight/5;
//监听雨滴,雨滴距离鼠标的直线距离小于35时,两点之间的距离公式
linelist.forEach(function (e) {
//雨滴距离鼠标的直线距离小于35时,两点之间的距离公式
var dis=Math.sqrt( ((e.posx+speedx*e.h)-mousePos[0])*((e.posx+speedx*e.h)-mousePos[0])+(e.posy+e.h-mousePos[1])*(e.posy+e.h-mousePos[1]));
if(dis<35){
//雨滴消失,产生小雨滴
madedrops(e.posx+speedx*e.h,e.posy+e.h);
e.die=true;
}
//当雨滴到达地面时,每个雨滴的地面不同,0.8到1个屏幕高度
//如果每个
if((e.posy+e.h)>mydeadline){
//每个雨滴都出水花太多了。给个0.9的概率
if(Math.random() > 0.9){
madedrops(e.posx+speedx*e.h,e.posy+e.h);
e.die=true;
}
}
//水滴超出屏幕高度,设置为消失
if(e.posy>=canvasEl.clientHeight){
e.die=true;
}else{
e.posy=e.posy+e.speed;
e.posx=e.posx+(e.speed*speedx);
}
});
//消失雨滴
for(var i=linelist.length-1;i>=0;i--){
if(linelist[i].die){
linelist.splice(i,1);
}
}
//清除界面
render();
//重绘页面
window.requestAnimationFrame(update);
}
function render() {
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvasEl.width, canvasEl.height);
linelist.forEach(
//绘制雨滴
function (line) {
ctx.strokeStyle =line.color;
ctx.lineWidth=4.5;
ctx.beginPath();
ctx.moveTo(line.posx,line.posy);
ctx.lineTo(line.posx+speedx*line.h,line.posy+line.h);
ctx.stroke();
});
ctx.lineWidth=1;
ctx.strokeStyle = "#fff";
//绘制溅射雨滴
dropList.forEach(function (e) {
ctx.beginPath();
ctx.arc(e.posx,e.posy,e.radius,Math.random()*Math.PI*2,1*Math.PI);
ctx.stroke();
});
}
}
</script>
</body>
</html>
参考:https://www.cnblogs.com/anxiaoyu/p/6689853.html
小球碰撞
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>小球碰撞反弹</title>
<style type="text/css">
#canvas1{
border: 4px dashed black;
margin: 0 auto;
display: block;
}
</style>
</head>
<body>
<canvas id="canvas1" width="600" height="600"></canvas>
</body>
<script type="text/javascript">
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
//随机函数
function randomNum (m,n) {
return Math.floor(Math.random() * (n - m + 1) + m);
}
//创建小球类
function Ball () {
//随机小球半径
this.r = randomNum(15,30);
//随机颜色
this.color = 'rgb(' + randomNum(0,255) + ',' + randomNum(0,255) + ',' + randomNum(0,255) + ')';
//随机小球的位置
this.x = randomNum(this.r,canvas.width-this.r);
this.y = randomNum(this.r,canvas.height-this.r);
//小球速度X轴1和-1;
this.speedX = randomNum(2,5) * randomNum(0,1) ? 1 : -1;
this.speedY = randomNum(2,5) * randomNum(0,1) ? 1 : -1;
}
//小球移动
Ball.prototype.move = function () {
this.x += this.speedX;
this.y += this.speedY;
//判断是否碰到边界
//左边界
if (this.x <= this.r) {
this.x = this.r;
//反弹
this.speedX *= -1;
}
//右边界
if (this.x >= canvas.width-this.r) {
this.x = canvas.width-this.r;
this.speedX *= -1;
}
if (this.y <= this.r) {
this.y = this.r;
this.speedY *= -1;
}
if (this.y >= canvas.height-this.r) {
this.y = canvas.height-this.r;
this.speedY *= -1;
}
}
//绘制小球
Ball.prototype.drawBall = function () {
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.fillStyle = this.color;
ctx.fill();
}
//创建小球的对象
var balls = [];
for (var i = 0;i < 10;i++) {
var ball = new Ball();
balls.push(ball);
}
//让小球移动
setInterval(function () {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0;i < balls.length;i++) {
balls[i].move();
balls[i].drawBall();
//移动后检测小球碰撞反弹
for (j = 0;j < balls.length;j++) {
//判断不是同一个球
if (balls[i] == balls[j]) {
continue;//不做碰撞检测
}
//碰撞检测
if (ballCrash(balls[i],balls[j])) {
/*
1.物理公式动量守恒,假设每个球的质地均匀,那么小球的质量与半径有关
2.我们用1一次方的算法,实际平面球质量和r的平方有关,立体球和r的三次方有关
3.由动量守恒,m1*v1+m2*v2=m1*v1'+m2*v2'
4.机械能守恒,平方我就不写了,两个方程联立
*/
var fzx=(balls[i].r - balls[j].r)*balls[i].speedX + 2*balls[j].r*balls[j].speedX;
var fzx2=2*balls[i].r*balls[i].speedX+(balls[i].r - balls[j].r)*balls[j].speedX;
var fzy=(balls[i].r - balls[j].r)*balls[i].speedY + 2*balls[j].r*balls[j].speedY;
var fzy2=2*balls[i].r*balls[i].speedY+(balls[i].r - balls[j].r)*balls[j].speedY;
var fm=balls[i].r + balls[j].r;
balls[i].speedX=(fzx/fm);
balls[i].speedY=(fzy/fm);
balls[j].speedX=(fzx2/fm);
balls[j].speedY=(fzy2/fm);
}
}
}
},1)
//碰撞检测
function ballCrash (ball1,ball2) {
//两个小球之间的距离
var distance = Math.sqrt(Math.pow(ball1.x - ball2.x,2) + Math.pow(ball1.y - ball2.y,2));
//两球的距离小于两个半径的和即为碰撞
if (distance == ball1.r + ball2.r) {
return true;//碰撞
}else if( distance < ball1.r + ball2.r){
if(Math.pow(ball1.speedX,2)+Math.pow(ball1.speedY,2)>Math.pow(ball2.speedX,2)+Math.pow(ball2.speedY,2)){
if(ball1.speedX>0){
ball2.x=ball2.x+ball1.r + ball2.r - distance;
if(ball1.speedY > 0){
ball2.y=ball2.y+ball1.r + ball2.r - distance;
}else{
ball2.y=ball2.y-ball1.r - ball2.r + distance;
}
}else{
ball2.x=ball2.x-ball1.r - ball2.r + distance;
if(ball1.speedY > 0){
ball2.y=ball2.y+ball1.r + ball2.r - distance;
}else{
ball2.y=ball2.y-ball1.r - ball2.r + distance;
}
}
}else{
if(ball2.speedX>0){
ball1.x=ball1.x+ball1.r + ball2.r - distance;
if(ball2.speedY > 0){
ball1.y=ball1.y+ball1.r + ball2.r - distance;
}else{
ball1.y=ball1.y-ball1.r - ball2.r + distance;
}
}else{
ball1.x=ball1.x-ball1.r - ball2.r + distance;
if(ball2.speedY > 0){
ball1.y=ball1.y+ball1.r + ball2.r - distance;
}else{
ball1.y=ball1.y-ball1.r - ball2.r + distance;
}
}
}
return true;
}
else{
return false;//没有碰撞
}
}
</script>
</html>
参考https://www.cnblogs.com/anxiaoyu/p/6707836.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>动态进度加载小球</title>
<style>
#c{
margin: 0 auto;
display: block;
}
#r{
display: block;
margin: 0 auto;
}
#r::before{
color: black;
content: attr(min);
padding-right: 10px;
}
#r::after{
color: black;
content: attr(max);
padding-left: 10px;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<input type="range" id="r" min="0" max="100" step="1">
<script>
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var range = document.getElementById('r');
//range控件信息
var rangeValue = range.value;
var nowRange = 0; //用于做一个临时的range
//画布属性
var mW = canvas.width = 250;
var mH = canvas.height = 250;
var lineWidth = 2;
//圆属性
var r = mH / 2; //圆心
var cR = r - 16 * lineWidth; //圆半径
//Sin 曲线属性
var sX = 0;
var sY = mH / 2;
var axisLength = mW; //轴长
var waveWidth = 0.015 ; //波浪宽度(曲线周期),数越小越宽
var waveHeight = 6; //波浪高度(波峰),数越大越高
var speed = 0.09; //波浪水平速度,数越大速度越快
var xOffset = 0; //波浪x偏移量
ctx.lineWidth = lineWidth;
//画圈函数
var IsdrawCircled = false;
var drawCircle = function(){
ctx.beginPath();
ctx.strokeStyle = '#1080d0';
//画外圆
ctx.arc(r, r, cR+5, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
//显示水部分的圆
ctx.arc(r, r, cR, 0, 2 * Math.PI);
//剪裁圆形,去掉多于的水
ctx.clip();
}
//画sin 曲线函数
var drawSin = function(xOffset){
ctx.save();
var points=[]; //用于存放绘制Sin曲线的点,用于封闭曲线
ctx.beginPath();
//在整个轴长上取点
for(var x = sX; x < sX + axisLength; x += 20 / axisLength){
//此处坐标(x,y)的取点,依靠公式 “振幅高*sin(x*振幅宽 + 振幅偏移量)”
//y=sin(TX+x)
var y = -Math.sin((sX + x) * waveWidth + xOffset);
//dY是波浪的高度,-是因为水从下往上
var dY = mH * (1 - nowRange / 100 );
points.push([x, dY + y * waveHeight]);
//描绘点
ctx.lineTo(x, dY + y * waveHeight);
}
//现在一条线从左端绘制到了右端
//封闭路径
//接着连右下端
ctx.lineTo(axisLength, mH);
//左下端
ctx.lineTo(sX, mH);
//曲线图的最左端
//封闭完成后,调用上面的ctx.clip(),去掉圆外面的水
ctx.lineTo(points[0][0],points[0][1]);
ctx.fillStyle = '#1c86d1';
ctx.fill();
ctx.restore();
};
//写百分比文本函数
var drawText = function(){
ctx.save();
var size = 0.4*cR;
ctx.font = size + 'px Microsoft Yahei';
ctx.textAlign = 'center';
ctx.fillStyle = "rgba(06, 85, 128, 0.8)";
ctx.fillText(nowRange + '%', r, r + size / 2);
ctx.restore();
};
var render = function(){
ctx.clearRect(0, 0, mW, mH);
//通过不断刷新来获取range的值
rangeValue = range.value;
if(IsdrawCircled == false){
drawCircle();
}
//如果拖动input,就安每次加减1的速度增减
if(nowRange <= rangeValue){
var tmp = 1;
nowRange += tmp;
}
if(nowRange > rangeValue){
var tmp = 1;
nowRange -= tmp;
}
//不停的偏移,让波浪动起来
drawSin(xOffset);
drawText();
//偏移量加大
xOffset += speed;
requestAnimationFrame(render);
}
render();
</script>
</body>
</html>