From e09b3e1d73d4eab52981b7764c62cbe1167f1313 Mon Sep 17 00:00:00 2001
From: Thibaud <thibaud.gasser@gmx.com>
Date: Thu, 26 Sep 2024 23:36:06 +0200
Subject: [PATCH] add bezier #3 demo

---
 bezier-2.js   | 18 +--------------
 bezier-3.html | 12 ++++++++++
 bezier-3.js   | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++
 common.js     | 27 +++++++++++++++++-----
 index.html    | 11 ++++++++-
 5 files changed, 108 insertions(+), 24 deletions(-)
 create mode 100644 bezier-3.html
 create mode 100644 bezier-3.js

diff --git a/bezier-2.js b/bezier-2.js
index e5d211a..794e6c3 100644
--- a/bezier-2.js
+++ b/bezier-2.js
@@ -1,23 +1,7 @@
-import { lerp, drawCircle, drawLine, drawDashedLine, resizeCanvas } from "./common.js"
+import { lerp, drawCircle, drawLine, drawDashedLine, resizeCanvas, cubicBezier } from "./common.js"
 
 const points = [];
 
-function cubicBezier(a, b, c, d, res=0.05) {
-    const eps = 0.001; // to prevent issues with float comparaison (p <= 1)
-    const curve = [];
-    for (let p = 0; p - 1 < eps; p += res) {
-        const ab = lerp(a, b, p); 
-        const bc = lerp(b, c, p); 
-        const cd = lerp(c, d, p); 
-        const abc = lerp(ab, bc, p);
-        const bcd = lerp(bc, cd, p);
-        const abcd = lerp(abc, bcd, p);
-        curve.push(abcd);
-        console.log(p);
-    }
-    return curve;
-}
-
 function init() {
     const canvas = document.getElementById("canvas");
     if (canvas.getContext) {
diff --git a/bezier-3.html b/bezier-3.html
new file mode 100644
index 0000000..2187aa3
--- /dev/null
+++ b/bezier-3.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Document</title>
+</head>
+<body style="margin: 0; padding 0; overflow: hidden; background-color: #000000">
+    <canvas id="canvas" width="800" height="600"></canvas>
+</body>
+<script type="module" src="bezier-3.js"></script>
+</html>
diff --git a/bezier-3.js b/bezier-3.js
new file mode 100644
index 0000000..6ad5ae1
--- /dev/null
+++ b/bezier-3.js
@@ -0,0 +1,64 @@
+import { resizeCanvas, drawCircle, drawLine, cubicBezier } from "./common.js";
+
+function drawPoints(ctx, points) {
+    const [a, b, c, d] = points;
+    drawLine(ctx, a, b, 0xFF00FF);
+    drawLine(ctx, c, d, 0xFF00FF);
+    for (const p of points) {
+        drawCircle(ctx, p, 2, 0xFF00FF);
+    }
+}
+
+function drawCurve(ctx, curve) {
+    for (let i=0; i < curve.length - 1; ++i) {
+        drawLine(ctx, curve[i], curve[i+1], 0xFFFFFF);
+    }
+}
+
+
+function init() {
+    const canvas = document.getElementById("canvas");
+    let selection = undefined;
+    let points = [
+        { x: 300, y: 100 },
+        { x: 400, y: 100 },
+        { x: 100, y: 300 },
+        { x: 300, y: 300 },
+    ];
+
+    if (canvas.getContext) {
+        const ctx = canvas.getContext("2d");
+        resizeCanvas(ctx); // Init canvas
+        drawPoints(ctx, points);
+        const bezier = cubicBezier(...points);
+        drawCurve(ctx, bezier);
+
+        canvas.onmousedown = (evt) => {
+            const { clientX, clientY } = evt;
+            for (const p of points) {
+                if (Math.abs(p.x - clientX) < 10 && Math.abs(p.y - clientY) < 10) {
+                    selection = points.indexOf(p);
+                }
+            }
+        };
+
+        canvas.onmousemove = (evt) => {
+            if (selection !== undefined) {
+                points[selection].x = evt.clientX;
+                points[selection].y = evt.clientY;
+                // redraw
+                ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+                const bezier = cubicBezier(...points);
+                drawCurve(ctx, bezier);
+                drawPoints(ctx, points);
+            }
+        };
+
+        canvas.onmouseup = () => {
+            selection = undefined;
+        };
+    }
+}
+
+init();
+
diff --git a/common.js b/common.js
index 153f57d..13cfd37 100644
--- a/common.js
+++ b/common.js
@@ -1,9 +1,3 @@
-export function resizeCanvas(ctx) {
-    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
-    ctx.canvas.width  = window.innerWidth;
-    ctx.canvas.height = window.innerHeight;
-}
-
 export function lerp(a, b, p) {
     return { 
         x: a.x + (b.x - a.x) * p,
@@ -11,6 +5,27 @@ export function lerp(a, b, p) {
     };
 }
 
+export function cubicBezier(a, b, c, d, res=0.05) {
+    const eps = 0.001; // to prevent issues with float comparaison (p <= 1)
+    const curve = [];
+    for (let p = 0; p - 1 < eps; p += res) {
+        const ab = lerp(a, b, p); 
+        const bc = lerp(b, c, p); 
+        const cd = lerp(c, d, p); 
+        const abc = lerp(ab, bc, p);
+        const bcd = lerp(bc, cd, p);
+        const abcd = lerp(abc, bcd, p);
+        curve.push(abcd);
+    }
+    return curve;
+}
+
+export function resizeCanvas(ctx) {
+    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+    ctx.canvas.width  = window.innerWidth;
+    ctx.canvas.height = window.innerHeight;
+}
+
 export function drawCircle(ctx, {x, y}, radius, color) {
     ctx.save();
     ctx.beginPath();
diff --git a/index.html b/index.html
index 26322bb..f4b5106 100644
--- a/index.html
+++ b/index.html
@@ -4,12 +4,21 @@
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Document</title>
+    <style>
+        body {
+            background-color: black;
+        }
+        li > a {
+            color: white;
+        }
+    </style>
 </head>
-<body style="margin: 0; padding 0; overflow: hidden; background-color: #000000">
+<body> 
     <ul>
         <li><a href="/grid.html">Grid</a></li>
         <li><a href="/bezier-1.html">Bezier demo #1</a></li>
         <li><a href="/bezier-2.html">Bezier demo #2</a></li>
+        <li><a href="/bezier-3.html">Bezier demo #3</a></li>
     </ul>
 </body>
 </html>