more textpath rendering fixes

This commit is contained in:
Anton Lavrenov 2020-11-17 11:19:23 -05:00
parent ad08fb2103
commit 691ef799c7
5 changed files with 120 additions and 49 deletions

View File

@ -8,7 +8,7 @@
* Konva JavaScript Framework v7.1.7
* http://konvajs.org/
* Licensed under the MIT
* Date: Mon Nov 16 2020
* Date: Tue Nov 17 2020
*
* Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS)
* Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva)
@ -11755,7 +11755,7 @@
x: Math.round(minX),
y: Math.round(minY),
width: Math.round(maxX - minX),
height: Math.round(maxY - minY)
height: Math.round(maxY - minY),
};
};
/**
@ -11791,14 +11791,14 @@
point = this.dataArray[i - 1].points.slice(-2);
return {
x: point[0],
y: point[1]
y: point[1],
};
}
if (length < 0.01) {
point = this.dataArray[i].points.slice(0, 2);
return {
x: point[0],
y: point[1]
y: point[1],
};
}
var cp = this.dataArray[i];
@ -11838,21 +11838,24 @@
// vertical line
pt = {
x: fromX,
y: fromY + rise
y: fromY + rise,
};
}
else if ((fromY - P1y) / (fromX - P1x + 0.00000001) === m) {
pt = {
x: fromX + run,
y: fromY + rise
y: fromY + rise,
};
}
else {
var ix, iy;
var len = this.getLineLength(P1x, P1y, P2x, P2y);
if (len < 0.00000001) {
return undefined;
}
// if (len < 0.00000001) {
// return {
// x: P1x,
// y: P1y,
// };
// }
var u = (fromX - P1x) * (P2x - P1x) + (fromY - P1y) * (P2y - P1y);
u = u / (len * len);
ix = P1x + u * (P2x - P1x);
@ -11866,7 +11869,7 @@
rise = m * run;
pt = {
x: ix + run,
y: iy + rise
y: iy + rise,
};
}
return pt;
@ -11888,7 +11891,7 @@
var y = P4y * CB1(pct) + P3y * CB2(pct) + P2y * CB3(pct) + P1y * CB4(pct);
return {
x: x,
y: y
y: y,
};
};
Path.getPointOnQuadraticBezier = function (pct, P1x, P1y, P2x, P2y, P3x, P3y) {
@ -11905,18 +11908,18 @@
var y = P3y * QB1(pct) + P2y * QB2(pct) + P1y * QB3(pct);
return {
x: x,
y: y
y: y,
};
};
Path.getPointOnEllipticalArc = function (cx, cy, rx, ry, theta, psi) {
var cosPsi = Math.cos(psi), sinPsi = Math.sin(psi);
var pt = {
x: rx * Math.cos(theta),
y: ry * Math.sin(theta)
y: ry * Math.sin(theta),
};
return {
x: cx + (pt.x * cosPsi - pt.y * sinPsi),
y: cy + (pt.x * sinPsi + pt.y * cosPsi)
y: cy + (pt.x * sinPsi + pt.y * cosPsi),
};
};
/*
@ -11974,7 +11977,7 @@
's',
'S',
'a',
'A'
'A',
];
// convert white spaces to commas
cs = cs.replace(new RegExp(' ', 'g'), ',');
@ -12199,9 +12202,9 @@
points: points,
start: {
x: startX,
y: startY
y: startY,
},
pathLength: this.calcLength(startX, startY, cmd || c, points)
pathLength: this.calcLength(startX, startY, cmd || c, points),
});
}
if (c === 'z' || c === 'Z') {
@ -12209,7 +12212,7 @@
command: 'z',
points: [],
start: undefined,
pathLength: 0
pathLength: 0,
});
}
}
@ -14391,7 +14394,7 @@
var attempts = 0;
p1 = undefined;
while (Math.abs(glyphWidth - currLen) / glyphWidth > 0.01 &&
attempts < 50) {
attempts < 5) {
attempts++;
var cumulativePathLength = currLen;
while (pathCmd === undefined) {
@ -14453,7 +14456,12 @@
currentT += (glyphWidth - currLen) / pathCmd.pathLength;
}
else {
currentT -= (currLen - glyphWidth) / pathCmd.pathLength;
currentT = currentT - (currLen - glyphWidth) / pathCmd.pathLength;
// that one is a weird check
// but I have to add it to fix some drawings (they are in the testing)
if (currentT < 0) {
currentT += 0.02;
}
}
if (currentT > 1.0) {
currentT = 1.0;

4
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -39,7 +39,7 @@ export class Path extends Shape<PathConfig> {
for (var i = 0; i < this.dataArray.length; ++i) {
this.pathLength += this.dataArray[i].pathLength;
}
this.on('dataChange.konva', function() {
this.on('dataChange.konva', function () {
this.dataArray = Path.parsePathData(this.data());
this.pathLength = 0;
for (var i = 0; i < this.dataArray.length; ++i) {
@ -108,7 +108,7 @@ export class Path extends Shape<PathConfig> {
}
getSelfRect() {
var points = [];
this.dataArray.forEach(function(data) {
this.dataArray.forEach(function (data) {
if (data.command === 'A') {
// Approximates by breaking curve into line segments
var start = data.points[4];
@ -192,7 +192,7 @@ export class Path extends Shape<PathConfig> {
x: Math.round(minX),
y: Math.round(minY),
width: Math.round(maxX - minX),
height: Math.round(maxY - minY)
height: Math.round(maxY - minY),
};
}
/**
@ -233,7 +233,7 @@ export class Path extends Shape<PathConfig> {
point = this.dataArray[i - 1].points.slice(-2);
return {
x: point[0],
y: point[1]
y: point[1],
};
}
@ -241,7 +241,7 @@ export class Path extends Shape<PathConfig> {
point = this.dataArray[i].points.slice(0, 2);
return {
x: point[0],
y: point[1]
y: point[1],
};
}
@ -312,20 +312,23 @@ export class Path extends Shape<PathConfig> {
// vertical line
pt = {
x: fromX,
y: fromY + rise
y: fromY + rise,
};
} else if ((fromY - P1y) / (fromX - P1x + 0.00000001) === m) {
pt = {
x: fromX + run,
y: fromY + rise
y: fromY + rise,
};
} else {
var ix, iy;
var len = this.getLineLength(P1x, P1y, P2x, P2y);
if (len < 0.00000001) {
return undefined;
}
// if (len < 0.00000001) {
// return {
// x: P1x,
// y: P1y,
// };
// }
var u = (fromX - P1x) * (P2x - P1x) + (fromY - P1y) * (P2y - P1y);
u = u / (len * len);
ix = P1x + u * (P2x - P1x);
@ -340,7 +343,7 @@ export class Path extends Shape<PathConfig> {
rise = m * run;
pt = {
x: ix + run,
y: iy + rise
y: iy + rise,
};
}
@ -365,7 +368,7 @@ export class Path extends Shape<PathConfig> {
return {
x: x,
y: y
y: y,
};
}
static getPointOnQuadraticBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y) {
@ -383,7 +386,7 @@ export class Path extends Shape<PathConfig> {
return {
x: x,
y: y
y: y,
};
}
static getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi) {
@ -391,11 +394,11 @@ export class Path extends Shape<PathConfig> {
sinPsi = Math.sin(psi);
var pt = {
x: rx * Math.cos(theta),
y: ry * Math.sin(theta)
y: ry * Math.sin(theta),
};
return {
x: cx + (pt.x * cosPsi - pt.y * sinPsi),
y: cy + (pt.x * sinPsi + pt.y * cosPsi)
y: cy + (pt.x * sinPsi + pt.y * cosPsi),
};
}
/*
@ -456,7 +459,7 @@ export class Path extends Shape<PathConfig> {
's',
'S',
'a',
'A'
'A',
];
// convert white spaces to commas
cs = cs.replace(new RegExp(' ', 'g'), ',');
@ -715,9 +718,9 @@ export class Path extends Shape<PathConfig> {
points: points,
start: {
x: startX,
y: startY
y: startY,
},
pathLength: this.calcLength(startX, startY, cmd || c, points)
pathLength: this.calcLength(startX, startY, cmd || c, points),
});
}
@ -726,7 +729,7 @@ export class Path extends Shape<PathConfig> {
command: 'z',
points: [],
start: undefined,
pathLength: 0
pathLength: 0,
});
}
}
@ -906,13 +909,13 @@ export class Path extends Shape<PathConfig> {
var cx = (x1 + x2) / 2.0 + Math.cos(psi) * cxp - Math.sin(psi) * cyp;
var cy = (y1 + y2) / 2.0 + Math.sin(psi) * cxp + Math.cos(psi) * cyp;
var vMag = function(v) {
var vMag = function (v) {
return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
};
var vRatio = function(u, v) {
var vRatio = function (u, v) {
return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
};
var vAngle = function(u, v) {
var vAngle = function (u, v) {
return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v));
};
var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);

View File

@ -297,7 +297,7 @@ export class TextPath extends Shape<TextPathConfig> {
p1 = undefined;
while (
Math.abs(glyphWidth - currLen) / glyphWidth > 0.01 &&
attempts < 50
attempts < 5
) {
attempts++;
var cumulativePathLength = currLen;
@ -386,7 +386,12 @@ export class TextPath extends Shape<TextPathConfig> {
} else if (glyphWidth > currLen) {
currentT += (glyphWidth - currLen) / pathCmd.pathLength;
} else {
currentT -= (currLen - glyphWidth) / pathCmd.pathLength;
currentT = currentT - (currLen - glyphWidth) / pathCmd.pathLength;
// that one is a weird check
// but I have to add it to fix some drawings (they are in the testing)
if (currentT < 0) {
currentT += 0.02;
}
}
if (currentT > 1.0) {

View File

@ -712,29 +712,84 @@ suite('TextPath', function () {
test('check bad calculations', function () {
var stage = addStage();
stage.draggable(true);
var layer = new Konva.Layer();
stage.add(layer);
var textpath = new Konva.TextPath({
x: 100,
y: 150,
fill: '#333',
fontSize: 16,
scaleX: 0.8,
scaleY: 0.8,
text:
'__________________________________________________________________________________________________________________________________________________________________________________________________________________',
data:
'M 109.98618090452261 138.6656132223618 C 135.94577638190955 48.80547503140701 149.91187876884422 79.79800957914573 151.40954773869348 117.23973382537689 S 123.00811620603017 419.616741991206 122.84170854271358 460.0538041771357 S 134.33883542713568 469.8304329459799 149.98115577889448 464.33898005653265 S 245.4620163316583 411.5856081972362 257.1105527638191 412.91686950376885 S 239.31850251256282 474.434854428392 249.96859296482413 475.76611573492465 S 338.21036306532665 425.67526648869347 348.5276381909548 424.3440051821608 S 337.3640408291457 461.1772344535176 338.5288944723618 464.33898005653265 S 346.8778454773869 466.79295744346734 358.52638190954775 451.4834524183417',
});
layer.add(textpath);
var path = new Konva.Path({
stroke: 'red',
scaleX: 0.8,
scaleY: 0.8,
data:
'M 109.98618090452261 138.6656132223618 C 135.94577638190955 48.80547503140701 149.91187876884422 79.79800957914573 151.40954773869348 117.23973382537689 S 123.00811620603017 419.616741991206 122.84170854271358 460.0538041771357 S 134.33883542713568 469.8304329459799 149.98115577889448 464.33898005653265 S 245.4620163316583 411.5856081972362 257.1105527638191 412.91686950376885 S 239.31850251256282 474.434854428392 249.96859296482413 475.76611573492465 S 338.21036306532665 425.67526648869347 348.5276381909548 424.3440051821608 S 337.3640408291457 461.1772344535176 338.5288944723618 464.33898005653265 S 346.8778454773869 466.79295744346734 358.52638190954775 451.4834524183417',
});
layer.add(path);
layer.draw();
var rect = textpath.getClientRect();
assert.equal(rect.height, 412.4370496991363, 'check height');
assert.equal(rect.height, 332.3365704376247, 'check height');
textpath.text('');
rect = textpath.getClientRect();
assert.equal(rect.height, 0, 'check height');
});
test('check bad calculations 2', function () {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var textpath = new Konva.TextPath({
x: 0,
y: 0,
fill: '#333',
fontSize: 10,
// strokeWidth: 100,
stroke: 'black',
scaleX: 0.4,
scaleY: 0.4,
text:
'....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................',
data:
'M 117.12814070351759 108.66938206658291 C 79.18719346733668 277.73956799623113 75.85761180904522 379.96743797110554 82.84673366834171 395.7761659861809 S 148.83130025125627 280.47708118718595 177.12060301507537 244.36661824748745 S 326.1725898241206 61.02036887562815 325.67336683417085 85.815110709799 S 174.998726758794 435.7304316896985 172.8354271356784 457.1970202575377 S 273.65633103015074 310.01551271984926 307.1042713567839 270.07767352386935 S 466.09929459798997 92.08432302135678 459.9422110552764 114.3829499057789 S 266.23512060301505 435.5226006595478 254.2537688442211 461.4821961369347 S 328.1430565326633 368.1639210113065 357.09798994974875 337.2120956344221 S 486.31961118090453 207.61623570979899 502.79396984924625 195.8012916143216 S 511.48859170854274 200.85065719221106 498.50879396984925 235.79626648869348 S 379.73086055276383 489.4401119660804 391.37939698492465 495.76360317211055 S 573.2022663316583 313.03941849874377 598.4962311557789 290.0751609610553 S 608.3285672110553 288.6610529208543 608.4949748743719 298.64551271984925 S 604.9168530150754 352.64801334799 599.9246231155779 375.778678548995 S 540.6820665829146 508.5077162374372 565.643216080402 497.19199513190955 S 690.3761155778894 408.77881799623117 814.1834170854271 278.6480252826633',
});
var path = new Konva.Path({
x: 0,
y: 0,
stroke: 'red',
scaleX: 0.4,
scaleY: 0.4,
data:
'M 117.12814070351759 108.66938206658291 C 79.18719346733668 277.73956799623113 75.85761180904522 379.96743797110554 82.84673366834171 395.7761659861809 S 148.83130025125627 280.47708118718595 177.12060301507537 244.36661824748745 S 326.1725898241206 61.02036887562815 325.67336683417085 85.815110709799 S 174.998726758794 435.7304316896985 172.8354271356784 457.1970202575377 S 273.65633103015074 310.01551271984926 307.1042713567839 270.07767352386935 S 466.09929459798997 92.08432302135678 459.9422110552764 114.3829499057789 S 266.23512060301505 435.5226006595478 254.2537688442211 461.4821961369347 S 328.1430565326633 368.1639210113065 357.09798994974875 337.2120956344221 S 486.31961118090453 207.61623570979899 502.79396984924625 195.8012916143216 S 511.48859170854274 200.85065719221106 498.50879396984925 235.79626648869348 S 379.73086055276383 489.4401119660804 391.37939698492465 495.76360317211055 S 573.2022663316583 313.03941849874377 598.4962311557789 290.0751609610553 S 608.3285672110553 288.6610529208543 608.4949748743719 298.64551271984925 S 604.9168530150754 352.64801334799 599.9246231155779 375.778678548995 S 540.6820665829146 508.5077162374372 565.643216080402 497.19199513190955 S 690.3761155778894 408.77881799623117 814.1834170854271 278.6480252826633',
});
layer.add(path);
// emulate different size function:
// I found the app with custom font
// we calculations were not correct
// so I just coppied text size from that app
textpath._getTextSize = () => {
return { height: 10, width: 5.9399871826171875 };
};
layer.add(textpath);
layer.draw();
var rect = textpath.getClientRect();
assert.equal(rect.width, 298.50744485064837);
assert.equal(rect.height, 170.74755779649587);
});
});