用CSS做一个椭圆轨道小球运动动画

木头的喵喵拖孩

个人CSS技能查漏补缺系列

关键在于使用关键帧(keyframs)时让两个动画重叠,并让其中一个动画延迟

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#wrapper {
--ballCount: 2; /* 小球数量 */
--ballAnimTime: 1s; /* 动画单轮总时间 */
--ballAnimDeley: calc(var(--ballAnimTime) / 4); /* 为了实现椭圆轨迹而计算的延迟时间,为单轮总时间除以4 */
--ballUnitAnimTime: calc(var(--ballAnimTime) / var(--ballCount)); /* 小球延迟,为单轮总时间除以小球数量 */

position: relative;
width: 60vw;
height: 30vw;
border: 1px solid black;
overflow: hidden;
resize: auto;
}

#wrapper > .ball {
position: absolute;
transform: translate(-50%, -50%);
width: 2vw;
height: 2vw;
border-radius: 50%;
background-color: blue;
}

/* Y轴移动动画 */
@keyframes moveY {
from {
top: 0;
}
to {
top: 100%;
}
}
/* X轴移动动画 */
@keyframes moveX {
from {
left: 0;
}
to {
left: 100%;
}
}

#wrapper > .ball1 {
/* moveY需要比moveX延迟一段时间,才能显示出椭圆轨迹,这个时间为--ballAnimDeley*/
/* animation: name duration timing-function delay iteration-count direction fill-mode; */
animation:
moveY calc(var(--ballAnimTime) / 2) cubic-bezier(0.6, 0.3, 0.3, 0.6) calc(-1 * (var(--ballAnimDeley) + 0 * var(--ballUnitAnimTime))) infinite alternate,
moveX calc(var(--ballAnimTime) / 2) cubic-bezier(0.6, 0.3, 0.3, 0.6) calc(-1 * 0 * var(--ballUnitAnimTime)) infinite alternate;
}

#wrapper > .ball2 {
animation:
moveY calc(var(--ballAnimTime) / 2) cubic-bezier(0.6, 0.3, 0.3, 0.6) calc(-1 * (var(--ballAnimDeley) + 1 * var(--ballUnitAnimTime))) infinite alternate,
moveX calc(var(--ballAnimTime) / 2) cubic-bezier(0.6, 0.3, 0.3, 0.6) calc(-1 * 1 * var(--ballUnitAnimTime)) infinite alternate;
}
</style>
</head>
<body>
<p>线框右下角可以拖拽改变大小</p>
<div id="wrapper">
<div class="ball ball1"></div>
<div class="ball ball2"></div>
</div>
</body>
</html>

<!-- more -->

参考https://www.cnblogs.com/lin494910940/p/14051631.html



用Javascript实现

后来发现css实现的效果不好,小球运动到盒子四边时会有明显的碰撞感,所以这里用js实现一下

目录结构

  • EllipsisGenerator.js
  • index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// EllipsisGenerator.js

/**
* 椭圆轨道坐标生成器类
*/
class EllipsisGenerator {
x;
y;
a;
b;
angle;
angleStep;

/**
* 构造一个椭圆轨道
* @param {Number} x 圆心x坐标
* @param {Number} y 圆心y坐标
* @param {Number} a x轴半径长度
* @param {Number} b y轴半径长度
* @param {Number} angle 起始角度 单位deg
* @param {Number} angleStep 角度自增值 单位deg
*/
constructor(x, y, a, b, angle = 0, angleStep = 1) {
this.x = x;
this.y = y;
this.a = a;
this.b = b;
this.angle = angle;
this.angleStep = angleStep;
}

/**
* *generate方法返回一个迭代器,每次调用迭代器的next方法就会使角度(this.angle)自增(this.angleStep),
* 然后返回角度射线与椭圆轨道的交点坐标(x,y),即椭圆轨道坐标
*/
*generate() {
while (true) {
let radians = this.angle * Math.PI / 180
, tx = this.a * Math.cos(radians)
, ty = this.b * Math.sin(radians);

yield {
x: this.x + tx,
y: this.y + ty
}

if (this.angle >= 360) {
this.angle = 1;
} else {
this.angle += this.angleStep;
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<canvas id="container" style="border: 1px solid"></canvas>
<script src="./EllipsisGenerator.js"></script>
<script>
const bubbleCount = 100; // 球球数量
const bubbleRadius = 10; // 球球半径
const frameRate = 40; // 渲染帧数;每秒40帧
const bubbleColor = 'yellowgreen';
const bubbles = [];
class Bubble {
x;
y;
r;
alpha;
constructor(x = 0, y = 0, r = 1, alpha = 1) {
this.x = x;
this.y = y;
this.r = r;
this.alpha = alpha;
}
}

const $star = document.getElementById('container');
const width = 600;
const height = 400;
$star.width = width;
$star.height = height;

const elliptic = new EllipsisGenerator(
width / 2,
height / 2,
width / 2 - bubbleRadius,
height / 2 - bubbleRadius,
0,
-1
);
const generate = elliptic.generate();

const ctx = $star.getContext('2d');

const run = () => {
ctx.clearRect(0, 0, width, height);
let { x, y } = generate.next().value;

if (bubbles.length >= bubbleCount) {
bubbles.shift();
}

let bubble = new Bubble(x, y, 2);
bubbles.push(bubble);

//渲染bubble数组
for (let i = 0; i < bubbles.length; i++) {
let bubble = bubbles[i];
bubble.alpha = (i + 1) * (1 / bubbleCount);
bubble.r = bubble.r * (i + 1) * (1 / bubbleCount);

ctx.save();
ctx.beginPath();
ctx.globalAlpha = bubble.alpha * 0.5;
ctx.fillStyle = bubbleColor;
ctx.arc(
bubble.x,
bubble.y,
bubble.r * 4,
0,
2 * Math.PI,
false
);
ctx.fill();
ctx.restore();
}

setTimeout(() => {
requestAnimationFrame(run);
}, 1000 / frameRate);
};

run();
</script>
</body>
</html>

  • 标题: 用CSS做一个椭圆轨道小球运动动画
  • 作者: 木头的喵喵拖孩
  • 创建于: 2023-05-12 12:03:50
  • 更新于: 2024-05-21 10:56:15
  • 链接: https://blog.xx-xx.top/2023/05/12/用CSS做一个椭圆轨道小球运动动画/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
此页目录
用CSS做一个椭圆轨道小球运动动画