mirror of
https://github.com/konvajs/konva.git
synced 2025-04-05 20:48:28 +08:00
more textpath rendering fixes
This commit is contained in:
parent
ad08fb2103
commit
691ef799c7
48
konva.js
48
konva.js
@ -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
4
konva.min.js
vendored
File diff suppressed because one or more lines are too long
@ -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]);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user