logo

原生JS实现抛物线与动态模糊:从数学建模到视觉优化

作者:狼烟四起2025.09.18 17:08浏览量:0

简介:本文通过原生JavaScript实现抛物线轨迹动画与动态模糊效果,结合数学公式、Canvas渲染和CSS滤镜技术,提供可复用的代码方案与性能优化建议。

原生JS实现抛物线动画以及动态模糊效果

在Web交互设计中,抛物线动画与动态模糊效果常用于模拟物体抛掷、弹窗飞入等场景。本文将通过原生JavaScript实现这两种视觉效果,结合数学公式、Canvas渲染和CSS滤镜技术,提供完整的代码实现与优化方案。

一、抛物线动画的数学基础与实现

1.1 抛物线运动模型

抛物线运动由水平匀速运动和垂直匀加速运动合成,其轨迹方程为:
[
\begin{cases}
x = v_0 \cdot t \cdot \cos\theta \
y = v_0 \cdot t \cdot \sin\theta - \frac{1}{2} g t^2
\end{cases}
]
其中:

  • ( v_0 ) 为初始速度
  • ( \theta ) 为抛射角度
  • ( g ) 为重力加速度(约9.8m/s²,需转换为像素单位)
  • ( t ) 为时间参数

1.2 原生JS实现步骤

步骤1:初始化参数

  1. const config = {
  2. startX: 50,
  3. startY: 300,
  4. targetX: 400,
  5. targetY: 100,
  6. duration: 1000, // 动画时长(ms)
  7. angle: 45, // 抛射角度(度)
  8. gravity: 0.2 // 重力系数(像素/帧²)
  9. };

步骤2:计算初始速度
通过终点坐标反推初始速度:

  1. function calculateInitialVelocity(start, target, angle, gravity) {
  2. const dx = target.x - start.x;
  3. const dy = target.y - start.y;
  4. const rad = angle * Math.PI / 180;
  5. // 解二次方程求时间t
  6. const a = -gravity / 2;
  7. const b = Math.tan(rad) * dx;
  8. const c = dy;
  9. const discriminant = b * b - 4 * a * c;
  10. if (discriminant < 0) return null; // 无解
  11. const t = (-b + Math.sqrt(discriminant)) / (2 * a);
  12. const v0x = dx / (t * Math.cos(rad));
  13. const v0y = (dy + 0.5 * gravity * t * t) / (t * Math.sin(rad));
  14. return { v0x, v0y, t };
  15. }

步骤3:动画帧处理
使用requestAnimationFrame实现平滑动画:

  1. function animateParabola(element, config) {
  2. const { startX, startY, duration } = config;
  3. const params = calculateInitialVelocity(
  4. { x: startX, y: startY },
  5. { x: config.targetX, y: config.targetY },
  6. config.angle,
  7. config.gravity
  8. );
  9. if (!params) return;
  10. let startTime = null;
  11. function animate(currentTime) {
  12. if (!startTime) startTime = currentTime;
  13. const elapsed = currentTime - startTime;
  14. const progress = Math.min(elapsed / duration, 1);
  15. // 线性插值计算当前位置
  16. const t = progress * params.t;
  17. const x = startX + params.v0x * Math.cos(config.angle * Math.PI / 180) * t;
  18. const y = startY + params.v0y * Math.sin(config.angle * Math.PI / 180) * t
  19. - 0.5 * config.gravity * t * t;
  20. element.style.transform = `translate(${x}px, ${y}px)`;
  21. if (progress < 1) {
  22. requestAnimationFrame(animate);
  23. }
  24. }
  25. requestAnimationFrame(animate);
  26. }

二、动态模糊效果的实现原理

2.1 模糊技术对比

技术方案 优点 缺点
CSS filter 实现简单,性能较好 静态模糊,无法动态调整
Canvas绘制 可控性强,支持动态模糊 需要手动计算像素模糊
WebGL 高性能,支持复杂效果 学习曲线陡峭

2.2 基于CSS滤镜的动态模糊

通过动态调整blur()值实现:

  1. function applyDynamicBlur(element, duration) {
  2. let startTime = null;
  3. const maxBlur = 10; // 最大模糊半径
  4. function blur(currentTime) {
  5. if (!startTime) startTime = currentTime;
  6. const elapsed = currentTime - startTime;
  7. const progress = Math.min(elapsed / duration, 1);
  8. // 模糊半径随时间变化(先增大后减小)
  9. const blurRadius = maxBlur * Math.sin(progress * Math.PI);
  10. element.style.filter = `blur(${blurRadius}px)`;
  11. if (progress < 1) {
  12. requestAnimationFrame(blur);
  13. }
  14. }
  15. requestAnimationFrame(blur);
  16. }

2.3 基于Canvas的高级模糊(可选)

对于需要更高质量的场景,可使用高斯模糊算法:

  1. function applyCanvasBlur(canvas, context, radius) {
  2. // 简化版高斯模糊实现
  3. const pixels = context.getImageData(0, 0, canvas.width, canvas.height);
  4. const data = pixels.data;
  5. for (let i = 0; i < data.length; i += 4) {
  6. const r = data[i];
  7. const g = data[i + 1];
  8. const b = data[i + 2];
  9. // 简单平均模糊(实际需加权计算)
  10. const avg = (r + g + b) / 3;
  11. data[i] = data[i + 1] = data[i + 2] = avg;
  12. }
  13. context.putImageData(pixels, 0, 0);
  14. }

三、性能优化与最佳实践

3.1 动画性能优化

  1. 使用transform替代top/left
    CSS transform属性触发GPU加速,避免重排。

  2. 节流requestAnimationFrame
    在复杂场景中,可通过throttle限制帧率:

    1. function throttle(fn, delay) {
    2. let lastCall = 0;
    3. return function(...args) {
    4. const now = Date.now();
    5. if (now - lastCall >= delay) {
    6. fn.apply(this, args);
    7. lastCall = now;
    8. }
    9. };
    10. }
  3. 分层渲染
    将静态背景与动态元素分离,减少重绘区域。

3.2 模糊效果优化

  1. 限制模糊范围
    避免全局模糊,仅对运动元素应用滤镜。

  2. 使用will-change属性
    提前告知浏览器元素变化:

    1. .blur-element {
    2. will-change: filter;
    3. }
  3. 降级方案
    在低端设备上禁用模糊效果:

    1. function isLowPerformanceDevice() {
    2. return /Mobile|Android|iPhone/i.test(navigator.userAgent)
    3. || window.innerWidth < 768;
    4. }

四、完整示例与扩展应用

4.1 抛物线+模糊组合效果

  1. const ball = document.getElementById('ball');
  2. animateParabola(ball, {
  3. startX: 50,
  4. startY: 300,
  5. targetX: 400,
  6. targetY: 100,
  7. duration: 1500,
  8. angle: 60,
  9. gravity: 0.25
  10. });
  11. applyDynamicBlur(ball, 1500);

4.2 扩展应用场景

  1. 购物车飞入效果
    将商品图标沿抛物线飞入购物车。

  2. 游戏粒子系统
    模拟爆炸碎片的抛物线运动与模糊拖尾。

  3. UI过渡动画
    弹窗从屏幕边缘飞入并带模糊背景。

五、总结与关键点

  1. 数学建模是核心
    抛物线动画需准确计算初始速度与时间参数。

  2. 性能优先
    优先使用CSS transformfilter,避免强制同步布局。

  3. 渐进增强
    根据设备性能动态调整效果复杂度。

通过本文的实现方案,开发者可快速集成抛物线动画与动态模糊效果,同时掌握底层原理与优化技巧。完整代码示例与数学推导过程已提供,可直接应用于项目开发。

相关文章推荐

发表评论