console
let box = document.querySelector('.box')
// 获取 canvas 元素和上下文
var line_canvas = document.getElementById("circleCanvas");
var line_ctx = line_canvas.getContext("2d");
var dot_canvas = document.getElementById("dotCanvas");
var dot_ctx = dot_canvas.getContext("2d");
let num = 1 // 数量
let first_radius = 50 // 第一个的半径
let interval = 10 // 间距
// 绘图中心点
let center_x = line_canvas.width / 2
let center_y = line_canvas.height
// 小球的线速度
var linearSpeed = 1; // 可以根据需要调整线速度的大小
let circle_list = []
let dot_list = []
// 随机生成颜色数组
function generateRainbowColors(numColors, saturation = 1, value = 1) {
function HSVtoRGB(h, s, v) {
let r, g, b, i, f, p, q, t;
if (s === 0) {
r = g = b = v;
} else {
h /= 60;
i = Math.floor(h);
f = h - i;
p = v * (1 - s);
q = v * (1 - s * f);
t = v * (1 - s * (1 - f));
switch (i % 6) {
case 0:
r = v; g = t; b = p;
break;
case 1:
r = q; g = v; b = p;
break;
case 2:
r = p; g = v; b = t;
break;
case 3:
r = p; g = q; b = v;
break;
case 4:
r = t; g = p; b = v;
break;
case 5:
r = v; g = p; b = q;
break;
}
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
const rainbowColors = [];
for (let i = 0; i < numColors; i++) {
// 计算当前色相值,从红色(0°)到紫色(360°)
const hue = (i / numColors) * 360;
// 使用指定的饱和度和亮度
const [r, g, b] = HSVtoRGB(hue, saturation, value);
// 转换成十六进制字符串
const color = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
rainbowColors.push(color);
}
return rainbowColors;
}
// 混合两种颜色
function mixColor(color1, color2, weight) {
var d2h = function (d) { return d.toString(16).padStart(2, '0'); }; // 将十进制值转为十六进制
var h2d = function (h) { return parseInt(h, 16); }; // 将十六进制值转为十进制
// 解析颜色
var color = "#";
for (var i = 1; i < 7; i += 2) {
var v1 = h2d(color1.substr(i, 2));
var v2 = h2d(color2.substr(i, 2));
// 混合两种颜色的分量
var val = d2h(Math.floor(v2 + (v1 - v2) * weight));
color += val;
}
return color;
}
// 绘制半圆
function drawCircle() {
circle_list.forEach(option => {
line_ctx.beginPath();
line_ctx.arc(center_x, center_y, option.radius, Math.PI, 0);
line_ctx.lineWidth = option.line_width; // 设置线宽来控制圆环的宽度
line_ctx.strokeStyle = option.color; // 设置圆环的颜色
line_ctx.stroke();
})
}
// 绘制小球
function drawDot() {
dot_ctx.clearRect(0, 0, dot_canvas.width, dot_canvas.height);
// 绘制每个小球
dot_list.forEach(function (ball) {
var x = center_x - ball.radius * Math.cos(ball.angle);
var y = center_y - ball.radius * Math.sin(ball.angle);
// 计算当前的角度所占比例
var weight = ball.angle / Math.PI; // 从 0 到 1 的权重
// 根据方向更新角度
if (ball.direction) {
ball.angle += ball.angularSpeed;
} else {
ball.angle -= ball.angularSpeed;
}
// 当圆点达到180度或0度时改变运动方向
if (ball.angle >= Math.PI || ball.angle <= 0) {
ball.direction = !ball.direction;
}
// 如果是逆时针方向 (direction == false),则从指定颜色混合到白色
// 如果是顺时针方向 (direction == true),则从白色混合到指定颜色
var color = ball.direction
? mixColor(ball.color, '#FFFFFF', weight)
: mixColor('#FFFFFF', ball.color, weight);
// 绘制小球
dot_ctx.beginPath();
dot_ctx.arc(x, y, 5, 0, 2 * Math.PI); // 小球的大小固定为半径 5
dot_ctx.fillStyle = color;
dot_ctx.fill();
});
requestAnimationFrame(drawDot);
}
function init() {
let colors = generateRainbowColors(num, 0.75, 0.8)
new Array(num).fill({}).forEach((item, index) => {
let radius = first_radius + index * interval
circle_list.push({
line_width: 2,
radius,
color: colors[index],
})
dot_list.push({
angularSpeed: linearSpeed / radius,
radius,
angle: 0,
color: colors[index],
direction: true
})
})
drawCircle()
drawDot()
}
init()
<div class="relative box">
<canvas class="absolute" width="600" height="400" id="circleCanvas"></canvas>
<canvas class="absolute" width="600" height="400" id="dotCanvas"></canvas>
</div>
.relative{
position: relative
}
.absolute{
position: absolute
}
.box{
width: 600px;
height: 400px;
background-color: #282828;
}