jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

SVG from Zero to Senior · Part 11 — Path Morphing & Shape Interpolation

Animate the d attribute itself: the golden rule of morphing (same command structure), interpolating coordinates, SMIL path animation, why circles fight stars, and how flubber resamples paths. With a scrubbable morph lab.

Mừng con trở lại, đồ đệ — con đã tốt nghiệp, nhưng sư phụ còn vài cuộn bí kíp. Trong mười bài cốt lõi con đã animate transformstroke. Giờ ta animate thứ căn bản nhất: chính đường viền của hình, thuộc tính d. Đây là path morphing — nút hamburger tan thành chữ X, nút play chảy thành pause, dấu tích nở ra từ hư không.

Kéo slider để morph bằng tay, chọn đích, rồi bấm animate.

Mở demo đầy đủ:

Quy tắc vàng của morphing

Morphing chỉ là nội suy giữa hai chuỗi d. Nhưng nó chỉ chạy mượt với một điều kiện:

Hai path phải có cùng cấu trúc lệnh — cùng số lệnh, cùng loại, cùng thứ tự.

Nếu hình A là M L L (polyline 3 điểm) và hình B cũng M L L, thì điểm 1 ánh xạ điểm 1, điểm 2 điểm 2, cứ thế. Con trộn từng toạ độ độc lập rồi dựng lại chuỗi.

Nội suy tuyến tính (lerp)

Cả cỗ máy là một hàm tí hon:

// blend two arrays of numbers by factor t (0 → 1)
function lerpPath(a, b, t) {
  return a.map((n, i) => n + (b[i] - n) * t);
}

Biểu diễn mỗi hình thành mảng phẳng các toạ độ, lerp các mảng, rồi viết số trở lại mẫu d:

const check = [55,105, 90,140, 150,60];   // M L L
const cross = [60,60,  100,100, 140,140];

const mid = lerpPath(check, cross, 0.5);
const d = `M ${mid[0]} ${mid[1]} L ${mid[2]} ${mid[3]} L ${mid[4]} ${mid[5]}`;

t = 0 là hình đầu, t = 1 là đích, và mọi giá trị giữa là một hình trung gian thật. Lái t bằng requestAnimationFrame và một hàm easing là con có morph mượt như bơ — đúng cái nút animate trong demo làm.

Lựa chọn thuần: SMIL trên d

Con morph được không cần JS bằng SMIL, nếu cấu trúc khớp:

<path d="M55 105 L90 140 L150 60" fill="none" stroke="#c8ff00" stroke-width="6">
  <animate attributeName="d" dur="0.6s" fill="freeze"
    values="M55 105 L90 140 L150 60;
            M60 60 L100 100 L140 140" />
</path>

Gọn và không phụ thuộc cho chuyển icon độc lập. CSS giờ cũng animate d được (d: path('…')) ở nơi hỗ trợ — cùng quy tắc cấu trúc.

Khi cấu trúc không khớp

Hình thật hiếm khi cùng cấu trúc — vòng tròn là arc, sao là line, logo là hàng tá Bézier. Nội suy ngây thơ khi đó cho ra rác hoặc đơn giản là từ chối. Cách sửa là resampling: chuyển cả hai path về cùng số điểm (thường toàn Bézier bậc ba), ghép chúng hợp lý, rồi mới nội suy.

Việc này không tầm thường, nên mới có thư viện:

  • nội suy hình tốt nhất; xử lý số điểm khác nhau và cả tách một hình thành nhiều.
  • morphing production với tự khớp điểm.
  • morph đơn giản khi cấu trúc đã khớp.

Quyết định senior: tự code lerp cho toggle icon khi con kiểm soát cả hai hình; dùng flubber/GSAP khi morph art bất kỳ.

Lời cảnh báo của sư phụ

  • Cùng cấu trúc hoặc hỏng. Khớp loại và số lệnh, hoặc resample trước.
  • Thứ tự điểm quan trọng. Dù khớp số lượng vẫn morph kỳ quặc nếu điểm liệt kê khác thứ tự — hình “lộn từ trong ra”.
  • Giữ số điểm vừa phải cho morph tự code; hàng nghìn số nội suy mỗi frame là việc của thư viện hoặc canvas.

Luyện tập, không thì coi như chưa học

  1. Hamburger → X: ba đường morph thành dấu X khi toggle.
  2. Play → pause: nội suy tam giác thành hai thanh — thiết kế cả hai cùng số điểm.
  3. Thử phá nó: morph path 3 điểm sang 5 điểm bằng lerp ngây thơ và xem nó hỏng, rồi sửa bằng cách đệm cho bằng số.

Phần tiếp theo

Giờ con biến hình đường viền theo thời gian. Tiếp theo, một component cực thực dụng dựng trên property con đã gặp: ở Phần 12 ta dựng vòng tiến trình và đồng hồ đo với toán stroke-dasharray/stroke-dashoffset — loader, vòng phần trăm, và đồng hồ tốc độ con thấy trong mọi dashboard.