Smooth animation system with interpolation support for view state transitions and layer property changes, enabling fluid user experiences and dynamic data visualization.
Abstract base class defining interface for view state interpolation during transitions.
/**
* Abstract base class for transition interpolators
* Defines interface for smooth transitions between view states
*/
abstract class TransitionInterpolator {
/** Compare transition properties for equality */
arePropsEqual(props1: any, props2: any): boolean;
/** Initialize transition properties */
initializeProps(startProps: any, endProps: any): {start: any; end: any};
/** Interpolate properties at given time t [0-1] */
interpolateProps(startProps: any, endProps: any, t: number): any;
/** Get transition duration in milliseconds */
getDuration?(startProps: any, endProps: any): number;
}Linear interpolation between view states for simple transitions.
/**
* Linear interpolation between view states
* Provides smooth linear transitions for specified properties
*/
class LinearInterpolator extends TransitionInterpolator {
/** Initialize linear interpolator */
constructor(transitionProps?: string[]);
/** Properties to interpolate */
readonly transitionProps: string[];
/** Compare properties for changes */
arePropsEqual(props1: any, props2: any): boolean;
/** Initialize interpolation */
initializeProps(startProps: any, endProps: any): {start: any; end: any};
/** Linear interpolation at time t */
interpolateProps(startProps: any, endProps: any, t: number): any;
}Usage Examples:
import { LinearInterpolator } from "@deck.gl/core";
// Simple zoom transition
const zoomInterpolator = new LinearInterpolator(['zoom']);
// Smooth transition to new zoom level
deck.setProps({
viewState: {
...currentViewState,
zoom: 15,
transitionDuration: 1000,
transitionInterpolator: zoomInterpolator
}
});
// Multi-property transition
const positionInterpolator = new LinearInterpolator([
'longitude',
'latitude',
'zoom',
'pitch',
'bearing'
]);
deck.setProps({
viewState: {
longitude: -74.006,
latitude: 40.7128,
zoom: 14,
pitch: 45,
bearing: 30,
transitionDuration: 2000,
transitionInterpolator: positionInterpolator,
transitionEasing: t => t * t // Quadratic easing
}
});Smooth camera flight transitions with easing for natural map navigation.
/**
* Smooth camera flight interpolator
* Provides natural arc-based transitions between geographic locations
*/
class FlyToInterpolator extends TransitionInterpolator {
/** Initialize fly-to interpolator */
constructor(opts?: FlyToInterpolatorOptions);
/** Compare properties for fly-to transition */
arePropsEqual(props1: any, props2: any): boolean;
/** Initialize fly-to transition */
initializeProps(startProps: any, endProps: any): {start: any; end: any};
/** Fly-to interpolation with arc movement */
interpolateProps(startProps: any, endProps: any, t: number): any;
/** Calculate optimal duration based on distance */
getDuration(startProps: any, endProps: any): number;
/** Flight speed constant */
readonly speed: number;
/** Flight curve parameter */
readonly curve: number;
/** Screen space speed factor */
readonly screenSpeedFactor: number;
/** Maximum duration limit */
readonly maxDuration: number;
}
interface FlyToInterpolatorOptions {
/** Flight speed (higher = faster) */
speed?: number;
/** Flight curve (1 = linear, >1 = curved) */
curve?: number;
/** Screen space speed adjustment */
screenSpeedFactor?: number;
/** Maximum transition duration */
maxDuration?: number;
}Usage Examples:
import { FlyToInterpolator } from "@deck.gl/core";
// Natural flight between cities
const flyToNewYork = () => {
deck.setProps({
viewState: {
longitude: -74.006,
latitude: 40.7128,
zoom: 14,
pitch: 45,
bearing: 0,
transitionInterpolator: new FlyToInterpolator({
speed: 1.5,
curve: 1.414
}),
onTransitionStart: () => {
console.log('Flying to New York...');
},
onTransitionEnd: () => {
console.log('Arrived in New York!');
}
}
});
};
// Long-distance flight with custom settings
const flyToTokyo = () => {
deck.setProps({
viewState: {
longitude: 139.6917,
latitude: 35.6895,
zoom: 12,
pitch: 30,
bearing: 90,
transitionInterpolator: new FlyToInterpolator({
speed: 2.0, // Faster flight
curve: 2.0, // More curved path
maxDuration: 8000 // Max 8 seconds
})
}
});
};
// Fly to bounds
const flyToBounds = (bounds) => {
const viewport = new WebMercatorViewport({
width: deck.width,
height: deck.height,
...deck.viewState
});
const fittedViewState = viewport.fitBounds(bounds, {
padding: 50
});
deck.setProps({
viewState: {
...fittedViewState,
transitionInterpolator: new FlyToInterpolator(),
transitionDuration: 3000
}
});
};Comprehensive transition configuration options for view states.
interface ViewStateTransition {
/** Target view state */
viewState: any;
/** Transition duration in milliseconds */
transitionDuration?: number;
/** Transition interpolator */
transitionInterpolator?: TransitionInterpolator;
/** Easing function [0-1] -> [0-1] */
transitionEasing?: (t: number) => number;
/** Interruption behavior */
transitionInterruption?: 'break' | 'snap-to-end' | 'ignore';
/** Called when transition starts */
onTransitionStart?: () => void;
/** Called during transition with current state */
onTransitionUpdate?: (viewState: any) => void;
/** Called when transition completes */
onTransitionEnd?: () => void;
/** Called when transition is interrupted */
onTransitionInterrupt?: () => void;
}
// Transition event constants
const TRANSITION_EVENTS: {
readonly BREAK: "transitionBreak";
readonly SNAP_TO_END: "transitionSnapToEnd";
readonly UPDATE: "transitionUpdate";
readonly END: "transitionEnd";
};Usage Examples:
// Advanced transition with callbacks
const smoothTransition = {
longitude: -122.4,
latitude: 37.8,
zoom: 16,
pitch: 60,
bearing: 45,
transitionDuration: 3000,
transitionInterpolator: new FlyToInterpolator({
speed: 1.2,
curve: 1.6
}),
// Custom easing function
transitionEasing: t => {
// Ease-in-out cubic
return t < 0.5
? 4 * t * t * t
: 1 - Math.pow(-2 * t + 2, 3) / 2;
},
transitionInterruption: 'break',
onTransitionStart: () => {
console.log('Transition started');
showLoadingIndicator();
},
onTransitionUpdate: (viewState) => {
updateProgressBar(viewState.transitionProgress);
},
onTransitionEnd: () => {
console.log('Transition completed');
hideLoadingIndicator();
},
onTransitionInterrupt: () => {
console.log('Transition interrupted');
hideLoadingIndicator();
}
};
deck.setProps({ viewState: smoothTransition });Built-in animation system for layer properties.
interface LayerTransitionSettings {
/** Animation type */
type?: 'interpolation' | 'spring' | 'gpu';
/** Duration in milliseconds */
duration?: number;
/** Easing function */
easing?: (t: number) => number;
/** Called when animation starts */
onStart?: () => void;
/** Called during animation */
onUpdate?: (t: number) => void;
/** Called when animation ends */
onEnd?: () => void;
/** Enable GPU-based transitions */
useGPU?: boolean;
/** Spring animation settings */
stiffness?: number;
damping?: number;
mass?: number;
}
interface LayerTransitions {
/** Transitions for each accessor property */
[accessorName: string]: LayerTransitionSettings | number;
}Usage Examples:
import { ScatterplotLayer } from "@deck.gl/layers";
// Layer with animated properties
const animatedLayer = new ScatterplotLayer({
id: 'animated-points',
data: data,
getPosition: d => d.coordinates,
getRadius: d => d.radius,
getColor: d => d.color,
// Configure transitions
transitions: {
// Smooth radius changes
getRadius: {
type: 'interpolation',
duration: 1000,
easing: t => 1 - Math.pow(1 - t, 3), // Ease-out cubic
onStart: () => console.log('Radius animation started'),
onEnd: () => console.log('Radius animation ended')
},
// Spring animation for colors
getColor: {
type: 'spring',
stiffness: 0.1,
damping: 0.8,
mass: 1
},
// Quick position updates
getPosition: 500 // Shorthand for 500ms linear interpolation
}
});
// Update data with transitions
const updateWithAnimation = (newData) => {
animatedLayer.setProps({
data: newData,
updateTriggers: {
getRadius: Math.random(),
getColor: Math.random(),
getPosition: Math.random()
}
});
};
// Animate data changes over time
const animateData = () => {
const animatedData = data.map(d => ({
...d,
radius: d.radius * (0.5 + Math.random()),
color: [
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255),
255
]
}));
updateWithAnimation(animatedData);
};
setInterval(animateData, 2000);High-performance GPU-based transitions for large datasets.
interface GPUTransitionSettings extends LayerTransitionSettings {
/** Force GPU implementation */
useGPU: true;
/** Buffer size for GPU computation */
bufferSize?: number;
/** Shader-based interpolation function */
interpolationShader?: string;
/** GPU memory optimization */
memoryOptimized?: boolean;
}Usage Examples:
// Large dataset with GPU transitions
const largeDataLayer = new ScatterplotLayer({
id: 'million-points',
data: millionPointsData,
getPosition: d => d.coordinates,
getRadius: d => d.radius,
getColor: d => d.color,
transitions: {
getRadius: {
type: 'gpu',
useGPU: true,
duration: 2000,
memoryOptimized: true,
bufferSize: 1024 * 1024 // 1MB buffer
},
getColor: {
type: 'gpu',
useGPU: true,
duration: 1500,
interpolationShader: `
vec4 interpolateColor(vec4 from, vec4 to, float t) {
// Custom GPU interpolation
return mix(from, to, smoothstep(0.0, 1.0, t));
}
`
}
}
});Built-in easing functions for smooth animations.
// Common easing functions
const EASING_FUNCTIONS = {
linear: (t: number) => t,
// Ease-in functions
easeInQuad: (t: number) => t * t,
easeInCubic: (t: number) => t * t * t,
easeInQuart: (t: number) => t * t * t * t,
easeInQuint: (t: number) => t * t * t * t * t,
easeInSine: (t: number) => 1 - Math.cos(t * Math.PI / 2),
easeInExpo: (t: number) => t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
easeInCirc: (t: number) => 1 - Math.sqrt(1 - t * t),
// Ease-out functions
easeOutQuad: (t: number) => t * (2 - t),
easeOutCubic: (t: number) => 1 - Math.pow(1 - t, 3),
easeOutQuart: (t: number) => 1 - Math.pow(1 - t, 4),
easeOutQuint: (t: number) => 1 - Math.pow(1 - t, 5),
easeOutSine: (t: number) => Math.sin(t * Math.PI / 2),
easeOutExpo: (t: number) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
easeOutCirc: (t: number) => Math.sqrt(1 - Math.pow(t - 1, 2)),
// Ease-in-out functions
easeInOutQuad: (t: number) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
easeInOutCubic: (t: number) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
easeInOutQuart: (t: number) => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * Math.pow(t - 1, 4),
easeInOutQuint: (t: number) => t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * Math.pow(t - 1, 5),
easeInOutSine: (t: number) => -(Math.cos(Math.PI * t) - 1) / 2,
easeInOutExpo: (t: number) => t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2,
easeInOutCirc: (t: number) => t < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2,
// Bounce and elastic
easeOutBounce: (t: number) => {
if (t < 1 / 2.75) return 7.5625 * t * t;
if (t < 2 / 2.75) return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
if (t < 2.5 / 2.75) return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
},
easeOutElastic: (t: number) => {
const c4 = (2 * Math.PI) / 3;
return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
}
};Advanced timeline-based animation system.
interface AnimationTimeline {
/** Add animation to timeline */
add(opts: {
target: any;
property: string;
from: any;
to: any;
duration: number;
delay?: number;
easing?: (t: number) => number;
}): void;
/** Play timeline */
play(): void;
/** Pause timeline */
pause(): void;
/** Stop and reset timeline */
stop(): void;
/** Seek to specific time */
seek(time: number): void;
/** Timeline duration */
readonly duration: number;
/** Current playback time */
readonly currentTime: number;
/** Whether timeline is playing */
readonly isPlaying: boolean;
}Usage Examples:
// Complex animation sequence
const createAnimationSequence = () => {
const timeline = new AnimationTimeline();
// Animate camera to overview position
timeline.add({
target: deck,
property: 'viewState',
from: currentViewState,
to: {
longitude: -100,
latitude: 40,
zoom: 4,
pitch: 45,
bearing: 0
},
duration: 2000,
easing: EASING_FUNCTIONS.easeInOutCubic
});
// Animate layer opacity
timeline.add({
target: layer,
property: 'opacity',
from: 0,
to: 1,
duration: 1000,
delay: 1000,
easing: EASING_FUNCTIONS.easeOutQuad
});
// Animate data reveal
timeline.add({
target: layer,
property: 'radiusScale',
from: 0,
to: 1,
duration: 1500,
delay: 2000,
easing: EASING_FUNCTIONS.easeOutElastic
});
return timeline;
};
// Orchestrate complex visualization intro
const introSequence = createAnimationSequence();
introSequence.play();
// Custom transition with progress tracking
const customTransition = (fromState, toState, onProgress) => {
const interpolator = new FlyToInterpolator({
speed: 1.5,
curve: 1.414
});
deck.setProps({
viewState: {
...toState,
transitionInterpolator: interpolator,
transitionDuration: 3000,
transitionEasing: EASING_FUNCTIONS.easeInOutCubic,
onTransitionUpdate: (viewState) => {
const progress = viewState.transitionProgress || 0;
onProgress(progress);
}
}
});
};