diff --git a/Happy_NewYear/README.md b/Happy_NewYear/README.md
new file mode 100644
index 0000000..ea875cf
--- /dev/null
+++ b/Happy_NewYear/README.md
@@ -0,0 +1,4 @@
+# 介绍
+基于canvas的2d新年祝福
+
+[demo](https://uncoder-fe.github.io/happyNewYear/?to=%E5%B0%8F%E5%BC%BA)
diff --git a/Happy_NewYear/bgm.mp3 b/Happy_NewYear/bgm.mp3
new file mode 100644
index 0000000..07b918d
Binary files /dev/null and b/Happy_NewYear/bgm.mp3 differ
diff --git a/Happy_NewYear/index.css b/Happy_NewYear/index.css
new file mode 100644
index 0000000..7a64fb1
--- /dev/null
+++ b/Happy_NewYear/index.css
@@ -0,0 +1,19 @@
+html,body,canvas{
+ margin: 0;
+ padding: 0;
+}
+.loading{
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: white;
+ z-index: 9999;
+}
+canvas{
+ max-width: 100%;
+}
+.img-list{
+ display: none;
+}
diff --git a/Happy_NewYear/index.html b/Happy_NewYear/index.html
new file mode 100644
index 0000000..218a87d
--- /dev/null
+++ b/Happy_NewYear/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+ 新年快乐
+
+
+
+
+
+
+
+
+
+
diff --git a/Happy_NewYear/index.js b/Happy_NewYear/index.js
new file mode 100644
index 0000000..a05afa0
--- /dev/null
+++ b/Happy_NewYear/index.js
@@ -0,0 +1,247 @@
+/**初始化 */
+document.addEventListener("WeixinJSBridgeReady", function () {
+ document.querySelector("#mp3").play();
+}, false);
+window.addEventListener("DOMContentLoaded", function () {
+ document.querySelector("#mp3").play();
+ initPage();
+});
+function initPage() {
+ var snowStyle = {
+ 1: document.querySelector("#snow1"),
+ 2: document.querySelector("#snow2"),
+ 3: document.querySelector("#snow3")
+ }
+ var canvasHeight = window.innerHeight;
+ var canvasWidth = window.innerWidth;
+ var myCanvas = document.querySelector('#happy-new-year');
+ myCanvas.setAttribute('height', canvasHeight);
+ myCanvas.setAttribute('width', canvasWidth);
+
+ var ctx = myCanvas.getContext('2d');
+ //画布渐变
+ var gradient = ctx.createLinearGradient(200, 480, 320, 480);
+ gradient.addColorStop(0, "#FF0000");
+ gradient.addColorStop(0.5, "#FF8000");
+ gradient.addColorStop(0.75, "#FFFF00");
+ gradient.addColorStop(1, "#7F00FF");
+ // 初始化数据
+ var num = 55;
+ var sonwPoints = getSonws();
+ var wordPoints = getWords();
+ var starPoints = getStar();
+
+ // 隐藏loading
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
+ document.querySelector('.loading').style.display = "none";
+
+ // 渲染动画
+ var rid = window.requestAnimationFrame(step);
+ function step() {
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
+ // 背景
+ ctx.save();
+ ctx.fillStyle = 'white';
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
+
+ initSnow();
+ initWord();
+ rid = window.requestAnimationFrame(step);
+ }
+
+ // 雪花文字动画
+ function initWord() {
+ var range = 25;
+ for (var i = 0; i < wordPoints.length; i++) {
+ var x = wordPoints[i].x;
+ var y = wordPoints[i].y;
+ var endx = wordPoints[i].endx;
+ var endy = wordPoints[i].endy;
+ var height = wordPoints[i].height;
+ var width = wordPoints[i].width;
+ var moveRange = wordPoints[i].moveRange;
+ var delay = wordPoints[i].delay;
+ var delayCount = wordPoints[i].delayCount;
+ var offset = wordPoints[i].offset;
+ var img = wordPoints[i].img;
+ range = moveRange + 2;
+ x = x + Math.sin(range / 360 * 2 * Math.PI) * offset;
+ y = y + 1.5;
+ if (delayCount < delay) {
+ delayCount++;
+ wordPoints[i].delayCount = delayCount;
+ continue;
+ }
+ if (y >= endy) {
+ x = endx;
+ y = endy;
+ }
+ wordPoints[i].x = x;
+ wordPoints[i].y = y;
+ wordPoints[i].moveRange = range;
+ ctx.beginPath();
+ ctx.drawImage(snowStyle[img], x, y, height, width);
+ }
+ }
+ // 雪花动画
+ function initSnow() {
+ var range = 25;
+ for (var i = 0; i < num; i++) {
+ var x = sonwPoints[i].x;
+ var y = sonwPoints[i].y;
+ var moveRange = sonwPoints[i].moveRange;
+ var offset = sonwPoints[i].offset;
+ var delay = sonwPoints[i].delay;
+ var delayCount = sonwPoints[i].delayCount;
+ var img = sonwPoints[i].img;
+ var height = sonwPoints[i].height;
+ var width = sonwPoints[i].width;
+ range = moveRange + 2;
+ x = x + Math.sin(range / 360 * 2 * Math.PI) * offset;
+ y = y + 1.5;
+ if (y > canvasHeight) { y = 0; }
+ if (delayCount < delay) {
+ delayCount++;
+ sonwPoints[i].delayCount = delayCount;
+ continue;
+ }
+ sonwPoints[i].x = x;
+ sonwPoints[i].y = y;
+ sonwPoints[i].moveRange = range;
+ ctx.beginPath();
+ ctx.drawImage(snowStyle[img], x, y, height, width);
+ }
+ }
+ // 雪花文字点
+ function getWords() {
+ // 名字
+ var name = window.decodeURIComponent(window.location.search.split('=')[1]);
+ ctx.save();
+ ctx.fillStyle = "#eee";
+ ctx.font = '75px ooxx';
+ ctx.fillText(name, (canvasWidth - 75 * name.length) / 2, canvasHeight / 2 - 100);
+ ctx.restore();
+
+ // 祝福语
+ ctx.save();
+ ctx.fillStyle = "#eee";
+ ctx.font = '90px ooxx';
+ ctx.fillText('新', (canvasWidth - 90 * 4) / 2, canvasHeight / 2 + 10);
+ ctx.fillText('年', (canvasWidth - 90 * 4) / 2 + 90, canvasHeight / 2 + 25)
+ ctx.fillText('快', (canvasWidth - 90 * 4) / 2 + 180, canvasHeight / 2 + 10)
+ ctx.fillText('乐', (canvasWidth - 90 * 4) / 2 + 270, canvasHeight / 2 + 25)
+ ctx.restore();
+
+ // 获取原始点坐标,色值
+ var iData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
+ var colorsData = iData.data;
+ var points = [];
+ // 取点
+ for (var i = 1; i <= canvasWidth; i += 6) {
+ for (var j = 1; j <= canvasHeight; j += 6) {
+ var x = i;
+ var y = j;
+ var index = canvasWidth * (j - 1) + i;
+ var a = colorsData[(index - 1) * 4 + 3];
+ if (a > 0) {
+ var size = Math.round(Math.random() * 4 + 8);
+ var config = {
+ x: x,
+ y: 0,
+ endx: x,
+ endy: y,
+ height: size,
+ width: size,
+ offset: 1,
+ moveRange: 2,
+ delay: Math.round(Math.random() * canvasHeight)
+ }
+ var point = new SnowPixel(config);
+ points.push(point);
+ }
+ }
+ }
+ return points;
+ }
+ // 雪花点
+ function getSonws() {
+ var pointsArry = [];
+ for (var i = 0; i < num; i++) {
+ var size = Math.round(Math.random() * 15 + 15);
+ var config = {
+ x: Math.round(Math.random() * canvasWidth),
+ y: 0,
+ endx: canvasWidth,
+ endy: canvasHeight,
+ height: size,
+ width: size,
+ offset: (Math.random() * 1.5).toFixed(1),
+ moveRange: Math.round(Math.random() * 10),
+ delay: Math.round(Math.random() * canvasHeight)
+ }
+ var point = new SnowPixel(config);
+ pointsArry.push(point);
+ }
+ return pointsArry;
+ }
+ // 流星点
+ function getStar() {
+ var points = [];
+ for (var i = 0; i < 5; i++) {
+ var point = new StarPixel(220 + 20 * i - 450, 0, 220 + 22 * i, 480, i);
+ points.push(point);
+ }
+ return points;
+ }
+ function StarPixel(x, y, endx, endy, color) {
+ var colors = ['#FF0000', '#FF8000', '#FF0000', '#7F00FF','#FF0000'];
+ // 起点
+ this.x = x;
+ this.y = y;
+ // 终点
+ this.endx = endx;
+ this.endy = endy;
+ this.color = colors[color];
+ this.delay = Math.random() * 100 + 200;
+ this.delayCount = 0;
+ }
+ function SnowPixel(config) {
+ this.x = config['x'] || 0;
+ this.y = config['y'] || 0;
+ this.endx = config['endx'] || 0;
+ this.endy = config['endy'] || 0;
+ this.height = config['height'] || 5;
+ this.width = config['width'] || 5;
+ this.offset = config['offset'] || 1;
+ this.moveRange = config['moveRange'] || 1;
+ this.delay = config['delay'] || 0;
+ this.delayCount = 0;
+ this.img = config['img'] || Math.round(Math.random() * 2 + 1);
+ }
+ // 返回切点位置
+ function returnQD(cx, cy, x, y, radius) {
+ var __dx = cx - x;
+ var __dy = cy - y;
+ //计算点击处与圆心相对于X轴的夹角
+ var __r1 = Math.atan2(__dy, __dx);
+ //计算点击处与圆心、点击处与切点1这两条线段间的夹角
+ var __d1 = Math.sqrt(__dx * __dx + __dy * __dy);
+ var __r2 = Math.asin(radius / __d1);
+ //计算从切点1向圆的垂直直径做垂线形成的直角三角形的一个角
+ var __r3 = __r1 - __r2;
+ //计算坐标系中的角度
+ var __r4 = __r3 - Math.PI / 2;
+ //计算切点1相对于圆心的x、y坐标
+ var __x1 = radius * Math.cos(__r4);
+ var __y1 = radius * Math.sin(__r4);
+
+ //计算点击处与切线2相对于X轴的夹角
+ var __r5 = Math.PI / 2 - __r1 - __r2;
+ //计算坐标系中的角度
+ var __r6 = -__r5;
+ //计算切点2相对于圆心的x、y坐标
+ var __x2 = radius * Math.cos(__r6);
+ var __y2 = radius * Math.sin(__r6);
+ return [{ x: cx + __x1, y: cy + __y1 }, { x: cx - __x2, y: cy - __y2 }]
+ }
+}
diff --git a/Happy_NewYear/snow-111.png b/Happy_NewYear/snow-111.png
new file mode 100644
index 0000000..a8ebf4e
Binary files /dev/null and b/Happy_NewYear/snow-111.png differ
diff --git a/Happy_NewYear/snow-222.png b/Happy_NewYear/snow-222.png
new file mode 100644
index 0000000..3837962
Binary files /dev/null and b/Happy_NewYear/snow-222.png differ
diff --git a/Happy_NewYear/snow-333.png b/Happy_NewYear/snow-333.png
new file mode 100644
index 0000000..a2c0ba2
Binary files /dev/null and b/Happy_NewYear/snow-333.png differ