创意特效分享:用代码绘制网页上的爱心

2023-11-05

在网页设计中,为了增加用户体验和吸引用户的注意力,常常需要添加一些特效来增添页面的互动性和趣味性。其中,爱心特效是一种常见且受欢迎的效果,能够在用户与网页进行交互时展现出迷人的动态效果。

通过使用HTML、CSS和JavaScript,我们可以编写简单而优雅的代码,将一个或多个爱心图案绘制到网页上。

目录

绘制多个爱心图案并赋予动画效果

跳动的爱心


绘制多个爱心图案并赋予动画效果

特效预览

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 Canvas爱心动画特效</title>

<style>
html, body {
  height: 100%;
  padding: 0;
  margin: 0;
  background: #000;
}
canvas {
  width: 100%;
  height: 100%;
}
</style>

</head>
<body>

<div style="text-align:center;clear:both;">
<script src="/gg_bd_ad_720x90.js" type="text/javascript"></script>
<script src="/follow.js" type="text/javascript"></script>
</div>

<canvas id="pinkboard"></canvas>

<script>
/*
 * Settings
 */
var settings = {
  particles: {
    length:   500, // maximum amount of particles
    duration:   2, // particle duration in sec
    velocity: 100, // particle velocity in pixels/sec
    effect: -0.75, // play with this for a nice effect
    size:      30, // particle size in pixels
  },
};

/*
 * RequestAnimationFrame polyfill by Erik M?ller
 */
(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;a<c.length&&!window.requestAnimationFrame;++a){window.requestAnimationFrame=window[c[a]+"RequestAnimationFrame"];window.cancelAnimationFrame=window[c[a]+"CancelAnimationFrame"]||window[c[a]+"CancelRequestAnimationFrame"]}if(!window.requestAnimationFrame){window.requestAnimationFrame=function(h,e){var d=new Date().getTime();var f=Math.max(0,16-(d-b));var g=window.setTimeout(function(){h(d+f)},f);b=d+f;return g}}if(!window.cancelAnimationFrame){window.cancelAnimationFrame=function(d){clearTimeout(d)}}}());

/*
 * Point class
 */
var Point = (function() {
  function Point(x, y) {
    this.x = (typeof x !== 'undefined') ? x : 0;
    this.y = (typeof y !== 'undefined') ? y : 0;
  }
  Point.prototype.clone = function() {
    return new Point(this.x, this.y);
  };
  Point.prototype.length = function(length) {
    if (typeof length == 'undefined')
      return Math.sqrt(this.x * this.x + this.y * this.y);
    this.normalize();
    this.x *= length;
    this.y *= length;
    return this;
  };
  Point.prototype.normalize = function() {
    var length = this.length();
    this.x /= length;
    this.y /= length;
    return this;
  };
  return Point;
})();

/*
 * Particle class
 */
var Particle = (function() {
  function Particle() {
    this.position = new Point();
    this.velocity = new Point();
    this.acceleration = new Point();
    this.age = 0;
  }
  Particle.prototype.initialize = function(x, y, dx, dy) {
    this.position.x = x;
    this.position.y = y;
    this.velocity.x = dx;
    this.velocity.y = dy;
    this.acceleration.x = dx * settings.particles.effect;
    this.acceleration.y = dy * settings.particles.effect;
    this.age = 0;
  };
  Particle.prototype.update = function(deltaTime) {
    this.position.x += this.velocity.x * deltaTime;
    this.position.y += this.velocity.y * deltaTime;
    this.velocity.x += this.acceleration.x * deltaTime;
    this.velocity.y += this.acceleration.y * deltaTime;
    this.age += deltaTime;
  };
  Particle.prototype.draw = function(context, image) {
    function ease(t) {
      return (--t) * t * t + 1;
    }
    var size = image.width * ease(this.age / settings.particles.duration);
    context.globalAlpha = 1 - this.age / settings.particles.duration;
    context.drawImage(image, this.position.x - size / 2, this.position.y - size / 2, size, size);
  };
  return Particle;
})();

/*
 * ParticlePool class
 */
var ParticlePool = (function() {
  var particles,
      firstActive = 0,
      firstFree   = 0,
      duration    = settings.particles.duration;
  
  function ParticlePool(length) {
    // create and populate particle pool
    particles = new Array(length);
    for (var i = 0; i < particles.length; i++)
      particles[i] = new Particle();
  }
  ParticlePool.prototype.add = function(x, y, dx, dy) {
    particles[firstFree].initialize(x, y, dx, dy);
    
    // handle circular queue
    firstFree++;
    if (firstFree   == particles.length) firstFree   = 0;
    if (firstActive == firstFree       ) firstActive++;
    if (firstActive == particles.length) firstActive = 0;
  };
  ParticlePool.prototype.update = function(deltaTime) {
    var i;
    
    // update active particles
    if (firstActive < firstFree) {
      for (i = firstActive; i < firstFree; i++)
        particles[i].update(deltaTime);
    }
    if (firstFree < firstActive) {
      for (i = firstActive; i < particles.length; i++)
        particles[i].update(deltaTime);
      for (i = 0; i < firstFree; i++)
        particles[i].update(deltaTime);
    }
    
    // remove inactive particles
    while (particles[firstActive].age >= duration && firstActive != firstFree) {
      firstActive++;
      if (firstActive == particles.length) firstActive = 0;
    }
    
    
  };
  ParticlePool.prototype.draw = function(context, image) {
    // draw active particles
    if (firstActive < firstFree) {
      for (i = firstActive; i < firstFree; i++)
        particles[i].draw(context, image);
    }
    if (firstFree < firstActive) {
      for (i = firstActive; i < particles.length; i++)
        particles[i].draw(context, image);
      for (i = 0; i < firstFree; i++)
        particles[i].draw(context, image);
    }
  };
  return ParticlePool;
})();

/*
 * Putting it all together
 */
(function(canvas) {
  var context = canvas.getContext('2d'),
      particles = new ParticlePool(settings.particles.length),
      particleRate = settings.particles.length / settings.particles.duration, // particles/sec
      time;
  
  // get point on heart with -PI <= t <= PI
  function pointOnHeart(t) {
    return new Point(
      160 * Math.pow(Math.sin(t), 3),
      130 * Math.cos(t) - 50 * Math.cos(2 * t) - 20 * Math.cos(3 * t) - 10 * Math.cos(4 * t) + 25
    );
  }
  
  // creating the particle image using a dummy canvas
  var image = (function() {
    var canvas  = document.createElement('canvas'),
        context = canvas.getContext('2d');
    canvas.width  = settings.particles.size;
    canvas.height = settings.particles.size;
    // helper function to create the path
    function to(t) {
      var point = pointOnHeart(t);
      point.x = settings.particles.size / 2 + point.x * settings.particles.size / 350;
      point.y = settings.particles.size / 2 - point.y * settings.particles.size / 350;
      return point;
    }
    // create the path
    context.beginPath();
    var t = -Math.PI;
    var point = to(t);
    context.moveTo(point.x, point.y);
    while (t < Math.PI) {
      t += 0.01; // baby steps!
      point = to(t);
      context.lineTo(point.x, point.y);
    }
    context.closePath();
    // create the fill
    context.fillStyle = '#ea80b0';
    context.fill();
    // create the image
    var image = new Image();
    image.src = canvas.toDataURL();
    return image;
  })();
  
  // render that thing!
  function render() {
    // next animation frame
    requestAnimationFrame(render);
    
    // update time
    var newTime   = new Date().getTime() / 1000,
        deltaTime = newTime - (time || newTime);
    time = newTime;
    
    // clear canvas
    context.clearRect(0, 0, canvas.width, canvas.height);
    
    // create new particles
    var amount = particleRate * deltaTime;
    for (var i = 0; i < amount; i++) {
      var pos = pointOnHeart(Math.PI - 2 * Math.PI * Math.random());
      var dir = pos.clone().length(settings.particles.velocity);
      particles.add(canvas.width / 2 + pos.x, canvas.height / 2 - pos.y, dir.x, -dir.y);
    }
    
    // update and draw particles
    particles.update(deltaTime);
    particles.draw(context, image);
  }
  
  // handle (re-)sizing of the canvas
  function onResize() {
    canvas.width  = canvas.clientWidth;
    canvas.height = canvas.clientHeight;
  }
  window.onresize = onResize;
  
  // delay rendering bootstrap
  setTimeout(function() {
    onResize();
    render();
  }, 10);
})(document.getElementById('pinkboard'));
</script>

</body>
</html>

跳动的爱心

效果预览

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>HTML5 Css爱心动画特效</title>    
</head>

<body>
    <div class="heart">
        <div class="left"></div>
        <div class="right"></div>
    </div>
</body>
<style>
	        body {
	            margin: 0;
	            background-color: black;
	        }
	        
	        .heart {
	            width: 200px;
	            height: 200px;
	            /*auto 左右自动相等 */
	            margin: 100px auto;
	            background-color: black;
	            /* 播放动画 动画名称 时间 匀速 无限播放 反向 */
	            animation: beat 1s linear infinite alternate;
	        }
	        /* 关键帧 */
	        
	        @keyframes beat {
	            /* 开始画面 */
	            0% {
	                transform: scale(1);
	            }
	            /* 结束画面 */
	            100% {
	                transform: scale(1.1);
	            }
	        }
	        
	        .left,
	        .right {
	            width: 100px;
	            height: 160px;
	            float: left;
	            background-color: pink;
	            /* 圆角 顺时针 左上 右上 右下 左下  半径 */
	            border-radius: 50px 50px 0 0;
	            /* 盒子阴影 水平方向 垂直方向 模糊半径 扩展  颜色 */
	            box-shadow: 0px 0px 20px 0px pink;
	        }
	        
	        .left {
	            /* 变换 移动 旋转 */
	            transform: translateX(29px) rotate(-45deg);
	        }
	        
	        .right {
	            transform: translateX(-29px) rotate(45deg);
	        }

</style>
</html>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创意特效分享:用代码绘制网页上的爱心 的相关文章

  • JavaScript 函数参数和范围

    我用下面列出的代码做了一些测试 function foo x alert y var y I am defined outside foo definition foo 上面的代码给了我一个警告 我是在 foo 定义之外定义的 然后另一个测
  • Internet Explorer 的数组indexOf 实现

    有很多关于如何将 indexOf 实现放入数组原型中以便它可以在 Internet Explorer 下工作的解决方案 但是我偶然发现了一个问题 到目前为止我所看到的任何地方似乎都没有解决这个问题 使用非常一致的MDC 的实施 https
  • 错误:导航器只能包含“屏幕”组件作为其直接子组件

    我是 React Native 新手 收到此错误 但无法解决它 我正在遵循主要的教程反应导航页面 https reactnavigation org docs screen options resolution 但我无法完成它 我将不胜感激
  • 为什么音频自动播放在 Google Chrome 中不起作用?

    我正在尝试在页面刚刚打开时自动播放音频文件 我的浏览器是谷歌浏览器更新到最新版本 这是代码
  • navigator.platform 在 ARM Mac 上的价值是什么?

    苹果有released https www apple com apple events november 2020 几款基于采用 ARM 架构的 M1 芯片的新计算机 与之前基于 x86 架构的计算机相比 的价值是多少navigator
  • 四列布局,无需媒体查询即可转换为单列

    我正在尝试创建一个四列布局 其中每列随着窗口的大小而增大和缩小 但每列都有最小宽度 当窗口太小而无法将所有四列放入单行时 它会转换到单个列 每个部分占据整个宽度 我无法使用 flex box 或 CSS 网格来做到这一点 我想在没有媒体查询
  • 如何防止缓慢脚本警告并强制浏览器继续运行脚本直到完成?

    更新 2013 年 7 月 5 日 自从我最初问这个问题以来 我学到了很多东西 在下面的一条评论中 有人建议我重新处理该任务 并找到一种方法来解决它 而不会有阻塞 UI 的风险 我说不可能 函数必须按原样运行 我实际上不记得我试图用这个函数
  • 所有属性的 JavaScript getter

    长话短说 我现在的情况是想要一个 PHP 风格的 getter 但是是 JavaScript 的 我的 JavaScript 仅在 Firefox 中运行 因此 Mozilla 特定的 JS 对我来说没问题 我能找到的制作 JS gette
  • 如何为 chrome 和 ie favicon(加载指示器)设置动画

    我的 PM 有一个要求 将图标更改为动画加载图像 仅当我将 link href 指向 gif 文件时 它才适用于 Firefox 我做了一些研究 发现 chrome 不支持动画图标 但wiki https en wikipedia org
  • Twitter bootstrap 3 RC2 - IE8 中的导航不起作用

    我正在使用 Twitter Bootstrap 3 RC2 在页面顶部创建一个导航栏 除了在 IE8 中之外 该导航栏工作正常 在 IE8 中 就像浏览器变小一样 因此菜单会折叠以供移动视图使用 但这种情况并非如此 现在我知道 TB3 仍在
  • 需要了解Javascript函数提升示例

    我阅读了 Javascript 提升的概念 它非常令人困惑 但我看到了一些示例并了解了提升的实际作用 所以基本上 提升是 JavaScript 的默认行为 即将所有声明移动到当前作用域的顶部 当前脚本或当前函数的顶部 但我无法理解以下实现
  • 不用AJAX,前台同步拖放文件上传?

    我有一个定期的网站
  • Scrapy在页面上找不到表单

    我正在尝试编写一个自动登录的蜘蛛这个网站 https www athletic net account login ReturnUrl 2Fdefault aspx 但是 当我尝试使用scrapy FormRequest from resp
  • 动态多个延迟 jQuery Ajax 调用

    使用 jQuery 的延迟模式http api jquery com jQuery when http api jquery com jQuery when 我正在尝试进行多个 jsonp ajax 调用并等待结果 然后再进行下一步 我可以
  • 将回调函数与原型函数一起使用

    在执行回调时 我无法弄清楚如何传递对象方法而不是排序 通用原型 方法 function Client this name hello Client prototype apiCall function method params callb
  • 如何在 C# 中通过 JavaScript 回调运行 QUnit 测试并获取测试结果?

    在我的几个项目中 我使用 MVC 模式将代码 关注点 分为 3 层 模型层和控制层都在 C 上运行 因此我使用 MSTest 或 NUnit 等测试框架来验证这些层的功能需求 对于视图层 我使用 QUnit 来测试 JavaScript 文
  • Ruby 数组到 Javascript 数组

    我有一个带有帐户 ID 的 Ruby 数组 我想将帐户 ID 的 Ruby 数组存储在 Javascript 数组中 我想知道最好的方法是什么 另外 当我尝试执行此操作时 Javascript 似乎认为如果只输入一个帐户 ID 则该 ID
  • 如何使用 Browserify 获取 html 模板

    我正在尝试找出一种简单的方法 在脚本中需要 html 模板 然后从 CLI 运行 browserify 假设我想获取一个模板并将其附加到正文中 index js var template require template html docu
  • 内联 YouTube 视频在 iOS 上的 cordova 应用程序中不起作用

    我用 cordova 开发了一个移动应用程序 我确实需要能够播放内联 YouTube 视频 我尝试了一段时间来解决它 我设置了属性playsinline to 1在 YouTube iframe API 中 I put
  • JavaScript 反静默技术来指示失败

    当错误确实发生并且函数无法继续执行时 在 JavaScript 中报告错误而不是依赖 null 和 undefined 是一个好方法 我可以想到三种方法 没做什么 抛出异常 assert 这是一个简单的示例场景 一个将传入的金额记入用户帐户

随机推荐

  • 性能监控-grafana+prometheus+node_exporter

    Prometheus是一个开源的系统监控和报警工具 它由SoundCloud开发并于2012年发布 后来成为了一个独立的开源项目 并得到了广泛的应用和支持 Prometheus的主要功能包括采集和存储各种系统和应用程序的监控数据 并提供强大
  • 基础算法题——学长的白日梦(快速幂、快速逐步求积)

    学长的白日梦 题目简单明了 只要将计算出 xi 即可 两个卡点 快速幂 快速逐步求积 由于这道题 mod 999999997 mod mod gt 10 19 不能直接用快速幂解决 中间求积会爆 于是我卡在逐步求余上动弹不得 唉 看了题解后
  • selenium找不到chrome浏览器的解决办法

    传入chrome exe的绝对路径 例如 options webdriver ChromeOptions options binary location C Program Files x86 Google Chrome Applicati
  • 关于RC电路特点以及几种常见的典型应用

    RC电路是由电阻R以及电容C组成的电路 只需要一个电阻R以及一个电容C 通过这两个器件的不同串并联 并选取不同的参数 可以实现几种不同的功能 RC电路在模拟电路 数字电路中得到了广泛的应用 R 的连接方式 RC 串联电路 电路的特点 由于有
  • mybatisplus group by 归组

    QueryWrapper
  • web前端文件上传可选择的4种方式

    在web前端开发中 文件上传属于很常见的功能 不论是图片 还是文档等等资源 或多或少会有上传的需求 一般都是从添加文件开始 然后读取文件信息 再通过一定的方式将文件上传到服务器上 以供后续展示或下载使用 本文将讲述文件上传中所能用到的4种添
  • 【AtCoder Beginner Contest 252】部分题解

    D Distinct Trio 题意 给定一个长度为 n n n的序列 a a a 求使得 1
  • Python编程:从入门到实践 项目《外星人入侵》完整代码

    blog github hexo的blog链接 github 我的github传送 学习 Python编程 从入门到实践 有段时间了 跟着书本把所有代码都敲了一遍 感悟很深 现在完成了 外星人入侵 项目 对于库 类 函数 方法都有一定的理解
  • Android 多行RadioGroup 实现

    需求如下 思路有多种 可以用自定义布局 RecycleView 代码动态控制布局 RadioGroup 等方式实现 今天我用的RadioGroup 实现思路如下 布局文件如下
  • DLNA第一步UPnP协议栈

    前面公司有DLNA项目 研究了一下 在网上关于DLNA的资源很少 就将自己的心得写出来 以供参考 其它的关于DLNA的介绍就不多说 要了解DLNA需要了解upnp 因为DLNA在upnp之上 初学者可以从http www upnp org下
  • std::sort 升序 ? 降序

    Std sort 这个函数 大家知道用 而且入可以 使用一个自定义的元素对比函数 比较郁闷的是 老是忘了 这个函数返回TRUE 对排序结果的影响 升序还是降序 于是用GTEST写了一段代码 测试代码 将就些看吧 class HandHogR
  • 自底向上和自顶向下的架构设计区别

    某日小明上数学课 他的老师给了很多个不同的直角三角板让小明用尺子去量三角板的三个边 并将长度记录下来 两个小时过去 小明完成任务 把数据拿给老师 老师给他说 还有一个任务就是观察三条边之间的数量关系 又是两个小时 聪明的小明连蹦带跳走进了办
  • vue父组件向子组件传值

    非常简单 相信大家一看就懂 复制到浏览器即可使用 注意别忘了引入vue哦 div div pmsg div div
  • 一台计算机如何安装2个版本的python,互不影响呢

    python学习过程中 很多教程都是python2 版本的 但是python2 到2020年就不在维护了 所以 现在教大家如何在一台计算机上安装python2 和python3 互不影响 可以自如的切换 不用任何第三方软件 简单省力 一次配
  • 熊啸锋:掌握这4个步骤,你的销售额至少增加3倍,风险降低10倍

    你好 我是熊啸锋老师 认识我的人都知道 我有一套快速成交陌生客户的秘诀 让你在零粉丝的情况下 快速的冷启动 用好这个秘诀之后 在不增加成本的情况下 你的利润至少增加3倍 风险降低10倍 具体怎么做呢 在分享这个秘诀之前 我们先来看看大部分人
  • latex中长公式换行,很好的办法

    今天在编辑公式时 有一个公式很长 写到一行就出去了 当时之前换行都是方程组或者在括号完之后换 都没有问题 但是今天我也换行的是在括号中间断开 这样出现问题 编辑的时候会出错误提醒 上网查了一些论坛 也有人和我一样的问题 但是都没有解决方案
  • 操作系统存储器管理之连续、页式、段式、段页式存储器管理方式

    基本内存分配方案 4 3 连续分配存储管理方式 连续分配方式 是指为一个用户程序分配一个连续的内存空间 4 3 1单一连续分配 内存分为两个区域 系统区 用户区 应用程序装入到用户区 可使用用户区全部空间 最简单 适用于单用户 单任务的OS
  • 抖音帐号注册需要注意什么

    虽然短视频是大势所趋 但是我们在抖音上也不能瞎玩 注册时需要避开哪些坑 怎样才能更快的吸引到第一批粉丝 新手一定不要错过今天的课程干货 首先 你要记住账号注册一卡一号一手机新手在抖音账号注册 其次 简介中需要用简练的语言体现出账号的内容及特
  • 基于VirtualBox虚拟机安装Ubuntu图文教程

    一 下载安装VirtualBox 官网下载VirtualBox 目前版本 VirtualBox 5 1 8 for Windows hosts x86 amd64 下载好了安装VirtualBox 一路Next就可以了 这个比较简单 运行V
  • 创意特效分享:用代码绘制网页上的爱心

    在网页设计中 为了增加用户体验和吸引用户的注意力 常常需要添加一些特效来增添页面的互动性和趣味性 其中 爱心特效是一种常见且受欢迎的效果 能够在用户与网页进行交互时展现出迷人的动态效果 通过使用HTML CSS和JavaScript 我们可