canvas 两种拖尾效果实现烟花:视觉盛宴的代码艺术
**引言**
在Web前端开发领域,HTML5 Canvas以其强大的图形渲染能力,为开发者提供了无限可能。本文将聚焦于如何利用Canvas API创建出绚丽夺目的烟花特效,并重点解析两种不同风格的烟花拖尾效果实现方式。通过详细的代码示例和解析,你将学会如何打造一场属于自己的线上烟火晚会,让观众沉浸在美轮美奂的视觉盛宴之中。
## **一、基础概念与准备工作**
### **1. 创建Canvas元素**
首先,在HTML中设置一个`canvas`元素作为画布:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas烟花特效</title>
<style>
canvas {
display: block;
margin: auto;
background-color: #000;
}
</style>
</head>
<body>
<canvas id="fireworksCanvas" width="800" height="600"></canvas>
<script src="fireworks.js"></script>
</body>
</html>
```
### **2. 获取Canvas上下文**
在JavaScript文件(如上例中的`fireworks.js`)中获取Canvas上下文:
```javascript
const canvas=document.getElementById('fireworksCanvas');
const ctx=canvas.getContext('2d');
```
## **二、基于点阵的烟花拖尾效果**
### **原理**
本方法采用点阵形式模拟烟花爆炸后的粒子轨迹,每个粒子随着时间推移逐渐消散或淡出。
```javascript
class Particle {
constructor(x, y, speed, color) {
this.x=x;
this.y=y;
this.speed=speed;
this.color=color;
// 其他属性...
}
update() {
// 更新粒子位置
this.y -=this.speed;
// 淡出处理...
}
draw(ctx) {
ctx.fillStyle=this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, 1, 0, Math.PI * 2);
ctx.fill();
}
}
// 烟花类,包含多个粒子对象
class FireworkWithDotsTrail {
// 初始化、更新、绘制方法...
}
```
### **实现过程**
1. 在烟花发射时生成一组随机位置、速度和颜色的粒子。
2. 每帧更新所有粒子的位置和透明度,并绘制到画布上。
3. 当粒子超出屏幕或者透明度达到一定程度时,重新生成新的粒子以维持烟花的持续效果。
## **三、基于线条追踪的烟花拖尾效果**
### **原理**
此方法通过连续记录烟花移动路径上的关键点,并连接这些点形成一条平滑的线条来展现拖尾效果。
```javascript
class FireworkWithLineTrail {
constructor(startX, startY, endX, endY, color) {
this.startX=startX;
this.startY=startY;
this.endX=endX;
this.endY=endY;
this.color=color;
this.trailPoints=[[startX, startY]];
}
update(position) {
this.endX=position.x;
this.endY=position.y;
this.trailPoints.push([this.endX, this.endY]);
// 清理过旧的轨迹点...
}
draw(ctx) {
ctx.beginPath();
ctx.strokeStyle=this.color;
for (let i=0; i < this.trailPoints.length - 1; i++) {
const [x1, y1]=this.trailPoints[i];
const [x2, y2]=this.trailPoints[i + 1];
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
}
ctx.stroke();
}
}
```
### **实现过程**
1. 初始化烟花发射位置和目标方向,创建一个包含起点坐标的轨迹点数组。
2. 每次烟花移动时,添加新的坐标点至轨迹点数组,并清理超出指定数量的旧轨迹点。
3. 绘制时,遍历轨迹点数组并连线,形成拖尾效果。
## **四、完整示例及动画循环**
为了实现动态效果,我们需要使用`requestAnimationFrame`进行动画循环:
```javascript
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
fireworks.forEach((firework)=> firework.updateAndDraw());
requestAnimationFrame(animate);
}
// 初始化若干烟花实例并开始动画循环
const fireworks=[/*...*/];
animate();
```
**结语**
通过以上介绍,我们成功地展示了如何利用Canvas技术在网页上实现两种不同的烟花拖尾效果。无论是点阵式的粒子轨迹,还是线条追踪形成的连贯轨迹,都能带给用户强烈的视觉冲击力。理解并掌握这两种实现方式,无疑会让你在Web前端设计与开发领域更加游刃有余,能够创造出更多惊艳的交互式视觉体验。而实际应用中,根据具体需求,还可以进一步优化细节,例如增加色彩渐变、粒子形状变化等特性,使烟花特效更为丰富多样。不断探索Canvas的无穷魅力,你将在Web世界中描绘出属于自己的璀璨星空!
教程
目录:
1. 绘制静态粒子图形效果
2. 添加静态粒子动画效果
3. 添加粒子碰撞动画效果
4. 添加粒子四面碰撞效果
基础要求:
1. 了解基础HTML标签,例如canvas标签
2. 了解Javascript的基础知识
第一步: 生成静态粒子图形
生成静态粒子图形,我们将会使用到Canvas的如下相关方法:
context.fillRect(x, y, width, height);
context.arc(x, y, r, sAngle, eAngle, counterclockwise);
其中,使用fillRect方法生成了整个动画场景,布满了画布全部区域,再使用arc方法来生成一个圆形,arc方法本身用来生成圆弧,但是如果生成一个360度的圆弧的话,就自然生成了圆形,完整代码如下:
var canvas=document.getElementById('gbcanvas'),
context=canvas.getContext('2d');
var posX=30, //定义圆心X坐标
posY=30, //定义圆心Y坐标
particleRadius=30; //定义半径
context.fillStyle='#E4E4E4';
context.fillRect(0,0,canvas.width,canvas.height); //生成画布背景色
context.beginPath;
context.fillStyle='#dd4814';
context.arc(posX, posY, particleRadius, 0 , Math.PI*2, true);
context.closePath;
context.fill;
在线演示&调试地址
http://www.igeekbar.com/igclass/code/5392196c-400d-466c-b0cb-647bbc3469cc.htm
第二步: 生成粒子运行效果
动画效果原理:
HTML5 画布动画生成原理,本质来说实现方式就是每隔固定时间段重新绘制画布内的图形,如下是代码:
var canvas=document.getElementById('gbcanvas'),
context=canvas.getContext('2d'),
posX=30,
posY=30,
particleRadius=30;
//定义setInterval来隔特定时间生成粒子,如下
setInterval(function{
//为了能够生成粒子移动效果,我们需要在每次绘制粒子之前清楚界面里的绘图
context.fillStyle='#E4E4E4';
context.fillRect(0,0,canvas.width,canvas.height); //使用背景色填充
posX+=2;
posY+=1;
context.arc(posX, posY, particleRadius, 0, Math.PI*2, true);
}, 10);
以上代码我们使用fillRect方法来先将整个背景色重新填充,再使用arc方法重新绘制圆形,来生成移动的效果
在线演示&调试地址
http://www.igeekbar.com/igclass/code/d2ff678f-23f1-4cab-9eba-9898d4393017.htm
第三步: 生成粒子碰撞效果
使用HTML5画布生成一个粒子碰撞地面效果,并且同时添加相关重力加速度效果。
首先定义粒子x轴和y轴的运动速度及重力加速度,如下:
speedX=10, //定义一个X轴方向的速度
speedY=10, //定义一个Y轴方向的速度
gravity=1; //定义一个重力的参数,即重力加速度
然后,设置粒子运动速度,即每次绘制粒子圆心坐标的变化,如下:
//以下代码设置运动速度
posX+=speedX;
posY+=speedY;
同时,保证Y轴拥有一个加速度效果,如下:
//添加重力加速度效果
speedY+=gravity;
最后,我们添加一个地面碰撞效果,判断当粒子的中心Y轴低于canvas的高度减去粒子半径,即粒子部分区域低于画布最低端的时候,重新定义粒子的位置,如下:
//接下来我们添加地面反弹效果,只需要判断当粒子运动到近画布底端的时候,粒子Y轴坐标反向
if(posY > canvas.height - particleRadius){
speedY*=-0.5; //这里设置粒子速度为负值,修改此数值可以修改粒子Y轴运动速度损耗量
speedX*=0.5; //这里设置粒子X轴速度的损耗量
posY=canvas.height - particleRadius; //这里当粒子低于画布最低端的时候,设置保证其不消失
}
在线演示&调试地址
http://www.igeekbar.com/igclass/code/8a3cfeb7-b052-4bf7-b3b1-8ec4e59584af.htm
第四步: 生成四面碰壁粒子效果
上面我们生成了粒子碰撞地面效果,本节我们添加粒子四面碰壁效果,基本代码如下:
//判断粒子位于画布右侧可显示区域外
if(posX > canvas.width - particleRadius){
speedX*=-1;
posX=canvas.width - particleRadius;
}
//判断粒子位于画布左侧可显示区域外
if(posX < particleRadius){
speedX*=-1;
posX=particleRadius;
}
//最后添加顶端的反弹效果
if(posY < particleRadius){
speedY*=-1;
posY=particleRadius;
}
大家可以看到,代码基本和碰撞地面效果类似,只不过判断粒子中心所处的坐标位置来修改粒子运动的方向。
在线演示&调试地址
http://www.igeekbar.com/igclass/code/87784219-f527-4f52-bfb2-62cd82bbc07d.htm
Done!以上就是几个HTML5实现粒子物理碰撞的例子, 希望大家能够觉得有用, 有任何问题,请给我留言哈
没有Canvas的年代,绘图只能借助Flash,页面不得不用JavaScript和Flash进行交互,而现在可以直接用Html5的canvas元素使用JavaScript在网页上绘制图形。
Canvas指定了尺寸,可以在这个范围内任意绘制。
Canvas拥有多种绘制路径、矩形、圆形、字符以及添加图形的方法。
由于浏览器对HTML5标准支持不一致,所以通常在<canvas>的内部添加一些说明性HTML代码,如果不支持将显示其内部的HTML。
<canvas width="100" height="100" id="canva"> <p>您的浏览器版本暂不支持Canvas,请进行升级</p> </canvas>
var canvas=document.getElementById('canva'); if (canvas.getContext){ var ctx=canvas.getContext('2d'); // drawing code here } else { // canvas-unsupported code here }
Canvas的坐标系统以左上角为原点,水平向右为X轴,垂直向下为Y轴,以像素为单位,所以每个点都是非负整数。
?
Canvas只支持一种原生图形的绘制:矩形。
所有其他图形都至少需要生成一种路径。
Canvas提供了几种方式绘制矩形:
描述方法参数创建矩形rect(x,y,width,height)x:矩形左上角X坐标
y:矩形左上角的Y坐标
width:矩形的宽度,以像素计
height:矩形的高度,以像素计
绘制一个填充颜色的矩形,默认黑色fillRect(x,y,width,height)x:矩形左上角X坐标
y:矩形左上角的Y坐标
width:矩形的宽度,以像素计
height:矩形的高度,以像素计
绘制一个矩形边框,默认黑色strokeRect(x,y,width,height)x:矩形左上角X坐标
y:矩形左上角的Y坐标
width:矩形的宽度,以像素计
height:矩形的高度,以像素计
在给定的矩形内清除指定的像素,然后这块区域变完全透明clearRect(x,y,width,height)x:要清除的矩形左上角X坐标
y:要清除的矩形矩形左上角的Y坐标
width:要清除的矩形矩形的宽度,以像素计
height:要清除的矩形矩形的高度,以像素计
例如:
?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>1.绘制矩形</title> <style> #canvas{ width: 500px; height: 200px; border: 1px solid red; } </style> </head> <body> <canvas id="canvas"></canvas> <script> window.onload=function () { var canvas=document.getElementById('canvas'); if (!canvas.getContext) return; var context=canvas.getContext('2d'); context.strokeRect(20,20,100,100); context.fillRect(30,30,80,80); context.clearRect(40,40,60,60); } </script> </body> </html>
图形的基本元素是路径。
路径通过不同颜色和宽度的线段、曲线相连形成不同形状的点集合。
一个路径,甚至一个子路径,都是闭合的。
步骤:
1. 创建路径起始点 -- beginPath()
2. 使用画图命令画出路径 -- moveTo()等
3. 路径封闭 -- closePath()
4. 一旦路径生成即可通过描边或填充路径来渲染图形 -- fill()
描述方法参数填充当前绘图fill()
绘制已定义的路径stroke()
起始一条路径,或重置当前当前路径beginPath()
把路径以定到画布指定点moveTo(x,y)x:路径的目标位置的X坐标
y:路径的目标位置的Y坐标
创建从当前点到起始点的路径closePath()
添加一个新点,然后再画布中创建从该点到最后指定点的线条lineTo(x,y)x:路径的目标位置的X坐标
y:路径的目标位置的Y坐标
从原始画布剪切任意形状和尺寸的区域clip()
创建二次贝赛尔曲线quadraticCurveTo(cpx,cpy,x,y)cpx:贝塞尔控制点的X坐标
cpy:贝塞尔控制点的Y坐标
x:结束点的X坐标
y:结束点的Y坐标
创建三次贝塞尔曲线bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)cp1x:第一个贝塞尔控制点的 x 坐标
cp1y:第一个贝塞尔控制点的 y 坐标
cp2x:第二个贝塞尔控制点的 x 坐标
cp2y:第二个贝塞尔控制点的 y坐标
x:结束点的 x 坐标
y:结束点的 y 坐标
创建弧、曲线(用于创建圆形或部分圆)arc(x,y,r,sAngle,eAngle,counterclockwise)x:圆的中心的 x 坐标
y:圆的中心的 y 坐标
r:圆的半径
sAngle:起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)
eAngle:结束角,以弧度计
counterclockwise:可选,规定在逆时针还是在顺时针绘图,False=顺时针,true=逆时针
创建两切线之间的弧、曲线arcTo(x1,y1,x2,y2,r)x1:弧的起点的 x 坐标
y1:弧的起点的 y 坐标
x2:弧的终点的 x 坐标
y2:弧的终点的 y 坐标
r:弧的半径
如果指定的点位于当前路径中,则返回true,否则返回falseisPointInPath(x,y)x:测试的 x 坐标
y:测试的 y 坐标
延伸:
一次贝塞尔曲线
?
二次贝塞尔曲线
转存失败
重新上传
取消
?
三次贝塞尔曲线
?
描述方法参数用于填充绘画的颜色、渐变或模式fillStylecolor|gradient|pattern
color:css颜色值
gradient:用于填充绘图的渐变对象(线性或放射性)
pattern:用于填充绘图的 pattern 对象
用于笔触的颜色、渐变或模式strokeStylecolor|gradient|pattern
color:css颜色值
gradient:用于填充绘图的渐变对象(线性或放射性)
pattern:用于填充绘图的 pattern 对象
用于阴影的颜色shadowColorcolor:css颜色值用于阴影的模糊级别shadowBlurnumber:模糊级别数阴影距形状的水平距离shadowOffsetXnumber:正值或负值,定义阴影与形状的水平距离阴影距形状的垂直距离shadowOffsetYnumber:正值或负值,定义阴影与形状的垂直距离
创建线性渐变createLinearGradient(x0,y0,x1,y1)x0:渐变开始点的 x 坐标 y0:渐变开始点的 y 坐标 x1:渐变结束点的 x 坐标 y1:渐变结束点的 y 坐标
在指定方向上重复指定的元素(元素可以是图片、视频,或者其他 <canvas> 元素)cratePattern(image,"repeat|repeat-x|repeat-y|no-repeat")image:规定要使用的图片、画布或视频元素 "repeat:默认。该模式在水平和垂直方向重复 repeat-x:该模式只在水平方向重复 repeat-y:该模式只在垂直方向重复 no-repeat:该模式只显示一次(不重复) "
创建放射状、环形的渐变createRadialGradient(x0,y0,r0,x1,y1,r1)x0:渐变的开始圆的 x 坐标 y0:渐变的开始圆的 y 坐标 r0:开始圆的半径 x1:渐变的结束圆的 x 坐标 y1:渐变的结束圆的 y 坐标 r1:结束圆的半径
规定渐变对象中的颜色和停止位置addColorStop(stop,color)stop:介于 0.0 与 1.0 之间的值,表示渐变中开始与结束之间的位置
color: css 颜色值
线条的结束端点样式lineCap"butt|round|square"
"
butt:默认。向线条的每个末端添加平直的边缘
round:向线条的每个末端添加圆形线帽
square:向线条的每个末端添加正方形线帽
"
两条线相交时,所创建的拐角类型lineJoin"bevel|round|miter"
"
bevel:创建斜角
round:创建圆角
miter:默认。创建尖角
"
当前的线条宽度lineWidthnumber:当前线条的宽度,以像素计
最大的斜接长度miterLimitnumber:正数。规定最大斜接长度。
如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 "bevel" 类型来显示
描述方法参数当前字体属性font
当前对齐方式textAlign
当前文本基线textBaseline
在画布上绘制被填充的文本fillText()
在画布上绘制未被填充的文本strokeText()
返回包含指定文本宽度的对象measureText()
描述方法参数在画布上绘制图像、画布或视频drawImageimg:规定要使用的图形、画布或视频
sx:可选,开始剪切的X坐标位置
sy:可选,开始剪切的Y坐标位置
swidth:可选,被剪切图形的宽度
sheight:可选,被剪切图形的高度
x:在画布上放置图形的X坐标位置
y:在画布上放置图形的Y坐标位置
width:可选,要使用的图形的宽度(伸展或缩小图像)
height:可选,要使用的图形的高度(伸展或缩小图像)
返回ImageData对象的宽度width
返回ImageData对象的高度height
返回一个对象,其包含指定的ImageData对象的图像数据data
创建新的、空白的ImageData对象crateImageData()
返回ImageData对象,该对象为画布上指定的矩形复制像素数据getImageData()
把图像数据(从指定的ImageData对象)放回画布上putImageData()
描述方法参数重新映射画布上的(0,0)位置translate()x:左右偏移量
y:上下偏移量
移动中心是坐标原点。
缩放当前绘图至更大或更小scale()scaleWIdth:缩放当前绘图宽度(1=100% 2=200%)
scaleHeight:缩放当前绘图高度(1=100% 2=200%)
旋转当前绘图rotate()angel:旋转角度,以弧度计,如需将角度转换为弧度,以degrees * Matn.PI/180公式计算。顺时针方向旋转,旋转中心是坐标原点。替换绘图的当前转换矩阵transform()a:水平缩放绘图
b:水平倾斜绘图
c:垂直倾斜绘图
d:垂直缩放绘图
e:水平移动绘图
f:垂直移动绘图
将当前转换重置为单位矩阵,然后运行transform()setTransform()a:水平旋转绘图
b:水平倾斜绘图
c:垂直倾斜绘图
d:垂直缩放绘图
e:水平移动绘图
f:垂直移动绘图
延伸:
1.translate:
?
2.rotate
转存失败
重新上传
取消
?
描述方法参数设置或返回绘图当前alpha或透明值globalAlphanumber:透明值,必须介于0.0-1.0之间设置或返回心图形如何绘制到已有的图像上globalCompositeOperation等多个属性操作,略。。
描述方法参数保存当前环境的状态save()
返回之前报错过的路径状态和属性restore()
createEvent()
getContext()
toDataURL()
基本步骤:
1. 在绘制每一帧动画之前,需要清空所有canvas -- clearRect()
2. 保存canvas状态
3. 绘制动画图形
4. 恢复canvas状态
*请认真填写需求信息,我们会在24小时内与您取得联系。