embroidery-qc-image 1.0.29 → 1.0.30
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/components/EmbroideryQCImage.d.ts.map +1 -1
- package/dist/index.esm.js +191 -104
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +191 -104
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmbroideryQCImage.d.ts","sourceRoot":"","sources":["../../src/components/EmbroideryQCImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAY,MAAM,UAAU,CAAC;AAChF,OAAO,yBAAyB,CAAC;AAiKjC,MAAM,WAAW,8BAA8B;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAofD,QAAA,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAmHvD,CAAC;
|
|
1
|
+
{"version":3,"file":"EmbroideryQCImage.d.ts","sourceRoot":"","sources":["../../src/components/EmbroideryQCImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAY,MAAM,UAAU,CAAC;AAChF,OAAO,yBAAyB,CAAC;AAiKjC,MAAM,WAAW,8BAA8B;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAofD,QAAA,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAmHvD,CAAC;AA2kDF,eAAO,MAAM,6BAA6B,GACxC,QAAQ,kBAAkB,EAC1B,UAAS,8BAAmC,KAC3C,OAAO,CAAC,IAAI,GAAG,IAAI,CAuBrB,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,QAAQ,kBAAkB,EAC1B,UAAS,8BAAmC,KAC3C,OAAO,CAAC,MAAM,GAAG,IAAI,CAuBvB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1160,25 +1160,123 @@ displayIndex, showLabels, scaleFactor, imageRefs, mockupBounds = null) => {
|
|
|
1160
1160
|
currentY += result.height;
|
|
1161
1161
|
}
|
|
1162
1162
|
if (showLabels.font && position.font) {
|
|
1163
|
-
// Render "Font: " với font mặc định
|
|
1164
1163
|
const prefix = "Font: ";
|
|
1165
|
-
ctx.font = `${otherFontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1166
|
-
const prefixWidth = ctx.measureText(prefix).width;
|
|
1167
|
-
let currentX = x + prefixWidth;
|
|
1168
|
-
ctx.fillText(prefix, x, currentY);
|
|
1169
|
-
// Render tên font với font từ config
|
|
1170
|
-
ctx.font = `${otherFontSize}px ${position.font}`;
|
|
1171
|
-
const fontNameWidth = ctx.measureText(position.font).width;
|
|
1172
|
-
ctx.fillText(position.font, currentX, currentY);
|
|
1173
|
-
currentX += fontNameWidth;
|
|
1174
|
-
// Render "(Mặc định)" hoặc "(Custom)" với font mặc định
|
|
1175
1164
|
const suffix = position.is_font_default === true ? " (Mặc định)" : " (Custom)";
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
ctx.fillText(suffix, currentX, currentY);
|
|
1179
|
-
// Tính toán height và di chuyển cursorY
|
|
1165
|
+
const fontName = position.font;
|
|
1166
|
+
const fullText = `${prefix}${fontName}${suffix}`;
|
|
1180
1167
|
const lineHeight = otherFontSize + lineGap;
|
|
1181
|
-
|
|
1168
|
+
const textTopY = currentY;
|
|
1169
|
+
const effectiveMaxWidth = mockupBounds
|
|
1170
|
+
? getEffectiveMaxWidth(x, textTopY, lineHeight, maxWidth, mockupBounds)
|
|
1171
|
+
: maxWidth;
|
|
1172
|
+
const MIN_FONT_FONT_SIZE = otherFontSize * 0.5;
|
|
1173
|
+
const measureFontTextWidth = (fontSize) => {
|
|
1174
|
+
ctx.font = `${fontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1175
|
+
const prefixWidth = ctx.measureText(prefix).width;
|
|
1176
|
+
ctx.font = `${fontSize}px ${position.font}`;
|
|
1177
|
+
const fontNameWidth = ctx.measureText(fontName).width;
|
|
1178
|
+
ctx.font = `${fontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1179
|
+
const suffixWidth = ctx.measureText(suffix).width;
|
|
1180
|
+
return prefixWidth + fontNameWidth + suffixWidth;
|
|
1181
|
+
};
|
|
1182
|
+
const checkFontSizeFits = (fontSize) => {
|
|
1183
|
+
const textTopY = currentY;
|
|
1184
|
+
const lineHeight = fontSize + lineGap;
|
|
1185
|
+
const effectiveMaxWidth = mockupBounds
|
|
1186
|
+
? getEffectiveMaxWidth(x, textTopY, lineHeight, maxWidth, mockupBounds)
|
|
1187
|
+
: maxWidth;
|
|
1188
|
+
const textWidth = measureFontTextWidth(fontSize);
|
|
1189
|
+
return textWidth <= effectiveMaxWidth;
|
|
1190
|
+
};
|
|
1191
|
+
let effectiveFontSize = otherFontSize;
|
|
1192
|
+
let needsWrap = false;
|
|
1193
|
+
// Bước 1: Thử giảm font size, kiểm tra xem có vừa chiều ngang không
|
|
1194
|
+
const baseMaxWidth = measureFontTextWidth(otherFontSize);
|
|
1195
|
+
if (baseMaxWidth > effectiveMaxWidth) {
|
|
1196
|
+
// Binary search để tìm font size lớn nhất mà vẫn vừa
|
|
1197
|
+
let left = MIN_FONT_FONT_SIZE;
|
|
1198
|
+
let right = otherFontSize;
|
|
1199
|
+
let bestFontSize = MIN_FONT_FONT_SIZE;
|
|
1200
|
+
while (right - left > 0.1) {
|
|
1201
|
+
const mid = (left + right) / 2;
|
|
1202
|
+
if (checkFontSizeFits(mid)) {
|
|
1203
|
+
bestFontSize = mid;
|
|
1204
|
+
left = mid;
|
|
1205
|
+
}
|
|
1206
|
+
else {
|
|
1207
|
+
right = mid;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (checkFontSizeFits(bestFontSize)) {
|
|
1211
|
+
// Bước 1 thành công: font size đã shrink vừa chiều ngang
|
|
1212
|
+
effectiveFontSize = Math.floor(bestFontSize);
|
|
1213
|
+
}
|
|
1214
|
+
else {
|
|
1215
|
+
// Bước 1 thất bại: đã shrink đến MIN nhưng vẫn không vừa, sang bước 2
|
|
1216
|
+
needsWrap = true;
|
|
1217
|
+
effectiveFontSize = otherFontSize;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
if (needsWrap) {
|
|
1221
|
+
// Bước 2: Xuống dòng với font size gốc
|
|
1222
|
+
ctx.font = `${effectiveFontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1223
|
+
const wrappedLines = buildWrappedLines(ctx, fullText, effectiveMaxWidth, x, textTopY, lineHeight, mockupBounds);
|
|
1224
|
+
wrappedLines.forEach((line, index) => {
|
|
1225
|
+
const lineY = textTopY + index * lineHeight;
|
|
1226
|
+
const lineEffectiveMaxWidth = mockupBounds
|
|
1227
|
+
? getEffectiveMaxWidth(x, lineY, lineHeight, maxWidth, mockupBounds)
|
|
1228
|
+
: maxWidth;
|
|
1229
|
+
let lineToRender = line;
|
|
1230
|
+
const lineWidth = ctx.measureText(lineToRender).width;
|
|
1231
|
+
if (lineWidth > lineEffectiveMaxWidth) {
|
|
1232
|
+
while (ctx.measureText(lineToRender).width > lineEffectiveMaxWidth && lineToRender.length > 0) {
|
|
1233
|
+
lineToRender = lineToRender.slice(0, -1);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
ctx.fillText(lineToRender, x, lineY);
|
|
1237
|
+
});
|
|
1238
|
+
currentY += wrappedLines.length * lineHeight;
|
|
1239
|
+
}
|
|
1240
|
+
else {
|
|
1241
|
+
// Bước 1 thành công: Render với font size đã shrink (1 dòng)
|
|
1242
|
+
const shrunkTextTopY = currentY;
|
|
1243
|
+
const shrunkLineHeight = effectiveFontSize + lineGap;
|
|
1244
|
+
const shrunkEffectiveMaxWidth = mockupBounds
|
|
1245
|
+
? getEffectiveMaxWidth(x, shrunkTextTopY, shrunkLineHeight, maxWidth, mockupBounds)
|
|
1246
|
+
: maxWidth;
|
|
1247
|
+
ctx.font = `${effectiveFontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1248
|
+
const prefixWidth = ctx.measureText(prefix).width;
|
|
1249
|
+
let currentX = x + prefixWidth;
|
|
1250
|
+
ctx.fillText(prefix, x, currentY);
|
|
1251
|
+
ctx.font = `${effectiveFontSize}px ${position.font}`;
|
|
1252
|
+
const fontNameWidth = ctx.measureText(fontName).width;
|
|
1253
|
+
const totalWidth = prefixWidth + fontNameWidth;
|
|
1254
|
+
if (totalWidth > shrunkEffectiveMaxWidth) {
|
|
1255
|
+
// Cần cắt font name
|
|
1256
|
+
let truncatedFontName = fontName;
|
|
1257
|
+
while (ctx.measureText(truncatedFontName).width > shrunkEffectiveMaxWidth - prefixWidth && truncatedFontName.length > 0) {
|
|
1258
|
+
truncatedFontName = truncatedFontName.slice(0, -1);
|
|
1259
|
+
}
|
|
1260
|
+
ctx.fillText(truncatedFontName, currentX, currentY);
|
|
1261
|
+
currentX += ctx.measureText(truncatedFontName).width;
|
|
1262
|
+
}
|
|
1263
|
+
else {
|
|
1264
|
+
ctx.fillText(fontName, currentX, currentY);
|
|
1265
|
+
currentX += fontNameWidth;
|
|
1266
|
+
}
|
|
1267
|
+
ctx.font = `${effectiveFontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1268
|
+
const remainingWidth = shrunkEffectiveMaxWidth - (currentX - x);
|
|
1269
|
+
if (remainingWidth > 0) {
|
|
1270
|
+
let truncatedSuffix = suffix;
|
|
1271
|
+
while (ctx.measureText(truncatedSuffix).width > remainingWidth && truncatedSuffix.length > 0) {
|
|
1272
|
+
truncatedSuffix = truncatedSuffix.slice(0, -1);
|
|
1273
|
+
}
|
|
1274
|
+
if (truncatedSuffix.length > 0) {
|
|
1275
|
+
ctx.fillText(truncatedSuffix, currentX, currentY);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
currentY += shrunkLineHeight;
|
|
1279
|
+
}
|
|
1182
1280
|
}
|
|
1183
1281
|
if (showLabels.color) {
|
|
1184
1282
|
const colorValue = position.character_colors?.join(", ") || position.color;
|
|
@@ -1324,126 +1422,115 @@ const renderIconPosition = (ctx, position, x, y, maxWidth, scaleFactor, imageRef
|
|
|
1324
1422
|
}
|
|
1325
1423
|
}
|
|
1326
1424
|
}
|
|
1327
|
-
// Tính available width cho icon value (trừ đi khoảng trống cho icon_image)
|
|
1328
1425
|
const availableWidth = Math.max(1, maxWidth - labelWidth - iconImageReservedWidth);
|
|
1329
|
-
|
|
1330
|
-
|
|
1426
|
+
const textCenterY = cursorY + iconImageHeight / 2;
|
|
1427
|
+
const valueStartX = x + labelWidth;
|
|
1428
|
+
const textTopY = textCenterY - iconFontSize / 2;
|
|
1429
|
+
const lineHeight = iconFontSize;
|
|
1430
|
+
const effectiveMaxWidth = mockupBounds
|
|
1431
|
+
? getEffectiveMaxWidth(valueStartX, textTopY, lineHeight, availableWidth, mockupBounds)
|
|
1432
|
+
: availableWidth;
|
|
1331
1433
|
const MIN_ICON_VALUE_FONT_SIZE = iconFontSize * 0.5;
|
|
1332
1434
|
const measureIconValueWidth = (fontSize) => {
|
|
1333
1435
|
ctx.font = `${fontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1334
1436
|
return ctx.measureText(` ${iconValue}`).width;
|
|
1335
1437
|
};
|
|
1438
|
+
const checkFontSizeFits = (fontSize) => {
|
|
1439
|
+
const textTopY = textCenterY - fontSize / 2;
|
|
1440
|
+
const lineHeight = fontSize;
|
|
1441
|
+
const effectiveMaxWidth = mockupBounds
|
|
1442
|
+
? getEffectiveMaxWidth(valueStartX, textTopY, lineHeight, availableWidth, mockupBounds)
|
|
1443
|
+
: availableWidth;
|
|
1444
|
+
const textWidth = measureIconValueWidth(fontSize);
|
|
1445
|
+
return textWidth <= effectiveMaxWidth;
|
|
1446
|
+
};
|
|
1336
1447
|
let effectiveIconValueFontSize = iconFontSize;
|
|
1337
|
-
const baseMaxWidth = measureIconValueWidth(iconFontSize);
|
|
1338
1448
|
let needsWrap = false;
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
//
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1449
|
+
// Bước 1: Thử giảm font size, kiểm tra xem có vừa chiều ngang không
|
|
1450
|
+
const baseMaxWidth = measureIconValueWidth(iconFontSize);
|
|
1451
|
+
if (baseMaxWidth > effectiveMaxWidth) {
|
|
1452
|
+
// Binary search để tìm font size lớn nhất mà vẫn vừa
|
|
1453
|
+
let left = MIN_ICON_VALUE_FONT_SIZE;
|
|
1454
|
+
let right = iconFontSize;
|
|
1455
|
+
let bestFontSize = MIN_ICON_VALUE_FONT_SIZE;
|
|
1456
|
+
while (right - left > 0.1) {
|
|
1457
|
+
const mid = (left + right) / 2;
|
|
1458
|
+
if (checkFontSizeFits(mid)) {
|
|
1459
|
+
bestFontSize = mid;
|
|
1460
|
+
left = mid;
|
|
1461
|
+
}
|
|
1462
|
+
else {
|
|
1463
|
+
right = mid;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
if (checkFontSizeFits(bestFontSize)) {
|
|
1467
|
+
// Bước 1 thành công: font size đã shrink vừa chiều ngang
|
|
1468
|
+
effectiveIconValueFontSize = Math.floor(bestFontSize);
|
|
1469
|
+
}
|
|
1470
|
+
else {
|
|
1471
|
+
// Bước 1 thất bại: đã shrink đến MIN nhưng vẫn không vừa, sang bước 2
|
|
1346
1472
|
needsWrap = true;
|
|
1347
|
-
effectiveIconValueFontSize =
|
|
1473
|
+
effectiveIconValueFontSize = iconFontSize;
|
|
1348
1474
|
}
|
|
1349
1475
|
}
|
|
1350
|
-
//
|
|
1351
|
-
const valueLineHeight = effectiveIconValueFontSize;
|
|
1352
|
-
let allWrappedLines = [];
|
|
1353
|
-
// Text align center: căn giữa theo chiều dọc trong block
|
|
1354
|
-
const textCenterY = cursorY + iconImageHeight / 2;
|
|
1355
|
-
const valueStartX = x + labelWidth;
|
|
1356
|
-
if (needsWrap) {
|
|
1357
|
-
// Dùng wrap text logic
|
|
1358
|
-
const wrappedLines = buildWrappedLines(ctx, iconValue, availableWidth, valueStartX, textCenterY, valueLineHeight, mockupBounds);
|
|
1359
|
-
allWrappedLines = wrappedLines;
|
|
1360
|
-
wrappedLines.length * valueLineHeight;
|
|
1361
|
-
}
|
|
1362
|
-
else {
|
|
1363
|
-
// Không cần wrap, chỉ một dòng
|
|
1364
|
-
allWrappedLines = [iconValue];
|
|
1365
|
-
}
|
|
1366
|
-
// Vẽ label với textBaseline = middle để align center với value
|
|
1476
|
+
// Bước 2: Nếu bước 1 thất bại, xuống dòng với font size gốc
|
|
1367
1477
|
ctx.textBaseline = "middle";
|
|
1368
1478
|
ctx.font = `bold ${iconFontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1369
1479
|
ctx.fillStyle = LAYOUT.LABEL_COLOR;
|
|
1370
1480
|
ctx.fillText(iconLabel, x, textCenterY);
|
|
1371
|
-
// Vẽ icon value với align center
|
|
1372
1481
|
ctx.font = `${effectiveIconValueFontSize}px ${LAYOUT.FONT_FAMILY}`;
|
|
1373
1482
|
ctx.fillStyle = DEFAULT_ERROR_COLOR;
|
|
1374
1483
|
let maxValueLineWidth = 0;
|
|
1375
|
-
|
|
1484
|
+
let totalTextHeight = iconImageHeight;
|
|
1376
1485
|
if (needsWrap) {
|
|
1377
|
-
//
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
if (w > maxValueLineWidth)
|
|
1393
|
-
maxValueLineWidth = w;
|
|
1394
|
-
}
|
|
1395
|
-
else {
|
|
1396
|
-
ctx.fillText(line, valueStartX, lineY);
|
|
1397
|
-
const w = ctx.measureText(line).width;
|
|
1398
|
-
if (w > maxValueLineWidth)
|
|
1399
|
-
maxValueLineWidth = w;
|
|
1486
|
+
// Bước 2: Xuống dòng với font size gốc
|
|
1487
|
+
const wrappedLines = buildWrappedLines(ctx, iconValue, effectiveMaxWidth, valueStartX, textTopY, lineHeight, mockupBounds);
|
|
1488
|
+
// Tính height dựa trên số dòng thực tế
|
|
1489
|
+
totalTextHeight = Math.max(iconImageHeight, wrappedLines.length * lineHeight);
|
|
1490
|
+
wrappedLines.forEach((line, index) => {
|
|
1491
|
+
const lineTopY = textTopY + index * lineHeight;
|
|
1492
|
+
const lineCenterY = lineTopY + lineHeight / 2;
|
|
1493
|
+
const lineEffectiveMaxWidth = mockupBounds
|
|
1494
|
+
? getEffectiveMaxWidth(valueStartX, lineTopY, lineHeight, availableWidth, mockupBounds)
|
|
1495
|
+
: availableWidth;
|
|
1496
|
+
let lineToRender = line;
|
|
1497
|
+
const lineWidth = ctx.measureText(lineToRender).width;
|
|
1498
|
+
if (lineWidth > lineEffectiveMaxWidth) {
|
|
1499
|
+
while (ctx.measureText(lineToRender).width > lineEffectiveMaxWidth && lineToRender.length > 0) {
|
|
1500
|
+
lineToRender = lineToRender.slice(0, -1);
|
|
1400
1501
|
}
|
|
1401
1502
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
maxValueLineWidth = w;
|
|
1407
|
-
}
|
|
1503
|
+
ctx.fillText(lineToRender, valueStartX, lineCenterY);
|
|
1504
|
+
const w = ctx.measureText(lineToRender).width;
|
|
1505
|
+
if (w > maxValueLineWidth)
|
|
1506
|
+
maxValueLineWidth = w;
|
|
1408
1507
|
});
|
|
1409
1508
|
}
|
|
1410
1509
|
else {
|
|
1411
|
-
//
|
|
1510
|
+
// Bước 1 thành công: Render với font size đã shrink (1 dòng)
|
|
1511
|
+
const shrunkTextTopY = textCenterY - effectiveIconValueFontSize / 2;
|
|
1512
|
+
const shrunkLineHeight = effectiveIconValueFontSize;
|
|
1513
|
+
const shrunkEffectiveMaxWidth = mockupBounds
|
|
1514
|
+
? getEffectiveMaxWidth(valueStartX, shrunkTextTopY, shrunkLineHeight, availableWidth, mockupBounds)
|
|
1515
|
+
: availableWidth;
|
|
1412
1516
|
const lineText = ` ${iconValue}`;
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
// Cắt text cho đến khi vừa với effectiveMaxWidth
|
|
1419
|
-
let truncatedLine = lineText;
|
|
1420
|
-
while (ctx.measureText(truncatedLine).width > effectiveMaxWidth && truncatedLine.length > 0) {
|
|
1421
|
-
truncatedLine = truncatedLine.slice(0, -1);
|
|
1422
|
-
}
|
|
1423
|
-
ctx.fillText(truncatedLine, valueStartX, textCenterY);
|
|
1424
|
-
const w = ctx.measureText(truncatedLine).width;
|
|
1425
|
-
if (w > maxValueLineWidth)
|
|
1426
|
-
maxValueLineWidth = w;
|
|
1427
|
-
}
|
|
1428
|
-
else {
|
|
1429
|
-
ctx.fillText(lineText, valueStartX, textCenterY);
|
|
1430
|
-
const w = ctx.measureText(lineText).width;
|
|
1431
|
-
if (w > maxValueLineWidth)
|
|
1432
|
-
maxValueLineWidth = w;
|
|
1517
|
+
let lineToRender = lineText;
|
|
1518
|
+
const lineWidth = ctx.measureText(lineToRender).width;
|
|
1519
|
+
if (lineWidth > shrunkEffectiveMaxWidth) {
|
|
1520
|
+
while (ctx.measureText(lineToRender).width > shrunkEffectiveMaxWidth && lineToRender.length > 0) {
|
|
1521
|
+
lineToRender = lineToRender.slice(0, -1);
|
|
1433
1522
|
}
|
|
1434
1523
|
}
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
maxValueLineWidth = w;
|
|
1440
|
-
}
|
|
1524
|
+
ctx.fillText(lineToRender, valueStartX, textCenterY);
|
|
1525
|
+
const w = ctx.measureText(lineToRender).width;
|
|
1526
|
+
if (w > maxValueLineWidth)
|
|
1527
|
+
maxValueLineWidth = w;
|
|
1441
1528
|
}
|
|
1442
1529
|
ctx.fillStyle = LAYOUT.LABEL_COLOR;
|
|
1443
1530
|
// Reset textBaseline về top cho các phần tiếp theo
|
|
1444
1531
|
ctx.textBaseline = LAYOUT.TEXT_BASELINE;
|
|
1445
1532
|
const iconResult = {
|
|
1446
|
-
height:
|
|
1533
|
+
height: totalTextHeight + lineGap,
|
|
1447
1534
|
// tổng width của cả label + value, dùng để canh icon image lệch sang phải
|
|
1448
1535
|
lastLineWidth: labelWidth + maxValueLineWidth};
|
|
1449
1536
|
// Kiểm tra xem phần icon image có vượt quá canvas không trước khi render
|