→ לכל המאגר

G46 · גרף תוצאות שנמתח בגלילה

GSAP GSAP · DrawSVG · MotionPath מספרים ונתוניםתהליך ושלבים ממתין

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

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

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

הדמו

גלול למטה, הדמו מגיע ↓

מה קרה בחצי שנה

0
פניות בחודש, לעומת 41 בהתחלה
ינוארפברוארמרץאפרילמאייוני
עוד מסלול גלילה. נסה גם חזרה למעלה ↑
מלכודת RTL שנתפסה בבדיקה: ה-SVG לא מושפע מכיוון העמוד, ולכן הקו תמיד עולה משמאל לימין, בעוד שורת התוויות ב-flex התהפכה והציגה את ינואר בימין. התוצאה הייתה גרף שבו ההתחלה מסומנת כחודש האחרון. הפתרון: direction:ltr על שורת התוויות, בדיוק כמו שעושים למספרים. הנקודה נעה על אותו path של הקו דרך MotionPath, ולכן היא לא יכולה להתנתק ממנו בשום רוחב מסך. המספר מונפש על אובייקט עזר ולא על ה-DOM, וה-onUpdate כותב אותו מעוגל. השטח שמתחת לקו הוא path נפרד שנסגר לתחתית, כי אי אפשר למלא path פתוח. בפרויקט אמיתי מייצרים את ה-d מהנתונים במקום לכתוב אותו ידנית.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --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}

/* G46 · גרף תוצאות שנמתח בגלילה */
.chart{padding-inline:var(--gutter, clamp(24px, 5vw, 96px))}
.chart-in{max-width:min(980px,94vw);margin-inline:auto;position:relative}
.chart-head{display:flex;align-items:flex-end;justify-content:space-between;gap:20px;flex-wrap:wrap;margin-bottom:clamp(18px,2vw,30px)}
.chart-head h3{font-size:clamp(24px,3vw,46px);margin:0;font-weight:800;max-width:20ch}
.chart-kpi{text-align:end}
.chart-val{font-size:clamp(38px,5vw,84px);font-weight:800;line-height:1;font-variant-numeric:tabular-nums;color:var(--accent, #4a3aff);direction:ltr}
.chart-lbl{font-size:14px;color:var(--muted, #6a6d85);margin-top:6px}
.chart-wrap{position:relative}
.chart-wrap svg{width:100%;height:auto;overflow:visible;display:block}
.chart-grid line{stroke:var(--line, #e4e4ee);stroke-width:1}
.chart-area{fill:url(#chartFill);opacity:0}
.chart-line{fill:none;stroke:var(--accent, #4a3aff);stroke-width:3;stroke-linecap:round;stroke-linejoin:round}
.chart-dot{fill:#fff;stroke:var(--accent, #4a3aff);stroke-width:3}
/* ציר הזמן ב-ltr כדי שהתוויות יתאימו לכיוון שבו הקו עולה. גרפים ומספרים נקראים משמאל לימין גם בעמוד עברי */
.chart-x{display:flex;justify-content:space-between;margin-top:12px;font-size:12px;color:var(--muted, #6a6d85);letter-spacing:.06em;direction:ltr}

HTML

<div class="stage chart"><div class="chart-in">
  <div class="chart-head">
    <h3>מה קרה בחצי שנה</h3>
    <div class="chart-kpi"><div class="chart-val" data-to="394">0</div><div class="chart-lbl">פניות בחודש, לעומת 41 בהתחלה</div></div>
  </div>
  <div class="chart-wrap">
    <svg viewBox="0 0 900 320" preserveAspectRatio="none" aria-label="גרף גידול בפניות">
      <defs><linearGradient id="chartFill" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0" stop-color="#4a3aff" stop-opacity=".28"/><stop offset="1" stop-color="#4a3aff" stop-opacity="0"/>
      </linearGradient></defs>
      <g class="chart-grid">
        <line x1="0" y1="40" x2="900" y2="40"/><line x1="0" y1="120" x2="900" y2="120"/>
        <line x1="0" y1="200" x2="900" y2="200"/><line x1="0" y1="280" x2="900" y2="280"/>
      </g>
      <path class="chart-area" d="M20,280 C160,268 250,232 340,214 C440,194 520,196 610,150 C700,104 780,74 880,38 L880,300 L20,300 Z"/>
      <path class="chart-line" id="chartLine" d="M20,280 C160,268 250,232 340,214 C440,194 520,196 610,150 C700,104 780,74 880,38"/>
      <circle class="chart-dot" id="chartDot" r="7" cx="20" cy="280"/>
    </svg>
    <div class="chart-x"><span>ינואר</span><span>פברואר</span><span>מרץ</span><span>אפריל</span><span>מאי</span><span>יוני</span></div>
  </div>
</div></div>

JS

gsap.registerPlugin(ScrollTrigger, DrawSVGPlugin, MotionPathPlugin);

(function(){
  const val=document.querySelector(".chart-val");
  const target=+val.dataset.to;
  const num={n:0};
  const tl=gsap.timeline({scrollTrigger:{trigger:".chart-in",start:"top 72%",end:"bottom 78%",scrub:.7}});
  tl.fromTo("#chartLine",{drawSVG:"0% 0%"},{drawSVG:"0% 100%",ease:"none"},0);
  // הנקודה נוסעת על אותו path בדיוק, ולכן היא תמיד יושבת על קצה הקו
  tl.to("#chartDot",{motionPath:{path:"#chartLine",align:"#chartLine",alignOrigin:[.5,.5]},ease:"none"},0);
  tl.to(".chart-area",{opacity:1,ease:"none"},0);
  tl.to(num,{n:target,ease:"none",onUpdate:()=>{val.textContent=Math.round(num.n).toLocaleString("he-IL");}},0);
})();