Created
November 19, 2016 21:04
-
-
Save dested/83adfc1afc684a7ed65b86ea01259661 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>Bezier</title> | |
</head> | |
<body> | |
<canvas id="canvas" width="1500" height="1200"></canvas> | |
<input type="range" value="0.5" oninput="updateBezier(this.value)" min="0" max="1" step="0.005" style="position:absolute; width:98%; left:0; top:0;" /> | |
<script type="text/javascript"> | |
function Point(x, y) { | |
this.x = x; | |
this.y = y; | |
} | |
function Line(p1, p2) { | |
this.Point1 = p1; | |
this.Point2 = p2; | |
} | |
Line.prototype.lerp = function(f) { | |
return new Point(lerp(this.Point1.x, this.Point2.x, f), lerp(this.Point1.y, this.Point2.y, f)); | |
} | |
var canvas = document.getElementById('canvas'); | |
var context = canvas.getContext('2d'); | |
var circleRadius = 10; | |
var rangeStep = 0.005; | |
var scale = 2; | |
var currentAnimateOffset = 0.5; | |
var p1 = new Point(250, 300); | |
var p2 = new Point(350, 300); | |
var p1Handle = new Point(100, 50); | |
var p2Handle = new Point(500, 50); | |
var bezierPoints = []; | |
var l1, l2, l3; | |
function calculateBezier() { | |
l1 = new Line(p1, p1Handle); | |
l2 = new Line(p1Handle, p2Handle); | |
l3 = new Line(p2Handle, p2); | |
bezierPoints = []; | |
for (var f = 0; f <= 1; f += rangeStep) { | |
bezierPoints.push(calcBezierLerp(f)); | |
}; | |
} | |
function calcBezierLerp(f) { | |
var pl1 = l1.lerp(f); | |
var pl2 = l2.lerp(f); | |
var pl3 = l3.lerp(f); | |
var bpl1 = new Line(pl1, pl2); | |
var bpl2 = new Line(pl2, pl3); | |
var cpl1 = bpl1.lerp(f); | |
var cpl2 = bpl2.lerp(f); | |
var dpl = new Line(cpl1, cpl2); | |
var p = dpl.lerp(f); | |
return { | |
pl1: pl1, | |
pl2: pl2, | |
pl3: pl3, | |
bpl1: bpl1, | |
bpl2: bpl2, | |
cpl1: cpl1, | |
cpl2: cpl2, | |
dpl: dpl, | |
p: p | |
}; | |
} | |
function draw() { | |
canvas.width = canvas.width; | |
context.save(); | |
context.scale(scale, scale) | |
context.save(); | |
context.lineWidth = 5; | |
context.beginPath(); | |
context.moveTo(bezierPoints[0].p.x, bezierPoints[0].p.y); | |
for (var i = 1; i < bezierPoints.length; i++) { | |
context.lineTo(bezierPoints[i].p.x, bezierPoints[i].p.y); | |
}; | |
context.stroke(); | |
context.restore(); | |
context.save(); | |
context.beginPath(); | |
context.moveTo(l1.Point1.x, l1.Point1.y); | |
context.lineTo(l1.Point2.x, l1.Point2.y); | |
context.stroke(); | |
context.restore(); | |
context.save(); | |
context.setLineDash([4, 4]) | |
context.beginPath(); | |
context.moveTo(l2.Point1.x, l2.Point1.y); | |
context.lineTo(l2.Point2.x, l2.Point2.y); | |
context.stroke(); | |
context.restore(); | |
context.save(); | |
context.beginPath(); | |
context.moveTo(l3.Point1.x, l3.Point1.y); | |
context.lineTo(l3.Point2.x, l3.Point2.y); | |
context.stroke(); | |
context.restore(); | |
context.save(); | |
drawCircle(p1Handle, circleRadius, 5); | |
drawCircle(p2Handle, circleRadius, 5); | |
drawCircle(p1, circleRadius, 5); | |
drawCircle(p2, circleRadius, 5); | |
context.restore(); | |
context.restore(); | |
drawLerp(currentAnimateOffset); | |
} | |
function drawLine(point1, point2, width) { | |
context.save(); | |
context.lineWidth = width; | |
context.beginPath(); | |
context.moveTo(point1.x, point1.y); | |
context.lineTo(point2.x, point2.y); | |
context.stroke(); | |
context.restore(); | |
} | |
function drawLerp(f) { | |
context.save(); | |
context.scale(scale, scale); | |
var bp = bezierPoints[(1 / rangeStep * f) | 0]; | |
drawLine(bp.pl1, bp.pl2, 1); | |
drawLine(bp.pl2, bp.pl3, 1); | |
drawCircle(bp.pl1, 5, 3); | |
drawCircle(bp.pl2, 5, 3); | |
drawCircle(bp.pl3, 5, 3); | |
drawLine(bp.cpl1, bp.cpl2, 1); | |
drawCircle(bp.cpl1, 3, 2); | |
drawCircle(bp.cpl2, 3, 2); | |
drawCircle(bp.p, 6, 1, 'red'); | |
context.restore(); | |
} | |
function drawCircle(point, radius, lineWidth, color) { | |
var centerX = point.x; | |
var centerY = point.y; | |
color = color || 'green'; | |
context.save(); | |
context.beginPath(); | |
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false); | |
context.fillStyle = color; | |
context.fill(); | |
context.lineWidth = lineWidth; | |
context.strokeStyle = '#003300'; | |
context.stroke(); | |
context.restore(); | |
} | |
function lerp(a, b, f) { | |
return a + f * (b - a); | |
} | |
function pointInCircle(point, centerOfCircle, radius) { | |
var x = point.x; | |
var y = point.y; | |
var centerX = centerOfCircle.x; | |
var centerY = centerOfCircle.y; | |
return Math.pow((x - centerX), 2) + Math.pow((y - centerY), 2) <= Math.pow(radius, 2); | |
} | |
var selectPoint; | |
canvas.onmousedown = function(e) { | |
var ePoint = new Point(e.x / scale, e.y / scale); | |
if (pointInCircle(ePoint, p1, circleRadius)) { | |
selectPoint = p1; | |
} else if (pointInCircle(ePoint, p2, circleRadius)) { | |
selectPoint = p2; | |
} else if (pointInCircle(ePoint, p1Handle, circleRadius)) { | |
selectPoint = p1Handle; | |
} else if (pointInCircle(ePoint, p2Handle, circleRadius)) { | |
selectPoint = p2Handle; | |
} | |
} | |
canvas.onmouseup = function(e) { | |
selectPoint = undefined; | |
} | |
canvas.onmousemove = function(e) { | |
if (!selectPoint) return; | |
var ePoint = new Point(e.x / scale, e.y / scale); | |
selectPoint.x = ePoint.x; | |
selectPoint.y = ePoint.y; | |
calculateBezier(); | |
draw(); | |
return false; | |
} | |
function updateBezier(f) { | |
currentAnimateOffset = f; | |
draw(); | |
} | |
calculateBezier(); | |
draw(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment