Value · 04
Clamp and map
钳制与区间映射 · clamp-mapConvert one interval to another and decide whether values may overshoot.
Scroll progress, pointer distance and opacity use different units. Normalizing before interpolating makes the mapping easy to inspect. Choose clamping deliberately: opacity usually stops at 0…1, while drag displacement may intentionally overshoot.
Formula
t = (x−a)/(b−a) y = c + (d−c)·t clamped: t ← clamp(t, 0, 1)
Parameters
| This page | Mature libraries | |
|---|---|---|
| input range | 0…1; subrange .3… .6 | GSAP normalize, mapRangeA subrange maps one scroll segment to a full 0→1. |
| clamped | true by default | GSAP mapRange is unclampedLibrary defaults differ; make the choice explicit. |
Doing it well
- State both input and output ranges instead of hiding
.3and.6in scattered conditions.GSAP src/gsap-core.js:555,574–578 - Clamp before mapping opacity. GSAP's
mapRangeextrapolates beyond the given input range.GSAP src/gsap-core.js:574–578 - Turn clamping off only when the interaction needs extrapolation, and handle the off-track result at render time.
In our cases
64 cases use clamping or range mapping, the most common value function in this group. picasso-ecommerce clamps its wheel-driven target progress to 0…1 so the scene stays at its scroll bounds.
Used in 64 cases
01Momentum Slider02Drag Gallery03Formation04Cardwall05Riffle07Rotunda09Lens Bloom10Frieze11Aperture12Folio13Cinema Reel14Stream Showcase15Hardback16Picasso Ecommerce17Assembly18Fathom19Emulsion20Portfolio Photographer
+46 more
21Reverie22Boutique23Nova24Alive25Shape Trail26Membrane27Liquid Type28Filament29Pixels30Cipher32Cutout33Crema34Aster35Spring37Amour38Fluid Gallery39Marathon40Atelier41Desk 9542Isle44Atlas45Aurora46Rooster Rush47Overworld48Moments49Burst50Dimension51Morph52Meow53Relay54Lumen55Serene56Fleur57Atrium58Skyward59Helix60Crate61Prism62Flashlight63Viewfinder64Sand65Arrange66Tunnel67Reel68Type69Loupe
Reference implementation · basics.js
export const clamp = (x, lo = 0, hi = 1) => Math.min(hi, Math.max(lo, x));
export const lerp = (a, b, t) => a + (b - a) * t;
/** Where x sits between a and b, as 0..1 (unclamped). */
export const normalize = (x, a, b) => (a === b ? 0 : (x - a) / (b - a));
/** Map x from [a, b] to [c, d]. Clamped by default, because overshooting inputs are the usual bug. */
export const mapRange = (x, a, b, c, d, clamped = true) => {
const t = normalize(x, a, b);
return lerp(c, d, clamped ? clamp(t) : t);
};