当前位置: 首页 > article >正文

用HTML5 Canvas打造交互式心形粒子动画:从基础到优化实战

用HTML5 Canvas打造交互式心形粒子动画:从基础到优化实战

在这里插入图片描述


引言

在Web交互设计中,粒子动画因其动态美感和视觉吸引力被广泛应用于节日特效、情感化界面等场景。本文将通过实战案例,详细讲解如何使用HTML5 Canvas和JavaScript实现一个「心之律动」交互式粒子艺术效果,包含心形粒子循环动画、鼠标轨迹粒子、烟花爆炸及坠落效果,并分享关键优化技巧。

技术栈概览

  • HTML5 Canvas:实现高性能粒子渲染
  • JavaScript:粒子系统逻辑控制
  • Tailwind CSS:快速构建UI界面
  • Font Awesome:图标库支持

一、基础框架搭建

1. 画布初始化

<canvas id="canvas"></canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');// 自适应屏幕尺寸
function resizeCanvas() {canvas.width = window.innerWidth;canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);

2. UI界面设计

使用Tailwind CSS构建半透明控制栏和信息面板,实现响应式布局:

<div class="controls"><div class="control-btn" id="reset-btn"><i class="fa fa-refresh"></i></div><!-- 暂停/增加/减少按钮 -->
</div><div class="info-panel"><div>粒子数量: <span id="particle-count">0</span></div><p><i class="fa fa-mouse-pointer"></i> 鼠标移动生成轨迹</p>
</div>

二、核心粒子系统实现

1. 粒子类设计

定义Particle类,通过type属性区分不同粒子类型(心形/鼠标轨迹/烟花/坠落),实现多态行为:

class Particle {constructor(x, y, type) {this.x = x;this.y = y;this.type = type;// 根据类型初始化不同属性type === 'heart' ? this.setupHeartParticle() :type === 'mouse' ? this.setupMouseParticle() :type === 'firework' ? this.setupFireworkParticle() :this.setupFallingParticle();}// 心形粒子专属属性setupHeartParticle() {this.layer = Math.floor(Math.random() * 4); // 0-3层this.color = particleColors[this.layer][Math.floor(Math.random() * 3)];this.size = 2 + (8 - this.layer * 2) * Math.random();this.angle = Math.random() * 2 * Math.PI; // 随机方向this.life = 150 + 100 * Math.random() - this.layer * 30; // 分层寿命}// 更新粒子状态update() {// 心形粒子使用极坐标运动if (this.type === 'heart') {this.x += Math.cos(this.angle) * this.speed;this.y += Math.sin(this.angle) * this.speed;}// 烟花粒子使用笛卡尔坐标+物理模拟else if (this.type === 'firework') {this.vx *= this.friction; // 摩擦力this.vy += this.gravity; // 重力this.x += this.vx;this.y += this.vy;}// 生命周期管理this.life--;this.currentAlpha = this.life / this.maxLife;}
}

三、心形动画核心实现

1. 心形参数方程

使用经典心形参数方程生成粒子初始位置:

// 心形参数方程:x=16sin³t,y=13cost-5cos2t-2cos3t-cos4t
generateHeartPoint(t, scale) {const x = 16 * Math.pow(Math.sin(t), 3);const y = 13 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t);// 映射到画布中心并缩放return {x: canvas.width/2 + x * (canvas.width*0.35*scale)/16,y: canvas.height/2 - y * (canvas.width*0.35*scale)/16};
}

2. 粒子循环再生机制

通过每帧检测心形粒子数量,动态补充消失的粒子,实现持续动画:

class HeartAnimation {constructor() {this.heartParticleCount = 1500; // 目标粒子数this.heartRegenRate = 5; // 每帧再生数量this.generateHeartParticles(this.heartParticleCount);}animate() {// 检测存活心形粒子数量let heartCount = this.particles.filter(p => p.type === 'heart').length;// 补充缺失粒子if (heartCount < this.heartParticleCount) {const toAdd = Math.min(this.heartRegenRate, this.heartParticleCount - heartCount);this.regenerateHeartParticles(toAdd);}requestAnimationFrame(this.animate.bind(this));}
}

四、烟花效果深度优化

1. 物理模拟增强

  • 笛卡尔坐标系:使用vx/vy分量精确控制运动
  • 重力系统this.gravity = 0.05模拟自由落体
  • 空气阻力this.friction = 0.97实现速度衰减
setupFireworkParticle() {this.vx = Math.cos(this.angle) * this.baseSpeed;this.vy = Math.sin(this.angle) * this.baseSpeed;this.gravity = 0.05;this.friction = 0.97 + Math.random()*0.01;
}

2. 多阶段爆炸效果

通过延迟释放不同类型粒子,模拟真实烟花层次感:

createFirework(x, y) {// 主爆炸this.createFireworkWave(x, y, 180, 0);// 150ms后释放外围粒子setTimeout(() => {this.createFireworkWave(x, y, 120, 10, false, 1.5);}, 150);// 250ms后释放精细粒子setTimeout(() => {this.createFireworkWave(x, y, 150, 15, true);}, 250);
}

3. 坠落效果转换

当烟花粒子速度低于阈值时,转换为坠落粒子并添加风力效果:

if (this.type === 'firework' && Math.abs(this.vy) < 0.3) {this.type = 'falling';this.setupFallingParticle(); // 启用风力和更快下落
}

五、交互功能实现

1. 鼠标轨迹生成

通过高频次生成带随机偏移的粒子,形成连续轨迹:

handleMouseMove(e) {const now = Date.now();if (now - this.lastMouseMove > 15) {// 每次移动生成6个偏移粒子for (let i=0; i<6; i++) {this.particles.push(new Particle(e.clientX + (Math.random()-0.5)*20, e.clientY + (Math.random()-0.5)*20, 'mouse'));}this.lastMouseMove = now;}
}

2. 控制按钮逻辑

实现粒子数量调整、动画暂停和重置功能:

handleIncrease() {this.heartParticleCount += 300;this.generateHeartParticles(300); // 批量生成
}handleReset() {this.particles = []; // 清空所有粒子this.generateHeartParticles(this.heartParticleCount); // 重新生成心形
}

六、性能优化要点

  1. 粒子生命周期管理:及时移除死亡粒子,避免内存泄漏
for (let i=this.particles.length-1; i>=0; i--) {if (!this.particles[i].isAlive()) {this.particles.splice(i, 1); // 逆序删除避免索引错乱}
}
  1. 画布清理策略:使用clearRect而非全量重绘
ctx.clearRect(0, 0, canvas.width, canvas.height); // 只清除可见区域
  1. 分层渲染优化:将不同类型粒子分组管理,减少状态判断

效果展示

  • 基础效果:中心悬浮动态心形,粒子随心跳效果呼吸缩放
  • 交互效果
    • 鼠标移动生成彩色拖尾轨迹
    • 点击屏幕触发多层烟花爆炸,伴随真实物理坠落
    • 底部控制栏可调整粒子数量、暂停动画、重置场景

总结

通过HTML5 Canvas的高性能渲染能力,结合物理模拟和粒子系统设计,我们实现了一个兼具视觉美感和交互乐趣的心形动画。核心技术点包括:

  • 基于参数方程的几何图形生成
  • 多类型粒子的状态机设计
  • 物理引擎(重力、摩擦力、风力)的实现
  • 交互式粒子系统的性能优化

完整代码

心之律动 | 交互式粒子艺术
<div class="overlay"><h1 class="title animate-pulse-slow">心之律动</h1><p class="subtitle">鼠标滑过留下痕迹,点击释放烟花</p>
</div><div class="controls"><div class="control-btn" id="reset-btn" title="重置"><i class="fa fa-refresh"></i></div><div class="control-btn" id="pause-btn" title="暂停/继续"><i class="fa fa-pause"></i></div><div class="control-btn" id="increase-btn" title="增加粒子"><i class="fa fa-plus"></i></div><div class="control-btn" id="decrease-btn" title="减少粒子"><i class="fa fa-minus"></i></div>
</div><div class="info-panel"><div class="particles-count"><span id="particle-count">粒子数量: 0</span></div><div class="instructions"><p><i class="fa fa-mouse-pointer heart-icon"></i> 鼠标移动: 留下粒子轨迹</p><p><i class="fa fa-hand-pointer-o heart-icon"></i> 点击: 释放烟花</p><p><i class="fa fa-refresh heart-icon"></i> 重置: 重新生成心形</p></div>
</div><script>// 初始化画布const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');// 设置画布尺寸function resizeCanvas() {canvas.width = window.innerWidth;canvas.height = window.innerHeight;}resizeCanvas();window.addEventListener('resize', resizeCanvas);// 粒子颜色方案const particleColors = ['#FF5E87', '#FF85A2', '#FFB3C6', '#FFC2D1', '#FFD7E4','#FF9AA2', '#FFB7B2', '#FFDAC1', '#E2F0CB', '#B5EAD7', '#C7CEEA','#A79AFF', '#C2A7FF', '#D8A7FF', '#EAA7FF', '#F5A7FF'];// 粒子类class Particle {constructor(x, y, type = 'heart') {this.x = x;this.y = y;this.type = type; // 'heart', 'mouse', 'firework', 'falling'// 根据粒子类型设置不同属性if (type === 'heart') {this.setupHeartParticle();} else if (type === 'mouse') {this.setupMouseParticle();} else if (type === 'firework') {this.setupFireworkParticle();} else if (type === 'falling') {this.setupFallingParticle();}// 为烟花粒子添加延迟效果if (type === 'firework') {this.delay = Math.random() * 15; // 延迟发射时间this.isActive = false;}}setupHeartParticle() {// 粒子层次(0=外层,1=中层,2=内层,3=中心)this.layer = Math.floor(Math.random() * 4);// 根据层次确定颜色const colorPools = [particleColors.slice(0, 3),  // 外层颜色 - 冷色particleColors.slice(3, 6),  // 中层颜色 - 中色particleColors.slice(6, 9),  // 内层颜色 - 暖色particleColors.slice(9)     // 中心颜色 - 最暖色];this.color = colorPools[this.layer][Math.floor(Math.random() * colorPools[this.layer].length)];// 根据层次确定大小this.size = 2 + Math.random() * (8 - this.layer * 2);// 根据层次确定速度this.speed = 0.1 + Math.random() * 0.3 + this.layer * 0.05;// 随机方向this.angle = Math.random() * Math.PI * 2;// 粒子寿命this.life = 150 + Math.random() * 100 - this.layer * 30;this.maxLife = this.life;}setupMouseParticle() {// 鼠标轨迹粒子属性 - 延长寿命this.color = particleColors[Math.floor(Math.random() * particleColors.length)];this.size = 1 + Math.random() * 3;this.speed = 0.05 + Math.random() * 0.1; // 降低速度,延长轨迹this.angle = Math.random() * Math.PI * 2;this.life = 100 + Math.random() * 80; // 延长寿命this.maxLife = this.life;}setupFireworkParticle() {// 烟花粒子属性 - 更大范围this.color = particleColors[Math.floor(Math.random() * particleColors.length)];this.size = 1.5 + Math.random() * 4;this.baseSpeed = 2 + Math.random() * 3; // 更高初始速度,更大范围this.angle = Math.random() * Math.PI * 2;this.life = 100 + Math.random() * 80; // 延长烟花粒子寿命this.maxLife = this.life;this.gravity = 0.05; // 增加重力效果this.friction = 0.97 + Math.random() * 0.01; // 添加摩擦力// 使用笛卡尔坐标系统this.vx = Math.cos(this.angle) * this.baseSpeed;this.vy = Math.sin(this.angle) * this.baseSpeed;}setupFallingParticle() {// 坠落粒子属性this.color = particleColors[Math.floor(Math.random() * particleColors.length)];this.size = 0.5 + Math.random() * 2;this.speed = 0.5 + Math.random() * 1.5;// 确保角度主要向下(π到2π之间)this.angle = Math.PI + (Math.random() - 0.5) * Math.PI * 0.6; this.life = 80 + Math.random() * 120;this.maxLife = this.life;this.gravity = 0.03; // 增加重力效果this.wind = (Math.random() - 0.5) * 0.003; // 水平风力,减小偏移}update() {// 烟花粒子延迟激活if (this.type === 'firework' && !this.isActive) {this.delay--;if (this.delay <= 0) {this.isActive = true;}return;}// 更新位置 - 使用笛卡尔坐标系统if (this.type === 'firework' && this.isActive) {// 应用摩擦力this.vx *= this.friction;this.vy *= this.friction;// 应用重力this.vy += this.gravity;this.x += this.vx;this.y += this.vy;// 当烟花粒子速度足够慢时,转换为坠落粒子if (Math.abs(this.vy) > 0.3 && Math.random() < 0.08 && this.life > 40) {this.type = 'falling';this.setupFallingParticle();}} else {// 其他粒子使用极坐标系统this.x += Math.cos(this.angle) * this.speed;this.y += Math.sin(this.angle) * this.speed;}if (this.type === 'falling') {this.speed += this.gravity;this.x += this.wind;}// 更新寿命this.life--;// 心跳效果 - 改变粒子大小和不透明度const heartbeatPhase = (Date.now() / 800) % (Math.PI * 2);const heartbeatFactor = 1.0 + 0.15 * Math.sin(heartbeatPhase);// 对于心形粒子,使用更明显的心跳效果if (this.type === 'heart') {this.currentSize = this.size * heartbeatFactor * (this.life / this.maxLife);this.currentAlpha = (this.life / this.maxLife) * (0.8 + 0.2 * Math.sin(heartbeatPhase + this.layer * 0.5));} else {this.currentSize = this.size * (this.life / this.maxLife);this.currentAlpha = this.life / this.maxLife;}}draw() {// 延迟的烟花粒子不绘制if (this.type === 'firework' && !this.isActive) {return;}// 绘制粒子ctx.fillStyle = this.color;ctx.beginPath();ctx.arc(this.x, this.y, this.currentSize, 0, Math.PI * 2);ctx.closePath();ctx.globalAlpha = this.currentAlpha;ctx.fill();ctx.globalAlpha = 1;}isAlive() {return this.life > 0;}}// 心形粒子动画类class HeartAnimation {constructor() {this.particles = [];this.isPaused = false;this.mouse = { x: 0, y: 0, isDown: false };this.lastMouseMove = 0;this.particleCount = 0;this.heartParticleCount = 1500; // 心形粒子目标数量this.heartRegenRate = 5; // 每帧重新生成的心形粒子数量// 绑定事件处理函数this.handleMouseMove = this.handleMouseMove.bind(this);this.handleMouseDown = this.handleMouseDown.bind(this);this.handleMouseUp = this.handleMouseUp.bind(this);this.handleReset = this.handleReset.bind(this);this.handlePause = this.handlePause.bind(this);this.handleIncrease = this.handleIncrease.bind(this);this.handleDecrease = this.handleDecrease.bind(this);// 注册事件监听器window.addEventListener('mousemove', this.handleMouseMove);window.addEventListener('mousedown', this.handleMouseDown);window.addEventListener('mouseup', this.handleMouseUp);document.getElementById('reset-btn').addEventListener('click', this.handleReset);document.getElementById('pause-btn').addEventListener('click', this.handlePause);document.getElementById('increase-btn').addEventListener('click', this.handleIncrease);document.getElementById('decrease-btn').addEventListener('click', this.handleDecrease);// 生成初始心形粒子this.generateHeartParticles(this.heartParticleCount);// 开始动画循环this.animate();}// 判断点是否在心形内部isInsideHeart(x, y, scale = 1) {// 归一化坐标const centerX = canvas.width / 2;const centerY = canvas.height / 2;const nx = (x - centerX) / (canvas.width / 2);const ny = (y - centerY) / (canvas.height / 2);// 心形方程: (x² + y² - 1)³ - x²y³ ≤ 0const heartEq = Math.pow(nx*nx + ny*ny - 1, 3) - nx*nx*ny*ny*ny;return heartEq <= 0;}// 生成心形参数方程的点generateHeartPoint(t, scale = 1) {// 心形参数方程const x = 16 * Math.pow(Math.sin(t), 3);const y = 13 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t);// 归一化并缩放const centerX = canvas.width / 2;const centerY = canvas.height / 2;const heartScale = Math.min(canvas.width, canvas.height) * 0.35 * scale;return {x: centerX + x * heartScale / 16,y: centerY - y * heartScale / 16  // 注意y轴是向下的};}// 生成心形粒子generateHeartParticles(count) {for (let i = 0; i < count; i++) {// 随机选择层次const layer = Math.floor(Math.random() * 4);// 根据层次确定缩放比例let scale;if (layer === 0) scale = 1.0;  // 外层else if (layer === 1) scale = 0.95;  // 中层else if (layer === 2) scale = 0.85;  // 内层else scale = 0.7;  // 中心层// 生成随机角度const t = Math.random() * Math.PI * 2;// 计算粒子位置const point = this.generateHeartPoint(t, scale);// 对于中心层,添加一些随机偏移,使其填充更均匀if (layer === 3) {const offset = Math.random() * 0.2 * (canvas.width / 2);point.x += (Math.random() - 0.5) * offset;point.y += (Math.random() - 0.5) * offset;// 确保点仍然在心形内部if (!this.isInsideHeart(point.x, point.y)) {continue;}}// 创建粒子this.particles.push(new Particle(point.x, point.y, 'heart'));}this.updateParticleCount();}// 重新生成心形粒子regenerateHeartParticles(count) {for (let i = 0; i < count; i++) {// 随机选择层次const layer = Math.floor(Math.random() * 4);// 根据层次确定缩放比例let scale;if (layer === 0) scale = 1.0;  // 外层else if (layer === 1) scale = 0.95;  // 中层else if (layer === 2) scale = 0.85;  // 内层else scale = 0.7;  // 中心层// 生成随机角度const t = Math.random() * Math.PI * 2;// 计算粒子位置const point = this.generateHeartPoint(t, scale);// 对于中心层,添加一些随机偏移,使其填充更均匀if (layer === 3) {const offset = Math.random() * 0.2 * (canvas.width / 2);point.x += (Math.random() - 0.5) * offset;point.y += (Math.random() - 0.5) * offset;// 确保点仍然在心形内部if (!this.isInsideHeart(point.x, point.y)) {continue;}}// 创建粒子this.particles.push(new Particle(point.x, point.y, 'heart'));}}// 鼠标移动处理handleMouseMove(e) {this.mouse.x = e.clientX;this.mouse.y = e.clientY;// 限制鼠标轨迹粒子生成频率const now = Date.now();if (now - this.lastMouseMove > 15) {  // 增加生成频率// 创建更多鼠标轨迹粒子,形成更连续的轨迹for (let i = 0; i < 6; i++) {const offsetX = (Math.random() - 0.5) * 20;  // 更大的偏移范围const offsetY = (Math.random() - 0.5) * 20;this.particles.push(new Particle(this.mouse.x + offsetX, this.mouse.y + offsetY, 'mouse'));}this.lastMouseMove = now;this.updateParticleCount();}}// 鼠标按下处理handleMouseDown() {this.mouse.isDown = true;this.createFirework(this.mouse.x, this.mouse.y);}// 鼠标释放处理handleMouseUp() {this.mouse.isDown = false;}// 创建烟花效果createFirework(x, y) {// 主烟花爆炸 - 分阶段释放粒子this.createFireworkWave(x, y, 180, 0);// 外围烟花 - 延迟释放,更大范围setTimeout(() => {if (this.isPaused) return;this.createFireworkWave(x, y, 120, 10, false, 1.5);}, 150);// 精细粒子 - 延迟释放,更精细的粒子setTimeout(() => {if (this.isPaused) return;this.createFireworkWave(x, y, 150, 15, true);}, 250);this.updateParticleCount();}// 创建一波烟花粒子createFireworkWave(x, y, count, baseDelay, fineParticles = false, speedMultiplier = 1) {for (let i = 0; i < count; i++) {const p = new Particle(x, y, 'firework');// 更精细的粒子if (fineParticles) {p.size = 0.5 + Math.random() * 1.5;p.baseSpeed = 1.5 + Math.random() * 2;p.life = 80 + Math.random() * 60;} else {p.size = 1 + Math.random() * 3;p.baseSpeed = (2 + Math.random() * 3) * speedMultiplier;}p.delay = baseDelay + Math.random() * 10;p.vx = Math.cos(p.angle) * p.baseSpeed;p.vy = Math.sin(p.angle) * p.baseSpeed;this.particles.push(p);}}// 重置动画handleReset() {// 清空现有粒子this.particles = [];// 生成新的心形粒子this.generateHeartParticles(this.heartParticleCount);}// 暂停/继续动画handlePause() {this.isPaused = !this.isPaused;const pauseBtn = document.getElementById('pause-btn');pauseBtn.innerHTML = this.isPaused ? '<i class="fa fa-play"></i>' : '<i class="fa fa-pause"></i>';}// 增加粒子数量handleIncrease() {this.heartParticleCount += 300;this.generateHeartParticles(300);}// 减少粒子数量handleDecrease() {// 保留最近添加的300个粒子if (this.heartParticleCount > 300) {this.heartParticleCount -= 300;// 移除部分粒子let removed = 0;for (let i = this.particles.length - 1; i >= 0; i--) {if (this.particles[i].type === 'heart') {this.particles.splice(i, 1);removed++;if (removed >= 300) break;}}this.updateParticleCount();}}// 更新粒子数量显示updateParticleCount() {this.particleCount = this.particles.length;document.getElementById('particle-count').textContent = `粒子数量: ${this.particleCount}`;}// 动画循环animate() {if (!this.isPaused) {// 清除画布ctx.clearRect(0, 0, canvas.width, canvas.height);// 计算当前心形粒子数量let heartParticles = 0;// 更新和绘制所有粒子for (let i = this.particles.length - 1; i >= 0; i--) {const particle = this.particles[i];if (particle.type === 'heart') {heartParticles++;}particle.update();if (particle.isAlive()) {particle.draw();} else {// 移除死亡的粒子this.particles.splice(i, 1);}}// 补充心形粒子if (heartParticles < this.heartParticleCount) {const toGenerate = Math.min(this.heartRegenRate,this.heartParticleCount - heartParticles);this.regenerateHeartParticles(toGenerate);}// 更新粒子数量显示if (this.particleCount !== this.particles.length) {this.updateParticleCount();}}// 继续动画循环requestAnimationFrame(this.animate.bind(this));}}// 初始化动画const animation = new HeartAnimation();
</script>

相关文章:

用HTML5 Canvas打造交互式心形粒子动画:从基础到优化实战

用HTML5 Canvas打造交互式心形粒子动画&#xff1a;从基础到优化实战 引言 在Web交互设计中&#xff0c;粒子动画因其动态美感和视觉吸引力被广泛应用于节日特效、情感化界面等场景。本文将通过实战案例&#xff0c;详细讲解如何使用HTML5 Canvas和JavaScript实现一个「心之律…...

Gartner《How to Create and Maintain a Knowledge Base forHumans and AI》学习报告

核心观点 本研究是一份 Gartne关于如何创建和维护面向人类与人工智能(AI)的知识库的研究报告。报告强调了知识库在知识管理(KM)中的核心地位,尤其是在生成式人工智能(GenAI)时代,一个结构良好的知识库是知识管理成功的关键,反之则可能成为整个知识管理实践的失败点。…...

【软件工具】批量OCR指定区域图片自动识别内容重命名软件使用教程及注意事项

批量OCR指定区域图片自动识别内容重命名软件使用教程及注意事项 1、操作步骤1-5&#xff1a; 安装与启动&#xff1a;安装成功后&#xff0c;在桌面或开始菜单找到软件图标&#xff0c;双击启动。 导入图片&#xff1a;进入软件主界面&#xff0c;点击 “导入图片” 按钮&a…...

PyTorch 中cumprod函数计算张量沿指定维度的累积乘积详解和代码示例

torch.cumprod 是 PyTorch 中用于 计算张量沿指定维度的累积乘积&#xff08;cumulative product&#xff09; 的函数。 1、函数原型 torch.cumprod(input, dim, *, dtypeNone, outNone) → Tensor参数说明&#xff1a; 参数说明input输入张量dim累积乘积的维度dtype可选&…...

docker镜像下载到本地,并导入服务器

应用场景 &#xff1a; 本地环境可以连接外网&#xff0c;但服务器连接不了外网&#xff0c;直接用docker pull 命令执行拉起镜像报异常。 1.本地拉取xuxueli/xxl-job-admin:2.2.0及查看所有下载的镜像 docker pull xuxueli/xxl-job-admin:2.2.0 docker images 2.保存镜像到…...

数据通信与计算机网络——数字传输

主要内容 数字到数字转换 线路编码 线路编码方案 块编码 扰动 模拟到数字转换 脉冲码调制&#xff08;PCM&#xff09; Delta调制&#xff08;DM&#xff09; 传输模式 并行传输 串行传输 一、数字到数字转换 将数字数据转换为数字信号涉及三种技术&#xff1a; 线…...

oracle 归档日志与RECOVERY_FILE_DEST 视图

1. RECOVERY_FILE_DEST 视图的作用 RECOVERY_FILE_DEST 是 Oracle 数据库用于 管理快速恢复区&#xff08;Fast Recovery Area, FRA&#xff09; 的一个视图。FRA 是 Oracle 提供的一种集中存储恢复相关文件&#xff08;如归档日志、备份文件、闪回日志等&#xff09;的区域。…...

黄柏基因组-小檗碱生物合成的趋同进化-文献精读142

Convergent evolution of berberine biosynthesis 小檗碱生物合成的趋同进化 摘要 小檗碱是一种有效的抗菌和抗糖尿病生物碱&#xff0c;主要从不同植物谱系中提取&#xff0c;特别是从小檗属&#xff08;毛茛目&#xff0c;早期分支的真双子叶植物&#xff09;和黄柏属&…...

前端杂货铺——TodoList

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…...

Spring Boot SSE流式输出+AI消息持久化升级实践:从粗暴到优雅的跃迁

在 AI 应用落地过程中&#xff0c;我们常常需要将用户和 AI 的对话以“完整上下文”的形式持久化到数据库中。但当 AI 回复非常长&#xff0c;甚至接近上万字时&#xff0c;传统的单条消息保存机制就会出问题。 在本篇文章中&#xff0c;我将深入讲解一次实际项目中对 对话持久…...

camera功能真的那么难用吗

背景 Android开发工作过程中&#xff0c;经常需要用到camera相关能力&#xff0c;比如&#xff1a;人脸识别&#xff0c;ai识别&#xff0c;拍照预览&#xff0c;摄像头录制等等需求。都需要使用到camera&#xff0c;且需要拿到camera的预览数据。但是每次开发这块代码都比较繁…...

Model Context Protocol (MCP) 是一个前沿框架

微软发布了 Model Context Protocol (MCP) 课程&#xff1a;mcp-for-beginners。 Model Context Protocol (MCP) 是一个前沿框架&#xff0c;涵盖 C#、Java、JavaScript、TypeScript 和 Python 等主流编程语言&#xff0c;规范 AI 模型与客户端应用之间的交互。 MCP 课程结构 …...

SQL Server 日期时间类型全解析:从精确存储到灵活转换

SQL Server 日期时间类型全解析&#xff1a;从精确存储到灵活转换 一、引言&#xff1a;日期时间处理的核心挑战 在数据管理中&#xff0c;日期时间类型是最常用却最容易出错的数据类型之一。不同业务场景对时间精度、时区感知、存储效率的需求差异极大&#xff1a; 金融交易…...

Android Test3 获取的ANDROID_ID值不同

Android Test3 获取的ANDROID_ID值不同 这篇文章来说明上一篇文章中说到的一个现象&#xff1a;在同一个项目中&#xff0c;创建不同的 app module&#xff0c;运行同一段测试代码&#xff0c;获取到的 ANDROID_ID 的值不同。 我也是第一次认真研究这个现象&#xff0c;这个还…...

[蓝桥杯 2024 国 B] 立定跳远

问题描述 在运动会上&#xff0c;小明从数轴的原点开始向正方向立定跳远。项目设置了 n 个检查点 a1,a2,...,an且 ai≥ai−1>0。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时&#xff0c;小明可以自行再增加 m 个检查点让自己跳得更轻松。在运动会前&#xf…...

内容力重塑品牌增长:开源AI大模型驱动下的智能名片与S2B2C商城赋能抖音生态种草范式

摘要&#xff1a;内容力已成为抖音生态中品牌差异化竞争的核心能力&#xff0c;通过有价值、强共鸣的内容实现产品"种草"与转化闭环。本文基于"开源AI大模型AI智能名片S2B2C商城小程序源码"技术架构&#xff0c;提出"技术赋能内容"的新型种草范式…...

手机号在网状态查询接口如何用PHP实现调用?

一、什么是手机号在网状态查询接口 通过精准探测手机号的状态&#xff0c;帮助平台减少此类问题的发生&#xff0c;提供更个性化的服务或进行地域性营销 二、应用场景 1. 金融风控 通过运营商在网态查询接口&#xff0c;金融机构可以核验贷款申请人的手机状态&#xff0c;拦…...

【Java微服务组件】分布式协调P4-一文打通Redisson:从API实战到分布式锁核心源码剖析

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录 引言Redisson基本信息Redisson网站 Redisson应用…...

一个简单的德劳内三角剖分实现

德劳内&#xff08;Delaunay&#xff09;三角剖分是一种经典的将点集进行三角网格化预处理的手段&#xff0c;在NavMesh、随机地牢生成等场景下都有应用。 具体内容百度一大堆&#xff0c;就不介绍了。 比较知名的算法是Bowyer-Watson算法&#xff0c;也就是逐点插入法。 下雨闲…...

Python入门手册:异常处理

在编程过程中&#xff0c;异常处理是一个非常重要的环节。它可以帮助我们处理程序运行时可能出现的错误和异常情况&#xff0c;确保程序的稳定性和可靠性。Python提供了强大的异常处理机制&#xff0c;使得我们能够优雅地处理各种异常情况。今天&#xff0c;就让我们一起深入学…...

C#子线程更新主线程UI及委托回调使用示例

1.声明线程方法 2.线程中传入对象 3.声明委托与使用 声明委托对象 委托作为参数传入方法 4.在线程中传入委托 5.调用传入的委托...

使用VuePress2.X构建个人知识博客,并且用个人域名部署到GitHub Pages中

使用VuePress2.X构建个人知识博客&#xff0c;并且用个人域名部署到GitHub Pages中 什么是VuePress VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 Markdown 来书写内容&#xff08;如文档、博客等&#xff09;&#xff0c;然后 VuePress 会帮助你生成一个…...

手写Promise.all

前言 之前在看远方os大佬直播的时候看到有让手写的Promise.all的问题&#xff0c;然后心血来潮自己准备手写一个 开始 首先&#xff0c;我们需要明确原本js提供的Promise.all的特性 Promise.all返回的是一个Promise如果传入的数据中有一个reject即整个all返回的就是reject&…...

调试器基本原理

调试器基本原理 前言 调试器(debugger)&#xff0c;是一种用于控制其他程序执行流程、监控和修改其他程序状态的软件工具。 调试器通过实时分析程序的执行状态&#xff0c;协助开发者定位代码错误、了解程序工作原理、性能调优及逆向工程等。 1. 调试器核心功能 1.1 控制程…...

2025年6月|注意力机制|面向精度与推理速度提升的YOLOv8模型结构优化研究:融合ACmix的自研改进方案

版本&#xff1a; 8.3.143(Ultralytics YOLOv8框架) ACmix模块原理 在目标检测任务中&#xff0c;小目标&#xff08;如裂缝、瑕疵、零件边缘等&#xff09;由于其尺寸较小、纹理信息稀疏&#xff0c;通常更容易受到图像中复杂背景或噪声的干扰&#xff0c;从而导致漏检或误检…...

JAVA开发代码小工具集合

目录 前言编号生成工具EasyExcel 工具断言工具HTTP 工具字符串 工具验证码生成工具Excel 工具Class 工具Enum 工具分页工具断言工具2IP 地址工具Map 工具 前言 这些工具都是日常开发中能用到的&#xff0c;前后端都有&#xff0c;觉得好用就拿过来了… 编号生成工具 import j…...

利用qcustomplot绘制曲线图

本文详细介绍了qcustomplot绘制曲线图的流程&#xff0c;一段代码一段代码运行看效果。通过阅读本文&#xff0c;读者可以了解到每一项怎么用代码进行配置&#xff0c;进而实现自己想要的图表效果。&#xff08;本文只针对曲线图&#xff09; 1 最简单的图形&#xff08;入门&…...

【基础算法】枚举(普通枚举、二进制枚举)

文章目录 一、普通枚举1. 铺地毯(1) 解题思路(2) 代码实现 2. 回文日期(1) 解题思路思路一&#xff1a;暴力枚举思路二&#xff1a;枚举年份思路三&#xff1a;枚举月日 (2) 代码实现 3. 扫雷(2) 解题思路(2) 代码实现 二、二进制枚举1. 子集(1) 解题思路(2) 代码实现 2. 费解的…...

智能对联网页小程序的仓颉之旅

#传统楹联遇上AI智能体&#xff1a;我的Cangjie Magic开发纪实 引言&#xff1a;一场跨越千年的数字对话 "云对雨&#xff0c;雪对风&#xff0c;晚照对晴空"。昨天晚上星空璀璨&#xff0c;当我用仓颉语言写下第一个智能对联网页小程序的Agent DSL代码时&#xff0…...

Go字符串切片操作详解:str1[:index]

在Go语言中&#xff0c;return str1[:index] 是一个​​字符串切片操作​​&#xff0c;它截取字符串的一部分。让我们深入解析这个操作的含义和原理&#xff1a; 基本语法和含义 str1&#xff1a;原始字符串[:index]&#xff1a;切片操作符str1[:index]&#xff1a; ​​起始…...