I'm working on a little script that should (eventually) create an animated motion tween between two paths. It's still a ways off and I'm sure there are things that can be done better, but here's where I'm at and the problem I'm experiencing:
I want to project the vertices outward from the centre of the rectangle (shape one) onto the path of the blob (shape two). See image below.
My end goal is for this to be a universal script where you can plug in points from shape one and shape two and have them morph into each other. This is just for my own interest so I don't want to use a plugin where it's already done. Thanks!
HTML:
<canvas id="canvas" width="100%" height="100%">
Canvas is not supported.
</canvas>
JS:
$(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
baseX = 500,
baseY = 350;
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
var Shape = function(baseX, baseY, points) {
this.baseX = baseX;
this.baseY = baseY;
this.points = points;
this.drawPoints = function(stroke) {
var points = this.points;
var rad = 5;
for (i=0; i<points.length; i++) {
ctx.beginPath();
ctx.fillStyle = 'gray';
var splitPoints = points[i].split(',');
switch(splitPoints[0]) {
case 'm':
ctx.arc(splitPoints[1], splitPoints[2], rad, 2 * Math.PI, false);
if (stroke === true) {
ctx.fill();
}
break;
case 'l':
ctx.arc(splitPoints[1], splitPoints[2], rad, 2 * Math.PI, false);
if (stroke === true) {
ctx.fill();
}
break;
case 'b':
ctx.arc(splitPoints[5], splitPoints[6], rad, 2 * Math.PI, false);
if (stroke === true) {
ctx.fill();
}
break;
}
}
ctx.closePath();
}
this.drawPath = function(stroke) {
var points = this.points;
ctx.beginPath();
for (i=0; i<points.length; i++) {
var splitPoints = points[i].split(',');
switch(splitPoints[0]) {
case 'm':
ctx.moveTo(splitPoints[1], splitPoints[2]);
break;
case 'l':
ctx.lineTo(splitPoints[1], splitPoints[2]);
break;
case 'b':
ctx.bezierCurveTo(splitPoints[1], splitPoints[2], splitPoints[3], splitPoints[4], splitPoints[5], splitPoints[6]);
break;
}
}
ctx.closePath();
if (stroke === true) {
ctx.stroke();
}
}
}
var rectanglePoints = [];
//type, ptx1, pty1, ptx2, pty2...
rectanglePoints.push(`m, ${baseX + 200}, ${baseY - 100}`);
rectanglePoints.push(`l, ${baseX + 200}, ${baseY + 100}`);
rectanglePoints.push(`l, ${baseX - 200}, ${baseY + 100}`);
rectanglePoints.push(`l, ${baseX - 200}, ${baseY - 100}`);
var rectangle = new Shape(baseX, baseY, rectanglePoints);
rectangle.drawPath(true);
rectangle.drawPoints(true);
var blobPoints = [];
//type, ptx1, pty1, ptx2, pty2...
blobPoints.push(`m, ${baseX + 100}, ${baseY - 300}`);
blobPoints.push(`b, ${baseX + 300}, ${baseY - 375}, ${baseX + 250}, ${baseY - 215}, ${baseX + 250}, ${baseY - 200}`);
blobPoints.push(`b, ${baseX + 150}, ${baseY + 150}, ${baseX + 200}, ${baseY + 150}, ${baseX + 250}, ${baseY + 200}`);
blobPoints.push(`b, ${baseX + 350}, ${baseY + 300}, ${baseX + 300}, ${baseY + 400}, ${baseX + 50}, ${baseY + 300}`);
blobPoints.push(`b, ${baseX}, ${baseY + 250}, ${baseX}, ${baseY + 250}, ${baseX - 100}, ${baseY + 200}`);
blobPoints.push(`b, ${baseX - 350}, ${baseY + 175}, ${baseX - 350}, ${baseY + 175}, ${baseX - 400}, ${baseY}`);
blobPoints.push(`b, ${baseX - 400}, ${baseY - 300}, ${baseX - 200}, ${baseY - 100}, ${baseX}, ${baseY - 250}`);
var blob = new Shape(baseX, baseY, blobPoints);
blob.drawPath(true);
blob.drawPoints(true);
var findCentroid = function(points) {
var xSum = 0;
var ySum = 0;
var xPoints = 0;
var yPoints = 0;
var centroid = [];
for (i=0; i<points.length; i++) {
var splitPoints = points[i].split(',');
switch(splitPoints[0]) {
case 'm':
xSum += splitPoints[1]/1;
ySum += splitPoints[2]/1;
xPoints += 1;
yPoints += 1;
break;
case 'l':
xSum += splitPoints[1]/1;
ySum += splitPoints[2]/1;
xPoints += 1;
yPoints += 1;
break;
case 'b':
xSum += splitPoints[1]/1;
ySum += splitPoints[2]/1;
xPoints += 1;
yPoints += 1;
break;
}
}
centroid.push(xSum/xPoints);
centroid.push(ySum/yPoints);
return centroid;
}
var projectPoints = function(shapeOne, shapeTwo) {
var pointsOne = shapeOne.points;
var pointsTwo = shapeTwo.points;
var centroid = findCentroid(rectanglePoints);
for (var i=0; i<pointsOne.length; i++) {
//ispointinstroke would be good but it doesn't have wide browser support. Use inpointinpath
var splitPoints = pointsOne[i].split(',');
switch(splitPoints[0]) {
case 'm':
x = splitPoints[1]/1;
y = splitPoints[2]/1;
break;
case 'l':
x = splitPoints[1]/1;
y = splitPoints[2]/1;
break;
case 'b':
x = splitPoints[5]/1;
y = splitPoints[6]/1;
break;
}
//get vector between the centroid and the current x,y value
var vectorX = x - centroid[0]/1;
var vectorY = y - centroid[1]/1;
//increment resolution
var incRes = 100;
termX = vectorX/incRes;
termY = vectorY/incRes;
shapeTwo.drawPath();
while (ctx.isPointInPath(centroid[0]/1 + termX, centroid[0]/1 + termY)) {
termX += vectorX/incRes;
termY += vectorY/incRes;
console.log(termX);
console.log(termY);
}
ctx.beginPath();
ctx.moveTo(centroid[0],centroid[1]);
ctx.lineTo(centroid[0] + termX, centroid[1] + termY);
ctx.stroke();
ctx.closePath();
}
}
projectPoints(rectangle, blob);
var centroid = findCentroid(rectanglePoints);
ctx.beginPath();
ctx.arc(centroid[0], centroid[1], 10, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
});
JSFiddle: https://jsfiddle.net/6g076jw0/1/