线条照射爱心动画特效:HTML5 Canvas的魅力展现

在网页设计和前端开发领域,使用HTML5的Canvas元素来创建动态视觉效果已经成为一种趋势。Canvas元素提供了在网页上进行实时图形渲染的能力,从简单的形状到复杂的动画,它都能胜任。本文将介绍如何利用Canvas实现一个线条照射爱心的动画特效,并深入探讨其实现原理和技术细节。

项目背景

假设我们需要为一个情人节专题页面添加一个浪漫的元素------一颗由无数光点汇聚而成的心形图案,这些光点逐渐向心形轮廓靠拢,形成一种光线汇聚的视觉效果。这个效果不仅美观,还能增强用户体验,使页面更具吸引力。效果图:

技术栈

  • HTML5:用于结构化页面。
  • CSS3:用于样式美化,特别是绝对定位和响应式设计。
  • JavaScript:用于逻辑处理和动画实现。
  • Canvas API:用于图形渲染。

实现步骤

  1. HTML结构定义 : 首先,在HTML文件中,我们嵌入了一个<canvas>标签,作为图形绘制的载体。为了确保动画能适应不同屏幕尺寸,我们将其宽度和高度设置为百分比,并通过CSS控制其实际尺寸。
html 复制代码
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>线条照射爱心动画</title>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<canvas width="300" height="300" style="width:100%;height:100vh;" id="c"></canvas>
<script  src="js/index.js"></script>
</body>
</html>
  1. CSS样式设置 : 使用CSS隐藏页面边框和滚动条,设置背景色,并确保<canvas>全屏显示。此外,定义了一个.info类,用于显示额外的信息或调试数据,但在此示例中并未使用。
css 复制代码
html,body{
     border: 0;
     padding: 0;
     margin: 0;
     overflow: hidden;
     background: #000;
}
.info{
  z-index:999;
  position : absolute;
  left:0;
  top:0;
  padding:10px;
  color:#fff;
  background: rgba(0,0,0,0.5);
  text-transform:capitalize;
}
  1. JavaScript逻辑处理

    • 获取Canvas上下文 :使用document.getElementByIdgetContext方法获取到Canvas元素及其绘图上下文。
    • 定义变量和数组:包括存储内部和外部爱心点、粒子的数组,以及一些控制参数如点的数量、阈值等。
    • 计算爱心点:通过数学公式计算构成心形的点,内外两层,以形成光照效果。
    • 粒子系统:为每个点关联一个粒子,用于模拟光线的汇聚过程。
    • 动画循环 :使用requestAnimationFrame实现动画的连续播放,每次循环更新粒子位置并重新绘制。
  2. 数学和算法应用

    • 距离计算:通过欧几里得距离公式计算两点间的距离,用于判断粒子是否接近目标点。
    • 颜色映射:使用HSL色彩空间,根据粒子到中心的距离动态改变颜色,增加视觉效果的丰富性。
  3. 响应式设计: 通过监听窗口大小变化,调整Canvas尺寸,确保动画在不同设备上都能良好呈现。为了方便需要的同学直接拿代码,我将3,4,5步js代码放一块,如下:

js 复制代码
var canvas = document.getElementById('c');
var ctx = canvas.getContext("2d");
var height = void 0,width = void 0,innerpoints = [],outerpoints = [],particles = [];

var noofpoints = 200,trashold = 10;
var x = void 0,y = void 0,p = void 0,n = void 0,point = void 0,dx = void 0,dy = void 0,color = void 0;
deltaangle = Math.PI * 2 / noofpoints,
r = Math.min(height, width) * 0.5;

var distance = function distance(x1, y1, x2, y2) {
  return Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2));
};
var mapVal = function mapVal(num, in_min, in_max, out_min, out_max) {
  return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
};
var resize = function resize() {
  height = ctx.canvas.clientHeight;
  width = ctx.canvas.clientWidth;

  if (ctx.canvas.clientWidth !== canvas.width ||
  ctx.canvas.clientHeight !== canvas.height)
  {
    console.log("resized");
    canvas.width = width;
    canvas.height = height;
    ctx.translate(canvas.width / 2, canvas.height / 2);
    ctx.rotate(-Math.PI);
    innerpoints = [];
    r = 10;
    for (var i = deltaangle; i <= Math.PI * 2; i += deltaangle) {
      x = r * 16 * Math.pow(Math.sin(i), 3);
      y = r * (13 * Math.cos(i) - 5 * Math.cos(2 * i) - 2 * Math.cos(3 * i) - Math.cos(4 * i));
      innerpoints.push({
        x: x,
        y: y });


      x = 10 * r * 16 * Math.pow(Math.sin(i), 3);
      y = 10 * r * (13 * Math.cos(i) - 5 * Math.cos(2 * i) - 2 * Math.cos(3 * i) - Math.cos(4 * i));
      outerpoints.push({
        x: x,
        y: y });


      var step = random(0.001, 0.003, true);
      particles.push({
        step: step,
        x: x,
        y: y });

    }
  }
};
var random = function random(min, max, isFloat) {
  if (isFloat) {
    return Math.random() * (max - min) + min;
  }
  return ~~(Math.random() * (max - min) + min);
};

resize();

//particles = [...outerpoints];
ctx.globalAlpha = 0.5;
ctx.globalCompositeOperation = 'source-over';
var draw = function draw() {
  ctx.fillStyle = "rgba(0,0,0,0.03)";
  ctx.fillRect(-width, -height, width * 2, height * 2);
  ctx.beginPath();

  for (var i = 0; i < innerpoints.length; i++) {
    s = outerpoints[i];
    d = innerpoints[i];
    point = particles[i];

    if (distance(point.x, point.y, d.x, d.y) > 10) {
      dx = d.x - s.x;
      dy = d.y - s.y;

      point.x += dx * point.step;
      point.y += dy * point.step;
      color = distance(0, 0, point.x, point.y);
      ctx.beginPath();
      ctx.fillStyle = "hsl(" + color % 360 + ",100%,50%)";
      ctx.arc(point.x, point.y, 2, 0, Math.PI * 2, false);
      ctx.closePath();
      ctx.fill();
    } else {
      point.x = d.x;
      point.y = d.y;
      ctx.beginPath();
      ctx.arc(point.x, point.y, 2, 0, Math.PI * 2, false);
      ctx.closePath();
      ctx.fill();
      particles[i].x = s.x;
      particles[i].y = s.y;
      particles[i].step = random(0.001, 0.003, true);
    }
  }

};


var render = function render() {
  resize();
  draw();
  requestAnimationFrame(render);
};

requestAnimationFrame(render);

结论

通过以上步骤,我们成功地利用HTML5 Canvas实现了线条照射爱心的动画特效。这一效果不仅展示了Canvas的强大功能,还融合了数学、色彩理论和响应式设计的实践,对于前端开发者来说是一次技术与艺术的完美结合。此动画可以广泛应用于各种场景,如节日专题、情感表达或品牌宣传,为网站增添一抹独特的创意和魅力。同时,它也提供了一个学习和实践Canvas API的绝佳案例,帮助开发者提升技能,探索更多创意可能性。

相关推荐
百万蹄蹄向前冲35 分钟前
2024不一样的VUE3期末考查
前端·javascript·程序员
轻口味1 小时前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami1 小时前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
wakangda2 小时前
React Native 集成原生Android功能
javascript·react native·react.js
吃杠碰小鸡2 小时前
lodash常用函数
前端·javascript
emoji1111112 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼2 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250032 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
m0_748235952 小时前
web复习(三)
前端