Hoạt Hình

Hệ thống hoạt hình nâng cao để tạo ra các hoạt hình động, quy trình và dựa trên biểu thức vượt xa các keyframe đơn giản.

Các Loại Hoạt Hình

Hệ thống hoạt hình hỗ trợ một số loại ngoài các keyframe truyền thống:

  • Biểu thức: Các biểu thức JavaScript được đánh giá theo từng khung hình
  • Quy trình: Các mẫu hoạt hình quy trình tích hợp sẵn
  • Chuỗi: Các hoạt hình tuần tự theo bước
  • Đường dẫn: Chuyển động dọc theo các đường Bezier

Các hoạt hình nâng cao này được định nghĩa trong thuộc tính mảng animations của các phần tử.

Hoạt Hình Node so với Keyframe

Hoạt Hình Node (mảng animations):

  • Hoạt hình quy trình, dựa trên biểu thức, hoặc theo đường dẫn
  • Được đánh giá mỗi khung hình
  • Ưu tiên cao hơn so với keyframe
  • Có thể ghi đè các giá trị keyframe

Keyframes (mảng keyframes):

  • Nội suy thuộc tính đơn giản giữa các điểm đã định nghĩa
  • Ưu tiên thấp hơn
  • Dễ đoán, dễ chỉnh sửa

Ưu Tiên Hoạt Hình

Khi nhiều phương pháp hoạt hình nhắm vào cùng một thuộc tính:

  1. Cao nhất: Hoạt hình node (biểu thức, quy trình, đường dẫn, chuỗi)
  2. Trung bình: Hoạt hình keyframe
  3. Thấp nhất: Giá trị thuộc tính tĩnh
Thuộc tínhLoạiBắt buộcVí dụPhạm vi giá trịMô tả
typestringtrue-expression | procedural | sequence | pathLoại hoạt hình.
enabledbooleanfalse--Liệu hoạt hình có đang hoạt động hay không.
targetstringtrue--Cú pháp thuộc tính để hoạt hình (ví dụ: "x", "rotation", "scaleX").
startTimenumberfalse--Thời gian bắt đầu của hoạt hình tương đối với thời gian bắt đầu của phần tử, tính bằng giây.
durationnumberfalse--Thời gian của hoạt hình tính bằng giây. Đối với các hoạt hình lặp lại, đây là chu kỳ lặp lại.
loopbooleanfalse--Liệu hoạt hình có lặp lại hay không.
blendModestringfalse-replace | add | multiplyCách hoạt hình này kết hợp với các hoạt hình khác: thay thế (ghi đè), thêm (tổng), nhân (tỷ lệ).
blendWeightnumberfalse--Sức mạnh/ảnh hưởng của hoạt hình này (0-1). Được sử dụng để kết hợp nhiều hoạt hình.

Hoạt Hình Biểu Thức

Các biểu thức là mã JavaScript được đánh giá theo từng khung hình, với quyền truy cập vào các biến ngữ cảnh hoạt hình.

Các Biến Ngữ Cảnh Có Sẵn

{
  time: number; // Thời gian tuyệt đối hiện tại (giây)
  localTime: number; // Thời gian tương đối so với điểm bắt đầu của phần tử
  duration: number; // Thời gian của phần tử
  progress: number; // Tiến độ đã chuẩn hóa (0-1)
  index: number; // Chỉ số phần tử trong nhóm
  total: number; // Tổng số phần tử trong nhóm
  fps: number; // Khung hình trên giây
  width: number; // Chiều rộng của canvas
  height: number; // Chiều cao của canvas
  value: any; // Giá trị thuộc tính hiện tại
}

Ví Dụ Về Biểu Thức

Hoạt hình nảy sử dụng các hàm Math:

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
  }
]
}

Biểu Thức Phức Tạp

Kết hợp nhiều hiệu ứng:

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
  }
]
}

Hoạt Hình Quy Trình

Các mẫu hoạt hình tích hợp sẵn với các tham số có thể cấu hình.

Các Loại Quy Trình

  • wiggle: Dao động ngẫu nhiên (hữu ích cho hiệu ứng camera cầm tay)
  • wave: Chuyển động sóng sine/cosine
  • bounce: Hiệu ứng nảy đàn hồi
  • pulse: Tăng giảm nhịp nhàng

Ví Dụ Về Wiggle

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

Hoạt Hình Chuỗi

Các hoạt hình theo bước thay đổi giá trị tại các khoảng thời gian cụ thể.

Thuộc tínhLoạiBắt buộcVí dụPhạm vi giá trịMô tả
valuesarraytrue--Mảng các giá trị để bước qua.
stepDurationnumbertrue--Thời gian của mỗi bước tính bằng giây.
loopbooleanfalse--Liệu có lặp lại chuỗi hay không.

Ví Dụ Về Chuỗi

Văn bản chuyển đổi qua các kích thước khác nhau:

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

Hoạt Hình Đường Dẫn

Hoạt hình các phần tử dọc theo các đường cong Bezier.

Thuộc tínhLoạiBắt buộcVí dụPhạm vi giá trịMô tả
pathstring | arraytrue--Dữ liệu đường dẫn SVG (thuộc tính d) hoặc mảng các điểm đường dẫn.
autoRotatebooleanfalse--Liệu có tự động xoay phần tử theo tiếp tuyến của đường dẫn hay không.
durationnumbertrue--Thời gian để hoàn thành toàn bộ đường dẫn.

Ví Dụ Về Đường Dẫn

Chuyển động tròn:

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
  }
]
}

Cú Pháp Đường Dẫn Thuộc Tính

Thuộc tính target sử dụng cú pháp dấu chấm để chỉ định các thuộc tính lồng nhau:

  • Đơn giản: "x", "y", "rotation"
  • Lồng nhau: "scale.x", "position.y"
  • Mảng: "colors[0]", "points[2].x"

Ví Dụ Về Giải Quyết Mục Tiêu

{
  "target": "x"              // Vị trí x của phần tử
  "target": "scaleX"         // Tỷ lệ chiều ngang
  "target": "alpha"          // Độ mờ
  "target": "fill.color"     // Màu sắc fill (nếu fill là đối tượng)
  "target": "points[0].x"    // Tọa độ x của điểm đầu tiên
}

Chế Độ Kết Hợp

Kiểm soát cách các hoạt hình kết hợp khi nhiều hoạt hình nhắm vào cùng một thuộc tính:

Thay Thế (Mặc định)

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

Hoàn toàn thay thế giá trị thuộc tính.

Thêm

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

Thêm vào giá trị hiện có (có trọng số). Hữu ích để tích lũy độ dịch chuyển.

Nhân

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

Nhân với giá trị hiện có. Hữu ích cho các hiệu ứng tỷ lệ.

Ví Dụ Về Nhiều Hoạt Hình

Kết hợp các loại hoạt hình khác nhau:

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 }
  }
]
}

Trong ví dụ này:

  • Biểu thức điều khiển vị trí ngang (chế độ thay thế)
  • Wiggle quy trình thêm sự biến đổi xoay nhẹ
  • Chuỗi nhấp nháy độ mờ
  • Keyframe tỷ lệ phần tử (ưu tiên thấp nhất)

Ghi Chú Quan Trọng

Sandbox Biểu Thức

  • Các biểu thức chạy trong ngữ cảnh bị hạn chế để đảm bảo an ninh
  • Chỉ có quyền truy cập vào các biến ngữ cảnh hoạt hình
  • Không thể truy cập DOM, thư viện bên ngoài, hoặc Node.js APIs
  • Lỗi đánh giá sẽ vô hiệu hóa hoạt hình

Hiệu Suất

  • Biểu Thức: Được đánh giá mỗi khung hình - giữ cho chúng đơn giản
  • Quy trình: Các hàm tích hợp sẵn được tối ưu hóa - rất hiệu quả
  • Chuỗi: Tải trọng tối thiểu, tốt cho các thay đổi rời rạc
  • Đường dẫn: Chi phí vừa phải, phụ thuộc vào độ phức tạp của đường dẫn

Thời Gian

  • startTimeduration là tương đối với thời gian start của phần tử
  • localTime trong các biểu thức bắt đầu từ 0 khi phần tử bắt đầu
  • Các hoạt hình tôn trọng ranh giới duration tổng thể của phần tử

Gỡ Lỗi

  • Nếu một hoạt hình không hoạt động, hãy kiểm tra:
    • enabled: true
    • Thuộc tính target tồn tại trên phần tử
    • Cú pháp biểu thức là JavaScript hợp lệ
    • startTime nằm trong khoảng thời gian của phần tử
    • Không có lỗi chính tả trong cú pháp thuộc tính

Các Trường Hợp Sử Dụng Thông Thường

Hiệu Ứng Theo Dõi Mượt Mà

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

Nảy Đàn Hồi

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

Lắc Camera

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

Hoạt Hình Chậm (trong nhóm)

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