jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

SVG from Zero to Senior · Part 12 — Progress Rings & Gauges

Build the loaders, percentage rings, and speedometers in every dashboard with one formula: stroke-dashoffset = circumference × (1 − percent). Plus the -90° start rotation, round caps, gradient rings, and a 270° gauge. With a live builder.

Có những component trông cao siêu nhưng dựa trên một công thức thanh lịch duy nhất. Vòng tiến trình tròn — cái loader phần trăm trong mọi dashboard, app thể dục, và trang thanh toán — chính là vậy. Một khi thấy được mánh con sẽ dựng chúng trong lúc ngủ.

Kéo phần trăm, độ rộng, và màu; rồi khám phá đồng hồ 270° bên dưới.

Mở demo đầy đủ:

Một công thức

Nhớ stroke-dasharraystroke-dashoffset ở Phần 3 và 6 chứ? Đây là ứng dụng đỉnh của chúng.

Lấy một vòng tròn có stroke. Chiều dài đường viền là chu vi:

C = 2 × π × r

Giờ làm pattern nét đứt thành một nét dài đúng bằng cả vòng (stroke-dasharray: C). Nét đó phủ cả vòng. Rồi đẩy nó đi bằng stroke-dashoffset:

dashoffset = C × (1 − percent)

  • cả nét bị đẩy ra → vòng rỗng.
  • nét nằm trọn trên vòng → đầy.
<svg viewBox="0 0 200 200">
  <g transform="rotate(-90 100 100)">           <!-- start at 12 o'clock -->
    <circle cx="100" cy="100" r="80" fill="none" stroke="#232323" stroke-width="12"/>
    <circle cx="100" cy="100" r="80" fill="none" stroke="#c8ff00" stroke-width="12"
            stroke-linecap="round"
            stroke-dasharray="502.6"             /* C = 2π·80 */
            stroke-dashoffset="160.8" />          /* C × (1 − 0.68) */
  </g>
</svg>
const C = 2 * Math.PI * r;
fill.style.strokeDasharray = C;
fill.style.strokeDashoffset = C * (1 - percent);  // percent in 0..1

Đó là toàn bộ component. Phần còn lại là đánh bóng.

Hai chi tiết làm nó trông đúng

  1. Bắt đầu ở 12 giờ. Stroke của vòng tròn bắt đầu ở 3 giờ. Bọc trong rotate(-90 cx cy) để tiến trình bắt đầu từ trên.
  2. Đầu bo tròn. stroke-linecap: round cho đầu nét mềm, hiện đại.

Animate nó mượt

stroke-dashoffset là một số animate được, một transition CSS một dòng làm vòng trượt tới giá trị mới:

.ring-fill {
  transition: stroke-dashoffset 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

Cập nhật offset trong JS và nó tự animate — không cần keyframe. Cho spinner xác định→không xác định, xoay cả SVG bằng @keyframes spin trong khi giữ khoảng hở dash cố định.

Vòng gradient & lựa chọn conic

Muốn màu fill đổi dọc cung? Một linearGradient trên stroke cho vẻ hai tông; cho cầu vồng quanh vòng thật con xoay gradient hoặc chuyển sang mask conic-gradient của CSS. Cho tiến trình thuần, cách stroke SVG thắng về độ sắc và kiểm soát animation.

Đồng hồ 270° (tốc kế)

Đồng hồ cùng ý tưởng, nhưng track chỉ phủ một phần vòng tròn. Dùng dasharray [độ-dài-cung, khoảng-hở-lớn] để chỉ cung hiện, xoay nhóm để khoảng hở nằm dưới, và fill là độ-dài-cung × giá-trị:

const C = 2 * Math.PI * r;
const arc = C * 0.75;                 // 270° = three-quarters
track.style.strokeDasharray = `${arc} ${C}`;       // show 270°, hide the rest
fill.style.strokeDasharray  = `${arc * value} ${C}`;
// rotate the group by 135° so the open quarter is centred at the bottom

Cùng toán chu vi, thêm một phép xoay — và con có tốc kế, đồng hồ pin, hay mặt số điểm.

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

  • Khớp bán kính trong công thức và markup. Sai bán kính là lỗi số 1 “vòng không bao giờ đầy”.
  • Tính stroke width khi định cỡ. Stroke cưỡi lên bán kính, nên stroke 12px trên r=80 sơn từ 74→86; thu r nếu nó cắt viewBox.
  • Xoay, đừng vẽ lại, để đổi góc bắt đầu. Vẽ arc path riêng là thừa khi rotate() làm được.

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

  1. Vòng 68%: dựng vòng, tính C trong JS, và animate từ 0 → 68% khi tải.
  2. Vòng đếm ngược: lái stroke-dashoffset từ một timer để vòng cạn dần trong 10 giây.
  3. Đồng hồ pin: một gauge 180° đổi fill sang đỏ khi dưới 20%.

Phần tiếp theo

Giờ con dựng được đồng hồ tròn chính xác. Tiếp theo ta nghịch ngợm và sinh tạo. Ở Phần 13 ta làm pattern sinh tạo và nền SVG — ô <pattern> lặp, máy sinh blob hữu cơ, và các nền hero nhẹ ship dưới dạng data-URI tí hon thay cho ảnh nặng.