→ לכל המאגר

G140 · טבעות יעד שמתמלאות בגלילה

GSAP GSAP · ScrollTrigger · SVG מספרים ונתונים ממתין

שלוש טבעות מקוננות, כל אחת מייצגת יעד אחר, שמתמלאות בקצב שונה ככל שגוללים, עם מקרא שהמספרים בו רצים. שלושה נתונים בתמונה אחת.

מתי משתמשים: תוצאות לקוח בשלושה מדדים, יעדי שנה, שביעות רצון לפי קטגוריה. בדיוק שלושה.

הדמו כאן עיצובי-ניטרלי בכוונה. כשהמהלך נכנס לפרויקט, מיובאת רק ההתנהגות: הצבעים, הרדיוסים, הפונטים והצללים יורשים את העיצוב של אותו פרויקט.

הדמו

גלול למטה, הדמו מגיע ↓
0אחוז מהלקוחות ממליצים
0אחוז עלייה בפניות
0אחוז חיסכון בזמן
עוד מסלול גלילה. נסה גם חזרה למעלה ↑
שלושה circle עם stroke-dasharray ו-dashoffset בסקראב, כל אחד ליעד שונה, עם סטאגר קטן. המספרים מחושבים מאותו progress. במובייל הטבעות מעל המקרא במקום לצידו.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --accent או --line משלו יורש אותם אוטומטית. הרכיב הזה מסתמך על dir="rtl".

פתח קובץ עצמאי ↗
הצג את הקוד כאן

CSS

/* מחלקות עזר של המאגר שהרכיב הזה משתמש בהן */
.stage{padding:var(--sec, clamp(120px, 12vw, 260px)) var(--gutter, clamp(24px, 5vw, 96px));position:relative}
.stage.tight{padding-block:clamp(48px,5vw,90px)}
.stage.full{padding-inline:0}

/* G140 · טבעות יעד שמתמלאות בגלילה */
.rg2{display:grid;grid-template-columns:auto 1fr;gap:clamp(24px,5vw,70px);align-items:center;max-width:900px;margin-inline:auto;padding-block:16vh 30vh}
.rg2 svg{width:min(320px,70vw);height:auto;transform:rotate(-90deg)}
.rg2 circle{fill:none;stroke-width:14;stroke-linecap:round}
.rg2 .trk{stroke:var(--line, #e4e4ee)}
.rg2 .r1{stroke:var(--accent, #4a3aff)}.rg2 .r2{stroke:#2b8a3e}.rg2 .r3{stroke:#e8590c}
.rg2-leg{display:grid;gap:18px}
.rg2-leg div{display:flex;align-items:center;gap:12px}
.rg2-leg i{width:14px;height:14px;border-radius:50%;flex:none}
.rg2-leg b{font-size:clamp(26px,3vw,40px);font-variant-numeric:tabular-nums;min-width:3.2ch;text-align:start}
.rg2-leg span{color:var(--muted, #6a6d85);font-size:15px}
@media(max-width:767px){.rg2{grid-template-columns:1fr;justify-items:center}}

HTML

<div class="stage"><div class="rg2">
  <svg viewBox="0 0 200 200" aria-hidden="true">
    <circle class="trk" cx="100" cy="100" r="88"/><circle class="trk" cx="100" cy="100" r="66"/><circle class="trk" cx="100" cy="100" r="44"/>
    <circle class="r1" cx="100" cy="100" r="88" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100"/>
    <circle class="r2" cx="100" cy="100" r="66" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100"/>
    <circle class="r3" cx="100" cy="100" r="44" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100"/>
  </svg>
  <div class="rg2-leg">
    <div><i style="background:var(--accent)"></i><b data-to="92">0</b><span>אחוז מהלקוחות ממליצים</span></div>
    <div><i style="background:#2b8a3e"></i><b data-to="74">0</b><span>אחוז עלייה בפניות</span></div>
    <div><i style="background:#e8590c"></i><b data-to="58">0</b><span>אחוז חיסכון בזמן</span></div>
  </div>
</div></div>

JS

gsap.registerPlugin(ScrollTrigger);

(function(){
  const rings=[".r1",".r2",".r3"].map(s=>document.querySelector(".rg2 "+s)),nums=gsap.utils.toArray(".rg2-leg b");
  const reduce=matchMedia("(prefers-reduced-motion: reduce)").matches;
  const tl=gsap.timeline({scrollTrigger:{trigger:".rg2",start:"top 75%",end:"top 25%",scrub:reduce?false:.5}});
  rings.forEach((r,i)=>{const to=+nums[i].dataset.to,o={v:0};
    tl.to(r,{strokeDashoffset:100-to,duration:1,ease:"power2.out"},i*.1)
      .to(o,{v:to,duration:1,ease:"power2.out",onUpdate(){nums[i].textContent=Math.round(o.v)+"%";}},i*.1);});
})();