역방향 선형보간 계산법과 시작값 결정 원리-3

calm·2025년 6월 29일
0

GSAP애니메이션

목록 보기
5/8

핵심 키워드: 비율기반 범위매핑 원리와 선형보간 메커니즘

375는 최대 변경 가능한 범위이고, progress는 그 범위 내에서 얼마나 진행되었는지를 나타내는 비율입니다. 이 개념을 수학적 원리부터 브라우저 내부 동작까지 완전히 분석해드리겠습니다.


🎯 핵심 원리: 범위 × 비율 = 실제 변화량

수학적 공식의 본질

실제_변화량 = 최대_변화_범위 × 진행_비율
실제_변화량 = 375 × progress

현재_값 = 시작_값 - 실제_변화량  
현재_값 = 400 - (375 × progress)

구체적 계산 과정

// progress = 0.3 (30% 진행)일 때:

1단계: 실제_변화량 = 375 × 0.3 = 112.5
2단계: 현재_값 = 400 - 112.5 = 287.5px

// 해석: "최대 375만큼 변할 수 있는데, 30%만큼 진행되어서 112.5만큼 변했다"

📏 범위(Range)의 정확한 의미

375가 나타내는 것

시작점: 400px (완전한 원)
끝점: 25px (둥근 사각형)  
범위: 400 - 25 = 375px (이동할 수 있는 최대 거리)

// 375 = "변화의 전체 스펙트럼"

일상생활 비유: 온도계

// 온도계 범위 설정
최고_온도 = 40 (여름 최고기온)
최저_온도 = 5 (겨울 최저기온)  
온도_범위 = 40 - 5 = 35 (변화 가능한 범위)

// 현재 온도 계산
진행률 = 0.6 (60% 지점)
실제_온도_하락 = 35 × 0.6 = 21도
현재_온도 = 40 - 21 = 19

🔢 Progress(비율)의 정확한 의미

비율의 수학적 정의

progress = (현재_위치 - 시작_위치) / (끝_위치 - 시작_위치)
progress = (scrollY - startPoint) / (endPoint - startPoint)

// progress는 항상 0~1 사이의 값
// 0 = 시작점 (0%)
// 0.5 = 중간점 (50%)  
// 1 = 끝점 (100%)

브라우저 내부 계산

// 스크롤 이벤트마다 실행되는 계산
function calculateProgress() {
  const scrollY = window.pageYOffset;        // 현재: 1500px
  const triggerStart = 0;                    // 시작: 0px
  const triggerEnd = 3000;                   // 끝: 3000px (300vh)
  
  const progress = (scrollY - triggerStart) / (triggerEnd - triggerStart);
  const progress = (1500 - 0) / (3000 - 0);
  const progress = 1500 / 3000 = 0.5;       // 50% 진행
  
  return progress;
}

🎬 실시간 계산 시뮬레이션

스크롤 위치별 상세 계산

// 각 스크롤 위치에서의 완전한 계산 과정

스크롤_0px (진행률 0%):
├── progress = 0 / 3000 = 0.0
├── 실제_변화량 = 375 × 0.0 = 0
└── borderRadius = 400 - 0 = 400px (완전한 원)

스크롤_750px (진행률 25%):  
├── progress = 750 / 3000 = 0.25
├── 실제_변화량 = 375 × 0.25 = 93.75
└── borderRadius = 400 - 93.75 = 306.25px

스크롤_1500px (진행률 50%):
├── progress = 1500 / 3000 = 0.5  
├── 실제_변화량 = 375 × 0.5 = 187.5
└── borderRadius = 400 - 187.5 = 212.5px

스크롤_3000px (진행률 100%):
├── progress = 3000 / 3000 = 1.0
├── 실제_변화량 = 375 × 1.0 = 375  
└── borderRadius = 400 - 375 = 25px (둥근 사각형)

🎨 시각적 모델: 슬라이더 비유

물리적 슬라이더로 이해하기

// 길이 375mm인 슬라이더가 있다고 상상
┌─────────────────────────────────────┐
│ 0mm    93.75mm   187.5mm    375mm   │  ← 슬라이더 눈금
│  0%      25%       50%      100%    │  ← 진행률
│ 400px   306px     212px      25px   │  ← 실제 borderRadius
└─────────────────────────────────────┘

// 슬라이더 핸들의 위치 = progress × 375
// borderRadius = 400 - 슬라이더_위치

도식화된 계산 과정

범위(375) ──┐
            │ × (곱셈)
진행률(0.5)──┘
            │
            ▼
      실제변화량(187.5)
            │
            │ - (빼기)  
시작값(400)──┘
            │
            ▼
        현재값(212.5)

🧮 범위 매핑의 수학적 증명

선형 매핑 공식의 유도

// 목표: A범위[a1, a2]를 B범위[b1, b2]로 매핑

// 1단계: 정규화 (0~1 범위로)
normalized = (input - a1) / (a2 - a1)

// 2단계: 목표 범위로 확장
output = b1 + normalized * (b2 - b1)

// 3단계: 통합 공식
output = b1 + ((input - a1) / (a2 - a1)) * (b2 - b1)

borderRadius에 적용

// 스크롤 범위 [0, 3000px]를 borderRadius 범위 [400px, 25px]로 매핑
borderRadius = 400 + ((scrollY - 0) / (3000 - 0)) * (25 - 400)
borderRadius = 400 + (scrollY / 3000) * (-375)
borderRadius = 400 - (scrollY / 3000) * 375
borderRadius = 400 - progress * 375

// progress = scrollY / 3000 (정규화된 비율)
// 375 = |25 - 400| (변화 범위)

브라우저 최적화: RAF 기반 계산

실제 브라우저 실행 코드

// 60FPS로 실행되는 실제 계산
function onAnimationFrame() {
  // 1단계: 현재 스크롤 위치 측정
  const scrollY = window.pageYOffset;
  
  // 2단계: 정규화된 진행률 계산 
  const progress = Math.max(0, Math.min(1, scrollY / 3000));
  
  // 3단계: 범위 내 실제 변화량 계산
  const actualChange = MAX_CHANGE_RANGE * progress;
  const actualChange = 375 * progress;
  
  // 4단계: 최종값 계산 및 적용
  const currentRadius = START_VALUE - actualChange;
  const currentRadius = 400 - actualChange;
  
  // 5단계: GPU로 렌더링
  element.style.borderRadius = currentRadius + 'px';
}

// RAF 루프에 등록
gsap.ticker.add(onAnimationFrame);

🎯 다른 속성들도 같은 원리

scale 속성 (정방향)

// 0.5에서 1.0으로 증가 (범위: 0.5)
const SCALE_RANGE = 1.0 - 0.5; // 0.5
scale = 0.5 + progress * SCALE_RANGE;
scale = 0.5 + progress * 0.5;

// progress = 0.6일 때:
// 실제_변화량 = 0.5 × 0.6 = 0.3
// scale = 0.5 + 0.3 = 0.8

opacity 속성 (역방향)

// 1.0에서 0.0으로 감소 (범위: 1.0)  
const OPACITY_RANGE = 1.0 - 0.0; // 1.0
opacity = 1.0 - progress * OPACITY_RANGE;
opacity = 1.0 - progress * 1.0;

// progress = 0.3일 때:
// 실제_변화량 = 1.0 × 0.3 = 0.3
// opacity = 1.0 - 0.3 = 0.7

🛠️ 범용 공식 생성기

모든 속성에 적용 가능한 함수

function createRangeMapper(startValue, endValue) {
  const range = Math.abs(endValue - startValue);
  const isReverse = endValue < startValue;
  
  return function(progress) {
    const actualChange = range * progress;
    
    if (isReverse) {
      return startValue - actualChange;  // 감소형
    } else {
      return startValue + actualChange;  // 증가형  
    }
  };
}

// 사용 예시
const getBorderRadius = createRangeMapper(400, 25);    // 역방향
const getScale = createRangeMapper(0.5, 1.0);          // 정방향
const getOpacity = createRangeMapper(1.0, 0.0);        // 역방향

// 실행
const currentRadius = getBorderRadius(0.4);  // 400 - (375 × 0.4) = 250
const currentScale = getScale(0.4);          // 0.5 + (0.5 × 0.4) = 0.7  
const currentOpacity = getOpacity(0.4);      // 1.0 - (1.0 × 0.4) = 0.6

🎭 완벽한 이해를 위한 최종 정리

핵심 개념 3단계

1️⃣ 범위 설정: "375 = 변할 수 있는 최대 거리"
2️⃣ 비율 측정: "progress = 현재 얼마나 진행되었나 (0~1)"  
3️⃣ 실제 적용: "375 × progress = 지금 실제로 변한 양"

일상 대화로 표현하면

"400에서 25까지 총 375만큼 변할 수 있어.
 지금 50% 진행됐으니까, 375의 50%인 187.5만큼 변했어.
 그러니까 400에서 187.5를 빼면 212.5가 현재값이야."

수학 공식의 의미

borderRadius = 400 - progress * 375

// 직역: "시작값에서 (비율 × 범위)만큼 뺀다"
// 의역: "전체 변화 중에서 현재 진행된 만큼만 적용한다"

완전 이해 검증

마스터 레벨 테스트:

  1. progress = 0.7일 때 borderRadius는?

    실제변화량 = 375 × 0.7 = 262.5
    borderRadius = 400 - 262.5 = 137.5px
  2. 새로운 범위 [100, 20]에서 progress = 0.4일 때는?

    범위 = 100 - 20 = 80
    실제변화량 = 80 × 0.4 = 32  
    현재값 = 100 - 32 = 68
  3. 증가형 [0.2, 0.8]에서 progress = 0.6일 때는?

    범위 = 0.8 - 0.2 = 0.6
    실제변화량 = 0.6 × 0.6 = 0.36
    현재값 = 0.2 + 0.36 = 0.56

🎉 축하합니다! 이제 범위 × 비율 = 실제변화량의 핵심을 완전히 마스터하셨습니다!

profile
공부한 내용을 기록합니다

0개의 댓글