Back to Dictionary
Data & Content Visualization
●●○Customize
Context dependent

Data Tweening

When filtering or changing datasets, SVG lines or pie slices seamlessly morph from one shape to the next instead of snapping instantly.

Use

Switching between time ranges (1W to 1M) on line charts

Avoid

When the two datasets share no common axes or context

Safer Alternative

No safer default listed.

Risk Level

Low risk

Live Demo

Active UsersLive Interpolation

What It Is

When filtering or changing datasets, SVG lines or pie slices seamlessly morph from one shape to the next instead of snapping instantly.

When to Use

  • Switching between time ranges (1W to 1M) on line charts
  • Filtering data in pie/donut charts

When NOT to Use

  • When the two datasets share no common axes or context

Configuration Tips

  • 01Use d3.js or framer-motion path interpolation to animate the 'd' attribute of SVG paths

You've Seen It In

RobinhoodCoinbaseFigma Analytics

AI Implementation Prompts

Move from a fast scaffold to production details, then tune timing and edge states.

Animate an SVG line chart transitioning smoothly between two different data arrays.

Reference Implementation

The same implementation approach used by the live preview, kept compact enough to inspect and adapt.

"use client";
import { useState, useEffect } from 'react';
import { motion } from 'framer-motion';

const paths = [
    "M 0 100 Q 50 20 100 80 T 200 60 T 300 110 T 400 40",
    "M 0 60 Q 50 120 100 40 T 200 90 T 300 20 T 400 100",
    "M 0 120 Q 50 10 100 100 T 200 30 T 300 120 T 400 60"
];

export function DataTweeningDemo({ isPlaying = false }: { isPlaying?: boolean }) {
    const [pathIndex, setPathIndex] = useState(0);

    useEffect(() => {
        if (!isPlaying) {
            setPathIndex(0);
            return;
        }

        const interval = setInterval(() => {
            setPathIndex((prev) => (prev + 1) % paths.length);
        }, 1500);

        return () => clearInterval(interval);
    }, [isPlaying]);

    return (
        <div className="flex h-64 w-full items-center justify-center overflow-hidden rounded-2xl bg-white p-4 shadow-sm ring-1 ring-stone-200">
            <div className="w-full max-w-sm h-40 bg-stone-50 rounded-xl relative overflow-hidden border border-stone-100 flex flex-col">
                <div className="p-4 flex justify-between items-center border-b border-stone-100 bg-white">
                    <span className="text-xs font-semibold text-stone-600 uppercase tracking-widest">Active Users</span>
                    <span className="text-[10px] bg-indigo-50 text-indigo-600 px-2 py-0.5 rounded font-bold uppercase tracking-wider">Live Interpolation</span>
                </div>
                <div className="flex-1 relative w-full flex items-center justify-center pt-4">
                    <svg viewBox="0 0 400 150" className="w-[120%] h-full stroke-indigo-500 overflow-visible" fill="none">
                        <motion.path
                            d={paths[pathIndex]}
                            strokeWidth="4"
                            strokeLinecap="round"
                            strokeLinejoin="round"
                            initial={false}
                            animate={{ d: paths[pathIndex] }}
                            transition={{ duration: 0.8, ease: "easeInOut" }}
                        />
                        {"text-stone-400 italic">/* Data point glowing dots */}
                        <motion.circle
                            r="6"
                            fill="white"
                            strokeWidth="3"
                            className="stroke-indigo-500 drop-shadow-md"
                            cx="200"
                            animate={{
                                "text-stone-400 italic">// Rough approximate middle points for visualization
                                cy: pathIndex === 0 ? 60 : pathIndex === 1 ? 90 : 30
                            }}
                            transition={{ duration: 0.8, ease: "easeInOut" }}
                        />
                    </svg>

                    {"text-stone-400 italic">/* Fake grid lines */}
                    <div className="absolute inset-0 pointer-events-none flex flex-col justify-between py-6 px-4">
                        <div className="w-full border-t border-stone-200 border-dashed" />
                        <div className="w-full border-t border-stone-200 border-dashed" />
                        <div className="w-full border-t border-stone-200 border-dashed" />
                    </div>
                </div>
            </div>
        </div>
    );
}