jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

SVG from Zero to Senior · Part 22 — Motion Paths & Following a Curve

Part 22: make anything travel along a curve. Master animateMotion, reuse a path with <mpath>, and use rotate="auto" so a traveler banks into the turn instead of sliding — plus the CSS offset-path equivalent. With a live demo.

In Part 21 you sequenced a scene in time. {Ở Phần 21 bạn dàn cảnh theo thời gian.} Now we move things through space along any curve you can draw. {Giờ ta cho mọi thứ di chuyển qua không gian dọc bất kỳ đường cong nào bạn vẽ được.} A comet streaking along an arc, a car driving a winding road, a label riding a wave — they all use one tool: <animateMotion>. {Một sao chổi lướt theo cung, một xe chạy đường quanh co, một nhãn cưỡi sóng — tất cả dùng một công cụ: <animateMotion>.} And the attribute that separates amateur from senior motion is rotate="auto". {Và thuộc tính tách chuyển động nghiệp dư khỏi senior là rotate="auto".}

The two arrows below follow the same path at the same speed — only rotate="auto" differs. Watch the green one bank into the S-curve. {Hai mũi tên dưới đi theo cùng đường ở cùng tốc độ — chỉ khác rotate="auto". Xem cái xanh lá nghiêng vào khúc cua chữ S.}

Open the full demo {Mở demo đầy đủ}: /tools/svg-motion-path-demo/.

<animateMotion> and reusing a path with <mpath> {<animateMotion> và tái dùng path với <mpath>}

animateMotion moves its parent element along a path. {animateMotion di chuyển phần tử cha của nó dọc một path.} You can inline the path in a path attribute, but the senior pattern is to draw the path once as a real <path> and reference it — so the visible road and the motion are guaranteed identical: {Bạn có thể nội tuyến path trong thuộc tính path, nhưng mẫu senior là vẽ path một lần thành <path> thật rồi tham chiếu — để con đường nhìn thấy và chuyển động chắc chắn trùng khớp:}

<path id="road" d="M30 200 C120 40, 300 40, 360 140 S440 220, 450 60" fill="none"/>

<g>
  <polygon points="0,-9 20,0 0,9 5,0" fill="#c8ff00"/>
  <animateMotion dur="5s" repeatCount="indefinite" rotate="auto">
    <mpath href="#road"/>
  </animateMotion>
</g>

Two senior details: {Hai chi tiết senior:} the traveler is drawn around its own origin (0,0)animateMotion places that origin on the path, so design your shape centered on (0,0). {vật được vẽ quanh gốc của chính nó (0,0)animateMotion đặt gốc đó lên path, nên hãy thiết kế hình tâm tại (0,0).} And the arrow points along +x, because at rotate="auto" the local +x axis is aligned to the tangent. {Và mũi tên hướng theo +x, vì với rotate="auto" trục +x cục bộ được căn theo tiếp tuyến.}

rotate — the difference between flying and sliding {rotate — khác biệt giữa bay và trượt}

ValueEffect {Hiệu ứng}
(none / 0)element keeps its original orientation — slides sideways {giữ hướng gốc — trượt ngang}
autorotates so local +x faces the tangent — banks into turns {xoay để +x hướng tiếp tuyến — nghiêng vào cua}
auto-reverselike auto, but facing backward along the path {như auto, nhưng quay ngược dọc path}
a number (deg)a fixed extra rotation {một góc xoay cố định thêm}

rotate="auto" is what makes a plane look like it’s flying the route instead of being dragged through it. {rotate="auto" làm chiếc máy bay trông như đang bay theo lộ trình thay vì bị kéo lê.}

Controlling pacing along the path: keyPoints & keyTimes {Điều khiển nhịp dọc path: keyPoints & keyTimes}

By default motion is constant-rate along the path. {Mặc định chuyển động đều tốc độ dọc path.} To pause, accelerate, or dwell at points, pair keyPoints (fractions 0–1 along the path) with keyTimes (fractions 0–1 of the duration): {Để dừng, tăng tốc, hay nán lại ở điểm, ghép keyPoints (phần 0–1 dọc path) với keyTimes (phần 0–1 của thời lượng):}

<animateMotion dur="6s" rotate="auto"
  keyPoints="0; 0.5; 0.5; 1"
  keyTimes="0; 0.4; 0.7; 1"
  calcMode="linear">
  <mpath href="#road"/>
</animateMotion>

Here the traveler reaches the path’s midpoint at 40% of the time, dwells there until 70% (same keyPoint, later keyTime), then finishes — perfect for a delivery stop or a beat in a story. {Ở đây vật tới trung điểm path ở 40% thời gian, nán lại tới 70% (cùng keyPoint, keyTime sau), rồi kết — hoàn hảo cho một điểm dừng giao hàng hay một nhịp trong câu chuyện.}

The modern CSS equivalent: offset-path {Tương đương CSS hiện đại: offset-path}

SVG isn’t the only way anymore. {SVG không còn là cách duy nhất.} CSS Motion Path does the same thing for any element (HTML or SVG), and it animates on the compositor: {CSS Motion Path làm điều tương tự cho mọi phần tử, và nó animate trên compositor:}

.traveler {
  offset-path: path('M30 200 C120 40, 300 40, 360 140 S440 220, 450 60');
  offset-rotate: auto;                 /* === rotate="auto" */
  animation: drive 5s linear infinite;
}
@keyframes drive { to { offset-distance: 100%; } }

Reach for offset-path in product UI (it’s GPU-friendly and respects CSS tooling); reach for <animateMotion> when the animation must live inside a portable .svg file. {Dùng offset-path trong UI sản phẩm (thân thiện GPU); dùng <animateMotion> khi animation phải nằm bên trong file .svg chuyển giao được.}

The master’s warnings {Lời cảnh báo của sư phụ}

  • Design the traveler around (0,0). Off-origin shapes orbit weirdly because the origin is what rides the path. {Thiết kế vật quanh (0,0). Hình lệch gốc sẽ quay quanh kỳ lạ.}
  • Point your shape along +x. With rotate="auto", +x is “forward”; a shape drawn pointing up will look 90° wrong. {Cho hình hướng theo +x. Với rotate="auto", +x là “trước”.}
  • keyPoints needs keyTimes and calcMode. Use them together or the pacing is ignored. {keyPoints cần keyTimescalcMode.}
  • For heavy or interactive motion, prefer offset-path/JS. Many simultaneous animateMotions can get expensive (Part 19). {Chuyển động nặng/tương tác thì ưu tiên offset-path/JS.}

Practice {Thực hành}

  1. Orient experiment {Thử nghiệm hướng}: take any icon, send it around a loop with and without rotate="auto", and feel the difference. {cho một icon đi vòng có và không rotate="auto".}
  2. Dwell {Nán lại}: use keyPoints/keyTimes to make a bus stop at two stations along a route. {cho xe buýt dừng ở hai trạm dọc tuyến.}
  3. Port to CSS {Chuyển sang CSS}: rebuild one traveler with offset-path + offset-rotate and compare smoothness. {dựng lại một vật bằng offset-path + offset-rotate.}

What’s next {Phần tiếp theo}

Your objects now move through space, facing the right way. {Vật của bạn giờ di chuyển qua không gian, hướng đúng.} But they’re still rigid. {Nhưng chúng vẫn cứng đờ.} To bring a character to life you need parts that move relative to each other. {Để thổi hồn một nhân vật bạn cần các bộ phận chuyển động tương đối với nhau.} In Part 23 we tackle character rigging — pivots with transform-origin, nested groups as joints, and a hierarchical transform chain that animates a waving arm and a walk cycle, the same skeleton idea behind every cartoon. {Ở Phần 23 ta xử lý rigging nhân vật — điểm xoay với transform-origin, nhóm lồng nhau làm khớp, và chuỗi transform phân cấp tạo cánh tay vẫy và chu kỳ bước đi.}