Skip to content

Commit

Permalink
fix(fabric.Text): Improve path's angle detection for text on a path (f…
Browse files Browse the repository at this point in the history
  • Loading branch information
asturur authored and shanicerae committed Jan 16, 2021
1 parent 7aa9346 commit 51b69b3
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 13 deletions.
11 changes: 6 additions & 5 deletions src/shapes/text.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,8 @@
if (positionInPath > totalPathLength) {
positionInPath %= totalPathLength;
}
// it would probably much fater to send all the grapheme position for a line
// and calculate path position/angle at once.
this._setGraphemeOnPath(positionInPath, graphemeInfo, startingPoint);
}
lineBounds[i] = graphemeInfo;
Expand Down Expand Up @@ -758,11 +760,10 @@
path = this.path;

// we are at currentPositionOnPath. we want to know what point on the path is.
var p1 = fabric.util.getPointOnPath(path.path, centerPosition - 0.1, path.segmentsInfo),
p2 = fabric.util.getPointOnPath(path.path, centerPosition + 0.1, path.segmentsInfo);
graphemeInfo.renderLeft = p1.x - startingPoint.x;
graphemeInfo.renderTop = p1.y - startingPoint.y;
graphemeInfo.angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
var info = fabric.util.getPointOnPath(path.path, centerPosition, path.segmentsInfo);
graphemeInfo.renderLeft = info.x - startingPoint.x;
graphemeInfo.renderTop = info.y - startingPoint.y;
graphemeInfo.angle = info.angle;
},

/**
Expand Down
63 changes: 55 additions & 8 deletions src/util/path.js
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,17 @@
};
}

function getTangentCubicIterator(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) {
return function (pct) {
var invT = 1 - pct,
tangentX = (3 * invT * invT * (p2x - p1x)) + (6 * invT * pct * (p3x - p2x)) +
(3 * pct * pct * (p4x - p3x)),
tangentY = (3 * invT * invT * (p2y - p1y)) + (6 * invT * pct * (p3y - p2y)) +
(3 * pct * pct * (p4y - p3y));
return Math.atan2(tangentY, tangentX);
};
}

function QB1(t) {
return t * t;
}
Expand All @@ -461,6 +472,16 @@
};
}

function getTangentQuadraticIterator(p1x, p1y, p2x, p2y, p3x, p3y) {
return function (pct) {
var invT = 1 - pct,
tangentX = (2 * invT * (p2x - p1x)) + (2 * pct * (p3x - p2x)),
tangentY = (2 * invT * (p2y - p1y)) + (2 * pct * (p3y - p2y));
return Math.atan2(tangentY, tangentX);
};
}


// this will run over a path segment ( a cubic or quadratic segment) and approximate it
// with 100 segemnts. This will good enough to calculate the length of the curve
function pathIterator(iterator, x1, y1) {
Expand All @@ -479,15 +500,16 @@
* The percentage will be then used to find the correct point on the canvas for the path.
* @param {Array} segInfo fabricJS collection of information on a parsed path
* @param {Number} distance from starting point, in pixels.
* @return {Number} length of segment
* @return {Object} info object with x and y ( the point on canvas ) and angle, the tangent on that point;
*/
function findPercentageForDistance(segInfo, distance) {
var perc = 0, tmpLen = 0, iterator = segInfo.iterator, tempP = { x: segInfo.x, y: segInfo.y },
p, nextLen, nextStep = 0.01;
p, nextLen, nextStep = 0.01, angleFinder = segInfo.angleFinder, lastPerc;
// nextStep > 0.0001 covers 0.00015625 that 1/64th of 1/100
// the path
while (tmpLen < distance && perc <= 1 && nextStep > 0.0001) {
p = iterator(perc);
lastPerc = perc;
nextLen = calcLineLength(tempP.x, tempP.y, p.x, p.y);
// compare tmpLen each cycle with distance, decide next perc to test.
if ((nextLen + tmpLen) > distance) {
Expand All @@ -501,6 +523,7 @@
tmpLen += nextLen;
}
}
p.angle = angleFinder(lastPerc);
return p;
}

Expand All @@ -514,7 +537,7 @@
var totalLength = 0, len = path.length, current,
//x2 and y2 are the coords of segment start
//x1 and y1 are the coords of the current point
x1 = 0, y1 = 0, x2 = 0, y2 = 0, info = [], iterator, tempInfo;
x1 = 0, y1 = 0, x2 = 0, y2 = 0, info = [], iterator, tempInfo, angleFinder;
for (var i = 0; i < len; i++) {
current = path[i];
tempInfo = {
Expand Down Expand Up @@ -544,7 +567,18 @@
current[5],
current[6]
);
angleFinder = getTangentCubicIterator(
x1,
y1,
current[1],
current[2],
current[3],
current[4],
current[5],
current[6]
);
tempInfo.iterator = iterator;
tempInfo.angleFinder = angleFinder;
tempInfo.length = pathIterator(iterator, x1, y1);
x1 = current[5];
y1 = current[6];
Expand All @@ -558,7 +592,16 @@
current[3],
current[4]
);
angleFinder = getTangentQuadraticIterator(
x1,
y1,
current[1],
current[2],
current[3],
current[4]
);
tempInfo.iterator = iterator;
tempInfo.angleFinder = angleFinder;
tempInfo.length = pathIterator(iterator, x1, y1);
x1 = current[3];
y1 = current[4];
Expand All @@ -584,29 +627,33 @@
if (!infos) {
infos = getPathSegmentsInfo(path);
}
// var distance = infos[infos.length - 1] * perc;
var i = 0;
while ((distance - infos[i].length > 0) && i < (infos.length - 2)) {
distance -= infos[i].length;
i++;
}
// var distance = infos[infos.length - 1] * perc;
var segInfo = infos[i], segPercent = distance / segInfo.length,
command = segInfo.command, segment = path[i];
command = segInfo.command, segment = path[i], info;

switch (command) {
case 'M':
return { x: segInfo.x, y: segInfo.y };
return { x: segInfo.x, y: segInfo.y, angle: 0 };
case 'Z':
case 'z':
return new fabric.Point(segInfo.x, segInfo.y).lerp(
info = new fabric.Point(segInfo.x, segInfo.y).lerp(
new fabric.Point(segInfo.destX, segInfo.destY),
segPercent
);
info.angle = Math.atan2(segInfo.destY - segInfo.y, segInfo.destX - segInfo.x);
return info;
case 'L':
return new fabric.Point(segInfo.x, segInfo.y).lerp(
info = new fabric.Point(segInfo.x, segInfo.y).lerp(
new fabric.Point(segment[1], segment[2]),
segPercent
);
info.angle = Math.atan2(segment[2] - segInfo.y, segment[1] - segInfo.x);
return info;
case 'C':
return findPercentageForDistance(segInfo, distance);
case 'Q':
Expand Down
Binary file modified test/visual/golden/text10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/visual/golden/textpath2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/visual/golden/textpath3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 51b69b3

Please sign in to comment.