How to Draw Smooth Curve Through Multiple Points using JavaScript?

Drawing smooth curves through multiple points is essential for creating visually appealing data visualizations and interactive graphics. JavaScript's Canvas API provides powerful methods to achieve this using mathematical curve algorithms.

When connecting multiple points with straight lines, the result appears jagged and unnatural. Smooth curves create more elegant visualizations by using mathematical interpolation between points.

Method 1: Using Quadratic Bézier Curves

This approach uses quadraticCurveTo() to create smooth curves by calculating midpoints between consecutive points as curve endpoints.

<!DOCTYPE html>
<html lang="en">
<head>
   <title>Smooth Curve with Quadratic Bézier</title>
   <style>
      canvas {
         border: 2px solid #333;
         display: block;
         margin: 20px auto;
      }
   </style>
</head>
<body>
   <canvas id="canvas1" width="600" height="300"></canvas>

   <script>
      const canvas = document.getElementById("canvas1");
      const ctx = canvas.getContext("2d");

      // Define points to connect
      const points = [
         { x: 50, y: 150 },
         { x: 150, y: 80 },
         { x: 250, y: 200 },
         { x: 350, y: 100 },
         { x: 450, y: 180 },
         { x: 550, y: 120 }
      ];

      function drawQuadraticCurve(points) {
         ctx.beginPath();
         ctx.moveTo(points[0].x, points[0].y);

         // Draw quadratic curves between points
         for (let i = 1; i < points.length - 1; i++) {
            const xMid = (points[i].x + points[i + 1].x) / 2;
            const yMid = (points[i].y + points[i + 1].y) / 2;
            ctx.quadraticCurveTo(points[i].x, points[i].y, xMid, yMid);
         }

         // Connect to the last point
         ctx.lineTo(points[points.length - 1].x, points[points.length - 1].y);
         
         ctx.strokeStyle = "#2196F3";
         ctx.lineWidth = 3;
         ctx.stroke();
      }

      // Draw control points for visualization
      function drawPoints(points) {
         points.forEach((point, index) => {
            ctx.beginPath();
            ctx.arc(point.x, point.y, 4, 0, 2 * Math.PI);
            ctx.fillStyle = "#f44336";
            ctx.fill();
            
            // Add point labels
            ctx.fillStyle = "#000";
            ctx.font = "12px Arial";
            ctx.fillText(`P${index}`, point.x + 8, point.y - 8);
         });
      }

      drawQuadraticCurve(points);
      drawPoints(points);
   </script>
</body>
</html>

Method 2: Using Catmull-Rom Spline

Catmull-Rom splines create smoother curves that pass through all control points, providing more natural-looking results for data visualization.

<!DOCTYPE html>
<html lang="en">
<head>
   <title>Smooth Curve with Catmull-Rom Spline</title>
   <style>
      canvas {
         border: 2px solid #333;
         display: block;
         margin: 20px auto;
      }
   </style>
</head>
<body>
   <canvas id="canvas2" width="600" height="300"></canvas>

   <script>
      const canvas2 = document.getElementById("canvas2");
      const ctx2 = canvas2.getContext("2d");

      const points2 = [
         { x: 50, y: 150 },
         { x: 150, y: 80 },
         { x: 250, y: 200 },
         { x: 350, y: 100 },
         { x: 450, y: 180 },
         { x: 550, y: 120 }
      ];

      function drawCatmullRomSpline(points) {
         if (points.length < 3) return;
         
         ctx2.beginPath();
         ctx2.moveTo(points[0].x, points[0].y);

         // Draw spline segments
         for (let i = 0; i < points.length - 1; i++) {
            const p0 = points[Math.max(i - 1, 0)];
            const p1 = points[i];
            const p2 = points[i + 1];
            const p3 = points[Math.min(i + 2, points.length - 1)];

            // Calculate control points for cubic Bézier curve
            const cp1x = p1.x + (p2.x - p0.x) / 6;
            const cp1y = p1.y + (p2.y - p0.y) / 6;
            const cp2x = p2.x - (p3.x - p1.x) / 6;
            const cp2y = p2.y - (p3.y - p1.y) / 6;

            ctx2.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2.x, p2.y);
         }

         ctx2.strokeStyle = "#4CAF50";
         ctx2.lineWidth = 3;
         ctx2.stroke();
      }

      function drawPoints2(points) {
         points.forEach((point, index) => {
            ctx2.beginPath();
            ctx2.arc(point.x, point.y, 4, 0, 2 * Math.PI);
            ctx2.fillStyle = "#FF9800";
            ctx2.fill();
            
            ctx2.fillStyle = "#000";
            ctx2.font = "12px Arial";
            ctx2.fillText(`P${index}`, point.x + 8, point.y - 8);
         });
      }

      drawCatmullRomSpline(points2);
      drawPoints2(points2);
   </script>
</body>
</html>

Comparison of Methods

Method Smoothness Passes Through Points Performance Best For
Quadratic Bézier Good No Fast Simple curves, icons
Catmull-Rom Spline Excellent Yes Moderate Data visualization, charts

Key Implementation Points

  • Control Points: Quadratic curves use midpoints as control points for smoother transitions
  • Spline Interpolation: Catmull-Rom ensures curves pass through all specified points
  • Edge Cases: Handle first and last points differently as they lack neighbors
  • Performance: For animations, consider caching calculated control points

Common Use Cases

Smooth curves are essential for:

  • Line charts and data visualization
  • Drawing applications and signature capture
  • Animation paths and motion graphics
  • Geographic path rendering on maps

Conclusion

JavaScript's Canvas API provides flexible methods for drawing smooth curves through multiple points. Use quadratic Bézier curves for simple applications and Catmull-Rom splines when curves must pass through all data points precisely.

Updated on: 2026-03-15T23:19:01+05:30

1K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements