265 lines
11 KiB
HTML
265 lines
11 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-cn">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>多画布 JS 动画演示</title>
|
||
<script src="https://wantsong.life/p5-demo/p5.js"></script>
|
||
<style>
|
||
body {
|
||
margin: 0;
|
||
padding: 20px;
|
||
display: flex;
|
||
flex-direction: column; /* Stack title and canvases */
|
||
align-items: center;
|
||
min-height: 100vh;
|
||
background-color: #1e1e1e; /* 深色背景 */
|
||
font-family: sans-serif;
|
||
color: #e0e0e0;
|
||
}
|
||
h1 {
|
||
margin-bottom: 20px;
|
||
}
|
||
#canvas-container-wrapper {
|
||
display: flex;
|
||
flex-wrap: wrap; /* 允许换行 */
|
||
gap: 20px; /* 画布之间的间距 */
|
||
justify-content: center; /* 水平居中 */
|
||
}
|
||
.canvas-container {
|
||
border: 1px solid #444; /* 给每个画布容器添加边框 */
|
||
box-shadow: 0 0 10px rgba(0,0,0,0.5);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div id="canvas-container-wrapper">
|
||
<div id="canvas-container-1" class="canvas-container"></div>
|
||
<div id="canvas-container-2" class="canvas-container"></div>
|
||
<div id="canvas-container-3" class="canvas-container"></div>
|
||
<div id="canvas-container-4" class="canvas-container"></div>
|
||
<div id="canvas-container-5" class="canvas-container"></div>
|
||
</div>
|
||
|
||
<script>
|
||
// 工厂函数,用于创建 p5.js sketch
|
||
const drawPatternPoint_original = (p, x, y_in, t_current, canvasWidth, canvasHeight) => {
|
||
// 参数来自原始公式 (有些是隐式的)
|
||
let k_p1 = 4, k_p2 = 2, k_p3 = 3, k_p4 = 29;
|
||
let e_p1 = 8, e_p2 = 13;
|
||
let q_p1 = 3, q_p2 = 2, q_p3 = 0.3;
|
||
let q_s_p1 = 25;
|
||
let q_k_mult_c1 = 9, q_k_mult_c2 = 4;
|
||
let q_k_mult_sine_e = 9, q_k_mult_sine_d = 3, q_k_mult_sine_t = 2;
|
||
let pt_p1 = 30, pt_p2 = 39;
|
||
|
||
const k_val = (k_p1 + p.sin(y_in * k_p2 - t_current) * k_p3) * p.cos(x / k_p4);
|
||
const e_val = y_in / e_p1 - e_p2;
|
||
const d_val = p.mag(k_val, e_val);
|
||
const c_val = d_val - t_current;
|
||
|
||
let k_for_division = k_val;
|
||
const min_k_magnitude = 0.1; // 防止除以非常小的数
|
||
if (Math.abs(k_for_division) < min_k_magnitude) {
|
||
k_for_division = min_k_magnitude * (Math.sign(k_for_division) || 1);
|
||
}
|
||
|
||
const q_val_calc = q_p1 * p.sin(k_val * q_p2) +
|
||
q_p3 / k_for_division +
|
||
p.sin(y_in / q_s_p1) * k_val *
|
||
(q_k_mult_c1 + q_k_mult_c2 * p.sin(e_val * q_k_mult_sine_e - d_val * q_k_mult_sine_d + t_current * q_k_mult_sine_t));
|
||
|
||
// 图案在“原始400x400画布”上的坐标(应用了原始偏移)
|
||
let pattern_x_component = q_val_calc + pt_p1 * p.cos(c_val);
|
||
let pattern_y_component = q_val_calc * p.sin(c_val) + d_val * pt_p2;
|
||
|
||
const original_global_x_offset = 200;
|
||
const original_global_y_offset = -220; // 原始公式的Y偏移
|
||
const original_canvas_width = 400;
|
||
const original_canvas_height = 400;
|
||
|
||
let x_on_original_canvas = pattern_x_component + original_global_x_offset;
|
||
let y_on_original_canvas = pattern_y_component + original_global_y_offset;
|
||
|
||
// 缩放到当前画布尺寸
|
||
const finalX = (x_on_original_canvas / original_canvas_width) * canvasWidth;
|
||
const finalY = (y_on_original_canvas / original_canvas_height) * canvasHeight;
|
||
|
||
p.point(finalX, finalY);
|
||
};
|
||
|
||
// --- 2. 新算法变体 1: "宇宙风车" ---
|
||
const drawPatternPoint_variant1 = (p, x_input, y_input, t_current, canvasWidth, canvasHeight) => {
|
||
const k_amp = 1.5 + p.sin(t_current * 0.15) * 0.5;
|
||
const k_freq1 = 0.025 + p.cos(t_current * 0.06) * 0.01;
|
||
const d_scale = 0.035 + p.sin(t_current * 0.08) * 0.01;
|
||
const q_amp = 1.8;
|
||
|
||
let k = k_amp * p.sin(x_input * k_freq1 - t_current * 1.2) * p.cos(y_input * k_freq1 * 0.8 + t_current * 0.6);
|
||
let e = p.atan2(y_input / 12 - 8, x_input / 22 - 6) + t_current * 0.25;
|
||
let d = p.mag(p.cos(x_input * d_scale + t_current*0.1), p.sin(y_input * d_scale - t_current*0.1)) * 60 + k * 25;
|
||
|
||
let c = d * 0.12 + e + t_current * 0.9;
|
||
|
||
let q_base = p.sin(k * q_amp + t_current * 2.2) + p.cos(d * 0.06 - t_current * 1.1);
|
||
let q = q_base * (70 + p.sin(e * 2.5 + t_current * 1.5) * 35);
|
||
q += p.tan((k + e * 0.5) * 0.1 + t_current * 0.33) * 8;
|
||
|
||
let pattern_x_component = q * p.cos(c) + d * p.sin(e * 1.2);
|
||
let pattern_y_component = q * p.sin(c) - d * p.cos(e * 1.2);
|
||
|
||
const original_global_x_offset = 200;
|
||
const original_global_y_offset = 200; // 调整Y偏移以适应新公式的视觉中心
|
||
const original_canvas_width = 400;
|
||
const original_canvas_height = 400;
|
||
|
||
let x_on_original_canvas = pattern_x_component + original_global_x_offset;
|
||
let y_on_original_canvas = pattern_y_component + original_global_y_offset;
|
||
|
||
const finalX = (x_on_original_canvas / original_canvas_width) * canvasWidth;
|
||
const finalY = (y_on_original_canvas / original_canvas_height) * canvasHeight;
|
||
p.point(finalX, finalY);
|
||
};
|
||
|
||
// --- 3. 新算法变体 2: "电光网格" ---
|
||
const drawPatternPoint_variant2 = (p, x_input, y_input, t_current, canvasWidth, canvasHeight) => {
|
||
const grid_scale = 0.12 + p.sin(t_current * 0.22) * 0.04;
|
||
const ripple_amp = 18 + p.cos(t_current * 0.35) * 6;
|
||
const d_factor = 1.8;
|
||
const q_mod = 35;
|
||
|
||
let gx = x_input * grid_scale;
|
||
let gy = y_input * grid_scale;
|
||
|
||
let k = p.sin(gx + t_current * 1.1) * ripple_amp + p.cos(gy - t_current * 0.9) * ripple_amp;
|
||
k += p.floor(gx * 0.5) * 8;
|
||
|
||
let e = p.cos(gy + t_current * 1.3) * ripple_amp - p.sin(gx - t_current * 0.7) * ripple_amp;
|
||
e += p.floor(gy * 0.5) * 8;
|
||
|
||
let d = p.mag(k, e) * d_factor;
|
||
d = (d % 180) + p.sin(t_current + gx*0.1)*20;
|
||
|
||
let c = p.atan2(e, k) + t_current * 0.55 + p.sin(gy*0.2)*0.5;
|
||
|
||
let q = (p.sin(d * 0.08 + t_current * 1.4) * q_mod) + (p.cos( (k/(Math.abs(k)>0.1?k:0.1)) * 0.06 - t_current) * q_mod);
|
||
q += (x_input % 60 - 30) * p.cos(t_current * 0.8 + gy * 0.3);
|
||
|
||
let pattern_x_component = q * p.cos(c + d*0.01) + k * 0.7;
|
||
let pattern_y_component = q * p.sin(c - d*0.01) + e * 0.7;
|
||
|
||
const original_global_x_offset = 200;
|
||
const original_global_y_offset = 200;
|
||
const original_canvas_width = 400;
|
||
const original_canvas_height = 400;
|
||
|
||
let x_on_original_canvas = pattern_x_component + original_global_x_offset;
|
||
let y_on_original_canvas = pattern_y_component + original_global_y_offset;
|
||
|
||
const finalX = (x_on_original_canvas / original_canvas_width) * canvasWidth;
|
||
const finalY = (y_on_original_canvas / original_canvas_height) * canvasHeight;
|
||
p.point(finalX, finalY);
|
||
};
|
||
|
||
// --- 4. 新算法变体 3: "流动丝线" ---
|
||
const drawPatternPoint_variant3 = (p, x_input, y_input, t_current, canvasWidth, canvasHeight) => {
|
||
const scale1 = 0.025 + p.sin(t_current * 0.06) * 0.01;
|
||
const scale2 = 0.035 + p.cos(t_current * 0.09) * 0.01;
|
||
const time_factor_k = 0.55 + p.sin(t_current * 0.11) * 0.2;
|
||
const time_factor_e = 0.35 + p.cos(t_current * 0.13) * 0.1;
|
||
|
||
let k_base = p.sin(x_input * scale1 + y_input * scale2 * 0.7 + t_current * time_factor_k);
|
||
let e_base = p.cos(x_input * scale2 * 0.7 - y_input * scale1 + t_current * time_factor_e);
|
||
|
||
let k = k_base * (90 + p.sin(t_current * 0.22 + x_input * 0.015) * 35);
|
||
let e = e_base * (90 + p.cos(t_current * 0.27 + y_input * 0.015) * 35);
|
||
|
||
let d = p.sqrt(k*k + e*e) * 0.35;
|
||
d = p.abs(p.tan(d * 0.06 + t_current * 0.33)) * 22;
|
||
d = p.constrain(d, 0, 160);
|
||
|
||
let angle_offset = p.sin(t_current * 0.45 + (x_input - y_input) * 0.006) * p.PI * 0.8;
|
||
let c = p.atan2(e_base, k_base) + angle_offset + t_current*0.2;
|
||
|
||
let q_val = p.sin(d * 0.11 - t_current * 1.3) * 55;
|
||
q_val += p.cos((k_base - e_base) * 5.5 + t_current * 2.1) * (35 + p.sin(t_current*0.55)*12);
|
||
|
||
let pattern_x_component = q_val * p.cos(c) + d * p.sin(c + p.PI / 1.8);
|
||
let pattern_y_component = q_val * p.sin(c) - d * p.cos(c + p.PI / 1.8);
|
||
|
||
const original_global_x_offset = 200;
|
||
const original_global_y_offset = 200;
|
||
const original_canvas_width = 400;
|
||
const original_canvas_height = 400;
|
||
|
||
let x_on_original_canvas = pattern_x_component + original_global_x_offset;
|
||
let y_on_original_canvas = pattern_y_component + original_global_y_offset;
|
||
|
||
const finalX = (x_on_original_canvas / original_canvas_width) * canvasWidth;
|
||
const finalY = (y_on_original_canvas / original_canvas_height) * canvasHeight;
|
||
p.point(finalX, finalY);
|
||
};
|
||
|
||
const sketchFactory = (config) => {
|
||
return (p) => {
|
||
p.t = 0; // 每个 sketch 独立的时间变量
|
||
const canvasWidth = config.canvasSize;
|
||
const canvasHeight = config.canvasSize;
|
||
const numPoints = config.points;
|
||
const type = config.type; // 这个 'type' 将用来选择绘图函数
|
||
|
||
let currentDrawingFunction; // 用于存储选定的绘图函数
|
||
|
||
// 根据 type 选择绘图函数
|
||
switch (type) {
|
||
case 1:
|
||
currentDrawingFunction = drawPatternPoint_variant1;
|
||
break;
|
||
case 2:
|
||
currentDrawingFunction = drawPatternPoint_variant2;
|
||
break;
|
||
case 3:
|
||
currentDrawingFunction = drawPatternPoint_variant3;
|
||
break;
|
||
// 您可以添加 case 4, case 5 等来对应更多的变体
|
||
default: // type 0 或其他未指定的值将使用原始算法
|
||
currentDrawingFunction = drawPatternPoint_original;
|
||
}
|
||
|
||
p.setup = () => {
|
||
p.createCanvas(canvasWidth, canvasHeight);
|
||
};
|
||
|
||
p.draw = () => {
|
||
p.background(9);
|
||
p.stroke(255, 96);
|
||
|
||
p.t += p.PI / 240; // 更新当前 sketch 的时间
|
||
|
||
for (let i = 0; i < numPoints; i++) {
|
||
// 调用选定的绘图函数
|
||
// 参数: p5实例, x输入, y输入, 当前时间, 画布宽, 画布高
|
||
currentDrawingFunction(p, i, i / 235, p.t, canvasWidth, canvasHeight);
|
||
}
|
||
};
|
||
};
|
||
};
|
||
|
||
// --- 6. 更新 canvasConfigs 以使用新的类型 ---
|
||
const canvasConfigs = [
|
||
{ type: 0, canvasSize: 400, points: 8000 }, // 使用原始算法
|
||
{ type: 1, canvasSize: 400, points: 2000 }, // 使用变体1
|
||
{ type: 2, canvasSize: 400, points: 8000 }, // 使用变体2
|
||
{ type: 3, canvasSize: 400, points: 8000 }, // 使用变体3
|
||
{ type: 1, canvasSize: 400, points: 8500 } // 再次使用变体1 (或选择其他类型,可以增加点数)
|
||
];
|
||
|
||
// --- 7. 创建 p5 实例 (这部分代码保持不变) ---
|
||
canvasConfigs.forEach((config, index) => {
|
||
const containerId = `canvas-container-${index + 1}`;
|
||
new p5(sketchFactory(config), containerId);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |