@clypra/engine 1.1.2 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +110 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +110 -62
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -263,35 +263,26 @@ function wrapTextToWidth(ctx, text, maxWidth, letterSpacing) {
|
|
|
263
263
|
const paragraphs = text.split("\n");
|
|
264
264
|
const lines = [];
|
|
265
265
|
for (const para of paragraphs) {
|
|
266
|
-
if (
|
|
266
|
+
if (para === "") {
|
|
267
267
|
lines.push("");
|
|
268
268
|
continue;
|
|
269
269
|
}
|
|
270
|
-
const words = para.split(/\s+/).filter(Boolean);
|
|
271
270
|
let current = "";
|
|
272
|
-
for (
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
271
|
+
for (let i = 0; i < para.length; i++) {
|
|
272
|
+
const char = para[i];
|
|
273
|
+
const tryLine = current + char;
|
|
274
|
+
if (measureLine(ctx, tryLine, letterSpacing) <= maxWidth) {
|
|
275
|
+
current = tryLine;
|
|
276
276
|
} else {
|
|
277
|
-
if (current)
|
|
278
|
-
|
|
279
|
-
let chunk = "";
|
|
280
|
-
for (const ch of word) {
|
|
281
|
-
const tryChunk = chunk + ch;
|
|
282
|
-
if (measureLine(ctx, tryChunk, letterSpacing) <= maxWidth) chunk = tryChunk;
|
|
283
|
-
else {
|
|
284
|
-
if (chunk) lines.push(chunk);
|
|
285
|
-
chunk = ch;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
current = chunk;
|
|
289
|
-
} else {
|
|
290
|
-
current = word;
|
|
277
|
+
if (current) {
|
|
278
|
+
lines.push(current);
|
|
291
279
|
}
|
|
280
|
+
current = char;
|
|
292
281
|
}
|
|
293
282
|
}
|
|
294
|
-
if (current)
|
|
283
|
+
if (current) {
|
|
284
|
+
lines.push(current);
|
|
285
|
+
}
|
|
295
286
|
}
|
|
296
287
|
return lines.length > 0 ? lines : [""];
|
|
297
288
|
}
|
|
@@ -317,17 +308,17 @@ function layoutWithFontSize(ctx, cfg, fontSize, lines) {
|
|
|
317
308
|
} else {
|
|
318
309
|
startX = safe.x + safe.width / 2;
|
|
319
310
|
}
|
|
320
|
-
let startY = safe.y + (safe.height - textBlockHeight) / 2 + fontSize * 0.
|
|
311
|
+
let startY = safe.y + (safe.height - textBlockHeight) / 2 + fontSize * 0.85;
|
|
321
312
|
if (cfg.textPosY === "top") {
|
|
322
|
-
startY = safe.y + fontSize * 0.
|
|
313
|
+
startY = safe.y + fontSize * 0.85;
|
|
323
314
|
} else if (cfg.textPosY === "bottom") {
|
|
324
|
-
startY = safe.y + safe.height - textBlockHeight + fontSize * 0.
|
|
315
|
+
startY = safe.y + safe.height - textBlockHeight + fontSize * 0.85;
|
|
325
316
|
}
|
|
326
317
|
let xMin = startX;
|
|
327
318
|
if (align === "center") xMin = startX - maxLineWidth / 2;
|
|
328
319
|
else if (align === "right") xMin = startX - maxLineWidth;
|
|
329
320
|
const yMin = startY - fontSize * 0.85;
|
|
330
|
-
const yMax = startY + (lines.length - 1) * fontSize * lineHeight + fontSize * 0.
|
|
321
|
+
const yMax = startY + (lines.length - 1) * fontSize * lineHeight + fontSize * 0.15;
|
|
331
322
|
return {
|
|
332
323
|
lines,
|
|
333
324
|
fontSize,
|
|
@@ -766,11 +757,11 @@ var InkBrushEngine = class {
|
|
|
766
757
|
if (letterSpacing !== 0) {
|
|
767
758
|
ctx.letterSpacing = `${letterSpacing}px`;
|
|
768
759
|
}
|
|
769
|
-
let startY = (height - textBlockHeight) / 2 + fontSize * 0.
|
|
760
|
+
let startY = (height - textBlockHeight) / 2 + fontSize * 0.85;
|
|
770
761
|
if (textPosY === "top") {
|
|
771
|
-
startY = 40 + fontSize * 0.
|
|
762
|
+
startY = 40 + fontSize * 0.85;
|
|
772
763
|
} else if (textPosY === "bottom") {
|
|
773
|
-
startY = height - 40 - textBlockHeight + fontSize * 0.
|
|
764
|
+
startY = height - 40 - textBlockHeight + fontSize * 0.85;
|
|
774
765
|
}
|
|
775
766
|
ctx.save();
|
|
776
767
|
if (skewX !== 0) {
|
|
@@ -918,11 +909,11 @@ var InkBrushEngine = class {
|
|
|
918
909
|
if (letterSpacing !== 0) {
|
|
919
910
|
ctx.letterSpacing = `${letterSpacing}px`;
|
|
920
911
|
}
|
|
921
|
-
let startY = (height - textBlockHeight) / 2 + fontSize * 0.
|
|
912
|
+
let startY = (height - textBlockHeight) / 2 + fontSize * 0.85;
|
|
922
913
|
if (textPosY === "top") {
|
|
923
|
-
startY = 40 + fontSize * 0.
|
|
914
|
+
startY = 40 + fontSize * 0.85;
|
|
924
915
|
} else if (textPosY === "bottom") {
|
|
925
|
-
startY = height - 40 - textBlockHeight + fontSize * 0.
|
|
916
|
+
startY = height - 40 - textBlockHeight + fontSize * 0.85;
|
|
926
917
|
}
|
|
927
918
|
ctx.save();
|
|
928
919
|
if (skewX !== 0) {
|
|
@@ -1007,6 +998,17 @@ function restoreLetterSpacing(ctx, saved) {
|
|
|
1007
998
|
function getCanvas2DContext2(canvas) {
|
|
1008
999
|
return canvas.getContext("2d");
|
|
1009
1000
|
}
|
|
1001
|
+
function ctxSupportsFilter(ctx) {
|
|
1002
|
+
try {
|
|
1003
|
+
const prev = ctx.filter;
|
|
1004
|
+
ctx.filter = "blur(4px)";
|
|
1005
|
+
const ok = typeof ctx.filter === "string" && ctx.filter.includes("blur");
|
|
1006
|
+
ctx.filter = prev;
|
|
1007
|
+
return ok;
|
|
1008
|
+
} catch {
|
|
1009
|
+
return false;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1010
1012
|
function renderTextEffectCore(ctx, cfg) {
|
|
1011
1013
|
if (cfg.customRenderer === "InkBrushEngine") {
|
|
1012
1014
|
const engine = new InkBrushEngine(cfg);
|
|
@@ -1316,19 +1318,31 @@ function renderTextEffectCore(ctx, cfg) {
|
|
|
1316
1318
|
const vpy = cHeight / 2 + (bevelVanishingPointY !== void 0 ? bevelVanishingPointY : 80) / 100 * (cHeight / 2);
|
|
1317
1319
|
const fl = Math.max(100, bevelFocalLength !== void 0 ? bevelFocalLength : 400);
|
|
1318
1320
|
if (bevelBlur && bevelBlur > 0) {
|
|
1319
|
-
ctx.save();
|
|
1320
|
-
ctx.filter = `blur(${bevelBlur}px)`;
|
|
1321
1321
|
const blurColor = bevelBlurColor || bevelShadow || "#000000";
|
|
1322
|
-
|
|
1323
|
-
const scale = fl / (fl + i);
|
|
1322
|
+
if (ctxSupportsFilter(ctx)) {
|
|
1324
1323
|
ctx.save();
|
|
1325
|
-
ctx.
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1324
|
+
ctx.filter = `blur(${bevelBlur}px)`;
|
|
1325
|
+
for (let i = bevelDepth; i > 0; i -= Math.max(1, Math.floor(bevelDepth / 4))) {
|
|
1326
|
+
const scale = fl / (fl + i);
|
|
1327
|
+
ctx.save();
|
|
1328
|
+
ctx.translate(vpx, vpy);
|
|
1329
|
+
ctx.scale(scale, scale);
|
|
1330
|
+
ctx.translate(-vpx, -vpy);
|
|
1331
|
+
renderLines("fill", blurColor);
|
|
1332
|
+
ctx.restore();
|
|
1333
|
+
}
|
|
1329
1334
|
ctx.restore();
|
|
1335
|
+
} else {
|
|
1336
|
+
for (let i = bevelDepth; i > 0; i -= Math.max(1, Math.floor(bevelDepth / 4))) {
|
|
1337
|
+
const scale = fl / (fl + i);
|
|
1338
|
+
ctx.save();
|
|
1339
|
+
ctx.translate(vpx, vpy);
|
|
1340
|
+
ctx.scale(scale, scale);
|
|
1341
|
+
ctx.translate(-vpx, -vpy);
|
|
1342
|
+
renderWithShadowTrick("fill", blurColor, bevelBlur, 0, 0, 100);
|
|
1343
|
+
ctx.restore();
|
|
1344
|
+
}
|
|
1330
1345
|
}
|
|
1331
|
-
ctx.restore();
|
|
1332
1346
|
}
|
|
1333
1347
|
ctx.save();
|
|
1334
1348
|
for (let i = bevelDepth; i > 0; i--) {
|
|
@@ -1375,14 +1389,21 @@ function renderTextEffectCore(ctx, cfg) {
|
|
|
1375
1389
|
return { dx: i, dy: i };
|
|
1376
1390
|
};
|
|
1377
1391
|
if (bevelBlur && bevelBlur > 0) {
|
|
1378
|
-
ctx.save();
|
|
1379
|
-
ctx.filter = `blur(${bevelBlur}px)`;
|
|
1380
1392
|
const blurColor = bevelBlurColor || bevelShadow || "#000000";
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1393
|
+
if (ctxSupportsFilter(ctx)) {
|
|
1394
|
+
ctx.save();
|
|
1395
|
+
ctx.filter = `blur(${bevelBlur}px)`;
|
|
1396
|
+
for (let i = bevelDepth; i > 0; i -= Math.max(1, Math.floor(bevelDepth / 4))) {
|
|
1397
|
+
const { dx, dy } = getDirOffset(i);
|
|
1398
|
+
renderLines("fill", blurColor, dx, dy);
|
|
1399
|
+
}
|
|
1400
|
+
ctx.restore();
|
|
1401
|
+
} else {
|
|
1402
|
+
for (let i = bevelDepth; i > 0; i -= Math.max(1, Math.floor(bevelDepth / 4))) {
|
|
1403
|
+
const { dx, dy } = getDirOffset(i);
|
|
1404
|
+
renderWithShadowTrick("fill", blurColor, bevelBlur, dx, dy, 100);
|
|
1405
|
+
}
|
|
1384
1406
|
}
|
|
1385
|
-
ctx.restore();
|
|
1386
1407
|
}
|
|
1387
1408
|
ctx.save();
|
|
1388
1409
|
for (let i = bevelDepth; i > 0; i--) {
|
|
@@ -1436,24 +1457,51 @@ function renderTextEffectCore(ctx, cfg) {
|
|
|
1436
1457
|
customStrokeStyle = grad;
|
|
1437
1458
|
}
|
|
1438
1459
|
const drawStrokeLayer = (color, width, blurAmount, opacity, position) => {
|
|
1439
|
-
ctx
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1460
|
+
if (blurAmount > 0 && ctxSupportsFilter(ctx)) {
|
|
1461
|
+
ctx.save();
|
|
1462
|
+
ctx.globalAlpha = opacity / 100;
|
|
1463
|
+
ctx.strokeStyle = color;
|
|
1443
1464
|
ctx.filter = `blur(${blurAmount}px)`;
|
|
1465
|
+
if (position === "outside") {
|
|
1466
|
+
ctx.lineWidth = width * 2;
|
|
1467
|
+
renderLines("stroke");
|
|
1468
|
+
} else if (position === "center") {
|
|
1469
|
+
ctx.lineWidth = width;
|
|
1470
|
+
renderLines("stroke");
|
|
1471
|
+
} else if (position === "inside") {
|
|
1472
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
1473
|
+
ctx.lineWidth = width * 2;
|
|
1474
|
+
renderLines("stroke");
|
|
1475
|
+
}
|
|
1476
|
+
ctx.restore();
|
|
1477
|
+
} else if (blurAmount > 0) {
|
|
1478
|
+
const colorStr = typeof color === "string" ? color : strokeColor;
|
|
1479
|
+
const spread = position === "center" ? width / 2 : width;
|
|
1480
|
+
if (position === "inside") {
|
|
1481
|
+
ctx.save();
|
|
1482
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
1483
|
+
renderWithShadowTrick("stroke", colorStr, blurAmount, 0, 0, opacity, void 0, spread);
|
|
1484
|
+
ctx.restore();
|
|
1485
|
+
} else {
|
|
1486
|
+
renderWithShadowTrick("stroke", colorStr, blurAmount, 0, 0, opacity, void 0, spread);
|
|
1487
|
+
}
|
|
1488
|
+
} else {
|
|
1489
|
+
ctx.save();
|
|
1490
|
+
ctx.globalAlpha = opacity / 100;
|
|
1491
|
+
ctx.strokeStyle = color;
|
|
1492
|
+
if (position === "outside") {
|
|
1493
|
+
ctx.lineWidth = width * 2;
|
|
1494
|
+
renderLines("stroke");
|
|
1495
|
+
} else if (position === "center") {
|
|
1496
|
+
ctx.lineWidth = width;
|
|
1497
|
+
renderLines("stroke");
|
|
1498
|
+
} else if (position === "inside") {
|
|
1499
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
1500
|
+
ctx.lineWidth = width * 2;
|
|
1501
|
+
renderLines("stroke");
|
|
1502
|
+
}
|
|
1503
|
+
ctx.restore();
|
|
1444
1504
|
}
|
|
1445
|
-
if (position === "outside") {
|
|
1446
|
-
ctx.lineWidth = width * 2;
|
|
1447
|
-
renderLines("stroke");
|
|
1448
|
-
} else if (position === "center") {
|
|
1449
|
-
ctx.lineWidth = width;
|
|
1450
|
-
renderLines("stroke");
|
|
1451
|
-
} else if (position === "inside") {
|
|
1452
|
-
ctx.globalCompositeOperation = "source-atop";
|
|
1453
|
-
ctx.lineWidth = width * 2;
|
|
1454
|
-
renderLines("stroke");
|
|
1455
|
-
}
|
|
1456
|
-
ctx.restore();
|
|
1457
1505
|
};
|
|
1458
1506
|
if (sType === "double") {
|
|
1459
1507
|
const outerWidth = strokeWidth + sWidthSecondary;
|