// It seems that classes have to go up here in Drupal Javascript. // Might be related to jQuery and loading order. // Class Point function Point(px, py) { this.px = px; this.py = py; } // class Circle function Circle(p, radius) { this.p = p; this.radius = radius; } Circle.prototype.show = function() { console.log(this.p.px + " - " + this.p.py + " - " + this.radius); } Circle.prototype.draw = function(ctx, color) { ctx.beginPath(); ctx.arc(this.p.px, this.p.py, this.radius, 0, 2 * Math.PI, false); ctx.fillStyle = color; ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = "black"; ctx.stroke(); } // Use the bbox. Circle.prototype.contains = function(t) { var left = this.p.px - this.radius; var right = this.p.px + this.radius; var top = this.p.py - this.radius; var bottom = this.p.py + this.radius; var bInside = (t.px > left) && (t.px < right) && (t.py > top) && (t.py < bottom); return bInside; } //------------------------ // End of classes. //------------------------ var canvas; var ctx; var WAITING = 0; var DRAGGING = 1; var state = WAITING; var activePoint = -1; var points = new Array(new Point(20, 215), new Point(90, 35), new Point(210, 65), new Point(225, 215)); var circles = new Array(); jQuery(document).ready(function() { canvas = document.getElementById("bezier-handles"); if (canvas.getContext) { ctx = canvas.getContext("2d"); // Create circles from points. for (var k = 0; k < points.length; k++) circles.push(new Circle(points[k], 3)); invalidate(); canvas.addEventListener("mousedown", mouseDown, false); canvas.addEventListener("mousemove", mouseMove, false); canvas.addEventListener("mouseup", mouseUp, false); } // if (canvas.getContext) }); // ready() function mouseDown(event) { var userPt = getMousePos(canvas, event); for (var k = 0; k < points.length; k++) if ((state == WAITING) && circles[k].contains(userPt)) { state = DRAGGING; activePoint = k; } } function mouseMove(event) { if (state == DRAGGING) { circles[activePoint].p = getMousePos(canvas, event); invalidate(); } } function mouseUp(event) { if (state == DRAGGING) state = WAITING; } function getMousePos(canvas, event) { // Ints not always returned! var rect = canvas.getBoundingClientRect(); return { px: event.clientX - Math.round(rect.left), py: event.clientY - Math.round(rect.top) }; } function drawLineWithPoints(ctx, p, q) { // Draw line with points at ends and in middle. ctx.save(); ctx.strokeStyle = "gray"; ctx.moveTo(p.px, p.py); ctx.lineTo(q.px, q.py); ctx.stroke(); (new Circle(p, 2)).draw(ctx, "black"); (new Circle(q, 2)).draw(ctx, "black"); (new Circle(getMidPoint(p, q), 2)).draw(ctx, "black"); ctx.restore(); } function getMidPoint(p, q) { return (new Point((p.px + q.px)/2, (p.py + q.py)/2)); } function invalidate() { //Here is where everything is redrawn when dragging. ctx.clearRect(0, 0, canvas.width, canvas.height); // Fill background white and draw frame. ctx.fillStyle = "white"; ctx.strokeStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeRect(0, 0, canvas.width, canvas.height); //-------------------------------------------------- // Draw the frame. //-------------------------------------------------- drawLineWithPoints(ctx, circles[0].p, circles[1].p); drawLineWithPoints(ctx, circles[1].p, circles[2].p); drawLineWithPoints(ctx, circles[2].p, circles[3].p); var q0 = getMidPoint(circles[0].p, circles[1].p); var q1 = getMidPoint(circles[1].p, circles[2].p); var q2 = getMidPoint(circles[2].p, circles[3].p); drawLineWithPoints(ctx, q0, q1); drawLineWithPoints(ctx, q1, q2); var r0 = getMidPoint(q0, q1); var r1 = getMidPoint(q1, q2); drawLineWithPoints(ctx, r0, r1); //-------------------------------------------------- // Draw the Bezier curve. ctx.beginPath(); ctx.strokeStyle = "blue"; ctx.moveTo(circles[0].p.px, circles[0].p.py); ctx.bezierCurveTo(circles[1].p.px, circles[1].p.py, // first control circles[2].p.px, circles[2].p.py, // second control circles[3].p.px, circles[3].p.py); // end point ctx.stroke(); // Draw the red circles. for (var k = 0; k < points.length; k++) circles[k].draw(ctx, "red"); }