maidraw 0.10.4 → 0.11.0

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.
Files changed (81) hide show
  1. package/README.md +17 -0
  2. package/assets/themes/chunithm/chart/common/versionless/logo/jpn/240.png +0 -0
  3. package/assets/themes/chunithm/chart/jp/verse/manifest.json +8 -8
  4. package/assets/themes/ongeki/{jp → best/jp}/brightMemoryLandscape/classic/manifest.json +2 -2
  5. package/assets/themes/ongeki/{jp → best/jp}/brightMemoryLandscape/refresh/manifest.json +2 -2
  6. package/assets/themes/ongeki/{jp → best/jp}/refreshLandscape/classic/manifest.json +2 -2
  7. package/assets/themes/ongeki/{jp → best/jp}/refreshLandscape/refresh/manifest.json +2 -2
  8. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/100.png +0 -0
  9. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/105.png +0 -0
  10. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/110.png +0 -0
  11. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/115.png +0 -0
  12. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/120.png +0 -0
  13. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/125.png +0 -0
  14. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/130.png +0 -0
  15. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/135.png +0 -0
  16. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/140.png +0 -0
  17. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/145.png +0 -0
  18. package/assets/themes/ongeki/chart/common/versionless/logo/jpn/150.png +0 -0
  19. package/assets/themes/ongeki/chart/jp/refresh/manifest.json +151 -0
  20. package/dist/chu/lib/adapter/lxns/index.d.ts +18 -8
  21. package/dist/chu/lib/adapter/lxns/index.js +15 -16
  22. package/dist/chu/lib/adapter/lxns/index.js.map +1 -1
  23. package/dist/chu/painter/chart/index.d.ts +3 -39
  24. package/dist/chu/painter/chart/index.js +5 -2
  25. package/dist/chu/painter/chart/index.js.map +1 -1
  26. package/dist/chu/painter/index.d.ts +3 -39
  27. package/dist/chu/painter/index.js +66 -100
  28. package/dist/chu/painter/index.js.map +1 -1
  29. package/dist/geki/index.d.ts +2 -0
  30. package/dist/geki/index.js +2 -0
  31. package/dist/geki/index.js.map +1 -1
  32. package/dist/geki/lib/adapter/index.d.ts +7 -0
  33. package/dist/geki/lib/adapter/index.js.map +1 -1
  34. package/dist/geki/lib/adapter/kamaiTachi/index.d.ts +7 -0
  35. package/dist/geki/lib/adapter/kamaiTachi/index.js +49 -0
  36. package/dist/geki/lib/adapter/kamaiTachi/index.js.map +1 -1
  37. package/dist/geki/lib/database.d.ts +132 -0
  38. package/dist/geki/lib/database.js +87 -12
  39. package/dist/geki/lib/database.js.map +1 -1
  40. package/dist/geki/lib/util.d.ts +99 -0
  41. package/dist/geki/lib/util.js +255 -0
  42. package/dist/geki/lib/util.js.map +1 -0
  43. package/dist/geki/painter/chart/index.d.ts +156 -0
  44. package/dist/geki/painter/chart/index.js +128 -0
  45. package/dist/geki/painter/chart/index.js.map +1 -0
  46. package/dist/geki/painter/index.d.ts +92 -0
  47. package/dist/geki/painter/index.js +812 -7
  48. package/dist/geki/painter/index.js.map +1 -1
  49. package/dist/lib/painter.js +2 -0
  50. package/dist/lib/painter.js.map +1 -1
  51. package/dist/mai/painter/chart/index.d.ts +4 -41
  52. package/dist/mai/painter/index.d.ts +4 -41
  53. package/dist/mai/painter/index.js +55 -96
  54. package/dist/mai/painter/index.js.map +1 -1
  55. package/package.json +1 -1
  56. /package/assets/themes/ongeki/{common → best/common}/brightmemory/background.png +0 -0
  57. /package/assets/themes/ongeki/{common → best/common}/brightmemory/logo.png +0 -0
  58. /package/assets/themes/ongeki/{common → best/common}/refresh/background.png +0 -0
  59. /package/assets/themes/ongeki/{common → best/common}/refresh/logo.png +0 -0
  60. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/a.png +0 -0
  61. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/aa.png +0 -0
  62. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/aaa.png +0 -0
  63. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/b.png +0 -0
  64. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/bb.png +0 -0
  65. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/bbb.png +0 -0
  66. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/c.png +0 -0
  67. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/d.png +0 -0
  68. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/s.png +0 -0
  69. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/ss.png +0 -0
  70. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/sss.png +0 -0
  71. /package/assets/themes/ongeki/{common → best/common}/versionless/achievement/sssp.png +0 -0
  72. /package/assets/themes/ongeki/{common → best/common}/versionless/emote.png +0 -0
  73. /package/assets/themes/ongeki/{common → best/common}/versionless/icon.png +0 -0
  74. /package/assets/themes/ongeki/{common → best/common}/versionless/milestone/ab.png +0 -0
  75. /package/assets/themes/ongeki/{common → best/common}/versionless/milestone/abp.png +0 -0
  76. /package/assets/themes/ongeki/{common → best/common}/versionless/milestone/fb.png +0 -0
  77. /package/assets/themes/ongeki/{common → best/common}/versionless/milestone/fc.png +0 -0
  78. /package/assets/themes/ongeki/{common → best/common}/versionless/numberMap.png +0 -0
  79. /package/assets/themes/ongeki/{common → best/common}/versionless/userplateAF2025.png +0 -0
  80. /package/assets/themes/ongeki/{common → best/common}/versionless/userplateIchigeki.png +0 -0
  81. /package/assets/themes/ongeki/{common → best/common}/versionless/void.png +0 -0
@@ -4,14 +4,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.OngekiPainterModule = exports.OngekiPainter = void 0;
7
+ const lodash_1 = __importDefault(require("lodash"));
7
8
  const sharp_1 = __importDefault(require("sharp"));
8
9
  const color_1 = __importDefault(require("color"));
9
10
  const v4_1 = require("zod/v4");
11
+ const linebreak_1 = __importDefault(require("linebreak"));
10
12
  const canvas_1 = require("canvas");
11
13
  const database_1 = require("../lib/database");
12
14
  const type_1 = require("../type");
13
15
  const util_1 = require("../../lib/util");
14
16
  const painter_1 = require("../../lib/painter");
17
+ const util_2 = require("../lib/util");
15
18
  class OngekiPainter extends painter_1.Painter {
16
19
  constructor({ theme: { schema, searchPaths, defaultTheme }, }) {
17
20
  super({ theme: { schema, searchPaths, defaultTheme } });
@@ -264,12 +267,6 @@ var OngekiPainterModule;
264
267
  ctx.fillStyle = jacketMaskGrad;
265
268
  ctx.fillRect(x + jacketSize / 2, y, (jacketSize * 3) / 4, jacketSize);
266
269
  } /** End Jacket Gradient Mask Draw*/
267
- ctx.beginPath();
268
- ctx.roundRect(x + element.scoreBubble.margin, y + element.scoreBubble.margin, element.scoreBubble.width -
269
- element.scoreBubble.margin * 2, element.scoreBubble.height * 0.806 -
270
- element.scoreBubble.margin * 2, (element.scoreBubble.height * 0.806 -
271
- element.scoreBubble.margin * 2) /
272
- 7);
273
270
  /** Begin Title Draw */ {
274
271
  util_1.Util.drawText(ctx, score.chart.name, x + (jacketSize * 7) / 8, y +
275
272
  element.scoreBubble.margin +
@@ -285,7 +282,7 @@ var OngekiPainterModule;
285
282
  0.806 *
286
283
  (0.144 + 0.072), element.scoreBubble.width -
287
284
  (jacketSize * 13) / 16 -
288
- element.scoreBubble.margin * 2, element.scoreBubble.height * 0.806 * 0.02, element.scoreBubble.height * 0.806 * 0.16);
285
+ element.scoreBubble.margin, element.scoreBubble.height * 0.806 * 0.02, (element.scoreBubble.height * 0.806 * 0.02) / 2);
289
286
  ctx.fillStyle = jacketMaskGradDark;
290
287
  ctx.fill();
291
288
  } /** End Separation Line Draw */
@@ -376,6 +373,7 @@ var OngekiPainterModule;
376
373
  const comboBackground = comboWidth * 0.9;
377
374
  const comboBgRatio = 64 / 272;
378
375
  const sizeDiff = comboWidth - comboBackground;
376
+ ctx.beginPath();
379
377
  ctx.fillStyle = "#e8eaec";
380
378
  ctx.roundRect(x +
381
379
  sizeDiff / 2 +
@@ -444,5 +442,812 @@ var OngekiPainterModule;
444
442
  ScoreGrid.draw = draw;
445
443
  })(ScoreGrid = Best50.ScoreGrid || (Best50.ScoreGrid = {}));
446
444
  })(Best50 = OngekiPainterModule.Best50 || (OngekiPainterModule.Best50 = {}));
445
+ let Chart;
446
+ (function (Chart) {
447
+ const JPN_LATEST = 150;
448
+ const INT_LATEST = 0;
449
+ const CHN_LATEST = 0;
450
+ const ONGEKI_VERSIONS = [
451
+ 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100,
452
+ ];
453
+ const ONGEKI_INT_VERSIONS = [];
454
+ const YINJI_VERSIONS = [];
455
+ function findVersion(v, region) {
456
+ const target = (() => {
457
+ switch (region) {
458
+ case "INT":
459
+ return ONGEKI_INT_VERSIONS;
460
+ case "CHN":
461
+ return YINJI_VERSIONS;
462
+ case "JPN":
463
+ default:
464
+ return ONGEKI_VERSIONS;
465
+ }
466
+ })();
467
+ for (const version of target) {
468
+ if (v >= version)
469
+ return version;
470
+ }
471
+ return null;
472
+ }
473
+ let ChartGrid;
474
+ (function (ChartGrid) {
475
+ ChartGrid.schema = painter_1.ThemeManager.Element.extend({
476
+ type: v4_1.z.literal("chart-grid"),
477
+ width: v4_1.z.number().min(1),
478
+ height: v4_1.z.number().min(1),
479
+ margin: v4_1.z.number().min(0),
480
+ gap: v4_1.z.number().min(0),
481
+ bubble: v4_1.z.object({
482
+ margin: v4_1.z.number().min(0),
483
+ color: v4_1.z.object({
484
+ basic: util_1.Util.z.color(),
485
+ advanced: util_1.Util.z.color(),
486
+ expert: util_1.Util.z.color(),
487
+ master: util_1.Util.z.color(),
488
+ lunatic: util_1.Util.z.color(),
489
+ }),
490
+ }),
491
+ color: v4_1.z.object({
492
+ card: util_1.Util.z.color(),
493
+ }),
494
+ sprites: v4_1.z.object({
495
+ achievement: v4_1.z.object({
496
+ d: v4_1.z.string(),
497
+ c: v4_1.z.string(),
498
+ b: v4_1.z.string(),
499
+ bb: v4_1.z.string(),
500
+ bbb: v4_1.z.string(),
501
+ a: v4_1.z.string(),
502
+ aa: v4_1.z.string(),
503
+ aaa: v4_1.z.string(),
504
+ s: v4_1.z.string(),
505
+ ss: v4_1.z.string(),
506
+ sss: v4_1.z.string(),
507
+ sssp: v4_1.z.string(),
508
+ }),
509
+ milestone: v4_1.z.object({
510
+ ab: v4_1.z.string(),
511
+ abp: v4_1.z.string(),
512
+ fc: v4_1.z.string(),
513
+ fb: v4_1.z.string(),
514
+ none: v4_1.z.string(),
515
+ }),
516
+ versions: v4_1.z.object({
517
+ JPN: v4_1.z.record(v4_1.z.string(), v4_1.z.string()),
518
+ }),
519
+ }),
520
+ });
521
+ async function draw(ctx, theme, element, chartId, scores, region = "JPN") {
522
+ /* Begin Background Draw */
523
+ ctx.roundRect(element.x, element.y, element.width, element.height, Math.min(theme.content.width, theme.content.height) *
524
+ (3 / 128));
525
+ ctx.fillStyle = element.color.card;
526
+ ctx.strokeStyle = new color_1.default(element.color.card)
527
+ .darken(0.6)
528
+ .hex();
529
+ ctx.lineWidth =
530
+ Math.min(theme.content.width, theme.content.height) *
531
+ (3 / 512);
532
+ ctx.stroke();
533
+ ctx.fill();
534
+ /* End Background Draw */
535
+ const difficulties = [];
536
+ for (let i = type_1.EDifficulty.BASIC; i <= type_1.EDifficulty.LUNATIC; ++i) {
537
+ const chart = database_1.Database.getLocalChart(chartId, i);
538
+ if (chart)
539
+ difficulties.push(chart);
540
+ }
541
+ const cardWidth = element.width - element.margin * 2;
542
+ const cardHeight = (element.height - element.margin * 2 - element.gap * 3) / 4;
543
+ for (let y = element.y + element.margin, i = 0; i < difficulties.length; ++i, y += cardHeight + element.gap) {
544
+ const chart = difficulties[i];
545
+ if (chart)
546
+ if (difficulties.length > 4 && i == 0) {
547
+ await drawChartGridCard(ctx, theme, element, chart, element.x + element.margin, y, (cardWidth - element.margin) / 2, cardHeight, true, region, scores[i]);
548
+ i++;
549
+ const chartA = difficulties[i];
550
+ if (chartA)
551
+ await drawChartGridCard(ctx, theme, element, chartA, element.x +
552
+ element.margin +
553
+ (cardWidth + element.margin) / 2, y, (cardWidth - element.margin) / 2, cardHeight, true, region, scores[i]);
554
+ }
555
+ else {
556
+ await drawChartGridCard(ctx, theme, element, chart, element.x + element.margin, y, cardWidth, cardHeight, false, region, scores[i]);
557
+ }
558
+ }
559
+ }
560
+ ChartGrid.draw = draw;
561
+ async function drawChartGridCard(ctx, theme, element, chart, x, y, width, height, isShort, targetRegion = "JPN", score) {
562
+ let curColor = "#FFFFFF";
563
+ switch (chart.difficulty) {
564
+ case type_1.EDifficulty.BASIC:
565
+ curColor = element.bubble.color.basic;
566
+ break;
567
+ case type_1.EDifficulty.ADVANCED:
568
+ curColor = element.bubble.color.advanced;
569
+ break;
570
+ case type_1.EDifficulty.EXPERT:
571
+ curColor = element.bubble.color.expert;
572
+ break;
573
+ case type_1.EDifficulty.MASTER:
574
+ curColor = element.bubble.color.master;
575
+ break;
576
+ case type_1.EDifficulty.LUNATIC:
577
+ curColor = element.bubble.color.lunatic;
578
+ break;
579
+ }
580
+ /** Begin Card Draw */
581
+ ctx.save();
582
+ ctx.fillStyle = new color_1.default(curColor).lighten(0.4).hexa();
583
+ ctx.beginPath();
584
+ ctx.roundRect(x, y, width, height, (height * 0.806) / 7);
585
+ ctx.strokeStyle = new color_1.default(curColor).darken(0.3).hexa();
586
+ ctx.lineWidth = element.bubble.margin / 4;
587
+ ctx.stroke();
588
+ ctx.fill();
589
+ ctx.beginPath();
590
+ ctx.roundRect(x, y, width, height, (height * 0.806) / 7);
591
+ ctx.clip();
592
+ /** Begin Main Content Draw */
593
+ {
594
+ ctx.save();
595
+ ctx.beginPath();
596
+ ctx.rect(x, y, width, height);
597
+ ctx.clip();
598
+ ctx.fillStyle = curColor;
599
+ ctx.fill();
600
+ const titleSize = height * (47 / 256);
601
+ /** Begin Difficulty Text & Separation Line Draw */
602
+ {
603
+ let difficultiy = "";
604
+ switch (chart.difficulty) {
605
+ case type_1.EDifficulty.BASIC:
606
+ difficultiy = "BASIC";
607
+ break;
608
+ case type_1.EDifficulty.ADVANCED:
609
+ difficultiy = "ADVANCED";
610
+ break;
611
+ case type_1.EDifficulty.EXPERT:
612
+ difficultiy = "EXPERT";
613
+ break;
614
+ case type_1.EDifficulty.MASTER:
615
+ difficultiy = "MASTER";
616
+ break;
617
+ case type_1.EDifficulty.LUNATIC:
618
+ difficultiy = "LUNATIC";
619
+ break;
620
+ }
621
+ const levelTextSize = titleSize * (5 / 8);
622
+ util_1.Util.drawText(ctx, difficultiy, x + element.bubble.margin, y +
623
+ element.bubble.margin +
624
+ titleSize -
625
+ element.bubble.margin * (1 / 4), titleSize, height * 0.806 * 0.04, Infinity, "left", "white", new color_1.default(curColor).darken(0.3).hexa());
626
+ const difficultyTextWidth = util_1.Util.measureText(ctx, difficultiy, titleSize, Infinity).width;
627
+ util_1.Util.drawText(ctx, `Lv. ${util_1.Util.truncate(chart.events
628
+ .filter((v) => v.version.region == targetRegion)
629
+ .reverse()
630
+ .find((v) => v.type == "existence")?.data
631
+ .level || 0, 1)}${score ? ` ↑${util_1.Util.truncate(score.rating, 1)}` : ""}`, x + element.bubble.margin * 2 + difficultyTextWidth, y +
632
+ element.bubble.margin +
633
+ titleSize -
634
+ element.bubble.margin * (1 / 4), levelTextSize, height * 0.806 * 0.04, Infinity, "left", "white", new color_1.default(curColor).darken(0.3).hexa());
635
+ ctx.beginPath();
636
+ ctx.roundRect(x + element.bubble.margin, y +
637
+ element.bubble.margin +
638
+ titleSize +
639
+ element.bubble.margin * (1 / 4), height * 2 - element.bubble.margin * 2, height * 0.806 * 0.02, height * 0.806 * 0.16);
640
+ ctx.fillStyle = new color_1.default(curColor).darken(0.3).hex();
641
+ ctx.fill();
642
+ }
643
+ /** End Difficulty Text & Separation Line Draw */
644
+ /** Begin Achievement Rate Draw */
645
+ {
646
+ const scoreSize = height * 0.806 * 0.208;
647
+ util_1.Util.drawText(ctx, score ? util_1.Util.truncate(score.score, 0) : "NO RECORD", x +
648
+ height * 2 -
649
+ element.bubble.margin -
650
+ height * 0.806 * 0.02, y +
651
+ element.bubble.margin +
652
+ titleSize +
653
+ element.bubble.margin * (5 / 8) +
654
+ scoreSize, scoreSize, height * 0.806 * 0.04, Infinity, "right", "white", new color_1.default(curColor).darken(0.3).hexa());
655
+ }
656
+ /** End Achievement Rate Draw */
657
+ /** Begin Achievement Rank Draw */
658
+ {
659
+ if (score) {
660
+ let rankImg;
661
+ switch (score.rank) {
662
+ case type_1.EAchievementTypes.D:
663
+ rankImg = theme.getFile(element.sprites.achievement.d);
664
+ break;
665
+ case type_1.EAchievementTypes.C:
666
+ rankImg = theme.getFile(element.sprites.achievement.c);
667
+ break;
668
+ case type_1.EAchievementTypes.B:
669
+ rankImg = theme.getFile(element.sprites.achievement.b);
670
+ break;
671
+ case type_1.EAchievementTypes.BB:
672
+ rankImg = theme.getFile(element.sprites.achievement.bb);
673
+ break;
674
+ case type_1.EAchievementTypes.BBB:
675
+ rankImg = theme.getFile(element.sprites.achievement.bbb);
676
+ break;
677
+ case type_1.EAchievementTypes.A:
678
+ rankImg = theme.getFile(element.sprites.achievement.a);
679
+ break;
680
+ case type_1.EAchievementTypes.AA:
681
+ rankImg = theme.getFile(element.sprites.achievement.aa);
682
+ break;
683
+ case type_1.EAchievementTypes.AAA:
684
+ rankImg = theme.getFile(element.sprites.achievement.aaa);
685
+ break;
686
+ case type_1.EAchievementTypes.S:
687
+ rankImg = theme.getFile(element.sprites.achievement.s);
688
+ break;
689
+ case type_1.EAchievementTypes.SS:
690
+ rankImg = theme.getFile(element.sprites.achievement.ss);
691
+ break;
692
+ case type_1.EAchievementTypes.SSS:
693
+ rankImg = theme.getFile(element.sprites.achievement.sss);
694
+ break;
695
+ default:
696
+ rankImg = theme.getFile(element.sprites.achievement.sssp);
697
+ }
698
+ const achievementRankHeight = height * 0.806 * 0.3 * 0.85;
699
+ const achievementRankWidth = achievementRankHeight * (286 / 143);
700
+ const img = new canvas_1.Image();
701
+ img.src = rankImg;
702
+ ctx.drawImage(img, x + element.bubble.margin * (1 / 2), y +
703
+ element.bubble.margin +
704
+ titleSize +
705
+ element.bubble.margin * (1 / 2), achievementRankWidth, achievementRankHeight);
706
+ /** End Achievement Rank Draw */
707
+ /** Begin Milestone Draw */
708
+ const comboImgRatio = 84 / 290;
709
+ const comboBgRatio = 64 / 272;
710
+ const comboWidth = achievementRankHeight / comboImgRatio;
711
+ const comboBackground = comboWidth * 0.9;
712
+ const sizeDiff = comboWidth - comboBackground;
713
+ const curX = x +
714
+ element.bubble.margin * (1 / 2) +
715
+ achievementRankWidth, curY = y +
716
+ element.bubble.margin * (3 / 2) +
717
+ titleSize;
718
+ ctx.beginPath();
719
+ ctx.fillStyle = "#e8eaec";
720
+ ctx.roundRect(curX + sizeDiff / 2, curY + ((sizeDiff * 3) / 2) * comboBgRatio, comboBackground, comboBackground * comboBgRatio, (comboBackground * comboBgRatio) / 2);
721
+ ctx.roundRect(curX + sizeDiff / 2, curY +
722
+ comboWidth * comboImgRatio +
723
+ sizeDiff * (1 / 2) * comboBgRatio, comboBackground, comboBackground * comboBgRatio, (comboBackground * comboBgRatio) / 2);
724
+ ctx.fill();
725
+ let comboImg;
726
+ switch (score.combo) {
727
+ case type_1.EComboTypes.NONE:
728
+ comboImg = theme.getFile(element.sprites.milestone.none);
729
+ break;
730
+ case type_1.EComboTypes.FULL_COMBO:
731
+ comboImg = theme.getFile(element.sprites.milestone.fc);
732
+ break;
733
+ case type_1.EComboTypes.ALL_BREAK:
734
+ comboImg = theme.getFile(element.sprites.milestone.ab);
735
+ break;
736
+ case type_1.EComboTypes.ALL_BREAK_PLUS:
737
+ comboImg = theme.getFile(element.sprites.milestone.abp);
738
+ break;
739
+ }
740
+ let bellImg;
741
+ switch (score.bell) {
742
+ case type_1.EBellTypes.NONE:
743
+ bellImg = theme.getFile(element.sprites.milestone.none);
744
+ break;
745
+ case type_1.EBellTypes.FULL_BELL:
746
+ bellImg = theme.getFile(element.sprites.milestone.fb);
747
+ break;
748
+ }
749
+ const combo = new canvas_1.Image();
750
+ combo.src = comboImg;
751
+ const bell = new canvas_1.Image();
752
+ bell.src = bellImg;
753
+ ctx.drawImage(combo, curX, curY, comboWidth, comboWidth * comboImgRatio);
754
+ ctx.drawImage(bell, curX, curY +
755
+ comboWidth * comboImgRatio -
756
+ sizeDiff * comboBgRatio, comboWidth, comboWidth * comboImgRatio);
757
+ }
758
+ }
759
+ /** End Milestone Draw */
760
+ /** Begin Version Draw */
761
+ {
762
+ const version = {
763
+ region: "JPN",
764
+ version: undefined,
765
+ };
766
+ const VER = chart.difficulty == type_1.EDifficulty.LUNATIC
767
+ ? chart.events.find((v) => v.type == "existence" &&
768
+ v.version.region == targetRegion)?.version
769
+ : chart.addVersion;
770
+ version.version = VER;
771
+ version.region = targetRegion;
772
+ const versionImageHeight = (height - element.bubble.margin * 2) *
773
+ (isShort ? 5 / 8 : 1 / 2);
774
+ const versionImageWidth = (versionImageHeight / 270) * 360;
775
+ const curx = x + width - element.bubble.margin, cury = y + element.bubble.margin;
776
+ if (version.version) {
777
+ const rawVersion = findVersion(util_2.OngekiUtil.getNumberVersion(version.version), targetRegion);
778
+ if (rawVersion) {
779
+ const versionImage = theme.getFile(element.sprites.versions[version.region][rawVersion]);
780
+ try {
781
+ (0, sharp_1.default)(versionImage);
782
+ if (versionImage) {
783
+ const versionImg = new canvas_1.Image();
784
+ versionImg.src = versionImage;
785
+ ctx.drawImage(versionImg, curx - versionImageWidth, cury, versionImageWidth, versionImageHeight);
786
+ }
787
+ }
788
+ catch { }
789
+ }
790
+ }
791
+ /** End Version Draw */
792
+ /** Begin Note Count Draw */
793
+ const noteCountTexts = Object.entries(chart.meta.notes).map(([k, v]) => `${util_1.Util.capitalize(k)}: ${v}`);
794
+ const noteCountTextSize = (height - element.bubble.margin * 4) /
795
+ noteCountTexts.length;
796
+ let noteCountLength = 0;
797
+ noteCountTexts.forEach((v, i) => {
798
+ util_1.Util.drawText(ctx, v, x +
799
+ element.bubble.margin * (3 / 2) +
800
+ height * 2, y +
801
+ element.bubble.margin +
802
+ noteCountTextSize +
803
+ (noteCountTextSize +
804
+ (element.bubble.margin * 2) /
805
+ (noteCountTexts.length - 1)) *
806
+ i, noteCountTextSize, height * 0.806 * 0.04, Infinity, "left", "white", new color_1.default(curColor).darken(0.3).hexa());
807
+ const length = util_1.Util.measureText(ctx, v, noteCountTextSize, Infinity).width;
808
+ if (length > noteCountLength)
809
+ noteCountLength = length;
810
+ });
811
+ /** End Note Count Draw */
812
+ /** Begin Internal Level Trend Draw */
813
+ if (!isShort) {
814
+ const CURRENT_VER = (() => {
815
+ switch (targetRegion) {
816
+ // case "INT":
817
+ // return INT_LATEST;
818
+ // case "CHN":
819
+ // return CHN_LATEST;
820
+ case "JPN":
821
+ default:
822
+ return JPN_LATEST;
823
+ }
824
+ })();
825
+ const maxWidth = width -
826
+ height * 2 -
827
+ element.bubble.margin * 4 -
828
+ noteCountLength -
829
+ versionImageWidth;
830
+ const maxFitTrendCount = Math.trunc(maxWidth / versionImageWidth);
831
+ const trendEvents = chart.events.filter((v) => v.type == "existence" &&
832
+ v.version.region == targetRegion);
833
+ let actualEvents = lodash_1.default.uniqWith(trendEvents, (a, b) => {
834
+ return lodash_1.default.isEqual(a.data.level, b.data.level);
835
+ });
836
+ if (actualEvents.length == maxFitTrendCount) {
837
+ }
838
+ else if (actualEvents.length > maxFitTrendCount) {
839
+ while (actualEvents.length > maxFitTrendCount)
840
+ actualEvents.shift();
841
+ actualEvents.shift();
842
+ actualEvents.shift();
843
+ actualEvents.unshift(trendEvents[0]);
844
+ actualEvents.push(trendEvents[trendEvents.length - 1]);
845
+ }
846
+ else if (trendEvents.length > maxFitTrendCount) {
847
+ actualEvents = lodash_1.default.filter(actualEvents, (v) => !(lodash_1.default.isEqual(v.version.gameVersion, trendEvents[0].version
848
+ .gameVersion) ||
849
+ lodash_1.default.isEqual(v.version.gameVersion, trendEvents[trendEvents.length - 1].version.gameVersion)));
850
+ for (let i = trendEvents.length - 2; i > 0 &&
851
+ actualEvents.length < maxFitTrendCount - 2; --i) {
852
+ const event = trendEvents[i];
853
+ if (event)
854
+ actualEvents.push(event);
855
+ actualEvents = lodash_1.default.uniqWith(actualEvents, (a, b) => {
856
+ return (lodash_1.default.isEqual(a.version.gameVersion.major, b.version.gameVersion.major) &&
857
+ lodash_1.default.isEqual(a.version.gameVersion.minor, b.version.gameVersion.minor));
858
+ });
859
+ }
860
+ actualEvents.unshift(trendEvents[0]);
861
+ actualEvents.push(trendEvents[trendEvents.length - 1]);
862
+ actualEvents = lodash_1.default.uniqWith(actualEvents, (a, b) => {
863
+ return (lodash_1.default.isEqual(a.version.gameVersion.major, b.version.gameVersion.major) &&
864
+ lodash_1.default.isEqual(a.version.gameVersion.minor, b.version.gameVersion.minor));
865
+ });
866
+ actualEvents = lodash_1.default.sortBy(actualEvents, (v) => util_2.OngekiUtil.getNumberVersion(v.version));
867
+ if (trendEvents.length > 1) {
868
+ if (actualEvents.length >= maxFitTrendCount)
869
+ actualEvents.pop();
870
+ actualEvents.push(trendEvents[trendEvents.length - 1]);
871
+ }
872
+ const removalEvent = chart.events.find((v) => v.type == "removal" &&
873
+ v.version.region == targetRegion);
874
+ if (removalEvent) {
875
+ actualEvents.pop();
876
+ actualEvents.push(removalEvent);
877
+ }
878
+ }
879
+ else {
880
+ actualEvents = [...trendEvents];
881
+ }
882
+ if (util_2.OngekiUtil.getNumberVersion(actualEvents[actualEvents.length - 1]
883
+ .version) < CURRENT_VER) {
884
+ while (actualEvents.length >= maxFitTrendCount)
885
+ actualEvents.pop();
886
+ actualEvents.push({
887
+ type: "removal",
888
+ version: util_2.OngekiUtil.Version.toEventVersion(util_2.OngekiUtil.Version.getNextVersion(trendEvents[trendEvents.length - 1]
889
+ .version)),
890
+ });
891
+ }
892
+ actualEvents = lodash_1.default.uniqWith(actualEvents, (a, b) => {
893
+ return (lodash_1.default.isEqual(a.version.gameVersion.major, b.version.gameVersion.major) &&
894
+ lodash_1.default.isEqual(a.version.gameVersion.minor, b.version.gameVersion.minor) &&
895
+ lodash_1.default.isEqual(a.type, b.type));
896
+ });
897
+ let positionAdjustment = 0;
898
+ let addGap = (maxWidth -
899
+ actualEvents.length * versionImageWidth) /
900
+ (actualEvents.length - 1);
901
+ if (addGap > maxWidth / 5) {
902
+ addGap = maxWidth / 5;
903
+ positionAdjustment =
904
+ (maxWidth -
905
+ (addGap * (actualEvents.length - 1) +
906
+ versionImageWidth *
907
+ actualEvents.length)) /
908
+ 2;
909
+ }
910
+ for (let i = 0, curx = x +
911
+ positionAdjustment +
912
+ height * 2 +
913
+ element.bubble.margin * (5 / 2) +
914
+ noteCountLength, cury = y +
915
+ element.bubble.margin +
916
+ versionImageHeight * (1 / 2); i < actualEvents.length; ++i) {
917
+ const event = actualEvents[i];
918
+ const rawVersion = findVersion(util_2.OngekiUtil.getNumberVersion(event.version), targetRegion);
919
+ if (rawVersion) {
920
+ const versionImage = theme.getFile(element.sprites.versions[targetRegion][rawVersion]);
921
+ try {
922
+ if (!versionImage)
923
+ throw "No versionImage";
924
+ (0, sharp_1.default)(versionImage);
925
+ const versionImg = new canvas_1.Image();
926
+ versionImg.src = versionImage;
927
+ ctx.drawImage(versionImg, curx, cury, versionImageWidth, versionImageHeight);
928
+ }
929
+ catch {
930
+ const str = `${event.version.gameVersion.major}.${event.version.gameVersion.minor}`;
931
+ const measurement = util_1.Util.measureText(ctx, str, noteCountTextSize * 1.2, Infinity);
932
+ util_1.Util.drawText(ctx, str, curx + versionImageWidth / 2, cury +
933
+ versionImageHeight / 2 -
934
+ (measurement.actualBoundingBoxDescent -
935
+ measurement.actualBoundingBoxAscent) /
936
+ 2, noteCountTextSize * 1.2, height * 0.806 * 0.04, Infinity, "center", "white", new color_1.default(curColor)
937
+ .darken(0.3)
938
+ .hexa());
939
+ }
940
+ if (event.type == "existence") {
941
+ let symbol = "";
942
+ if (i != 0) {
943
+ const lastEvent = actualEvents[i - 1];
944
+ if (lastEvent.type == "existence") {
945
+ if (lastEvent.data.level <
946
+ event.data.level)
947
+ symbol = "↑";
948
+ else if (lastEvent.data.level >
949
+ event.data.level)
950
+ symbol = "↓";
951
+ else if (lastEvent.data.level ==
952
+ event.data.level)
953
+ symbol = "→";
954
+ }
955
+ }
956
+ util_1.Util.drawText(ctx, `${symbol}${util_1.Util.truncate(event.data.level, 1)}`, curx + versionImageWidth / 2, cury +
957
+ versionImageHeight +
958
+ noteCountTextSize, noteCountTextSize, height * 0.806 * 0.04, Infinity, "center", "white", new color_1.default(curColor)
959
+ .darken(0.3)
960
+ .hexa());
961
+ }
962
+ else if (event.type == "removal") {
963
+ util_1.Util.drawText(ctx, `❌`, curx + versionImageWidth / 2, cury +
964
+ versionImageHeight +
965
+ noteCountTextSize, noteCountTextSize, height * 0.806 * 0.04, Infinity, "center", "white", new color_1.default(curColor)
966
+ .darken(0.3)
967
+ .hexa());
968
+ }
969
+ curx += versionImageWidth + addGap;
970
+ }
971
+ }
972
+ }
973
+ }
974
+ /** End Internal Level Trend Draw */
975
+ ctx.restore();
976
+ }
977
+ /** End Main Content Draw */
978
+ ctx.fillStyle = new color_1.default(curColor).lighten(0.4).hexa();
979
+ ctx.beginPath();
980
+ ctx.roundRect(x, y + height * 0.742, height * 2, height * (1 - 0.742), [0, (height * 0.806) / 7, 0, (height * 0.806) / 7]);
981
+ ctx.fill();
982
+ /** Begin Difficulty & Platinum Rating Draw */
983
+ {
984
+ ctx.save();
985
+ ctx.clip();
986
+ util_1.Util.drawText(ctx, chart.designer || "-", x + element.bubble.margin, y + height * (0.806 + (1 - 0.806) / 2), height * 0.806 * 0.128, height * 0.806 * 0.04, Infinity, "left", "white", new color_1.default(curColor).darken(0.3).hexa());
987
+ ctx.restore();
988
+ util_1.Util.drawText(ctx, `${score ? `${score.platinumScore}/` : "MAX PT SCR: "}${chart.meta.maxPlatinumScore}`, x + height * 2 - element.bubble.margin, y + height - element.bubble.margin * 3.1, height * 0.806 * 0.128, height * 0.806 * 0.04, Infinity, "right", "white", new color_1.default(curColor).darken(0.3).hexa());
989
+ }
990
+ /** End Difficulty & Platinum Rating Draw */
991
+ ctx.restore();
992
+ /** End Card Draw */
993
+ }
994
+ })(ChartGrid = Chart.ChartGrid || (Chart.ChartGrid = {}));
995
+ let DetailInfo;
996
+ (function (DetailInfo) {
997
+ DetailInfo.schema = painter_1.ThemeManager.Element.extend({
998
+ type: v4_1.z.literal("detail-info"),
999
+ width: v4_1.z.number().min(1),
1000
+ height: v4_1.z.number().min(1),
1001
+ margin: v4_1.z.number().min(0),
1002
+ color: v4_1.z.object({
1003
+ card: util_1.Util.z.color(),
1004
+ }),
1005
+ });
1006
+ async function draw(ctx, theme, element, chartId) {
1007
+ const jacketMargin = element.margin;
1008
+ const textMargin = element.margin;
1009
+ const backGroundBorderRadius = Math.min(theme.content.width, theme.content.height) *
1010
+ (3 / 128);
1011
+ let chart = null;
1012
+ for (let i = type_1.EDifficulty.BASIC; i <= type_1.EDifficulty.LUNATIC; ++i) {
1013
+ chart = database_1.Database.getLocalChart(chartId, i);
1014
+ if (chart !== null)
1015
+ break;
1016
+ }
1017
+ const jacket = await database_1.Database.fetchJacket(chartId);
1018
+ /* Begin Background Draw */
1019
+ ctx.beginPath();
1020
+ ctx.roundRect(element.x, element.y, element.width, element.height, backGroundBorderRadius);
1021
+ ctx.fillStyle = element.color.card;
1022
+ ctx.strokeStyle = new color_1.default(element.color.card)
1023
+ .darken(0.6)
1024
+ .hex();
1025
+ ctx.lineWidth = backGroundBorderRadius / 4;
1026
+ ctx.stroke();
1027
+ ctx.fill();
1028
+ /* End Background Draw */
1029
+ /* Begin jacket draw */
1030
+ if (jacket) {
1031
+ const jacketImage = new canvas_1.Image();
1032
+ const jacketBorderRadius = backGroundBorderRadius / 2;
1033
+ jacketImage.src = jacket;
1034
+ ctx.beginPath();
1035
+ ctx.roundRect(element.x + jacketMargin, element.y + jacketMargin, element.width - jacketMargin * 2, element.width - jacketMargin * 2, jacketBorderRadius);
1036
+ ctx.save();
1037
+ ctx.clip();
1038
+ ctx.drawImage(jacketImage, element.x + jacketMargin, element.y + jacketMargin, element.width - jacketMargin * 2, element.width - jacketMargin * 2);
1039
+ ctx.restore();
1040
+ }
1041
+ /* End jacket draw */
1042
+ /* Begin Detail Draw */
1043
+ if (chart) {
1044
+ const textSizeTitle = element.width * (1 / 16);
1045
+ const textSizeSecondary = element.width * (1 / 24);
1046
+ const { actualBoundingBoxAscent: ascent, actualBoundingBoxDescent: decent, } = util_1.Util.measureText(ctx, chart.name, textSizeTitle, Infinity);
1047
+ const titleActualHeight = Math.abs(ascent - decent);
1048
+ const textLineWidth = element.width * (7 / 512);
1049
+ const textColor = new color_1.default(element.color.card)
1050
+ .darken(0.5)
1051
+ .hex();
1052
+ const textTitleMaxWidth = element.width - textMargin * 2;
1053
+ const titleMetrics = util_1.Util.measureText(ctx, chart.name, textSizeTitle, textTitleMaxWidth);
1054
+ util_1.Util.drawText(ctx, chart.name, element.x + textMargin, element.y +
1055
+ jacketMargin +
1056
+ textMargin * (1 / 2) +
1057
+ (element.width - jacketMargin * 2) +
1058
+ textSizeTitle, textSizeTitle, textLineWidth, textTitleMaxWidth, "left", "white", textColor);
1059
+ util_1.Util.drawText(ctx, chart.artist, element.x + textMargin, element.y +
1060
+ jacketMargin +
1061
+ textMargin * (1 / 2) +
1062
+ (element.width - jacketMargin * 2) +
1063
+ textSizeTitle * 2, textSizeSecondary, textLineWidth, element.width - textMargin * 2, "left", "white", textColor);
1064
+ function getBpmRange(bpms) {
1065
+ const uniqueBpms = lodash_1.default.uniq(bpms);
1066
+ if (uniqueBpms.length <= 0)
1067
+ return "0";
1068
+ else if (uniqueBpms.length == 1)
1069
+ return `${uniqueBpms[0]}`;
1070
+ else {
1071
+ const minBpm = Math.min(...uniqueBpms);
1072
+ const maxBpm = Math.max(...uniqueBpms);
1073
+ return `${minBpm}-${maxBpm}`;
1074
+ }
1075
+ }
1076
+ util_1.Util.drawText(ctx, `#${chart.id} BPM: ${getBpmRange(chart.bpms)}`, element.x + textMargin, element.y +
1077
+ jacketMargin +
1078
+ textMargin * (1 / 2) +
1079
+ (element.width - jacketMargin * 2) +
1080
+ textSizeTitle * 3, textSizeSecondary, textLineWidth, element.width - textMargin * 2, "left", "white", textColor);
1081
+ const EVENT_JPN = chart.events
1082
+ .filter((v) => v.version.region == "JPN" &&
1083
+ util_2.OngekiUtil.getNumberVersion(v.version) >=
1084
+ JPN_LATEST)
1085
+ .map((v) => v.type);
1086
+ const EVENT_INT = chart.events
1087
+ .filter((v) =>
1088
+ // @ts-expect-error
1089
+ v.version.region == "INT" &&
1090
+ util_2.OngekiUtil.getNumberVersion(v.version) >=
1091
+ INT_LATEST)
1092
+ .map((v) => v.type);
1093
+ const EVENT_CHN = chart.events
1094
+ .filter((v) =>
1095
+ // @ts-expect-error
1096
+ v.version.region == "CHN" &&
1097
+ util_2.OngekiUtil.getNumberVersion(v.version) >=
1098
+ CHN_LATEST)
1099
+ .map((v) => v.type);
1100
+ const EXIST_JPN = EVENT_JPN.includes("existence") &&
1101
+ !EVENT_JPN.includes("removal")
1102
+ ? "🇯🇵"
1103
+ : "";
1104
+ const EXIST_INT = EVENT_INT.includes("existence") &&
1105
+ !EVENT_INT.includes("removal")
1106
+ ? "🌏"
1107
+ : "";
1108
+ const EXIST_CHN = EVENT_CHN.includes("existence") &&
1109
+ !EVENT_CHN.includes("removal")
1110
+ ? "🇨🇳"
1111
+ : "";
1112
+ const title = [];
1113
+ if (EXIST_JPN)
1114
+ title.push(EXIST_JPN);
1115
+ if (EXIST_INT)
1116
+ title.push(EXIST_INT);
1117
+ if (EXIST_CHN)
1118
+ title.push(EXIST_CHN);
1119
+ await util_1.Util.drawEmojiOrGlyph(ctx, title.join(" "), element.x + element.width - textMargin, element.y +
1120
+ jacketMargin +
1121
+ textMargin * (1 / 2) +
1122
+ (element.width - jacketMargin * 2) +
1123
+ textSizeTitle * 3, textSizeSecondary * (9 / 8), element.width - textMargin * 2, "right", "white", textColor);
1124
+ }
1125
+ /* End Detail Draw */
1126
+ }
1127
+ DetailInfo.draw = draw;
1128
+ })(DetailInfo = Chart.DetailInfo || (Chart.DetailInfo = {}));
1129
+ let CharacterInfo;
1130
+ (function (CharacterInfo) {
1131
+ CharacterInfo.schema = painter_1.ThemeManager.Element.extend({
1132
+ type: v4_1.z.literal("character-info"),
1133
+ width: v4_1.z.number().min(1),
1134
+ height: v4_1.z.number().min(1),
1135
+ margin: v4_1.z.number().min(0),
1136
+ color: v4_1.z.object({
1137
+ card: util_1.Util.z.color(),
1138
+ }),
1139
+ });
1140
+ async function draw(ctx, theme, element, character) {
1141
+ const jacketMargin = element.margin;
1142
+ const textMargin = element.margin;
1143
+ const backGroundBorderRadius = Math.min(theme.content.width, theme.content.height) *
1144
+ (3 / 128);
1145
+ const characterImg = character
1146
+ ? await database_1.Database.getCardImage(character.card.id)
1147
+ : null;
1148
+ /* Begin Background Draw */
1149
+ ctx.beginPath();
1150
+ ctx.roundRect(element.x, element.y, element.width, element.height, backGroundBorderRadius);
1151
+ ctx.fillStyle = element.color.card;
1152
+ ctx.strokeStyle = new color_1.default(element.color.card)
1153
+ .darken(0.6)
1154
+ .hex();
1155
+ ctx.lineWidth = backGroundBorderRadius / 4;
1156
+ ctx.stroke();
1157
+ ctx.fill();
1158
+ /* End Background Draw */
1159
+ ctx.save();
1160
+ ctx.clip();
1161
+ /* Begin character draw */
1162
+ const characterImgRatio = 768 / 1052;
1163
+ const characterImage = new canvas_1.Image();
1164
+ const characterBorderRadius = backGroundBorderRadius / 2;
1165
+ const characterImgHeight = element.height - jacketMargin * 2;
1166
+ const characterImgWidth = characterImgHeight * characterImgRatio;
1167
+ if (characterImg) {
1168
+ characterImage.src = characterImg;
1169
+ ctx.beginPath();
1170
+ ctx.roundRect(element.x, element.y +
1171
+ jacketMargin * 2 +
1172
+ characterImgHeight * (30 / 100), characterImgWidth, characterImgHeight * (70 / 100), [characterImgWidth / 2, characterImgWidth / 2, 0, 0]);
1173
+ ctx.fillStyle = new color_1.default(element.color.card)
1174
+ .lighten(0.1)
1175
+ .hex();
1176
+ ctx.strokeStyle = new color_1.default(element.color.card)
1177
+ .darken(0.3)
1178
+ .hex();
1179
+ ctx.lineWidth = backGroundBorderRadius / 4;
1180
+ ctx.fill();
1181
+ ctx.beginPath();
1182
+ ctx.roundRect(element.x, element.y + jacketMargin * 2, characterImgWidth, characterImgHeight, [0, characterBorderRadius, 0, 0]);
1183
+ ctx.save();
1184
+ ctx.clip();
1185
+ ctx.drawImage(characterImage, element.x, element.y + jacketMargin * 2, characterImgWidth, characterImgHeight);
1186
+ ctx.restore();
1187
+ }
1188
+ /* End character draw */
1189
+ /* Begin Detail Draw */
1190
+ const textSizeSecondary = jacketMargin;
1191
+ const textLineWidth = element.width * (7 / 512);
1192
+ const textColor = new color_1.default(element.color.card)
1193
+ .darken(0.5)
1194
+ .hex();
1195
+ if (character) {
1196
+ const characterNameMetrics = util_1.Util.measureText(ctx, `Lv.${character.level} ${character.character.name}`, textSizeSecondary, Infinity);
1197
+ const characterNameActualHeight = Math.abs(characterNameMetrics.actualBoundingBoxAscent -
1198
+ characterNameMetrics.actualBoundingBoxDescent);
1199
+ util_1.Util.drawText(ctx, `Lv.${character.level} ${character.character.name}`, element.x + characterImgWidth / 2, element.y + jacketMargin + characterNameActualHeight, textSizeSecondary, textLineWidth, Infinity, "center", "white", textColor);
1200
+ if (character.character.comment) {
1201
+ const card = database_1.Database.getLocalCard(character.card.id);
1202
+ if (card) {
1203
+ const chara = database_1.Database.getLocalCharacter(card?.characterId);
1204
+ if (chara) {
1205
+ function getRandomFromArray(arr) {
1206
+ return arr[Math.floor(Math.random() * arr.length)];
1207
+ }
1208
+ if (chara.voiceLines.length > 0) {
1209
+ const curX = element.x +
1210
+ characterImgWidth -
1211
+ jacketMargin * 3, curY = element.y +
1212
+ jacketMargin * 2 +
1213
+ characterImgHeight * (35 / 100) +
1214
+ characterNameActualHeight / 2;
1215
+ ctx.save();
1216
+ ctx.translate(curX, curY);
1217
+ ctx.rotate((4 * Math.PI) / 180);
1218
+ const content = `「${getRandomFromArray(chara.voiceLines)}」`;
1219
+ const lines = [];
1220
+ const breaker = new linebreak_1.default(content);
1221
+ let lastPossibleBreak = 0, lastBreak = 0;
1222
+ for (let bk = breaker.nextBreak(); bk; lastPossibleBreak = bk.position,
1223
+ bk = breaker.nextBreak()) {
1224
+ const cur = content.substring(lastBreak, bk.position);
1225
+ if (cur.length > 8) {
1226
+ lines.push(content
1227
+ .substring(lastBreak, lastPossibleBreak)
1228
+ .trim());
1229
+ lastBreak = lastPossibleBreak;
1230
+ }
1231
+ }
1232
+ lines.push(content.substring(lastBreak).trim());
1233
+ for (let i = 0; i < lines.length; ++i) {
1234
+ const line = lines[i];
1235
+ const secondaryMetrics = util_1.Util.measureText(ctx, lines[i - 1] || "", textSizeSecondary, Infinity);
1236
+ const textHeight = Math.abs(secondaryMetrics.actualBoundingBoxAscent -
1237
+ secondaryMetrics.actualBoundingBoxDescent);
1238
+ util_1.Util.drawText(ctx, line, 0, textHeight * (3 / 2) * i, textSizeSecondary, textLineWidth, Infinity, "left", "white", textColor);
1239
+ }
1240
+ ctx.restore();
1241
+ }
1242
+ }
1243
+ }
1244
+ }
1245
+ }
1246
+ /* End Detail Draw */
1247
+ ctx.restore();
1248
+ }
1249
+ CharacterInfo.draw = draw;
1250
+ })(CharacterInfo = Chart.CharacterInfo || (Chart.CharacterInfo = {}));
1251
+ })(Chart = OngekiPainterModule.Chart || (OngekiPainterModule.Chart = {}));
447
1252
  })(OngekiPainterModule || (exports.OngekiPainterModule = OngekiPainterModule = {}));
448
1253
  //# sourceMappingURL=index.js.map