动画

用于创建动态、程序化和基于表达式的动画的高级动画系统,超越简单的关键帧。

动画类型

动画系统支持多种类型,超越传统的关键帧:

  • 表达式:每帧评估的 JavaScript 表达式
  • 程序化:内置的程序化动画模式
  • 序列:基于步骤的顺序动画
  • 路径:沿贝塞尔路径的运动

这些高级动画在元素的 animations 数组属性中定义。

节点动画与关键帧

节点动画 (animations 数组):

  • 程序化、基于表达式或跟随路径的动画
  • 每帧评估
  • 优先级高于关键帧
  • 可以覆盖关键帧值

关键帧 (keyframes 数组):

  • 在定义点之间简单的属性插值
  • 优先级较低
  • 可预测,易于编辑

动画优先级

当多个动画方法针对同一属性时:

  1. 最高:节点动画(表达式、程序化、路径、序列)
  2. 中等:关键帧动画
  3. 最低:静态属性值
属性类型必需示例值范围描述
typestringtrue-expression | procedural | sequence | path动画的类型。
enabledbooleanfalse--动画是否处于活动状态。
targetstringtrue--要动画的属性路径(例如,`"x"`、`"rotation"`、`"scaleX"`)。
startTimenumberfalse--相对于元素开始的动画开始时间,以秒为单位。
durationnumberfalse--动画的持续时间(以秒为单位)。对于循环动画,这是循环周期。
loopbooleanfalse--动画是否循环。
blendModestringfalse-replace | add | multiply此动画与其他动画的组合方式:替换(覆盖)、添加(求和)、乘法(缩放)。
blendWeightnumberfalse--此动画的强度/影响力(0-1)。用于混合多个动画。

表达式动画

表达式是每帧评估的 JavaScript 代码,可以访问动画上下文变量。

可用的上下文变量

{
  time: number; // 当前绝对时间(秒)
  localTime: number; // 相对于元素开始的时间
  duration: number; // 元素持续时间
  progress: number; // 标准化进度(0-1)
  index: number; // 组内元素索引
  total: number; // 组内总元素数
  fps: number; // 每秒帧数
  width: number; // 画布宽度
  height: number; // 画布高度
  value: any; // 当前属性值
}

表达式示例

使用数学函数的弹跳动画:

expressionAnimation.json
{
"id": "element-1",
"type": "Image",
"start": 0,
"duration": 5,
"animations": [
  {
    "type": "expression",
    "target": "y",
    "enabled": true,
    "expression": "100 + Math.abs(Math.sin(localTime * 3)) * 200",
    "startTime": 0,
    "duration": 5,
    "loop": true
  }
]
}

复杂表达式

组合多个效果:

complexExpression.json
{
"animations": [
  {
    "type": "expression",
    "target": "rotation",
    "expression": "(localTime * 2 * Math.PI / duration) + Math.sin(localTime * 4) * 0.1",
    "loop": true
  },
  {
    "type": "expression",
    "target": "scaleX",
    "expression": "1 + Math.sin(localTime * 5) * 0.2",
    "loop": true
  }
]
}

程序化动画

具有可配置参数的内置动画模式。

程序化类型

  • wiggle:随机振荡(适用于手持相机效果)
  • wave:正弦/余弦波运动
  • bounce:弹性弹跳效果
  • pulse:节奏缩放

Wiggle 示例

wiggleAnimation.json
{
"animations": [
  {
    "type": "procedural",
    "proceduralType": "wiggle",
    "target": "rotation",
    "enabled": true,
    "frequency": 2,
    "amplitude": 0.1,
    "loop": true
  }
]
}

序列动画

在特定间隔内更改值的基于步骤的动画。

属性类型必需示例值范围描述
valuesarraytrue--要逐步遍历的值数组。
stepDurationnumbertrue--每个步骤的持续时间,以秒为单位。
loopbooleanfalse--是否循环序列。

序列示例

文本循环不同大小:

sequenceAnimation.json
{
"animations": [
  {
    "type": "sequence",
    "target": "fontSize",
    "enabled": true,
    "values": [24, 32, 40, 32, 24],
    "stepDuration": 0.5,
    "loop": true
  }
]
}

路径动画

沿贝塞尔曲线路径为元素添加动画。

属性类型必需示例值范围描述
pathstring | arraytrue--SVG 路径数据(d 属性)或路径点数组。
autoRotatebooleanfalse--是否自动旋转元素以跟随路径切线。
durationnumbertrue--完成完整路径的时间。

路径示例

圆形运动:

pathAnimation.json
{
"animations": [
  {
    "type": "path",
    "target": "position",
    "enabled": true,
    "path": "M 100,100 a 200,200 0 1,1 0,1 Z",
    "autoRotate": true,
    "duration": 4,
    "loop": true
  }
]
}

属性路径语法

target 属性使用点表示法来指定嵌套属性:

  • 简单"x""y""rotation"
  • 嵌套"scale.x""position.y"
  • 数组"colors[0]""points[2].x"

目标解析示例

{
  "target": "x"              // 元素的 x 位置
  "target": "scaleX"         // 水平缩放
  "target": "alpha"          // 不透明度
  "target": "fill.color"     // 填充颜色(如果填充是对象)
  "target": "points[0].x"    // 第一个点的 x 坐标
}

混合模式

控制当多个动画目标相同属性时,它们是如何组合的:

替换(默认)

{
  "blendMode": "replace",
  "blendWeight": 1.0
}

完全替换属性值。

添加

{
  "blendMode": "add",
  "blendWeight": 0.5
}

添加到现有值(加权)。适用于累积偏移量。

乘法

{
  "blendMode": "multiply",
  "blendWeight": 1.0
}

乘以现有值。适用于缩放效果。

多重动画示例

结合不同的动画类型:

multipleAnimations.json
{
"id": "animated-element",
"type": "Shape",
"animations": [
  {
    "type": "expression",
    "target": "x",
    "expression": "width / 2 + Math.sin(localTime * 2) * 300",
    "blendMode": "replace",
    "loop": true
  },
  {
    "type": "procedural",
    "proceduralType": "wiggle",
    "target": "rotation",
    "frequency": 3,
    "amplitude": 0.2,
    "blendMode": "add",
    "blendWeight": 0.5
  },
  {
    "type": "sequence",
    "target": "alpha",
    "values": [1, 0.8, 1],
    "stepDuration": 0.3,
    "loop": true,
    "blendMode": "multiply"
  }
],
"keyframes": [
  {
    "id": "kf-1",
    "time": 0,
    "stateObj": { "scaleX": 1 }
  },
  {
    "id": "kf-2",
    "time": 2,
    "stateObj": { "scaleX": 1.5 }
  }
]
}

在此示例中:

  • 表达式控制水平位置(替换模式)
  • 程序化振动添加细微的旋转变化
  • 序列脉冲不透明度
  • 关键帧缩放元素(优先级最低)

重要说明

表达式沙箱

  • 表达式在受限的上下文中运行以确保安全
  • 只能访问动画上下文变量
  • 不能访问 DOM、外部库或 Node.js API
  • 评估错误将禁用动画

性能

  • 表达式:每帧评估 - 保持简单
  • 程序化:优化的内置函数 - 非常高效
  • 序列:开销最小,适合离散变化
  • 路径:中等成本,取决于路径复杂性

定时

  • startTimeduration 相对于元素的 start 时间
  • 表达式中的 localTime 在元素开始时为 0
  • 动画遵循元素的整体 duration 边界

调试

  • 如果动画不起作用,请检查:
    • enabled: true
    • 元素上存在 target 属性
    • 表达式语法是有效的 JavaScript
    • startTime 在元素的持续时间内
    • 没有属性路径拼写错误

常见用例

平滑跟随效果

{
  "type": "expression",
  "target": "x",
  "expression": "value + (targetX - value) * 0.1"
}

弹性弹跳

{
  "type": "expression",
  "target": "scaleY",
  "expression": "1 + Math.exp(-localTime * 3) * Math.cos(localTime * 8) * 0.5"
}

相机抖动

{
  "type": "procedural",
  "proceduralType": "wiggle",
  "target": "x",
  "frequency": 10,
  "amplitude": 5
}

阶梯动画(分组)

{
  "type": "expression",
  "target": "alpha",
  "expression": "Math.max(0, Math.min(1, (localTime - index * 0.1) * 2))"
}