arkui 动画曲线

参考文档

https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-curve#curvesinterpolatingspring10

可视化工具网站

https://easingwizard.com/
https://www.desmos.com/calculator/k01p40v0ct?lang=zh-CN

基本介绍

import { curves } from '@kit.ArkUI'
curves.interpolatingSpring(10, 1, 228, 30) // 创建一个时长由弹簧参数决定的弹簧插值曲线
/**
代码核心功能:
该代码片段用于创建一个弹簧插值曲线,曲线的时长由弹簧参数决定。这在动画或界面过渡效果中非常有用,可以根据物理模拟的弹簧运动来平滑过渡。代码逻辑走读:
1. 导入模块:代码首先从`@kit.ArkUI`模块中导入`curves`对象,这个对象包含了各种用于动画和过渡效果的函数和方法。
2. 创建弹簧插值曲线:调用`curves.interpolatingSpring`方法,传入四个参数:`10`(初始位置)、`1`(初始速度)、`228`(弹簧常数)和`30`(摩擦常数)。这个方法根据这些参数创建一个弹簧插值曲线,曲线的时长和形状由这些参数定义。
3. 曲线应用:生成的曲线可以用于界面元素的动画效果,使其在移动或变化时遵循弹簧运动的物理规律,从而实现平滑、自然的过渡。
本次解答由人工智能生成,仅供参考
*/
  • damping(阻尼):控制弹簧震荡的衰减速度。
    阻尼值越小,弹簧震荡次数越多,衰减越慢(如软弹簧,弹性强);
    阻尼值越大,震荡越快停止,甚至可能无明显回弹(如硬弹簧,接近刚性)。
  • stiffness(刚度 / 劲度系数):控制弹簧的 “硬度”。
    刚度越大,弹簧越 “硬”,运动速度快、回弹幅度小(如金属弹簧);
    刚度越小,弹簧越 “软”,运动更平缓、回弹幅度大(如橡胶弹簧)。
  • mass(质量):模拟被弹簧拉动的物体质量(部分实现中默认固定值)。
    质量越大,动画启动和停止的惯性越强,运动更迟缓;质量越小,响应越灵敏。
  • initialVelocity(初始速度):动画开始时的初始运动速度,影响初始震荡的幅度(如快速滑动后的惯性回弹)。
    from(起始值) 与 to(目标值):定义动画的起始状态和最终稳定的目标状态(如位置、大小、透明度等属性值)。

代码

弹簧曲线动画

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from scipy.interpolate import make_interp_spline
import matplotlib.widgets as widgets# 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "Heiti TC", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False  # 正确显示负号class ParametricSpringAnimation:def __init__(self):# 物理参数(默认值)self.initial_velocity = -2.0   # 初始速度(负值表示向左运动)self.mass = 1.0                # 质量self.stiffness = 5.0           # 刚度(劲度系数)self.damping = 0.5             # 阻尼系数# 弹簧基本参数self.start_point = np.array([2, 5])  # 弹簧固定端self.equilibrium_pos = 8            # 平衡位置X坐标self.spring_coils = 12              # 弹簧圈数self.coil_height = 0.6              # 线圈高度# 状态变量self.current_pos = self.equilibrium_pos  # 当前位置self.current_vel = self.initial_velocity  # 当前速度self.time = 0.0                           # 时间# 动画参数self.total_frames = 300                  # 总帧数self.fps = 60                            # 帧率self.dt = 1.0 / self.fps                 # 时间步长# 创建图形和轴self.fig = plt.figure(figsize=(12, 8))self.ax = self.fig.add_axes([0.1, 0.3, 0.8, 0.6])  # 主绘图区self.fig.suptitle('参数可控的插值弹簧曲线动画', fontsize=16)# 设置主坐标轴范围self.ax.set_xlim(0, 12)self.ax.set_ylim(2, 12)self.ax.set_xlabel('X轴')self.ax.set_ylabel('Y轴')self.ax.grid(True, alpha=0.3)self.ax.set_aspect('equal', adjustable='box')# 初始化绘图元素self.spring_line, = self.ax.plot([], [], 'b-', linewidth=3)  # 弹簧曲线self.fixed_point, = self.ax.plot([], [], 'ro', markersize=10)  # 固定端点self.mass_point, = self.ax.plot([], [], 'go', markersize=15)  # 重物self.trace_line, = self.ax.plot([], [], 'r-', linewidth=1, alpha=0.3)  # 轨迹线# 轨迹记录self.trace_points = []# 信息文本self.info_text = self.ax.text(0.02, 0.98, '', transform=self.ax.transAxes, verticalalignment='top', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))# 添加参数控制面板self.add_parameter_controls()def add_parameter_controls(self):"""添加参数控制滑块"""# 初始速度滑块ax_vel = self.fig.add_axes([0.2, 0.2, 0.65, 0.03])self.vel_slider = widgets.Slider(ax=ax_vel,label='初始速度',valmin=-5.0,valmax=5.0,valinit=self.initial_velocity,valstep=0.1)# 质量滑块ax_mass = self.fig.add_axes([0.2, 0.15, 0.65, 0.03])self.mass_slider = widgets.Slider(ax=ax_mass,label='质量',valmin=0.1,valmax=5.0,valinit=self.mass,valstep=0.1)# 刚度滑块ax_stiff = self.fig.add_axes([0.2, 0.1, 0.65, 0.03])self.stiff_slider = widgets.Slider(ax=ax_stiff,label='刚度',valmin=1.0,valmax=20.0,valinit=self.stiffness,valstep=0.5)# 阻尼滑块ax_damp = self.fig.add_axes([0.2, 0.05, 0.65, 0.03])self.damp_slider = widgets.Slider(ax=ax_damp,label='阻尼',valmin=0.1,valmax=2.0,valinit=self.damping,valstep=0.1)# 重置按钮ax_reset = self.fig.add_axes([0.85, 0.05, 0.1, 0.04])self.reset_btn = widgets.Button(ax_reset, '重置')# 绑定事件处理函数self.vel_slider.on_changed(self.update_parameters)self.mass_slider.on_changed(self.update_parameters)self.stiff_slider.on_changed(self.update_parameters)self.damp_slider.on_changed(self.update_parameters)self.reset_btn.on_clicked(self.reset_animation)def init_animation(self):"""初始化动画元素"""self.spring_line.set_data([], [])self.fixed_point.set_data([], [])self.mass_point.set_data([], [])self.trace_line.set_data([], [])self.info_text.set_text('')return self.spring_line, self.fixed_point, self.mass_point, self.trace_line, self.info_textdef update_parameters(self, val):"""更新物理参数"""self.initial_velocity = self.vel_slider.valself.mass = self.mass_slider.valself.stiffness = self.stiff_slider.valself.damping = self.damp_slider.valself.reset_animation(None)  # 参数改变后重置动画def reset_animation(self, event):"""重置动画状态"""self.current_pos = self.equilibrium_posself.current_vel = self.initial_velocityself.time = 0.0self.trace_points = []def generate_spring_points(self, end_x):"""生成弹簧上的点并进行插值平滑"""end_point = np.array([end_x, self.start_point[1]])# 计算弹簧总长度和方向length = np.linalg.norm(end_point - self.start_point)# 生成弹簧的控制点t = np.linspace(0, 1, self.spring_coils * 2 + 1)x = self.start_point[0] + t * (end_point[0] - self.start_point[0])# 生成弹簧的波动形状y = self.start_point[1] + np.sin(t * self.spring_coils * 2 * np.pi) * self.coil_height# 使用三次样条插值使曲线更平滑spl = make_interp_spline(t, np.column_stack((x, y)), k=3)t_smooth = np.linspace(0, 1, 200)  # 更密集的点smooth_points = spl(t_smooth)return smooth_pointsdef calculate_physics(self):"""根据物理规律计算下一帧状态"""# 胡克定律:F = -k(x - x0) - c*vdisplacement = self.current_pos - self.equilibrium_posforce = -self.stiffness * displacement - self.damping * self.current_vel# 牛顿第二定律:a = F/macceleration = force / self.mass# 更新速度和位置self.current_vel += acceleration * self.dtself.current_pos += self.current_vel * self.dt# 限制位置范围,防止弹簧过度拉伸if self.current_pos < self.start_point[0] + 1.0:self.current_pos = self.start_point[0] + 1.0self.current_vel = 0.0if self.current_pos > 11.0:self.current_pos = 11.0self.current_vel = 0.0self.time += self.dtdef update_animation(self, frame):"""更新动画帧"""# 计算物理状态self.calculate_physics()# 生成弹簧曲线点spring_points = self.generate_spring_points(self.current_pos)# 更新弹簧曲线self.spring_line.set_data(spring_points[:, 0], spring_points[:, 1])# 更新固定端点self.fixed_point.set_data(self.start_point[0], self.start_point[1])# 更新重物位置self.mass_point.set_data(self.current_pos, self.start_point[1])# 更新轨迹self.trace_points.append([self.time, self.current_pos - self.equilibrium_pos])if len(self.trace_points) > 1000:  # 限制轨迹点数量self.trace_points.pop(0)# 绘制轨迹if len(self.trace_points) > 1:trace_array = np.array(self.trace_points)self.trace_line.set_data(trace_array[:, 0], trace_array[:, 1] + self.equilibrium_pos)# 更新信息文本displacement = self.current_pos - self.equilibrium_posself.info_text.set_text(f'时间: {self.time:.1f}s\n'f'位移: {displacement:.2f}\n'f'速度: {self.current_vel:.2f}')return self.spring_line, self.fixed_point, self.mass_point, self.trace_line, self.info_textdef create_animation(self, save_path=None):"""创建并显示动画"""anim = FuncAnimation(self.fig,self.update_animation,frames=self.total_frames,init_func=self.init_animation,interval=1000/self.fps,  # 每帧间隔毫秒blit=True,repeat=True  # 动画循环播放)# 修复matplotlib版本兼容性问题anim._resize_id = None# 如果提供了保存路径,则保存动画if save_path:try:anim.save(save_path, writer='ffmpeg', fps=self.fps)print(f"动画已保存至: {save_path}")except Exception as e:print(f"保存动画失败: {e}")print("请确保已安装ffmpeg")plt.show()if __name__ == "__main__":# 创建并显示弹簧动画spring_anim = ParametricSpringAnimation()# 如需保存动画,取消下面一行的注释并指定路径spring_anim.create_animation('parametric_spring_animation.mp4')# 显示动画spring_anim.create_animation()

贝塞尔曲线动画

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import matplotlib.animation as animation# 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False  # 正确显示负号class BezierAnimation:def __init__(self):# 初始化控制点 - 可以修改这些点来获得不同的曲线self.controls = np.array([[0, 0],    # 起点[2, 0],    # 控制点1[2, 5],    # 控制点2[5, 5]     # 终点])self.num_points = 100  # 曲线上的点数量self.t = np.linspace(0, 1, self.num_points)  # 参数t从0到1# 创建图形和轴self.fig, self.ax = plt.subplots(figsize=(8, 6))self.fig.suptitle('贝塞尔曲线动画演示', fontsize=15)# 设置坐标轴范围self.ax.set_xlim(-1, 6)self.ax.set_ylim(-1, 5)self.ax.set_xlabel('X轴')self.ax.set_ylabel('Y轴')self.ax.grid(True)# 初始化绘图元素self.control_line, = self.ax.plot([], [], 'r--', alpha=0.6)  # 控制点连接线self.control_points, = self.ax.plot([], [], 'ro', markersize=8)  # 控制点self.bezier_curve, = self.ax.plot([], [], 'b-', linewidth=2)  # 贝塞尔曲线self.animated_point, = self.ax.plot([], [], 'go', markersize=10)  # 曲线上的动画点# 添加控制点标签self.control_labels = [self.ax.text(0, 0, '', fontsize=12) for _ in range(len(self.controls))]# 动画帧数量self.animation_frames = 100def bezier_curve_calc(self, t):"""计算贝塞尔曲线上的点"""n = len(self.controls) - 1  # 曲线阶数 = 控制点数量 - 1result = np.zeros(2)for i in range(n + 1):# 计算二项式系数binom = np.math.comb(n, i)# 计算贝塞尔基函数basis = binom * (t ** i) * ((1 - t) ** (n - i))# 累加计算曲线上的点result += basis * self.controls[i]return resultdef init_animation(self):"""初始化动画"""self.control_line.set_data([], [])self.control_points.set_data([], [])self.bezier_curve.set_data([], [])self.animated_point.set_data([], [])for label in self.control_labels:label.set_text('')return (self.control_line, self.control_points, self.bezier_curve, self.animated_point, *self.control_labels)def update_animation(self, frame):"""更新动画帧"""# 计算当前帧对应的t值current_t = frame / self.animation_frames# 更新控制点显示self.control_points.set_data(self.controls[:, 0], self.controls[:, 1])self.control_line.set_data(self.controls[:, 0], self.controls[:, 1])# 更新控制点标签for i, label in enumerate(self.control_labels):label.set_position((self.controls[i, 0] + 0.1, self.controls[i, 1] + 0.1))label.set_text(f'P{i}')# 计算当前t值范围内的贝塞尔曲线curve_points = np.array([self.bezier_curve_calc(t) for t in self.t if t <= current_t])if len(curve_points) > 0:self.bezier_curve.set_data(curve_points[:, 0], curve_points[:, 1])# 更新动画点(当前t对应的点)current_point = self.bezier_curve_calc(current_t)self.animated_point.set_data(current_point[0], current_point[1])return (self.control_line, self.control_points, self.bezier_curve, self.animated_point, *self.control_labels)def create_animation(self, save_path=None):"""创建并显示动画"""anim = FuncAnimation(self.fig, self.update_animation, frames=self.animation_frames + 1,init_func=self.init_animation, interval=50,  # 每帧间隔毫秒blit=True)# 如果提供了保存路径,则保存动画if save_path:# 需要安装ffmpeg才能保存为mp4anim.save(save_path, writer='ffmpeg', fps=20)plt.tight_layout()plt.show()if __name__ == "__main__":# 创建并显示贝塞尔曲线动画bezier_anim = BezierAnimation()# 如需保存动画,取消下面一行的注释并指定路径# 保存并显示动画bezier_anim.create_animation('bezier_animation.mp4')# 显示动画bezier_anim.create_animation()

弹簧动画模拟器

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>弹簧曲线模拟器</title><script src="https://cdn.tailwindcss.com"></script><link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"><script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script><script>tailwind.config = {theme: {extend: {colors: {primary: '#3B82F6',secondary: '#10B981',accent: '#8B5CF6',dark: '#1E293B',light: '#F8FAFC'},fontFamily: {sans: ['Inter', 'system-ui', 'sans-serif'],},}}}</script><style type="text/tailwindcss">@layer utilities {.card-shadow {box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.02);}.slider-thumb {@apply appearance-none w-5 h-5 rounded-full bg-primary cursor-pointer;}.fixed-dimension {width: 400px;height: 200px;flex-shrink: 0;overflow: hidden;}}input[type="range"]::-webkit-slider-thumb {@apply slider-thumb;}input[type="range"]::-moz-range-thumb {@apply slider-thumb;}</style>
</head>
<body class="bg-gray-50 font-sans text-dark"><div class="container mx-auto px-4 py-8 max-w-5xl"><header class="text-center mb-10"><h1 class="text-[clamp(1.8rem,4vw,2.5rem)] font-bold text-dark mb-2">弹簧曲线模拟器</h1><p class="text-gray-600 max-w-2xl mx-auto">调整参数以模拟不同弹簧特性,实时查看位移-时间曲线</p></header><div class="grid grid-cols-1 lg:grid-cols-3 gap-8"><!-- 控制面板 --><div class="lg:col-span-1"><div class="bg-white rounded-xl-6 card-shadowshadow"><h2 class="text-xl font-semibold mb-6 flex items-center"><i class="fa fa-sliders text-primary mr-2"></i>参数控制</h2><div class="space-y-6"><!-- 初始速度 --><div><div class="flex justify-between mb-1"><label for="velocity" class="text-sm font-medium text-gray-700">初始速度</label><span id="velocity-value" class="text-sm font-medium text-primary">-10</span></div><input type="range" id="velocity" min="-50" max="50" value="-10" class="w-full h-2 bg-gray-200 rounded-lg"><div class="flex justify-between text-xs text-gray-500 mt-1"><span>-50</span><span>0</span><span>50</span></div></div><!-- 质量 --><div><div class="flex justify-between mb-1"><label for="mass" class="text-sm font-medium text-gray-700">质量</label><span id="mass-value" class="text-sm font-medium text-primary">1.0</span></div><input type="range" id="mass" min="0.1" max="5" step="0.1" value="1.0" class="w-full h-2 bg-gray-200 rounded-lg"><div class="flex justify-between text-xs text-gray-500 mt-1"><span>0.1</span><span>2.5</span><span>5.0</span></div></div><!-- 刚度 --><div><div class="flex justify-between mb-1"><label for="stiffness" class="text-sm font-medium text-gray-700">刚度</label><span id="stiffness-value" class="text-sm font-medium text-primary">100</span></div><input type="range" id="stiffness" min="10" max="500" value="100" class="w-full h-2 bg-gray-200 rounded-lg"><div class="flex justify-between text-xs text-gray-500 mt-1"><span>10</span><span>250</span><span>500</span></div></div><!-- 阻尼 --><div><div class="flex justify-between mb-1"><label for="damping" class="text-sm font-medium text-gray-700">阻尼</label><span id="damping-value" class="text-sm font-medium text-primary">10</span></div><input type="range" id="damping" min="0" max="50" value="10" class="w-full h-2 bg-gray-200 rounded-lg"><div class="flex justify-between text-xs text-gray-500 mt-1"><span>0</span><span>25</span><span>50</span></div></div><!-- 初始位置 --><div><div class="flex justify-between mb-1"><label for="position" class="text-sm font-medium text-gray-700">初始位置</label><span id="position-value" class="text-sm font-medium text-primary">100</span></div><input type="range" id="position" min="-200" max="200" value="100" class="w-full h-2 bg-gray-200 rounded-lg"><div class="flex justify-between text-xs text-gray-500 mt-1"><span>-200</span><span>0</span><span>200</span></div></div><!-- 动画速度 --><div><div class="flex justify-between mb-1"><label for="speed" class="text-sm font-medium text-gray-700">动画速度</label><span id="speed-value" class="text-sm font-medium text-primary">1.0x</span></div><input type="range" id="speed" min="0.1" max="3" step="0.1" value="1.0" class="w-full h-2 bg-gray-200 rounded-lg"><div class="flex justify-between text-xs text-gray-500 mt-1"><span>慢速</span><span>正常</span><span>快速</span></div></div><div class="pt-4"><button id="simulate-btn" class="w-full bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-allduration-300 flex items-center justify-center"><i class="fa fa-play mr-2"></i> 开始模拟</button></div></div></div><div class="bg-white rounded-xl p-6 mt-6 card-shadow"><h2 class="text-xl font-semibold mb-4 flex items-center"><i class="fa fa-info-circle text-accent mr-2"></i>参数说明</h2><ul class="text-sm text-gray-600 space-y-2"><li class="flex items-start"><i class="fa fa-arrow-right text-primary mt-1 mr-2"></i><span><strong>初始速度</strong>:物体开始运动的速度,正值向右,负值向左</span></li><li class="flex items-start"><i class="fa fa-arrow-right text-primary mt-1 mr-2"></i><span><strong>质量</strong>:物体的质量,越大惯性越大</span></li><li class="flex items-start"><i class="fa fa-arrow-right text-primary mt-1 mr-2"></i><span><strong>刚度</strong>:弹簧的硬度,越大弹簧越硬</span></li><li class="flex items-start"><i class="fa fa fa-arrow-right text-primary mt-1 mr-2"></i><span><strong>阻尼</strong>:阻力大小,越大震荡衰减越快</span></li><li class="flex items-start"><i class="fa fa fa fa-arrow-right text-primary mt-1 mr-2"></i><span><strong>初始位置</strong>:物体的起始位置,偏离平衡位置的距离</span></li><li class="flex items-start"><i class="fa fa-arrow-right text-primary mt-1 mr-2"></i><span><strong>动画速度</strong>:控制动画播放速度,1.0x为正常速度</span></li></ul></div></div><!-- 可视化区域 --><div class="lg:col-span-2"><div class="bg-white rounded-xl p-6 card-shadow"><!-- 弹簧动画动画演示(固定大小) --><div class="mb-6"><h2 class="text-lg font-semibold mb-2 flex items-center"><i class="fa fa-film text-secondary mr-2"></i>弹簧动画</h2><div class="fixed-dimension border borderborderborderborderborder-gray-200 rounded-lg bg-gray-50 relative"><div id="spring-container" class="absolute inset-0 flex items-center px-4"><!-- 墙面 --><div class="w-3 h-12 bg-gray-400 rounded-sm"></div><!-- 弹簧 --><div id="spring" class="flex-1 h-3 flex justifyjustify-between items-centeritems-center mx-1"><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div><div class="h-full w-1 bg-primary"></div></div><!-- 物体 --><div id="mass-object" class="w-12 h-12 bg-accent rounded-full-full-fullflexitemsitemsitemsitems-centertext-white font-bold text-sm">m</div></div></div></div><!-- 曲线图 --><div><h2 class="text-lg font-semibold mb-2 flex items-center"><i class="fa fa-line-chart text-primary mr-2"></i>位移-时间曲线</h2><div class="fixed-dimension border border-gray-200 rounded-lg"><canvas id="spring-chart"></canvas></div></div></div></div></div><footer class="mt-12 text-center text-gray-500 text-sm"><p>弹簧曲线曲线模拟器基于胡克定律模拟:F = -kx - cv</p></footer></div><script>// 获取DOM元素const velocitySlider = document.getElementById('velocity');const velocityValue = document.getElementById('velocity-value');const massSlider = document.getElementById('mass');const massValue = document.getElementById('mass-value');const stiffnessSlider = document.getElementById('stiffness');const stiffnessValue = document.getElementById('stiffness-value');const dampingSlider = document.getElementById('damping');const dampingValue = document.getElementById('damping-value');const positionSlider = document.getElementById('position');const positionValue = document.getElementById('position-value');const speedSlider = document.getElementById('speed');const speedValue = document.getElementById('speed-value');const simulateBtn = document.getElementById('simulate-btn');const massObject = document.getElementById('mass-object');const springContainer = document.getElementById('spring-container');// 更新显示的参数值velocitySlider.addEventListener('input', () => {velocityValue.textContent = velocitySlider.value;});massSlider.addEventListener('input', () => {massValue.textContent = parseFloat(massSlider.value).toFixed(1);});stiffnessSlider.addEventListener('input', () => {stiffnessValue.textContent = stiffnessSlider.value;});dampingSlider.addEventListener('input', () => {dampingValue.textContent = dampingSlider.value;});positionSlider.addEventListener('input', () => {positionValue.textContent = positionSlider.value;});speedSlider.addEventListener('input', () => {speedValue.textContent = parseFloat(speedSlider.value).toFixed(1) + 'x';// 如果模拟正在运行,实时时更新速度if (simulation && simulation.isRunning) {simulation.speedFactor = parseFloat(speedSlider.value);}});// 初始化图表const ctx = document.getElementById('spring-chart').getContext('2d');let springChart = new Chart(ctx, {type: 'line',data: {labels: [],datasets: [{label: '位移',data: [],borderColor: '#3B82F6',backgroundColor: 'rgba(59, 130, 246, 0.1)',borderWidth: 2,fill: true,tension: 0.1,pointRadius: 0}]},options: {responsive: true,maintainAspectRatio: false,scales: {x: {title: {display: true,text: '时间 (ms)',font: {size: 10}},ticks: {font: {size: 8}}},y: {title: {display: true,text: '位移',font: {size: 10}},min: -250,max: 250,ticks: {font: {size: 8}}}},animation: false,interaction: {intersect: false,mode: 'index'},plugins: {legend: {labels: {font: {size: 10}}}}}});// 弹簧模拟类class SpringSimulation {constructor(params) {// 物理参数this.stiffness = params.stiffness;  // 刚度this.damping = params.damping;      // 阻尼this.mass = params.mass;            // 质量this.initialPosition = params.position; // 初始位置this.initialVelocity = params.velocity; // 初始速度this.speedFactor = params.speed || 1.0; // 动画速度因子// 状态变量this.position = params.position;    // 当前位置this.velocity = params.velocity;    // 当前速度this.time = 0;                      // 时间this.history = [];                  // 历史数据this.isRunning = false;             // 模拟是否运行this.animationFrameId = null;       // 动画帧IDthis.lastTime = 0;                  // 上一帧时间// 固定容器宽度(400px减去内边距和元素宽度)this.containerWidth = 400 - 30 - 48; // 固定计算,不受窗口影响this.centerX = this.containerWidth / 2; // 平衡位置}// 更新模拟状态update(currentTime) {if (!this.lastTime) this.lastTime = currentTime;// 应用速度因子调整时间增量const deltaTime = ((currentTime - this.lastTime) / 1000) * this.speedFactor;this.lastTime = currentTime;// 计算加速度: F = -kx - cv, a = F/mconst acceleration = (-this.stiffness * this.position - this.damping * this.velocity) / this.mass;// 更新速度和位置this.velocity += acceleration * deltaTime;this.position += this.velocity * deltaTime;// 记录时间和位置this.time += (currentTime - (this.lastTime - (currentTime - this.lastTime))) / 1000 * 1000;this.history.push({time: this.time,position: this.position});// 更新物体位置const objectX = this.centerX + this.position;massObject.style.transform = `translateX(${objectX}px)`;// 检查是否应该停止模拟if (Math.abs(this.velocity) < 0.1 && Math.abs(this.position) < 0.5) {this.stop();return false;}return true;}// 开始模拟start() {this.isRunning = true;this.lastTime = 0;this.history = [];this.time = 0;// 重置图表springChart.data.labels = [];springChart.data.datasets[0].data = [];springChart.update();// 初始位置const initialX = this.centerX + this.initialPosition;massObject.style.transform = `translateX(${initialX}px)`;// 动画循环const animate = (timestamp) => {if (!this.isRunning) return;const shouldContinue = this.update(timestamp);// 更新图表if (this.history.length % 2 === 0) {springChart.data.labels.push(Math.round(this.time));springChart.data.datasets[0].data.push(this.position);// 限制图表数据点数量if (springChart.data.labels.length > 100) {springChart.data.labels.shift();springChart.data.datasets[0].data.shift();}springChart.update();}if (shouldContinue) {this.animationFrameId = requestAnimationFrame(animate);}};this.animationFrameId = requestAnimationFrame(animate);}// 停止模拟stop() {this.isRunning = false;if (this.animationFrameId) {cancelAnimationFrame(this.animationFrameId);}}}// 模拟控制let simulation = null;simulateBtn.addEventListener('click', () => {// 如果已有模拟在运行,先停止if (simulation && simulation.isRunning) {simulation.stop();}// 获取参数const params = {velocity: parseFloat(velocitySlider.value),mass: parseFloat(massSlider.value),stiffness: parseFloat(stiffnessSlider.value),damping: parseFloat(dampingSlider.value),position: parseFloat(positionSlider.value),speed: parseFloat(speedSlider.value)};// 创建并启动新模拟simulation = new SpringSimulation(params);simulation.start();// 更新按钮文本simulateBtn.innerHTML = '<i class="fa fa-refresh mr-2"></i> 重新模拟';});// 初始位置设置window.addEventListener('load', () => {const containerWidth = 400 - 30 - 48; // 固定值const centerX = containerWidth / 2;const initialX = centerX + parseFloat(positionSlider.value);massObject.style.transform = `translateX(${initialX}px)`;});// 移除窗口大小变化的影响window.removeEventListener('resize', () => {});</script>
</body>
</html>

弹簧曲线curves.interpolatingSpring(10, 1, 228, 30)

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches# 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False  # 正确显示负号def calculate_spring_curve(mass, stiffness, damping, initial_velocity, duration=1.0, fps=100):"""计算弹簧曲线的数值点"""dt = 1.0 / fpstotal_frames = int(duration * fps)time_points = []position_points = []velocity_points = []position = 0.0  # 初始位置在平衡位置velocity = initial_velocityfor _ in range(total_frames):time = len(time_points) * dt# 计算力和加速度 (F = -kx - cv, a = F/m)force = -stiffness * position - damping * velocityacceleration = force / mass# 更新速度和位置velocity += acceleration * dtposition += velocity * dttime_points.append(time)position_points.append(position)velocity_points.append(velocity)return np.array(time_points), np.array(position_points), np.array(velocity_points)# 计算ArkUI interpolatingSpring(10, 1, 228, 30)的曲线数据
mass = 10.0
stiffness = 1.0
damping = 228.0
initial_velocity = 16.0time, position, velocity = calculate_spring_curve(mass, stiffness, damping, initial_velocity, duration=1.0
)# 创建图形
fig, ax = plt.subplots(figsize=(10, 6))
fig.suptitle('curves.interpolatingSpring(10, 1, 228, 30) 数值曲线', fontsize=16)# 绘制位移曲线
ax.plot(time, position, 'b-', linewidth=2, label='位移')
ax.set_xlabel('时间 (秒)')
ax.set_ylabel('位移')
ax.grid(True, alpha=0.3)
ax.set_xlim(0, max(time))
ax.set_ylim(min(position)*1.1, max(position)*1.1)# 标记关键 points
peak1_idx = np.argmax(position)
peak1_time = time[peak1_idx]
peak1_pos = position[peak1_idx]trough1_idx = np.argmin(position)
trough1_time = time[trough1_idx]
trough1_pos = position[trough1_idx]# 添加关键点标注
ax.plot(peak1_time, peak1_pos, 'ro', markersize=8)
ax.annotate(f'峰值: ({peak1_time:.2f}s, {peak1_pos:.2f})',xy=(peak1_time, peak1_pos),xytext=(peak1_time+0.05, peak1_pos+0.2),arrowprops=dict(arrowstyle='->', color='red'))ax.plot(trough1_time, trough1_pos, 'go', markersize=8)
ax.annotate(f'谷值: ({trough1_time:.2f}s, {trough1_pos:.2f})',xy=(trough1_time, trough1_pos),xytext=(trough1_time+0.05, trough1_pos-0.3),arrowprops=dict(arrowstyle='->', color='green'))# 添加参数说明
param_text = (f'参数: mass={mass}, stiffness={stiffness}\n'f'damping={damping}, initialVelocity={initial_velocity}')
plt.figtext(0.15, 0.01, param_text, fontsize=10, bbox=dict(facecolor='white', alpha=0.8, boxstyle='round,pad=0.5'))# 添加图例
ax.legend()plt.tight_layout(rect=[0, 0.05, 1, 0.95])
plt.show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91957.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91957.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大语言模型(LLM)技术架构与工程实践:从原理到部署

在自然语言处理领域,大语言模型(LLM)已成为颠覆性技术。从 GPT 系列到 LLaMA、ChatGLM,这些参数规模动辄百亿甚至万亿的模型,不仅实现了流畅的自然语言交互,更在代码生成、逻辑推理等复杂任务中展现出惊人能力。本文将从技术底层拆解 LLM 的核心架构,分析训练与推理的关…

python后端之DRF框架(上篇)

一、DRF框架介绍 1、web应用开发模式 1.1、前后端不分离1.2、前后端分离2、RESTful介绍 RESTful是目前最流行的API设计风格 &#xff0c; REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。 1、每一个URI代表1种资源&#xff1b; 2、客…

信创数据库-DM(达梦)数据库安装教程

官方安装文档在这&#xff1a;安装前准备 | 达梦技术文档 本文也是基于这个来写的&#xff0c;微调了一下。 1&#xff0c;下载安装包 体验版直接到官方下载即可&#xff1a;产品下载 | 达梦在线服务平台 如果是有需要商业版等&#xff0c;需要联系客服申请。 安装包要选择CPU…

docker常用命令集(6)

接前一篇文章&#xff1a;docker常用命令集&#xff08;5&#xff09; 本文内容参考&#xff1a; Docker login/logout 命令 | 菜鸟教程 Docker命令_docker login-CSDN博客 特此致谢&#xff01; 9. docker login 简介 docker login命令用于登录到docker注册表&#xff08…

[LINUX操作系统]shell脚本之循环

1.编写脚本for1.sh,使用for循环创建20账户&#xff0c;账户名前缀由用户从键盘输入&#xff0c;账户初始密码由用户输入&#xff0c;例如:test1、test2、test3......[rootmaster ~]# vim for1.sh #!/bin/bashread -p "请输入账户名称前缀&#xff1a;" prefixread -p…

空间设计:不是餐厅的装饰游戏

餐厅空间设计&#xff0c;是通过布局规划与环境营造&#xff0c;将功能需求、品牌调性与顾客体验融合的系统性工程 —— 它不仅决定顾客「坐得舒不舒服」&#xff0c;更影响「愿不愿意再来」「会不会主动分享」的消费决策。体验感知的第一触点&#xff1a;顾客进门 3 秒内&…

XSS-DOM 2

目录 1 DOMPurify 1.1 漏洞源码 1.2 加载框架 ​编辑 setTimeout 1.3 ok&#xff1f; 1.4 window和document 1.5 Overwrite&#xff08;document.x&#xff09; 1.5.1 打印cookie 1.6 Overwrite2&#xff08;document.x.y&#xff09; 1.6.1 form表单 1.7 toString…

从数据丢失到动画流畅:React状态同步与远程数据加载全解析

在前端开发中&#xff0c;数据状态管理与界面同步始终是核心挑战。近期我在处理一个书签管理应用时&#xff0c;遇到了远程数据加载后无法显示、界面更新异常&#xff0c;甚至动画闪烁等一系列问题。经过多轮调试与优化&#xff0c;最终实现了数据的正确加载与流畅的界面交互。…

MySQL半同步复制机制详解:AFTER_SYNC vs AFTER_COMMIT 的优劣与选择

目录深入分析与利弊对比1. AFTER_COMMIT (不推荐)2. AFTER_SYNC (强烈推荐&#xff0c;MySQL 8.0 默认)总结与强烈建议最佳实践 MySQL 半同步复制主要有两种实现方式&#xff0c;其核心区别在于主库何时回复客户端事务提交成功&#xff08;即何时认为事务完成&#xff09;&…

GEE实战 | 4种非监督分类算法深度解析,附可直接运行的完整代码

在遥感影像处理领域&#xff0c;非监督分类凭借其无需人工标注样本的优势&#xff0c;成为快速了解地物分布的得力助手。它能自动依据像素光谱特征的相似性完成聚类&#xff0c;这种“无师自通”的特性&#xff0c;让地理空间分析变得更加高效。 今天&#xff0c;我们就来深入…

基于落霞归雁思维框架的软件需求管理实践指南

作者&#xff1a;落霞归雁 日期&#xff1a;2025-08-02 摘要 在 VUCA 时代&#xff0c;需求变更成本已占软件总成本的 40% 以上。本文将“落霞归雁”思维框架&#xff08;观察现象 → 找规律 → 应用规律 → 实践验证&#xff09;引入需求工程全生命周期&#xff0c;通过 4 个阶…

企业级AI Agent构建实践:从理论到落地的完整指南

&#x1f680; 引言 随着人工智能技术的快速发展&#xff0c;AI应用正在从简单的工具转变为智能伙伴。企业级AI Agent作为这一变革的核心载体&#xff0c;正在重新定义我们与软件系统的交互方式。本文将深入探讨如何构建一个真正意义上的企业级AI Agent系统。 &#x1f3af; …

电商项目_性能优化_限流-降级-熔断

针对电商系统&#xff0c;在遇到大流量时&#xff0c;必须要考虑如何保障系统的稳定运行&#xff0c;常用的手段&#xff1a;限流&#xff0c;降级&#xff0c;拒绝服务。 一、限流 限流算法&#xff1a;计数器、滑动窗口、漏铜算法、令牌桶算法。 限流的方案 前端限流接入…

javaweb开发之Servlet笔记

第五章 Servlet 一 Servlet简介 1.1 动态资源和静态资源 静态资源 无需在程序运行时通过代码运行生成的资源,在程序运行之前就写好的资源. 例如:html css js img ,音频文件和视频文件 动态资源 需要在程序运行时通过代码运行生成的资源,在程序运行之前无法确定的数据,运行时…

sqli-labs靶场less26/a

less261.我们打开这一关来看一下&#xff0c;他提示我们空格和其他一些什么都被过滤了2.我们来尝试绕过,按照之前的做法&#xff0c;可以看到闭合方式为单引号&#xff0c;并且过滤了--与#3.我们来尝试绕过一下&#xff0c;发现可以以下的方式绕过&#xff0c;空格用&#xff0…

从Docker衔接到导入黑马商城以及前端登录显示用户或密码错误的相关总结(个人理解,仅供参考)

目录 一、前言 二、从Docker衔接到导入黑马点评 三、谈谈端口映射及我的前端登录显示用户或密码错误 四、总结 一、前言 在学习24黑马SpringCloud课程时&#xff0c;说实话Docker那一块再到导入黑马商城是真的有点折磨&#xff0c;个人感觉老师水平还是很强的&#xff0c;但…

控制建模matlab练习10:滞后补偿器

此练习主要是&#xff1a;关于滞后补偿器。 ①滞后补偿器作用&#xff1b; ②不同滞后补偿器的效果&#xff1b; 一、为什么使用滞后补偿器 滞后补偿器&#xff1a;主要用于改善系统的稳态误差&#xff1b;滞后补偿器设计思路&#xff1a;同时为系统增加一个极点和零点&#xf…

力扣-108.将有序数组转换为二叉搜索树

题目链接 108.将有序数组转换为二叉搜索树 class Solution {public TreeNode Traverse(int[] nums, int begin, int end) {if (end < begin)return null;int mid (begin end) / 2;TreeNode root new TreeNode(nums[mid]);root.left Traverse(nums, begin, mid - 1);ro…

`npm error code CERT_HAS_EXPIRED‘ 问题

问题: npm error code CERT_HAS_EXPIRED npm error errno CERT_HAS_EXPIRED npm error request to https://r2.cnpmjs.org/string_decoder/-/string_decoder-1.3.0.tgz failed, reason: certificate has expired npm error A complete log of this run can be found in: /home…

数据结构---概念、数据与数据之间的关系(逻辑结构、物理结构)、基本功能、数据结构内容、单向链表(概念、对象、应用)

数据结构在数据结构部分&#xff0c;研究数据在内存中如何存储。数据存储的形式有两种&#xff1a;变量和数组&#xff08;数据结构的顺序表&#xff09;。一、什么是数据结构&#xff1f;数据类型被用来组织和存储数据。程序设计 数据结构 算法二、数据与数据之间的关系1、逻…