From c0b58e99165eb06fcd1bc8dac00b2f7f63399808 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Wed, 23 Dec 2020 19:29:04 +0100 Subject: [PATCH] fix(fabric.Text): Text on path, fix non linear distance of chars over path (#6671) --- src/util/path.js | 76 +++++++++++++++++++++---------- test/visual/golden/textpath3.png | Bin 0 -> 12835 bytes test/visual/text_path.js | 17 +++++++ 3 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 test/visual/golden/textpath3.png diff --git a/src/util/path.js b/src/util/path.js index 319e153cca1..7220702e91d 100644 --- a/src/util/path.js +++ b/src/util/path.js @@ -229,7 +229,13 @@ return segsNorm; }; - + /** + * This function take a parsed SVG path and make it simpler for fabricJS logic. + * simplification consist of: only UPPERCASE absolute commands ( relative converted to absolute ) + * S converted in C, T converted in Q, A converted in C. + * @param {Array} path the array of commands of a parsed svg path for fabric.Path + * @return {Array} the simplified array of commands of a parsed svg path for fabric.Path + */ function makePathSimpler(path) { // x and y represent the last point of the path. the previous command point. // we add them to each relative command to make it an absolute comment. @@ -455,6 +461,8 @@ }; } + // 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) { var tempP = { x: x1, y: y1 }, p, tmpLen = 0, perc; for (perc = 0.01; perc <= 1; perc += 0.01) { @@ -465,7 +473,43 @@ return tmpLen; } - //measures the length of a pre-simplified path + /** + * Given a pathInfo, and a distance in pixels, find the percentage from 0 to 1 + * that correspond to that pixels run over the path. + * 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 + */ + function findPercentageForDistance(segInfo, distance) { + var perc = 0, tmpLen = 0, iterator = segInfo.iterator, tempP = { x: segInfo.x, y: segInfo.y }, + p, nextLen, nextStep = 0.01; + // 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); + 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) { + // we discard this step and we make smaller steps. + nextStep /= 2; + perc -= nextStep; + } + else { + tempP = p; + perc += nextStep; + tmpLen += nextLen; + } + } + return p; + } + + /** + * Run over a parsed and simplifed path and extrac some informations. + * informations are length of each command and starting point + * @param {Array} path fabricJS parsed path commands + * @return {Array} path commands informations + */ function getPathSegmentsInfo(path) { var totalLength = 0, len = path.length, current, //x2 and y2 are the coords of segment start @@ -500,6 +544,7 @@ current[5], current[6] ); + tempInfo.iterator = iterator; tempInfo.length = pathIterator(iterator, x1, y1); x1 = current[5]; y1 = current[6]; @@ -513,6 +558,7 @@ current[3], current[4] ); + tempInfo.iterator = iterator; tempInfo.length = pathIterator(iterator, x1, y1); x1 = current[3]; y1 = current[4]; @@ -546,6 +592,7 @@ } var segInfo = infos[i], segPercent = distance / segInfo.length, command = segInfo.command, segment = path[i]; + switch (command) { case 'M': return { x: segInfo.x, y: segInfo.y }; @@ -555,35 +602,15 @@ new fabric.Point(segInfo.destX, segInfo.destY), segPercent ); - break; case 'L': return new fabric.Point(segInfo.x, segInfo.y).lerp( new fabric.Point(segment[1], segment[2]), segPercent ); - break; case 'C': - return getPointOnCubicBezierIterator( - segInfo.x, - segInfo.y, - segment[1], - segment[2], - segment[3], - segment[4], - segment[5], - segment[6] - )(segPercent); - break; + return findPercentageForDistance(segInfo, distance); case 'Q': - return getPointOnQuadraticBezierIterator( - segInfo.x, - segInfo.y, - segment[1], - segment[2], - segment[3], - segment[4] - )(segPercent); - break; + return findPercentageForDistance(segInfo, distance); } } @@ -685,6 +712,7 @@ /** * Draws arc + * @deprecated * @param {CanvasRenderingContext2D} ctx * @param {Number} fx * @param {Number} fy diff --git a/test/visual/golden/textpath3.png b/test/visual/golden/textpath3.png new file mode 100644 index 0000000000000000000000000000000000000000..ff84eab2e0aa6b052afdbd13511c831e9439443c GIT binary patch literal 12835 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

fv03#!PE_8GF~KE1S0RgmV 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 literal 0 HcmV?d00001 diff --git a/test/visual/text_path.js b/test/visual/text_path.js index e75ddfc7cd7..5b5ec2f2a8d 100644 --- a/test/visual/text_path.js +++ b/test/visual/text_path.js @@ -58,5 +58,22 @@ height: 200, }); + function textpath3(canvas, callback) { + var path = new fabric.Path('M -194 -109 C 538 -300 154 50 98 29'); + var text = new fabric.Text('Testing constant distance on bezier curve.', { path: path, top: 30, left: 30 }); + canvas.add(text); + canvas.renderAll(); + callback(canvas.lowerCanvasEl); + } + + tests.push({ + test: 'Textpath on a particular bezier', + code: textpath3, + golden: 'textpath3.png', + percentage: 0.09, + width: 610, + height: 270, + }); + tests.forEach(visualTestLoop(QUnit)); })();