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
英文地址,請注明出處:http://en.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、邏…