@galacean/effects-plugin-rich-text 2.7.4 → 2.8.0-alpha.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/alipay.js +1 -1
- package/dist/alipay.js.map +1 -1
- package/dist/alipay.mjs +1 -1
- package/dist/alipay.mjs.map +1 -1
- package/dist/douyin.js +1 -1
- package/dist/douyin.js.map +1 -1
- package/dist/douyin.mjs +1 -1
- package/dist/douyin.mjs.map +1 -1
- package/dist/index.js +1007 -272
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +1008 -273
- package/dist/index.mjs.map +1 -1
- package/dist/rich-text-component.d.ts +61 -18
- package/dist/rich-text-layout.d.ts +61 -0
- package/dist/strategies/align/rich-horizontal-align.d.ts +10 -0
- package/dist/strategies/align/rich-vertical-align.d.ts +10 -0
- package/dist/strategies/overflow/rich-clipped-overflow.d.ts +10 -0
- package/dist/strategies/overflow/rich-display-overflow.d.ts +10 -0
- package/dist/strategies/overflow/rich-visible-overflow.d.ts +10 -0
- package/dist/strategies/rich-text-factory.d.ts +26 -0
- package/dist/strategies/rich-text-interfaces.d.ts +104 -0
- package/dist/strategies/wrap/rich-wrap-disabled.d.ts +15 -0
- package/dist/strategies/wrap/rich-wrap-enabled.d.ts +15 -0
- package/dist/weapp.js +1 -1
- package/dist/weapp.js.map +1 -1
- package/dist/weapp.mjs +1 -1
- package/dist/weapp.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* Description: Galacean Effects player rich text plugin
|
|
4
4
|
* Author: Ant Group CO., Ltd.
|
|
5
5
|
* Contributors: 云垣
|
|
6
|
-
* Version: v2.
|
|
6
|
+
* Version: v2.8.0-alpha.1
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import * as EFFECTS from '@galacean/effects';
|
|
10
|
-
import { AbstractPlugin,
|
|
10
|
+
import { AbstractPlugin, spec, effectsClass, applyMixins, TextComponentBase, TextStyle, math, assertExist, MaskableGraphic, registerPlugin, VFXItem, logger } from '@galacean/effects';
|
|
11
11
|
|
|
12
12
|
function _set_prototype_of(o, p) {
|
|
13
13
|
_set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
|
|
@@ -330,6 +330,123 @@ typeof SuppressedError === "function" ? SuppressedError : function _SuppressedEr
|
|
|
330
330
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
331
331
|
};
|
|
332
332
|
|
|
333
|
+
var RichTextLayout = /*#__PURE__*/ function() {
|
|
334
|
+
function RichTextLayout(options) {
|
|
335
|
+
this.width = 0;
|
|
336
|
+
this.height = 0;
|
|
337
|
+
var size = options.size, _options_textOverflow = options.textOverflow, textOverflow = _options_textOverflow === void 0 ? spec.TextOverflow.clip : _options_textOverflow, _options_textVerticalAlign = options.textVerticalAlign, textVerticalAlign = _options_textVerticalAlign === void 0 ? spec.TextVerticalAlign.middle : _options_textVerticalAlign, _options_textAlign = options.textAlign, textAlign = _options_textAlign === void 0 ? spec.TextAlignment.left : _options_textAlign, _options_letterSpace = options.letterSpace, letterSpace = _options_letterSpace === void 0 ? 0 : _options_letterSpace, _options_lineHeight = options.lineHeight, lineHeight = _options_lineHeight === void 0 ? 0.571 : _options_lineHeight, _options_wrapEnabled = options.wrapEnabled, wrapEnabled = _options_wrapEnabled === void 0 ? false : _options_wrapEnabled, _options_maxTextWidth = options.maxTextWidth, maxTextWidth = _options_maxTextWidth === void 0 ? 350 : _options_maxTextWidth, _options_maxTextHeight = options.maxTextHeight, maxTextHeight = _options_maxTextHeight === void 0 ? 1000 : _options_maxTextHeight, _options_sizeMode = options.sizeMode, sizeMode = _options_sizeMode === void 0 ? spec.TextSizeMode.autoWidth : _options_sizeMode, _options_useLegacyRichText = options.// @ts-expect-error 兼容旧版
|
|
338
|
+
useLegacyRichText, useLegacyRichText = _options_useLegacyRichText === void 0 ? false : _options_useLegacyRichText;
|
|
339
|
+
this.letterSpace = letterSpace;
|
|
340
|
+
this.lineHeight = lineHeight;
|
|
341
|
+
this.useLegacyRichText = useLegacyRichText;
|
|
342
|
+
this.overflow = textOverflow;
|
|
343
|
+
this.textVerticalAlign = textVerticalAlign;
|
|
344
|
+
this.textAlign = textAlign;
|
|
345
|
+
this.width = size ? size[0] : 100;
|
|
346
|
+
this.height = size ? size[1] : 100;
|
|
347
|
+
this.wrapEnabled = wrapEnabled;
|
|
348
|
+
this.maxTextWidth = maxTextWidth;
|
|
349
|
+
this.maxTextHeight = maxTextHeight;
|
|
350
|
+
this.sizeMode = sizeMode;
|
|
351
|
+
}
|
|
352
|
+
var _proto = RichTextLayout.prototype;
|
|
353
|
+
_proto.getOffsetY = function getOffsetY(style, lineCount, lineHeight, fontSize, totalLineHeight) {
|
|
354
|
+
var outlineWidth = style.outlineWidth, fontScale = style.fontScale;
|
|
355
|
+
// /3 计算Y轴偏移量,以匹配编辑器行为
|
|
356
|
+
var offsetY = (lineHeight - fontSize) / 3;
|
|
357
|
+
// 计算基础偏移量
|
|
358
|
+
var baseOffset = fontSize + outlineWidth * fontScale;
|
|
359
|
+
// 除去首行之外的总高度,用于 bottom 对齐时将第一行向上偏移
|
|
360
|
+
var commonCalculation = totalLineHeight !== undefined ? totalLineHeight : lineHeight * (lineCount - 1);
|
|
361
|
+
var offsetResult = 0;
|
|
362
|
+
switch(this.textVerticalAlign){
|
|
363
|
+
case spec.TextVerticalAlign.top:
|
|
364
|
+
offsetResult = baseOffset + offsetY;
|
|
365
|
+
break;
|
|
366
|
+
case spec.TextVerticalAlign.middle:
|
|
367
|
+
offsetResult = (this.height * fontScale - commonCalculation + baseOffset) / 2;
|
|
368
|
+
break;
|
|
369
|
+
case spec.TextVerticalAlign.bottom:
|
|
370
|
+
offsetResult = this.height * fontScale - commonCalculation - offsetY;
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
return offsetResult;
|
|
374
|
+
};
|
|
375
|
+
_proto.getOffsetX = function getOffsetX(style, maxWidth) {
|
|
376
|
+
var offsetX = 0;
|
|
377
|
+
switch(this.textAlign){
|
|
378
|
+
case spec.TextAlignment.left:
|
|
379
|
+
offsetX = style.outlineWidth * style.fontScale;
|
|
380
|
+
break;
|
|
381
|
+
case spec.TextAlignment.middle:
|
|
382
|
+
offsetX = (this.width * style.fontScale - maxWidth) / 2;
|
|
383
|
+
break;
|
|
384
|
+
case spec.TextAlignment.right:
|
|
385
|
+
offsetX = this.width * style.fontScale - maxWidth;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
return offsetX;
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* 富文本垂直对齐计算
|
|
392
|
+
* @param style - 字体样式
|
|
393
|
+
* @param lineHeights - 每行高度数组
|
|
394
|
+
* @param fontSize - 字体大小
|
|
395
|
+
* @returns 第一行基线的Y坐标
|
|
396
|
+
*/ _proto.getOffsetYRich = function getOffsetYRich(style, lineHeights, fontSize) {
|
|
397
|
+
if (lineHeights.length === 0) {
|
|
398
|
+
// 空文本时返回 0,避免计算异常;后续策略可按需要再调整
|
|
399
|
+
return 0;
|
|
400
|
+
}
|
|
401
|
+
var outlineWidth = style.outlineWidth, fontScale = style.fontScale;
|
|
402
|
+
var total = lineHeights.reduce(function(a, b) {
|
|
403
|
+
return a + b;
|
|
404
|
+
}, 0);
|
|
405
|
+
var offsetY = (lineHeights[0] - fontSize) / 3;
|
|
406
|
+
var baseOffset = fontSize + outlineWidth * fontScale;
|
|
407
|
+
var commonCalculation = total - lineHeights[0];
|
|
408
|
+
var offsetResult = 0;
|
|
409
|
+
switch(this.textVerticalAlign){
|
|
410
|
+
case spec.TextVerticalAlign.top:
|
|
411
|
+
offsetResult = baseOffset + offsetY;
|
|
412
|
+
break;
|
|
413
|
+
case spec.TextVerticalAlign.middle:
|
|
414
|
+
offsetResult = (this.height * fontScale - total) / 2 + baseOffset;
|
|
415
|
+
break;
|
|
416
|
+
case spec.TextVerticalAlign.bottom:
|
|
417
|
+
offsetResult = this.height * fontScale - commonCalculation - offsetY;
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
return offsetResult;
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
* 富文本横向对齐计算
|
|
424
|
+
* @param style - 字体样式
|
|
425
|
+
* @param maxWidth - 文本框最大宽度
|
|
426
|
+
* @param contentW - 文本实际宽度
|
|
427
|
+
* @returns 水平偏移量
|
|
428
|
+
*/ _proto.getOffsetXRich = function getOffsetXRich(style, maxWidth, contentW) {
|
|
429
|
+
switch(this.textAlign){
|
|
430
|
+
case spec.TextAlignment.left:
|
|
431
|
+
return style.outlineWidth;
|
|
432
|
+
case spec.TextAlignment.middle:
|
|
433
|
+
return (maxWidth - contentW) / 2;
|
|
434
|
+
case spec.TextAlignment.right:
|
|
435
|
+
return maxWidth - contentW;
|
|
436
|
+
default:
|
|
437
|
+
return 0;
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
/**
|
|
441
|
+
* 设置文本框尺寸
|
|
442
|
+
* - 不包含 fontScale 缩放
|
|
443
|
+
*/ _proto.setSize = function setSize(width, height) {
|
|
444
|
+
this.width = width;
|
|
445
|
+
this.height = height;
|
|
446
|
+
};
|
|
447
|
+
return RichTextLayout;
|
|
448
|
+
}();
|
|
449
|
+
|
|
333
450
|
/**
|
|
334
451
|
* 将颜色名称转换为 RGBA
|
|
335
452
|
* @param colorName - 颜色名称
|
|
@@ -402,31 +519,620 @@ typeof SuppressedError === "function" ? SuppressedError : function _SuppressedEr
|
|
|
402
519
|
}
|
|
403
520
|
}
|
|
404
521
|
|
|
522
|
+
/**
|
|
523
|
+
* 富文本换行禁用策略
|
|
524
|
+
* 实现逻辑:仅基于\n换行,无自动换行
|
|
525
|
+
*/ var RichWrapDisabledStrategy = /*#__PURE__*/ function() {
|
|
526
|
+
function RichWrapDisabledStrategy() {}
|
|
527
|
+
var _proto = RichWrapDisabledStrategy.prototype;
|
|
528
|
+
_proto.computeLines = function computeLines(processedOptions, context, style, layout, singleLineHeight, fontScale, letterSpace, scaleFactor) {
|
|
529
|
+
var _this = this;
|
|
530
|
+
var lines = [];
|
|
531
|
+
var baselines = [];
|
|
532
|
+
var gapPx = (layout.lineHeight || 0) * fontScale;
|
|
533
|
+
var currentLine = this.createNewLine();
|
|
534
|
+
var maxLineWidth = 0;
|
|
535
|
+
var totalHeight = 0;
|
|
536
|
+
var finishCurrentLine = function() {
|
|
537
|
+
if (currentLine.chars.length === 0) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
// 第1行用真实首行高度,其余行用 gapPx
|
|
541
|
+
currentLine.lineHeight = lines.length === 0 ? (currentLine.lineAscent || 0) + (currentLine.lineDescent || 0) : gapPx;
|
|
542
|
+
// 记录本行基线
|
|
543
|
+
var baseline = lines.length === 0 ? 0 : baselines[baselines.length - 1] + gapPx;
|
|
544
|
+
baselines.push(baseline);
|
|
545
|
+
totalHeight += currentLine.lineHeight;
|
|
546
|
+
lines.push(currentLine);
|
|
547
|
+
maxLineWidth = Math.max(maxLineWidth, currentLine.width);
|
|
548
|
+
currentLine = _this.createNewLine();
|
|
549
|
+
};
|
|
550
|
+
processedOptions.forEach(function(options) {
|
|
551
|
+
var text = options.text, isNewLine = options.isNewLine, fontSize = options.fontSize;
|
|
552
|
+
if (isNewLine) {
|
|
553
|
+
// 先结束上一行
|
|
554
|
+
finishCurrentLine();
|
|
555
|
+
}
|
|
556
|
+
// 用当前片段字体(权重/家族)设置测量字体
|
|
557
|
+
var fontStyle = options.fontStyle || style.fontStyle || "normal";
|
|
558
|
+
context.font = fontStyle + " " + (options.fontWeight || style.textWeight) + " 10px " + (options.fontFamily || style.fontFamily);
|
|
559
|
+
// 记录段起始 x
|
|
560
|
+
currentLine.offsetX.push(currentLine.width);
|
|
561
|
+
// 逐字宽度和高度测量(asc/desc 测量)
|
|
562
|
+
var segmentInnerX = 0;
|
|
563
|
+
var charArr = [];
|
|
564
|
+
var lineAscent = 0;
|
|
565
|
+
var lineDescent = 0;
|
|
566
|
+
for(var i = 0; i < text.length; i++){
|
|
567
|
+
var ch = text[i];
|
|
568
|
+
var m = context.measureText(ch);
|
|
569
|
+
var w = m.width;
|
|
570
|
+
var charWidth = (w <= 0 ? 0 : w) * fontSize * scaleFactor * fontScale;
|
|
571
|
+
// 测量 asc/desc 并按目标字号缩放
|
|
572
|
+
var scale = fontSize * fontScale * scaleFactor;
|
|
573
|
+
var asc = m.actualBoundingBoxAscent * scale;
|
|
574
|
+
var desc = m.actualBoundingBoxDescent * scale;
|
|
575
|
+
lineAscent = Math.max(lineAscent, asc);
|
|
576
|
+
lineDescent = Math.max(lineDescent, desc);
|
|
577
|
+
if (i > 0) {
|
|
578
|
+
segmentInnerX += letterSpace; // 先加"前一个字符与当前字符之间"的间距
|
|
579
|
+
}
|
|
580
|
+
charArr.push({
|
|
581
|
+
char: ch,
|
|
582
|
+
x: segmentInnerX
|
|
583
|
+
});
|
|
584
|
+
segmentInnerX += charWidth;
|
|
585
|
+
}
|
|
586
|
+
currentLine.chars.push(charArr);
|
|
587
|
+
currentLine.width += segmentInnerX;
|
|
588
|
+
currentLine.richOptions.push(options);
|
|
589
|
+
// 累计行级 asc/desc
|
|
590
|
+
currentLine.lineAscent = Math.max(currentLine.lineAscent || 0, lineAscent);
|
|
591
|
+
currentLine.lineDescent = Math.max(currentLine.lineDescent || 0, lineDescent);
|
|
592
|
+
});
|
|
593
|
+
// 结束最后一行
|
|
594
|
+
finishCurrentLine();
|
|
595
|
+
// 计算 bbox
|
|
596
|
+
var bboxTop = Infinity;
|
|
597
|
+
var bboxBottom = -Infinity;
|
|
598
|
+
if (lines.length === 0) {
|
|
599
|
+
return {
|
|
600
|
+
lines: lines,
|
|
601
|
+
maxLineWidth: maxLineWidth,
|
|
602
|
+
totalHeight: totalHeight,
|
|
603
|
+
bboxTop: 0,
|
|
604
|
+
bboxBottom: 0,
|
|
605
|
+
bboxHeight: 0
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
for(var i = 0; i < lines.length; i++){
|
|
609
|
+
bboxTop = Math.min(bboxTop, baselines[i] - (lines[i].lineAscent || 0));
|
|
610
|
+
bboxBottom = Math.max(bboxBottom, baselines[i] + (lines[i].lineDescent || 0));
|
|
611
|
+
}
|
|
612
|
+
var bboxHeight = bboxBottom - bboxTop;
|
|
613
|
+
return {
|
|
614
|
+
lines: lines,
|
|
615
|
+
maxLineWidth: maxLineWidth,
|
|
616
|
+
totalHeight: totalHeight,
|
|
617
|
+
bboxTop: bboxTop,
|
|
618
|
+
bboxBottom: bboxBottom,
|
|
619
|
+
bboxHeight: bboxHeight
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
/**
|
|
623
|
+
* 创建新行
|
|
624
|
+
*/ _proto.createNewLine = function createNewLine() {
|
|
625
|
+
return {
|
|
626
|
+
richOptions: [],
|
|
627
|
+
offsetX: [],
|
|
628
|
+
width: 0,
|
|
629
|
+
lineHeight: 0,
|
|
630
|
+
offsetY: 0,
|
|
631
|
+
chars: [],
|
|
632
|
+
lineAscent: 0,
|
|
633
|
+
lineDescent: 0
|
|
634
|
+
};
|
|
635
|
+
};
|
|
636
|
+
return RichWrapDisabledStrategy;
|
|
637
|
+
}();
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* 富文本自动换行策略
|
|
641
|
+
* 实现逻辑:基于\n换行及自动换行
|
|
642
|
+
*/ var RichWrapEnabledStrategy = /*#__PURE__*/ function() {
|
|
643
|
+
function RichWrapEnabledStrategy() {}
|
|
644
|
+
var _proto = RichWrapEnabledStrategy.prototype;
|
|
645
|
+
_proto.computeLines = function computeLines(processedOptions, context, style, layout, singleLineHeight, fontScale, letterSpace, scaleFactor) {
|
|
646
|
+
var _this = this;
|
|
647
|
+
var lines = [];
|
|
648
|
+
var baselines = [];
|
|
649
|
+
var gapPx = (layout.lineHeight || 0) * fontScale;
|
|
650
|
+
var currentLine = this.createNewLine();
|
|
651
|
+
var maxLineWidth = 0;
|
|
652
|
+
var totalHeight = 0;
|
|
653
|
+
// 切块缓冲变量
|
|
654
|
+
var segStartX = null;
|
|
655
|
+
var segmentInnerX = 0;
|
|
656
|
+
var chunkChars = [];
|
|
657
|
+
var chunkOptions = null; // 跟踪当前切块所属options
|
|
658
|
+
// 结束当前行(含缓冲切块)
|
|
659
|
+
var finishCurrentLine = function() {
|
|
660
|
+
flushChunk();
|
|
661
|
+
if (currentLine.chars.length === 0) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
// 第1行用真实首行高度,其余行用 gapPx
|
|
665
|
+
currentLine.lineHeight = lines.length === 0 ? (currentLine.lineAscent || 0) + (currentLine.lineDescent || 0) : gapPx;
|
|
666
|
+
// 记录本行基线
|
|
667
|
+
var baseline = lines.length === 0 ? 0 : baselines[baselines.length - 1] + gapPx;
|
|
668
|
+
baselines.push(baseline);
|
|
669
|
+
totalHeight += currentLine.lineHeight;
|
|
670
|
+
lines.push(currentLine);
|
|
671
|
+
maxLineWidth = Math.max(maxLineWidth, currentLine.width);
|
|
672
|
+
currentLine = _this.createNewLine();
|
|
673
|
+
segStartX = null;
|
|
674
|
+
segmentInnerX = 0;
|
|
675
|
+
chunkChars = [];
|
|
676
|
+
chunkOptions = null;
|
|
677
|
+
};
|
|
678
|
+
// 刷新当前切块
|
|
679
|
+
var flushChunk = function() {
|
|
680
|
+
if (chunkChars.length === 0) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
if (segStartX === null) {
|
|
684
|
+
segStartX = currentLine.width;
|
|
685
|
+
}
|
|
686
|
+
currentLine.offsetX.push(segStartX);
|
|
687
|
+
currentLine.chars.push(chunkChars);
|
|
688
|
+
if (chunkOptions) {
|
|
689
|
+
currentLine.richOptions.push(chunkOptions);
|
|
690
|
+
}
|
|
691
|
+
// 重置缓冲
|
|
692
|
+
segStartX = null;
|
|
693
|
+
segmentInnerX = 0;
|
|
694
|
+
chunkChars = [];
|
|
695
|
+
chunkOptions = null;
|
|
696
|
+
};
|
|
697
|
+
processedOptions.forEach(function(options) {
|
|
698
|
+
var text = options.text, isNewLine = options.isNewLine, fontSize = options.fontSize;
|
|
699
|
+
// 设置测量字体(包含fontStyle)
|
|
700
|
+
var fontStyle = options.fontStyle || style.fontStyle || "normal";
|
|
701
|
+
context.font = fontStyle + " " + (options.fontWeight || style.textWeight) + " 10px " + (options.fontFamily || style.fontFamily);
|
|
702
|
+
// 显式换行符优先处理
|
|
703
|
+
if (isNewLine) {
|
|
704
|
+
flushChunk();
|
|
705
|
+
finishCurrentLine();
|
|
706
|
+
}
|
|
707
|
+
// 逐字符处理
|
|
708
|
+
for(var i = 0; i < text.length; i++){
|
|
709
|
+
var ch = text[i];
|
|
710
|
+
// 获取基础宽度并计算实际宽度(动态缩放)
|
|
711
|
+
var m = context.measureText(ch);
|
|
712
|
+
var baseW = m.width;
|
|
713
|
+
var charWidth = (baseW <= 0 ? 0 : baseW) * fontSize * scaleFactor * fontScale;
|
|
714
|
+
// 测量 asc/desc 并按目标字号缩放
|
|
715
|
+
var scale = fontSize * fontScale * scaleFactor;
|
|
716
|
+
var asc = m.actualBoundingBoxAscent * scale;
|
|
717
|
+
var desc = m.actualBoundingBoxDescent * scale;
|
|
718
|
+
// 计算预期宽度(包含字符间距)
|
|
719
|
+
var spacing = chunkChars.length > 0 ? letterSpace : 0;
|
|
720
|
+
var willWidth = currentLine.width + spacing + charWidth;
|
|
721
|
+
// 自动换行判断
|
|
722
|
+
if (willWidth > (layout.maxTextWidth || Infinity)) {
|
|
723
|
+
flushChunk();
|
|
724
|
+
finishCurrentLine();
|
|
725
|
+
}
|
|
726
|
+
// 初始化切块起点和所属options
|
|
727
|
+
if (segStartX === null) {
|
|
728
|
+
segStartX = currentLine.width;
|
|
729
|
+
chunkOptions = options; // 绑定当前切块到options
|
|
730
|
+
}
|
|
731
|
+
// 添加字符间距(非首字符)
|
|
732
|
+
if (chunkChars.length > 0) {
|
|
733
|
+
segmentInnerX += letterSpace;
|
|
734
|
+
currentLine.width += letterSpace;
|
|
735
|
+
}
|
|
736
|
+
// 添加字符到切块(x为切块内相对坐标)
|
|
737
|
+
chunkChars.push({
|
|
738
|
+
char: ch,
|
|
739
|
+
x: segmentInnerX
|
|
740
|
+
});
|
|
741
|
+
// 累计行级 asc/desc
|
|
742
|
+
currentLine.lineAscent = Math.max(currentLine.lineAscent || 0, asc);
|
|
743
|
+
currentLine.lineDescent = Math.max(currentLine.lineDescent || 0, desc);
|
|
744
|
+
// 更新位置和宽度
|
|
745
|
+
segmentInnerX += charWidth;
|
|
746
|
+
currentLine.width += charWidth;
|
|
747
|
+
}
|
|
748
|
+
// 文本段结束,落盘当前切块
|
|
749
|
+
flushChunk();
|
|
750
|
+
});
|
|
751
|
+
// 结束最后一行
|
|
752
|
+
finishCurrentLine();
|
|
753
|
+
// 计算 bbox
|
|
754
|
+
var bboxTop = Infinity;
|
|
755
|
+
var bboxBottom = -Infinity;
|
|
756
|
+
for(var i = 0; i < lines.length; i++){
|
|
757
|
+
bboxTop = Math.min(bboxTop, baselines[i] - (lines[i].lineAscent || 0));
|
|
758
|
+
bboxBottom = Math.max(bboxBottom, baselines[i] + (lines[i].lineDescent || 0));
|
|
759
|
+
}
|
|
760
|
+
var bboxHeight = bboxBottom - bboxTop;
|
|
761
|
+
return {
|
|
762
|
+
lines: lines,
|
|
763
|
+
maxLineWidth: maxLineWidth,
|
|
764
|
+
totalHeight: totalHeight,
|
|
765
|
+
bboxTop: bboxTop,
|
|
766
|
+
bboxBottom: bboxBottom,
|
|
767
|
+
bboxHeight: bboxHeight
|
|
768
|
+
};
|
|
769
|
+
};
|
|
770
|
+
/**
|
|
771
|
+
* 创建新行
|
|
772
|
+
*/ _proto.createNewLine = function createNewLine() {
|
|
773
|
+
return {
|
|
774
|
+
richOptions: [],
|
|
775
|
+
offsetX: [],
|
|
776
|
+
width: 0,
|
|
777
|
+
lineHeight: 0,
|
|
778
|
+
offsetY: 0,
|
|
779
|
+
chars: [],
|
|
780
|
+
lineAscent: 0,
|
|
781
|
+
lineDescent: 0
|
|
782
|
+
};
|
|
783
|
+
};
|
|
784
|
+
return RichWrapEnabledStrategy;
|
|
785
|
+
}();
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* 富文本 Display 溢出策略
|
|
789
|
+
* 在溢出策略中对所有几何量进行一次性缩放
|
|
790
|
+
*/ var RichDisplayOverflowStrategy = /*#__PURE__*/ function() {
|
|
791
|
+
function RichDisplayOverflowStrategy() {}
|
|
792
|
+
var _proto = RichDisplayOverflowStrategy.prototype;
|
|
793
|
+
_proto.apply = function apply(lines, sizeResult, layout, style) {
|
|
794
|
+
// 安全处理除零情况
|
|
795
|
+
var safeDiv = function(a, b) {
|
|
796
|
+
return Math.abs(b) > 1e-5 ? a / b : 1;
|
|
797
|
+
};
|
|
798
|
+
var availableW = Math.max(1, layout.maxTextWidth || sizeResult.canvasWidth);
|
|
799
|
+
var availableH = Math.max(1, layout.maxTextHeight || sizeResult.canvasHeight);
|
|
800
|
+
var _sizeResult_contentWidth;
|
|
801
|
+
var contentW = Math.max(1, (_sizeResult_contentWidth = sizeResult.contentWidth) != null ? _sizeResult_contentWidth : sizeResult.canvasWidth);
|
|
802
|
+
var _sizeResult_bboxHeight;
|
|
803
|
+
var contentH = Math.max(1, (_sizeResult_bboxHeight = sizeResult.bboxHeight) != null ? _sizeResult_bboxHeight : sizeResult.canvasHeight);
|
|
804
|
+
// 只缩小不放大
|
|
805
|
+
var s = Math.min(1, safeDiv(availableW, contentW), safeDiv(availableH, contentH));
|
|
806
|
+
// 浮点精度处理
|
|
807
|
+
if (s > 0.9999) {
|
|
808
|
+
return {
|
|
809
|
+
globalScale: 1
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
// 统一缩放所有几何量
|
|
813
|
+
for(var _iterator = _create_for_of_iterator_helper_loose(lines), _step; !(_step = _iterator()).done;){
|
|
814
|
+
var line = _step.value;
|
|
815
|
+
line.width *= s;
|
|
816
|
+
line.lineHeight *= s; // 缩小行距(你的 gap-only 模式行高=gapPx)
|
|
817
|
+
if (line.offsetX) {
|
|
818
|
+
for(var i = 0; i < line.offsetX.length; i++){
|
|
819
|
+
line.offsetX[i] *= s;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
for(var _iterator1 = _create_for_of_iterator_helper_loose(line.chars || []), _step1; !(_step1 = _iterator1()).done;){
|
|
823
|
+
var seg = _step1.value;
|
|
824
|
+
for(var _iterator2 = _create_for_of_iterator_helper_loose(seg), _step2; !(_step2 = _iterator2()).done;){
|
|
825
|
+
var ch = _step2.value;
|
|
826
|
+
ch.x *= s;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
for(var _iterator3 = _create_for_of_iterator_helper_loose(line.richOptions || []), _step3; !(_step3 = _iterator3()).done;){
|
|
830
|
+
var opt = _step3.value;
|
|
831
|
+
opt.fontSize *= s; // 缩小字形
|
|
832
|
+
}
|
|
833
|
+
// 同步缩放 asc/desc
|
|
834
|
+
if (line.lineAscent != null) {
|
|
835
|
+
line.lineAscent *= s;
|
|
836
|
+
}
|
|
837
|
+
if (line.lineDescent != null) {
|
|
838
|
+
line.lineDescent *= s;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return {
|
|
842
|
+
globalScale: s
|
|
843
|
+
};
|
|
844
|
+
};
|
|
845
|
+
return RichDisplayOverflowStrategy;
|
|
846
|
+
}();
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Clip 溢出策略
|
|
850
|
+
* 超出画布部分自然裁切
|
|
851
|
+
*/ var RichClippedOverflowStrategy = /*#__PURE__*/ function() {
|
|
852
|
+
function RichClippedOverflowStrategy() {}
|
|
853
|
+
var _proto = RichClippedOverflowStrategy.prototype;
|
|
854
|
+
_proto.apply = function apply(lines, sizeResult, layout, style) {
|
|
855
|
+
// 不进行任何缩放,直接返回单位缩放系数
|
|
856
|
+
return {
|
|
857
|
+
globalScale: 1
|
|
858
|
+
};
|
|
859
|
+
};
|
|
860
|
+
return RichClippedOverflowStrategy;
|
|
861
|
+
}();
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Visible 溢出策略
|
|
865
|
+
* 允许内容超出画布可见
|
|
866
|
+
*/ var RichVisibleOverflowStrategy = /*#__PURE__*/ function() {
|
|
867
|
+
function RichVisibleOverflowStrategy() {}
|
|
868
|
+
var _proto = RichVisibleOverflowStrategy.prototype;
|
|
869
|
+
_proto.apply = function apply(lines, sizeResult, layout, style) {
|
|
870
|
+
// 不进行任何缩放或裁剪
|
|
871
|
+
return {
|
|
872
|
+
globalScale: 1
|
|
873
|
+
};
|
|
874
|
+
};
|
|
875
|
+
return RichVisibleOverflowStrategy;
|
|
876
|
+
}();
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* 富文本水平对齐策略
|
|
880
|
+
* 直接使用已缩放的行宽计算偏移量
|
|
881
|
+
*/ var RichHorizontalAlignStrategyImpl = /*#__PURE__*/ function() {
|
|
882
|
+
function RichHorizontalAlignStrategyImpl() {}
|
|
883
|
+
var _proto = RichHorizontalAlignStrategyImpl.prototype;
|
|
884
|
+
_proto.getHorizontalOffsets = function getHorizontalOffsets(lines, sizeResult, overflowResult, layout, style) {
|
|
885
|
+
var frameW = layout.maxTextWidth;
|
|
886
|
+
var compX = sizeResult.baselineCompensationX || 0;
|
|
887
|
+
// 统一用 frame 宽做容器
|
|
888
|
+
var baseOffsets = lines.map(function(line) {
|
|
889
|
+
return layout.getOffsetXRich(style, frameW, line.width);
|
|
890
|
+
});
|
|
891
|
+
// 仅 visible 叠加水平补偿,clip/display 不加
|
|
892
|
+
var lineOffsets = layout.overflow === spec.TextOverflow.visible ? baseOffsets.map(function(x) {
|
|
893
|
+
return x + compX;
|
|
894
|
+
}) : baseOffsets;
|
|
895
|
+
return {
|
|
896
|
+
lineOffsets: lineOffsets
|
|
897
|
+
};
|
|
898
|
+
};
|
|
899
|
+
return RichHorizontalAlignStrategyImpl;
|
|
900
|
+
}();
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* 富文本垂直对齐策略
|
|
904
|
+
* 直接使用已缩放的行高
|
|
905
|
+
*/ var RichVerticalAlignStrategyImpl = /*#__PURE__*/ function() {
|
|
906
|
+
function RichVerticalAlignStrategyImpl() {}
|
|
907
|
+
var _proto = RichVerticalAlignStrategyImpl.prototype;
|
|
908
|
+
_proto.getVerticalOffsets = function getVerticalOffsets(lines, sizeResult, overflowResult, layout, style, singleLineHeight) {
|
|
909
|
+
var lineHeights = lines.map(function(line) {
|
|
910
|
+
return line.lineHeight;
|
|
911
|
+
});
|
|
912
|
+
var compY = sizeResult.baselineCompensationY || 0;
|
|
913
|
+
var baselineY = 0;
|
|
914
|
+
if (lines.length === 0) {
|
|
915
|
+
return {
|
|
916
|
+
baselineY: 0,
|
|
917
|
+
lineYOffsets: []
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
switch(layout.overflow){
|
|
921
|
+
case spec.TextOverflow.visible:
|
|
922
|
+
{
|
|
923
|
+
// frame-based 计算
|
|
924
|
+
var frameH = layout.maxTextHeight;
|
|
925
|
+
var _sizeResult_bboxTop;
|
|
926
|
+
var bboxTop = (_sizeResult_bboxTop = sizeResult.bboxTop) != null ? _sizeResult_bboxTop : 0;
|
|
927
|
+
var _sizeResult_bboxHeight, _sizeResult_bboxBottom;
|
|
928
|
+
var bboxBottom = (_sizeResult_bboxBottom = sizeResult.bboxBottom) != null ? _sizeResult_bboxBottom : bboxTop + ((_sizeResult_bboxHeight = sizeResult.bboxHeight) != null ? _sizeResult_bboxHeight : 0);
|
|
929
|
+
var _sizeResult_bboxHeight1;
|
|
930
|
+
var bboxHeight = (_sizeResult_bboxHeight1 = sizeResult.bboxHeight) != null ? _sizeResult_bboxHeight1 : bboxBottom - bboxTop;
|
|
931
|
+
// 计算 frame 基线
|
|
932
|
+
var baselineYFrame = 0;
|
|
933
|
+
switch(layout.textVerticalAlign){
|
|
934
|
+
case spec.TextVerticalAlign.top:
|
|
935
|
+
baselineYFrame = -bboxTop;
|
|
936
|
+
break;
|
|
937
|
+
case spec.TextVerticalAlign.middle:
|
|
938
|
+
baselineYFrame = (frameH - bboxHeight) / 2 - bboxTop;
|
|
939
|
+
break;
|
|
940
|
+
case spec.TextVerticalAlign.bottom:
|
|
941
|
+
baselineYFrame = frameH - bboxHeight - bboxTop;
|
|
942
|
+
break;
|
|
943
|
+
}
|
|
944
|
+
baselineY = baselineYFrame + compY; // 关键:叠加"向下移动 E"
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
947
|
+
case spec.TextOverflow.clip:
|
|
948
|
+
{
|
|
949
|
+
var firstLine = lines[0];
|
|
950
|
+
if (firstLine) {
|
|
951
|
+
var _Math;
|
|
952
|
+
var richSizes = firstLine.richOptions.map(function(o) {
|
|
953
|
+
return o.fontSize;
|
|
954
|
+
});
|
|
955
|
+
var firstMax = (_Math = Math).max.apply(_Math, [].concat(richSizes.length ? richSizes : [
|
|
956
|
+
style.fontSize
|
|
957
|
+
]));
|
|
958
|
+
var fontSizeForOffset = firstMax * style.fontScale * singleLineHeight;
|
|
959
|
+
baselineY = layout.getOffsetYRich(style, lineHeights, fontSizeForOffset) + compY;
|
|
960
|
+
} else {
|
|
961
|
+
baselineY = layout.getOffsetYRich(style, lineHeights, style.fontSize * style.fontScale) + compY;
|
|
962
|
+
}
|
|
963
|
+
break;
|
|
964
|
+
}
|
|
965
|
+
case spec.TextOverflow.display:
|
|
966
|
+
{
|
|
967
|
+
// display 垂直对齐改为基于 bbox,而不是 getOffsetYRich
|
|
968
|
+
var frameH1 = layout.maxTextHeight;
|
|
969
|
+
// 用缩放后的行数据重建 baselines 和 bbox
|
|
970
|
+
var baselines = [
|
|
971
|
+
0
|
|
972
|
+
];
|
|
973
|
+
for(var i = 1; i < lines.length; i++){
|
|
974
|
+
baselines[i] = baselines[i - 1] + lines[i].lineHeight;
|
|
975
|
+
}
|
|
976
|
+
// 计算 bboxTop / bboxBottom(使用行的测量值 lineAscent/lineDescent)
|
|
977
|
+
var bboxTop1 = Infinity;
|
|
978
|
+
var bboxBottom1 = -Infinity;
|
|
979
|
+
for(var i1 = 0; i1 < lines.length; i1++){
|
|
980
|
+
var _lines_i_lineAscent;
|
|
981
|
+
var asc = (_lines_i_lineAscent = lines[i1].lineAscent) != null ? _lines_i_lineAscent : 0;
|
|
982
|
+
var _lines_i_lineDescent;
|
|
983
|
+
var desc = (_lines_i_lineDescent = lines[i1].lineDescent) != null ? _lines_i_lineDescent : 0;
|
|
984
|
+
bboxTop1 = Math.min(bboxTop1, baselines[i1] - asc);
|
|
985
|
+
bboxBottom1 = Math.max(bboxBottom1, baselines[i1] + desc);
|
|
986
|
+
}
|
|
987
|
+
var bboxHeight1 = bboxBottom1 - bboxTop1;
|
|
988
|
+
// 计算 display 模式的基线
|
|
989
|
+
var baselineDisplayY = 0;
|
|
990
|
+
switch(layout.textVerticalAlign){
|
|
991
|
+
case spec.TextVerticalAlign.top:
|
|
992
|
+
baselineDisplayY = -bboxTop1;
|
|
993
|
+
break;
|
|
994
|
+
case spec.TextVerticalAlign.middle:
|
|
995
|
+
baselineDisplayY = (frameH1 - bboxHeight1) / 2 - bboxTop1;
|
|
996
|
+
break;
|
|
997
|
+
case spec.TextVerticalAlign.bottom:
|
|
998
|
+
baselineDisplayY = frameH1 - bboxHeight1 - bboxTop1;
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
// 后续 lineYOffsets 保持按行高累计
|
|
1002
|
+
var lineYOffsets = [];
|
|
1003
|
+
var currentY = baselineDisplayY;
|
|
1004
|
+
for(var i2 = 0; i2 < lines.length; i2++){
|
|
1005
|
+
lineYOffsets.push(currentY);
|
|
1006
|
+
if (i2 < lines.length - 1) {
|
|
1007
|
+
currentY += lines[i2 + 1].lineHeight;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
return {
|
|
1011
|
+
baselineY: baselineDisplayY,
|
|
1012
|
+
lineYOffsets: lineYOffsets
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
// 下面行偏移保持不变
|
|
1017
|
+
var lineYOffsets1 = [];
|
|
1018
|
+
var currentY1 = baselineY;
|
|
1019
|
+
lines.forEach(function(line, index) {
|
|
1020
|
+
lineYOffsets1.push(currentY1);
|
|
1021
|
+
if (index < lines.length - 1) {
|
|
1022
|
+
currentY1 += lines[index + 1].lineHeight;
|
|
1023
|
+
}
|
|
1024
|
+
});
|
|
1025
|
+
return {
|
|
1026
|
+
baselineY: baselineY,
|
|
1027
|
+
lineYOffsets: lineYOffsets1
|
|
1028
|
+
};
|
|
1029
|
+
};
|
|
1030
|
+
return RichVerticalAlignStrategyImpl;
|
|
1031
|
+
}();
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* 富文本策略工厂
|
|
1035
|
+
* 负责创建各种策略实例
|
|
1036
|
+
*/ var RichTextStrategyFactory = /*#__PURE__*/ function() {
|
|
1037
|
+
function RichTextStrategyFactory() {}
|
|
1038
|
+
/**
|
|
1039
|
+
* 创建换行策略
|
|
1040
|
+
* 根据wrapEnabled参数决定使用哪种策略
|
|
1041
|
+
*/ RichTextStrategyFactory.createWrapStrategy = function createWrapStrategy(wrapEnabled) {
|
|
1042
|
+
if (wrapEnabled) {
|
|
1043
|
+
return new RichWrapEnabledStrategy();
|
|
1044
|
+
} else {
|
|
1045
|
+
return new RichWrapDisabledStrategy();
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
/**
|
|
1049
|
+
* 创建溢出策略
|
|
1050
|
+
* 支持三种模式:clip(裁切)、display(行级缩放)、visible(不缩放不裁剪)
|
|
1051
|
+
*/ RichTextStrategyFactory.createOverflowStrategy = function createOverflowStrategy(mode) {
|
|
1052
|
+
switch(mode){
|
|
1053
|
+
case spec.TextOverflow.clip:
|
|
1054
|
+
return new RichClippedOverflowStrategy();
|
|
1055
|
+
case spec.TextOverflow.display:
|
|
1056
|
+
return new RichDisplayOverflowStrategy();
|
|
1057
|
+
case spec.TextOverflow.visible:
|
|
1058
|
+
default:
|
|
1059
|
+
return new RichVisibleOverflowStrategy();
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
/**
|
|
1063
|
+
* 创建水平对齐策略
|
|
1064
|
+
*/ RichTextStrategyFactory.createHorizontalAlignStrategy = function createHorizontalAlignStrategy() {
|
|
1065
|
+
return new RichHorizontalAlignStrategyImpl();
|
|
1066
|
+
};
|
|
1067
|
+
/**
|
|
1068
|
+
* 创建垂直对齐策略
|
|
1069
|
+
*/ RichTextStrategyFactory.createVerticalAlignStrategy = function createVerticalAlignStrategy() {
|
|
1070
|
+
return new RichVerticalAlignStrategyImpl();
|
|
1071
|
+
};
|
|
1072
|
+
return RichTextStrategyFactory;
|
|
1073
|
+
}();
|
|
1074
|
+
|
|
405
1075
|
var seed = 0;
|
|
406
|
-
var RichTextComponent = /*#__PURE__*/ function(
|
|
407
|
-
_inherits(RichTextComponent,
|
|
1076
|
+
var RichTextComponent = /*#__PURE__*/ function(MaskableGraphic) {
|
|
1077
|
+
_inherits(RichTextComponent, MaskableGraphic);
|
|
408
1078
|
function RichTextComponent(engine) {
|
|
409
1079
|
var _this;
|
|
410
|
-
_this =
|
|
1080
|
+
_this = MaskableGraphic.call(this, engine) || this;
|
|
1081
|
+
_this.isDirty = true;
|
|
1082
|
+
_this.text = "";
|
|
411
1083
|
_this.processedTextOptions = [];
|
|
412
|
-
// 字体高度的倍数(字体高度上下多出来的部分就是行间距)
|
|
413
1084
|
_this.singleLineHeight = 1.571;
|
|
414
1085
|
_this.size = null;
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
* canvas 大小
|
|
420
|
-
*/ _this.canvasSize = null;
|
|
1086
|
+
_this.initialized = false;
|
|
1087
|
+
_this.canvasSize = null;
|
|
1088
|
+
_this.SCALE_FACTOR = 0.1;
|
|
1089
|
+
_this.ALPHA_FIX_VALUE = 1 / 255;
|
|
421
1090
|
_this.name = "MRichText" + seed++;
|
|
1091
|
+
_this.initTextBase(engine);
|
|
1092
|
+
// 延迟初始化策略,等到textLayout被赋值后再初始化
|
|
1093
|
+
_this.richWrapStrategy = RichTextStrategyFactory.createWrapStrategy();
|
|
1094
|
+
_this.richOverflowStrategy = RichTextStrategyFactory.createOverflowStrategy(spec.TextOverflow.display);
|
|
1095
|
+
_this.richHorizontalAlignStrategy = RichTextStrategyFactory.createHorizontalAlignStrategy();
|
|
1096
|
+
_this.richVerticalAlignStrategy = RichTextStrategyFactory.createVerticalAlignStrategy();
|
|
422
1097
|
return _this;
|
|
423
1098
|
}
|
|
424
1099
|
var _proto = RichTextComponent.prototype;
|
|
1100
|
+
_proto.onUpdate = function onUpdate(dt) {
|
|
1101
|
+
MaskableGraphic.prototype.onUpdate.call(this, dt);
|
|
1102
|
+
this.updateTexture();
|
|
1103
|
+
};
|
|
1104
|
+
_proto.onDestroy = function onDestroy() {
|
|
1105
|
+
MaskableGraphic.prototype.onDestroy.call(this);
|
|
1106
|
+
this.disposeTextTexture();
|
|
1107
|
+
};
|
|
1108
|
+
_proto.fromData = function fromData(data) {
|
|
1109
|
+
MaskableGraphic.prototype.fromData.call(this, data);
|
|
1110
|
+
var interaction = data.interaction, options = data.options;
|
|
1111
|
+
this.interaction = interaction;
|
|
1112
|
+
this.textStyle = new TextStyle(options);
|
|
1113
|
+
this.textLayout = new RichTextLayout(options);
|
|
1114
|
+
this.text = options.text ? options.text.toString() : " ";
|
|
1115
|
+
if (this.textLayout.useLegacyRichText) {
|
|
1116
|
+
this.textLayout.textVerticalAlign = spec.TextVerticalAlign.middle;
|
|
1117
|
+
}
|
|
1118
|
+
this.updateStrategies();
|
|
1119
|
+
this.renderText(options);
|
|
1120
|
+
// 设置默认颜色(math.Color)
|
|
1121
|
+
this.material.setColor("_Color", new math.Color(1, 1, 1, 1));
|
|
1122
|
+
};
|
|
1123
|
+
/**
|
|
1124
|
+
* 使用策略结果绘制文本
|
|
1125
|
+
*/ _proto.updateStrategies = function updateStrategies() {
|
|
1126
|
+
var layout = this.textLayout;
|
|
1127
|
+
if (layout) {
|
|
1128
|
+
this.richWrapStrategy = RichTextStrategyFactory.createWrapStrategy(layout.wrapEnabled);
|
|
1129
|
+
this.richOverflowStrategy = RichTextStrategyFactory.createOverflowStrategy(layout.overflow);
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
425
1132
|
_proto.generateTextProgram = function generateTextProgram(text) {
|
|
426
1133
|
var _this = this;
|
|
427
1134
|
this.processedTextOptions = [];
|
|
428
1135
|
var program = generateProgram(function(text, context) {
|
|
429
|
-
// 如果富文本仅包含换行符,则在每个换行符后添加一个空格
|
|
430
1136
|
if (/^\n+$/.test(text)) {
|
|
431
1137
|
text = text.replace(/\n/g, "\n ");
|
|
432
1138
|
}
|
|
@@ -457,48 +1163,69 @@ var RichTextComponent = /*#__PURE__*/ function(TextComponent) {
|
|
|
457
1163
|
});
|
|
458
1164
|
program(text);
|
|
459
1165
|
};
|
|
460
|
-
|
|
1166
|
+
/**
|
|
1167
|
+
* 根据配置更新文本样式和布局
|
|
1168
|
+
*/ _proto.updateWithOptions = function updateWithOptions(options) {
|
|
1169
|
+
this.textStyle = new TextStyle(options);
|
|
1170
|
+
this.textLayout = new RichTextLayout(options);
|
|
1171
|
+
this.text = options.text ? options.text.toString() : " ";
|
|
1172
|
+
// TextLayout 构造函数已经正确处理了 textVerticalAlign,这里不需要再设置
|
|
1173
|
+
if (this.textLayout.useLegacyRichText) {
|
|
1174
|
+
this.textLayout.textVerticalAlign = spec.TextVerticalAlign.middle;
|
|
1175
|
+
}
|
|
1176
|
+
this.updateStrategies();
|
|
1177
|
+
this.isDirty = true;
|
|
1178
|
+
};
|
|
1179
|
+
_proto.renderText = function renderText(options) {
|
|
1180
|
+
var size = options.size;
|
|
1181
|
+
if (size) {
|
|
1182
|
+
this.canvasSize = new math.Vector2(size[0], size[1]);
|
|
1183
|
+
}
|
|
1184
|
+
this.updateTexture();
|
|
1185
|
+
};
|
|
1186
|
+
/**
|
|
1187
|
+
* 更新文本
|
|
1188
|
+
* @returns
|
|
1189
|
+
*/ _proto.updateTexture = function updateTexture(flipY) {
|
|
461
1190
|
if (flipY === void 0) flipY = true;
|
|
462
|
-
if (!this.isDirty || !this.context || !this.canvas) {
|
|
1191
|
+
if (!this.isDirty || !this.context || !this.canvas || !this.textStyle || !this.textLayout) {
|
|
463
1192
|
return;
|
|
464
1193
|
}
|
|
465
|
-
|
|
466
|
-
var useLegacy =
|
|
1194
|
+
var layout = this.textLayout;
|
|
1195
|
+
var useLegacy = layout.useLegacyRichText === true;
|
|
467
1196
|
this.singleLineHeight = useLegacy ? 1.571 : 1.0;
|
|
1197
|
+
// 根据useLegacyRichText字段来判断使用哪种渲染模式
|
|
468
1198
|
if (useLegacy) {
|
|
469
1199
|
this.updateTextureLegacy(flipY);
|
|
470
1200
|
} else {
|
|
471
|
-
this.
|
|
1201
|
+
this.updateTextureWithStrategies(flipY);
|
|
472
1202
|
}
|
|
473
1203
|
};
|
|
474
|
-
|
|
1204
|
+
/**
|
|
1205
|
+
* 解析富文本
|
|
1206
|
+
*/ _proto.updateTextureLegacy = function updateTextureLegacy(flipY) {
|
|
475
1207
|
var _this = this;
|
|
476
|
-
if (!this.isDirty || !this.context || !this.canvas) {
|
|
1208
|
+
if (!this.isDirty || !this.context || !this.canvas || !this.textStyle) {
|
|
477
1209
|
return;
|
|
478
1210
|
}
|
|
479
|
-
// 解析富文本
|
|
480
1211
|
this.generateTextProgram(this.text);
|
|
481
|
-
var
|
|
482
|
-
var
|
|
1212
|
+
var width = 0, height = 0;
|
|
1213
|
+
var layout = this.textLayout;
|
|
1214
|
+
var textStyle = this.textStyle;
|
|
1215
|
+
var overflow = layout.overflow, _layout_letterSpace = layout.letterSpace, letterSpace = _layout_letterSpace === void 0 ? 0 : _layout_letterSpace;
|
|
483
1216
|
var context = this.context;
|
|
484
|
-
var width = 0;
|
|
485
|
-
var height = 0;
|
|
486
|
-
context.save();
|
|
487
1217
|
var charsInfo = [];
|
|
488
|
-
var fontHeight = textStyle.fontSize *
|
|
1218
|
+
var fontHeight = textStyle.fontSize * textStyle.fontScale;
|
|
489
1219
|
var charInfo = {
|
|
490
1220
|
richOptions: [],
|
|
491
1221
|
offsetX: [],
|
|
492
1222
|
width: 0,
|
|
493
|
-
// 包括字体和上下行间距的高度
|
|
494
1223
|
lineHeight: fontHeight * this.singleLineHeight,
|
|
495
|
-
// 字体偏移高度(也就是行间距)
|
|
496
1224
|
offsetY: fontHeight * (this.singleLineHeight - 1) / 2
|
|
497
1225
|
};
|
|
498
1226
|
// 遍历解析后的文本选项
|
|
499
1227
|
this.processedTextOptions.forEach(function(options) {
|
|
500
1228
|
var text = options.text, isNewLine = options.isNewLine, fontSize = options.fontSize;
|
|
501
|
-
// 如果是新行,则将之前行的信息存入 charsInfo 并且初始化新行的 charInfo
|
|
502
1229
|
if (isNewLine) {
|
|
503
1230
|
charsInfo.push(charInfo);
|
|
504
1231
|
width = Math.max(width, charInfo.width);
|
|
@@ -509,12 +1236,9 @@ var RichTextComponent = /*#__PURE__*/ function(TextComponent) {
|
|
|
509
1236
|
lineHeight: fontHeight * _this.singleLineHeight,
|
|
510
1237
|
offsetY: fontHeight * (_this.singleLineHeight - 1) / 2
|
|
511
1238
|
};
|
|
512
|
-
// 管理行的总高度调整 canvas 尺寸
|
|
513
1239
|
height += charInfo.lineHeight;
|
|
514
1240
|
}
|
|
515
|
-
// 恢复默认设置
|
|
516
1241
|
context.font = (options.fontWeight || textStyle.textWeight) + " 10px " + (options.fontFamily || textStyle.fontFamily);
|
|
517
|
-
// 计算得到每个字段的宽度 textWidth
|
|
518
1242
|
var textMetrics = context.measureText(text);
|
|
519
1243
|
var textWidth = textMetrics.width;
|
|
520
1244
|
if (textMetrics.actualBoundingBoxLeft !== undefined && textMetrics.actualBoundingBoxRight !== undefined) {
|
|
@@ -523,32 +1247,28 @@ var RichTextComponent = /*#__PURE__*/ function(TextComponent) {
|
|
|
523
1247
|
textWidth = Math.max(textWidth, actualWidth);
|
|
524
1248
|
}
|
|
525
1249
|
}
|
|
526
|
-
var textHeight = fontSize * _this.singleLineHeight *
|
|
1250
|
+
var textHeight = fontSize * _this.singleLineHeight * textStyle.fontScale;
|
|
527
1251
|
if (textHeight > charInfo.lineHeight) {
|
|
528
1252
|
height += textHeight - charInfo.lineHeight;
|
|
529
1253
|
charInfo.lineHeight = textHeight;
|
|
530
|
-
charInfo.offsetY = fontSize *
|
|
1254
|
+
charInfo.offsetY = fontSize * textStyle.fontScale * (_this.singleLineHeight - 1) / 2;
|
|
531
1255
|
}
|
|
532
1256
|
charInfo.offsetX.push(charInfo.width);
|
|
533
|
-
|
|
534
|
-
charInfo.width += (textWidth <= 0 ? 0 : textWidth) * fontSize * _this.SCALE_FACTOR * _this.textStyle.fontScale + text.length * letterSpace;
|
|
535
|
-
// 将富文本数据存入 charInfo
|
|
1257
|
+
charInfo.width += (textWidth <= 0 ? 0 : textWidth) * fontSize * _this.SCALE_FACTOR * textStyle.fontScale + text.length * letterSpace;
|
|
536
1258
|
charInfo.richOptions.push(options);
|
|
537
1259
|
});
|
|
538
|
-
// 存储最后一行的字符信息,并且更新最终的宽度和高度用于确定 canvas 尺寸
|
|
539
1260
|
charsInfo.push(charInfo);
|
|
540
1261
|
width = Math.max(width, charInfo.width);
|
|
541
1262
|
height += charInfo.lineHeight;
|
|
1263
|
+
// 存储最后一行的字符信息,并且更新最终的宽度和高度用于确定canvas尺寸
|
|
542
1264
|
if (width === 0 || height === 0) {
|
|
543
1265
|
this.isDirty = false;
|
|
544
|
-
context.restore();
|
|
545
1266
|
return;
|
|
546
1267
|
}
|
|
547
1268
|
if (this.size === undefined || this.size === null) {
|
|
548
1269
|
this.size = this.item.transform.size.clone();
|
|
549
1270
|
}
|
|
550
1271
|
var _this_size = this.size, _this_size_x = _this_size.x, x = _this_size_x === void 0 ? 1 : _this_size_x, _this_size_y = _this_size.y, y = _this_size_y === void 0 ? 1 : _this_size_y;
|
|
551
|
-
// 首次渲染时初始化 canvas 尺寸和组件变换
|
|
552
1272
|
if (!this.initialized) {
|
|
553
1273
|
this.canvasSize = !this.canvasSize ? new math.Vector2(width, height) : this.canvasSize;
|
|
554
1274
|
var _this_canvasSize = this.canvasSize, canvasWidth = _this_canvasSize.x, canvasHeight = _this_canvasSize.y;
|
|
@@ -558,318 +1278,333 @@ var RichTextComponent = /*#__PURE__*/ function(TextComponent) {
|
|
|
558
1278
|
}
|
|
559
1279
|
assertExist(this.canvasSize);
|
|
560
1280
|
var _this_canvasSize1 = this.canvasSize, canvasWidth1 = _this_canvasSize1.x, canvasHeight1 = _this_canvasSize1.y;
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
this.
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
// fix bug 1/255
|
|
567
|
-
context.fillStyle = "rgba(255, 255, 255, " + this.ALPHA_FIX_VALUE + ")";
|
|
568
|
-
if (!flipY) {
|
|
569
|
-
context.translate(0, canvasHeight1);
|
|
570
|
-
context.scale(1, -1);
|
|
571
|
-
}
|
|
572
|
-
if (charsInfo.length === 0) {
|
|
573
|
-
context.restore();
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
var charsLineHeight = textLayout.getOffsetY(textStyle, charsInfo.length, fontHeight * this.singleLineHeight, textStyle.fontSize);
|
|
577
|
-
charsInfo.forEach(function(charInfo, index) {
|
|
578
|
-
var richOptions = charInfo.richOptions, offsetX = charInfo.offsetX, width = charInfo.width;
|
|
579
|
-
var charWidth = width;
|
|
580
|
-
var offset = offsetX;
|
|
581
|
-
if (overflow === spec.TextOverflow.display) {
|
|
582
|
-
if (width > canvasWidth1) {
|
|
583
|
-
var canvasScale = canvasWidth1 / width;
|
|
584
|
-
charWidth *= canvasScale;
|
|
585
|
-
offset = offsetX.map(function(x) {
|
|
586
|
-
return x * canvasScale;
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
var x = _this.textLayout.getOffsetX(textStyle, charWidth);
|
|
591
|
-
if (index > 0) {
|
|
592
|
-
charsLineHeight += charInfo.lineHeight - charInfo.offsetY;
|
|
1281
|
+
layout.width = canvasWidth1 / textStyle.fontScale;
|
|
1282
|
+
layout.height = canvasHeight1 / textStyle.fontScale;
|
|
1283
|
+
this.renderToTexture(canvasWidth1, canvasHeight1, flipY, function(context) {
|
|
1284
|
+
if (charsInfo.length === 0) {
|
|
1285
|
+
return;
|
|
593
1286
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
var
|
|
597
|
-
var
|
|
1287
|
+
var charsLineHeight = layout.getOffsetY(textStyle, charsInfo.length, fontHeight * _this.singleLineHeight, textStyle.fontSize);
|
|
1288
|
+
charsInfo.forEach(function(charInfo, index) {
|
|
1289
|
+
var richOptions = charInfo.richOptions, offsetX = charInfo.offsetX, width = charInfo.width;
|
|
1290
|
+
var charWidth = width;
|
|
1291
|
+
var offset = offsetX;
|
|
598
1292
|
if (overflow === spec.TextOverflow.display) {
|
|
599
1293
|
if (width > canvasWidth1) {
|
|
600
|
-
|
|
1294
|
+
var canvasScale = canvasWidth1 / width;
|
|
1295
|
+
charWidth *= canvasScale;
|
|
1296
|
+
offset = offsetX.map(function(x) {
|
|
1297
|
+
return x * canvasScale;
|
|
1298
|
+
});
|
|
601
1299
|
}
|
|
602
1300
|
}
|
|
603
|
-
var
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
1301
|
+
var x = layout.getOffsetX(textStyle, charWidth);
|
|
1302
|
+
if (index > 0) {
|
|
1303
|
+
charsLineHeight += charInfo.lineHeight - charInfo.offsetY;
|
|
1304
|
+
}
|
|
1305
|
+
richOptions.forEach(function(options, index) {
|
|
1306
|
+
var fontScale = textStyle.fontScale, textColor = textStyle.textColor, textFamily = textStyle.fontFamily, textWeight = textStyle.textWeight, richStyle = textStyle.fontStyle;
|
|
1307
|
+
var text = options.text, fontSize = options.fontSize, _options_fontColor = options.fontColor, fontColor = _options_fontColor === void 0 ? textColor : _options_fontColor, _options_fontFamily = options.fontFamily, fontFamily = _options_fontFamily === void 0 ? textFamily : _options_fontFamily, _options_fontWeight = options.fontWeight, fontWeight = _options_fontWeight === void 0 ? textWeight : _options_fontWeight, _options_fontStyle = options.fontStyle, fontStyle = _options_fontStyle === void 0 ? richStyle : _options_fontStyle;
|
|
1308
|
+
var textSize = fontSize;
|
|
1309
|
+
if (overflow === spec.TextOverflow.display) {
|
|
1310
|
+
if (width > canvasWidth1) {
|
|
1311
|
+
textSize /= width / canvasWidth1;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
var strOffsetX = offset[index] + x;
|
|
1315
|
+
// fix bug 1/255
|
|
1316
|
+
context.font = fontStyle + " " + fontWeight + " " + textSize * fontScale + "px " + fontFamily;
|
|
1317
|
+
var r = fontColor[0], g = fontColor[1], b = fontColor[2], a = fontColor[3];
|
|
1318
|
+
context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + a + ")";
|
|
1319
|
+
context.fillText(text, strOffsetX, charsLineHeight);
|
|
1320
|
+
});
|
|
607
1321
|
});
|
|
608
|
-
});
|
|
609
|
-
// 与 toDataURL() 两种方式都需要像素读取操作
|
|
610
|
-
var imageData = context.getImageData(0, 0, this.canvas.width, this.canvas.height);
|
|
611
|
-
var texture = Texture.createWithData(this.engine, {
|
|
612
|
-
data: new Uint8Array(imageData.data),
|
|
613
|
-
width: imageData.width,
|
|
614
|
-
height: imageData.height
|
|
615
1322
|
}, {
|
|
616
|
-
|
|
617
|
-
magFilter: glContext.LINEAR,
|
|
618
|
-
minFilter: glContext.LINEAR,
|
|
619
|
-
wrapS: glContext.CLAMP_TO_EDGE,
|
|
620
|
-
wrapT: glContext.CLAMP_TO_EDGE
|
|
1323
|
+
disposeOld: false
|
|
621
1324
|
});
|
|
622
|
-
|
|
623
|
-
this.renderer.texture = texture;
|
|
624
|
-
this.material.setTexture("_MainTex", texture);
|
|
1325
|
+
// 与 toDataURL() 两种方式都需要像素读取操作
|
|
625
1326
|
this.isDirty = false;
|
|
626
|
-
context.restore();
|
|
627
1327
|
};
|
|
628
|
-
|
|
1328
|
+
/**
|
|
1329
|
+
* 使用策略管线路径的渲染方法
|
|
1330
|
+
*/ _proto.updateTextureWithStrategies = function updateTextureWithStrategies(flipY) {
|
|
629
1331
|
var _this = this;
|
|
630
|
-
|
|
631
|
-
|
|
1332
|
+
if (!this.isDirty || !this.context || !this.canvas) {
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
632
1335
|
// 解析富文本
|
|
633
1336
|
this.generateTextProgram(this.text);
|
|
634
|
-
var
|
|
635
|
-
var
|
|
1337
|
+
var layout = this.textLayout;
|
|
1338
|
+
var _layout_letterSpace = layout.letterSpace, letterSpace = _layout_letterSpace === void 0 ? 0 : _layout_letterSpace;
|
|
636
1339
|
var context = this.context;
|
|
637
|
-
var width = 0;
|
|
638
|
-
var height = 0;
|
|
639
1340
|
if (!context) {
|
|
640
1341
|
return;
|
|
641
1342
|
}
|
|
642
|
-
|
|
643
|
-
var
|
|
644
|
-
|
|
645
|
-
var charInfo = {
|
|
646
|
-
richOptions: [],
|
|
647
|
-
offsetX: [],
|
|
648
|
-
width: 0,
|
|
649
|
-
// 包括字体和上下行间距的高度
|
|
650
|
-
lineHeight: fontHeight * this.singleLineHeight + (this.textLayout.lineGap || 0) * this.textStyle.fontScale,
|
|
651
|
-
// 字体偏移高度(也就是行间距)
|
|
652
|
-
offsetY: (this.textLayout.lineGap || 0) * this.textStyle.fontScale / 2,
|
|
653
|
-
chars: []
|
|
654
|
-
};
|
|
655
|
-
// 遍历解析后的文本选项
|
|
656
|
-
this.processedTextOptions.forEach(function(options) {
|
|
657
|
-
var text = options.text, isNewLine = options.isNewLine, fontSize = options.fontSize;
|
|
658
|
-
// 如果是新行,则结束上一行并开始新行
|
|
659
|
-
if (isNewLine) {
|
|
660
|
-
// 结束上一行:累加行高并重置charInfo
|
|
661
|
-
height += charInfo.lineHeight;
|
|
662
|
-
charsInfo.push(charInfo);
|
|
663
|
-
width = Math.max(width, charInfo.width);
|
|
664
|
-
// 初始化新行
|
|
665
|
-
charInfo = {
|
|
666
|
-
richOptions: [],
|
|
667
|
-
offsetX: [],
|
|
668
|
-
width: 0,
|
|
669
|
-
lineHeight: fontHeight * _this.singleLineHeight + (_this.textLayout.lineGap || 0) * _this.textStyle.fontScale,
|
|
670
|
-
offsetY: (_this.textLayout.lineGap || 0) * _this.textStyle.fontScale / 2,
|
|
671
|
-
chars: []
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
// 恢复默认设置
|
|
675
|
-
context.font = (options.fontWeight || textStyle.textWeight) + " 10px " + (options.fontFamily || textStyle.fontFamily);
|
|
676
|
-
var textHeight = fontSize * _this.singleLineHeight * _this.textStyle.fontScale + (_this.textLayout.lineGap || 0) * _this.textStyle.fontScale;
|
|
677
|
-
// 更新当前行的最大行高
|
|
678
|
-
if (textHeight > charInfo.lineHeight) {
|
|
679
|
-
charInfo.lineHeight = textHeight;
|
|
680
|
-
charInfo.offsetY = (_this.textLayout.lineGap || 0) * _this.textStyle.fontScale / 2;
|
|
681
|
-
}
|
|
682
|
-
charInfo.offsetX.push(charInfo.width);
|
|
683
|
-
// 逐字计算宽度以实现字符间距
|
|
684
|
-
var segmentInnerX = 0;
|
|
685
|
-
var charArr = [];
|
|
686
|
-
for(var i = 0; i < text.length; i++){
|
|
687
|
-
var char = text[i];
|
|
688
|
-
var tempcharWidth = context.measureText(char).width;
|
|
689
|
-
var charWidth = (tempcharWidth <= 0 ? 0 : tempcharWidth) * fontSize * _this.SCALE_FACTOR * _this.textStyle.fontScale;
|
|
690
|
-
charArr.push({
|
|
691
|
-
char: char,
|
|
692
|
-
x: segmentInnerX,
|
|
693
|
-
width: charWidth
|
|
694
|
-
});
|
|
695
|
-
segmentInnerX += charWidth + letterSpace;
|
|
696
|
-
}
|
|
697
|
-
charInfo.chars.push(charArr);
|
|
698
|
-
charInfo.width += segmentInnerX;
|
|
699
|
-
charInfo.richOptions.push(options);
|
|
700
|
-
});
|
|
701
|
-
// 结束最后一行
|
|
702
|
-
height += charInfo.lineHeight;
|
|
703
|
-
charsInfo.push(charInfo);
|
|
704
|
-
width = Math.max(width, charInfo.width);
|
|
705
|
-
if (width === 0 || height === 0) {
|
|
1343
|
+
// 步骤1: 换行策略计算行信息
|
|
1344
|
+
var wrapResult = this.richWrapStrategy.computeLines(this.processedTextOptions, context, this.textStyle, layout, this.singleLineHeight, this.textStyle.fontScale, letterSpace, this.SCALE_FACTOR);
|
|
1345
|
+
if (wrapResult.lines.length === 0 || wrapResult.maxLineWidth === 0 || wrapResult.totalHeight === 0) {
|
|
706
1346
|
this.isDirty = false;
|
|
707
|
-
context.restore();
|
|
708
1347
|
return;
|
|
709
1348
|
}
|
|
1349
|
+
// 步骤2: 尺寸处理
|
|
1350
|
+
var sizeResult = this.resolveCanvasSize(wrapResult, layout, this.textStyle, this.singleLineHeight);
|
|
1351
|
+
// 首次渲染时初始化 canvas 尺寸和组件变换
|
|
1352
|
+
this.setCanvasSize(sizeResult);
|
|
1353
|
+
// 步骤3: 溢出策略处理
|
|
1354
|
+
var overflowResult = this.richOverflowStrategy.apply(wrapResult.lines, sizeResult, layout, this.textStyle);
|
|
1355
|
+
// 步骤4: 水平对齐策略
|
|
1356
|
+
var horizontalAlignResult = this.richHorizontalAlignStrategy.getHorizontalOffsets(wrapResult.lines, sizeResult, overflowResult, layout, this.textStyle);
|
|
1357
|
+
// 步骤5: 垂直对齐策略
|
|
1358
|
+
var TextVerticalAlignResult = this.richVerticalAlignStrategy.getVerticalOffsets(wrapResult.lines, sizeResult, overflowResult, layout, this.textStyle, this.singleLineHeight);
|
|
1359
|
+
// 使用 this.canvasSize 统一设置画布尺寸
|
|
1360
|
+
assertExist(this.canvasSize);
|
|
1361
|
+
var _this_canvasSize = this.canvasSize, canvasWidth = _this_canvasSize.x, canvasHeight = _this_canvasSize.y;
|
|
1362
|
+
layout.width = canvasWidth / this.textStyle.fontScale;
|
|
1363
|
+
layout.height = canvasHeight / this.textStyle.fontScale;
|
|
1364
|
+
this.renderToTexture(canvasWidth, canvasHeight, flipY, function(context) {
|
|
1365
|
+
// 步骤6: 绘制文本
|
|
1366
|
+
_this.drawTextWithStrategies(context, wrapResult.lines, horizontalAlignResult, TextVerticalAlignResult, overflowResult, _this.textStyle);
|
|
1367
|
+
}, {
|
|
1368
|
+
disposeOld: false
|
|
1369
|
+
});
|
|
1370
|
+
this.isDirty = false;
|
|
1371
|
+
};
|
|
1372
|
+
_proto.setCanvasSize = function setCanvasSize(sizeResult) {
|
|
1373
|
+
var _this = this;
|
|
710
1374
|
if (this.size === undefined || this.size === null) {
|
|
711
1375
|
this.size = this.item.transform.size.clone();
|
|
712
1376
|
}
|
|
713
1377
|
var _this_size = this.size, _this_size_x = _this_size.x, x = _this_size_x === void 0 ? 1 : _this_size_x, _this_size_y = _this_size.y, y = _this_size_y === void 0 ? 1 : _this_size_y;
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1378
|
+
var layout = this.textLayout;
|
|
1379
|
+
switch(layout.overflow){
|
|
1380
|
+
case spec.TextOverflow.visible:
|
|
1381
|
+
{
|
|
1382
|
+
var _Math;
|
|
1383
|
+
var frameW = layout.maxTextWidth;
|
|
1384
|
+
var frameH = layout.maxTextHeight;
|
|
1385
|
+
var _sizeResult_bboxTop;
|
|
1386
|
+
var bboxTop = (_sizeResult_bboxTop = sizeResult.bboxTop) != null ? _sizeResult_bboxTop : 0;
|
|
1387
|
+
var _sizeResult_bboxHeight, _sizeResult_bboxBottom;
|
|
1388
|
+
var bboxBottom = (_sizeResult_bboxBottom = sizeResult.bboxBottom) != null ? _sizeResult_bboxBottom : bboxTop + ((_sizeResult_bboxHeight = sizeResult.bboxHeight) != null ? _sizeResult_bboxHeight : 0);
|
|
1389
|
+
var _sizeResult_bboxHeight1;
|
|
1390
|
+
var bboxHeight = (_sizeResult_bboxHeight1 = sizeResult.bboxHeight) != null ? _sizeResult_bboxHeight1 : bboxBottom - bboxTop;
|
|
1391
|
+
// 计算 frame 基线
|
|
1392
|
+
var baselineYFrame = 0;
|
|
1393
|
+
switch(layout.textVerticalAlign){
|
|
1394
|
+
case spec.TextVerticalAlign.top:
|
|
1395
|
+
baselineYFrame = -bboxTop;
|
|
1396
|
+
break;
|
|
1397
|
+
case spec.TextVerticalAlign.middle:
|
|
1398
|
+
baselineYFrame = (frameH - bboxHeight) / 2 - bboxTop;
|
|
1399
|
+
break;
|
|
1400
|
+
case spec.TextVerticalAlign.bottom:
|
|
1401
|
+
baselineYFrame = frameH - bboxHeight - bboxTop;
|
|
1402
|
+
break;
|
|
1403
|
+
}
|
|
1404
|
+
// 上下溢出检测
|
|
1405
|
+
var contentTopInFrame = baselineYFrame + bboxTop;
|
|
1406
|
+
var contentBottomInFrame = baselineYFrame + bboxBottom;
|
|
1407
|
+
var overflowTop = Math.max(0, -contentTopInFrame);
|
|
1408
|
+
var overflowBottom = Math.max(0, contentBottomInFrame - frameH);
|
|
1409
|
+
// 垂直扩张
|
|
1410
|
+
var expandTop = overflowTop;
|
|
1411
|
+
var expandBottom = overflowBottom;
|
|
1412
|
+
switch(layout.textVerticalAlign){
|
|
1413
|
+
case spec.TextVerticalAlign.top:
|
|
1414
|
+
{
|
|
1415
|
+
var E = overflowBottom;
|
|
1416
|
+
expandTop = E;
|
|
1417
|
+
expandBottom = E;
|
|
1418
|
+
break;
|
|
1419
|
+
}
|
|
1420
|
+
case spec.TextVerticalAlign.bottom:
|
|
1421
|
+
{
|
|
1422
|
+
var E1 = overflowTop;
|
|
1423
|
+
expandTop = E1;
|
|
1424
|
+
expandBottom = E1;
|
|
1425
|
+
break;
|
|
1426
|
+
}
|
|
1427
|
+
case spec.TextVerticalAlign.middle:
|
|
1428
|
+
{
|
|
1429
|
+
// 保持非对称:上扩 overflowTop,下扩 overflowBottom
|
|
1430
|
+
expandTop = overflowTop;
|
|
1431
|
+
expandBottom = overflowBottom;
|
|
1432
|
+
break;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
// 位移补偿:始终使用 expandTop
|
|
1436
|
+
var compY = expandTop;
|
|
1437
|
+
// 水平扩张
|
|
1438
|
+
var lines = sizeResult.lines || [];
|
|
1439
|
+
var xOffsetsFrame = lines.map(function(line) {
|
|
1440
|
+
return layout.getOffsetXRich(_this.textStyle, frameW, line.width);
|
|
771
1441
|
});
|
|
1442
|
+
var leftMost = xOffsetsFrame.length > 0 ? (_Math = Math).min.apply(_Math, [].concat(xOffsetsFrame)) : 0;
|
|
1443
|
+
var ex = Math.max(0, -leftMost);
|
|
1444
|
+
var expandLeft = ex;
|
|
1445
|
+
var expandRight = ex;
|
|
1446
|
+
var finalW = frameW + expandLeft + expandRight;
|
|
1447
|
+
var finalH = frameH + expandTop + expandBottom;
|
|
1448
|
+
// 记录补偿,供垂直对齐策略叠加
|
|
1449
|
+
sizeResult.baselineCompensationX = expandLeft;
|
|
1450
|
+
sizeResult.baselineCompensationY = compY;
|
|
1451
|
+
sizeResult.canvasWidth = finalW;
|
|
1452
|
+
sizeResult.canvasHeight = finalH;
|
|
1453
|
+
this.canvasSize = new math.Vector2(finalW, finalH);
|
|
1454
|
+
var _this_size1;
|
|
1455
|
+
var _ref = (_this_size1 = this.size) != null ? _this_size1 : this.item.transform.size, _ref_x = _ref.x, x1 = _ref_x === void 0 ? 1 : _ref_x, _ref_y = _ref.y, y1 = _ref_y === void 0 ? 1 : _ref_y;
|
|
1456
|
+
this.item.transform.size.set(x1 * finalW * this.SCALE_FACTOR * this.SCALE_FACTOR, y1 * finalH * this.SCALE_FACTOR * this.SCALE_FACTOR);
|
|
1457
|
+
this.size = this.item.transform.size.clone();
|
|
1458
|
+
this.initialized = true;
|
|
1459
|
+
break;
|
|
772
1460
|
}
|
|
773
|
-
|
|
774
|
-
|
|
1461
|
+
case spec.TextOverflow.clip:
|
|
1462
|
+
{
|
|
1463
|
+
var frameW1 = layout.maxTextWidth;
|
|
1464
|
+
var frameH1 = layout.maxTextHeight;
|
|
1465
|
+
// 直接使用 frame 尺寸作为画布尺寸
|
|
1466
|
+
sizeResult.canvasWidth = frameW1;
|
|
1467
|
+
sizeResult.canvasHeight = frameH1;
|
|
1468
|
+
// clip 模式不需要任何补偿
|
|
1469
|
+
sizeResult.baselineCompensationX = 0;
|
|
1470
|
+
sizeResult.baselineCompensationY = 0;
|
|
1471
|
+
// 设置 canvas 和节点变换
|
|
1472
|
+
this.canvasSize = new math.Vector2(frameW1, frameH1);
|
|
1473
|
+
// 把 layout 的尺寸更新为 frame 尺寸
|
|
1474
|
+
layout.width = frameW1 / this.textStyle.fontScale;
|
|
1475
|
+
layout.height = frameH1 / this.textStyle.fontScale;
|
|
1476
|
+
var _this_size2;
|
|
1477
|
+
var _ref1 = (_this_size2 = this.size) != null ? _this_size2 : this.item.transform.size, _ref_x1 = _ref1.x, x2 = _ref_x1 === void 0 ? 1 : _ref_x1, _ref_y1 = _ref1.y, y2 = _ref_y1 === void 0 ? 1 : _ref_y1;
|
|
1478
|
+
this.item.transform.size.set(x2 * frameW1 * this.SCALE_FACTOR * this.SCALE_FACTOR, y2 * frameH1 * this.SCALE_FACTOR * this.SCALE_FACTOR);
|
|
1479
|
+
this.size = this.item.transform.size.clone();
|
|
1480
|
+
this.initialized = true;
|
|
1481
|
+
break;
|
|
1482
|
+
}
|
|
1483
|
+
case spec.TextOverflow.display:
|
|
1484
|
+
{
|
|
1485
|
+
if (!this.initialized) {
|
|
1486
|
+
this.canvasSize = new math.Vector2(layout.maxTextWidth, layout.maxTextHeight);
|
|
1487
|
+
this.item.transform.size.set(x * this.canvasSize.x * this.SCALE_FACTOR * this.SCALE_FACTOR, y * this.canvasSize.y * this.SCALE_FACTOR * this.SCALE_FACTOR);
|
|
1488
|
+
this.size = this.item.transform.size.clone();
|
|
1489
|
+
this.initialized = true;
|
|
1490
|
+
}
|
|
1491
|
+
break;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
/**
|
|
1496
|
+
* 尺寸处理
|
|
1497
|
+
*/ _proto.resolveCanvasSize = function resolveCanvasSize(wrapResult, layout, style, singleLineHeight) {
|
|
1498
|
+
var canvasWidth = Math.max(1, wrapResult.maxLineWidth || 0);
|
|
1499
|
+
var canvasHeight = Math.max(1, wrapResult.totalHeight || 0); // stepTotalHeight
|
|
1500
|
+
layout.width = canvasWidth / style.fontScale;
|
|
1501
|
+
layout.height = canvasHeight / style.fontScale;
|
|
1502
|
+
return {
|
|
1503
|
+
canvasWidth: canvasWidth,
|
|
1504
|
+
canvasHeight: canvasHeight,
|
|
1505
|
+
contentWidth: wrapResult.maxLineWidth,
|
|
1506
|
+
bboxTop: wrapResult.bboxTop,
|
|
1507
|
+
bboxBottom: wrapResult.bboxBottom,
|
|
1508
|
+
bboxHeight: wrapResult.bboxHeight,
|
|
1509
|
+
// 为 visible 模式的画布尺寸计算保留行信息
|
|
1510
|
+
lines: wrapResult.lines
|
|
1511
|
+
};
|
|
1512
|
+
};
|
|
1513
|
+
/**
|
|
1514
|
+
* 使用策略结果绘制文本
|
|
1515
|
+
*/ _proto.drawTextWithStrategies = function drawTextWithStrategies(context, lines, horizontalAlignResult, TextVerticalAlignResult, overflowResult, textStyle) {
|
|
1516
|
+
var currentBaselineY = TextVerticalAlignResult.baselineY;
|
|
1517
|
+
var lineOffsets = horizontalAlignResult.lineOffsets;
|
|
1518
|
+
lines.forEach(function(line, index) {
|
|
1519
|
+
var richOptions = line.richOptions, chars = line.chars;
|
|
1520
|
+
var xOffset = lineOffsets[index];
|
|
1521
|
+
var yOffset = currentBaselineY;
|
|
775
1522
|
richOptions.forEach(function(options, segIndex) {
|
|
776
1523
|
var fontScale = textStyle.fontScale, textColor = textStyle.textColor, textFamily = textStyle.fontFamily, textWeight = textStyle.textWeight, richStyle = textStyle.fontStyle;
|
|
777
1524
|
var fontSize = options.fontSize, _options_fontColor = options.fontColor, fontColor = _options_fontColor === void 0 ? textColor : _options_fontColor, _options_fontFamily = options.fontFamily, fontFamily = _options_fontFamily === void 0 ? textFamily : _options_fontFamily, _options_fontWeight = options.fontWeight, fontWeight = _options_fontWeight === void 0 ? textWeight : _options_fontWeight, _options_fontStyle = options.fontStyle, fontStyle = _options_fontStyle === void 0 ? richStyle : _options_fontStyle;
|
|
1525
|
+
// 直接使用原始字体大小(已在行数据中预缩放)
|
|
778
1526
|
var textSize = fontSize;
|
|
779
|
-
if (overflow === spec.TextOverflow.display && width > canvasWidth1) {
|
|
780
|
-
textSize /= width / canvasWidth1;
|
|
781
|
-
}
|
|
782
|
-
var strOffsetX = offset[segIndex] + x;
|
|
783
1527
|
context.font = fontStyle + " " + fontWeight + " " + textSize * fontScale + "px " + fontFamily;
|
|
784
|
-
|
|
1528
|
+
var r = fontColor[0], g = fontColor[1], b = fontColor[2], a = fontColor[3];
|
|
1529
|
+
context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + a + ")";
|
|
785
1530
|
// 逐字绘制
|
|
786
|
-
var
|
|
1531
|
+
var segStartX = line.offsetX && line.offsetX[segIndex] ? line.offsetX[segIndex] : 0;
|
|
1532
|
+
var charArr = chars[segIndex];
|
|
787
1533
|
charArr.forEach(function(charDetail) {
|
|
788
|
-
|
|
1534
|
+
// 直接使用缩放后的字符位置
|
|
1535
|
+
context.fillText(charDetail.char, xOffset + segStartX + charDetail.x, yOffset);
|
|
789
1536
|
});
|
|
790
1537
|
});
|
|
791
1538
|
// 推进到下一行
|
|
792
|
-
if (index <
|
|
793
|
-
|
|
1539
|
+
if (index < lines.length - 1) {
|
|
1540
|
+
currentBaselineY += lines[index + 1].lineHeight;
|
|
794
1541
|
}
|
|
795
1542
|
});
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
width: imageData.width,
|
|
800
|
-
height: imageData.height
|
|
801
|
-
}, {
|
|
802
|
-
flipY: flipY,
|
|
803
|
-
magFilter: glContext.LINEAR,
|
|
804
|
-
minFilter: glContext.LINEAR,
|
|
805
|
-
wrapS: glContext.CLAMP_TO_EDGE,
|
|
806
|
-
wrapT: glContext.CLAMP_TO_EDGE
|
|
807
|
-
});
|
|
808
|
-
this.renderer.texture = texture;
|
|
809
|
-
this.material.setTexture("_MainTex", texture);
|
|
810
|
-
this.isDirty = false;
|
|
811
|
-
context.restore();
|
|
1543
|
+
};
|
|
1544
|
+
_proto.unsupported = function unsupported(name) {
|
|
1545
|
+
throw new Error("RichTextComponent does not support " + name + " at runtime.");
|
|
812
1546
|
};
|
|
813
1547
|
/**
|
|
814
1548
|
* 该方法富文本组件不支持
|
|
815
1549
|
* @param value - 水平偏移距离
|
|
816
1550
|
* @returns
|
|
817
1551
|
*/ _proto.setShadowOffsetY = function setShadowOffsetY(value) {
|
|
818
|
-
|
|
1552
|
+
this.unsupported("setShadowOffsetY");
|
|
819
1553
|
};
|
|
820
1554
|
/**
|
|
821
1555
|
* 该方法富文本组件不支持
|
|
822
1556
|
* @param value - 模糊程度
|
|
823
1557
|
*/ _proto.setShadowBlur = function setShadowBlur(value) {
|
|
824
|
-
|
|
1558
|
+
this.unsupported("setShadowBlur");
|
|
825
1559
|
};
|
|
826
1560
|
/**
|
|
827
1561
|
* 该方法富文本组件不支持
|
|
828
1562
|
* @param value - 水平偏移距离
|
|
829
1563
|
*/ _proto.setShadowOffsetX = function setShadowOffsetX(value) {
|
|
830
|
-
|
|
1564
|
+
this.unsupported("setShadowOffsetX");
|
|
831
1565
|
};
|
|
832
1566
|
/**
|
|
833
1567
|
* 该方法富文本组件不支持
|
|
834
1568
|
* @param value - 阴影颜色
|
|
835
1569
|
*/ _proto.setShadowColor = function setShadowColor(value) {
|
|
836
|
-
|
|
1570
|
+
this.unsupported("setShadowColor");
|
|
837
1571
|
};
|
|
838
1572
|
/**
|
|
839
1573
|
* 该方法富文本组件不支持
|
|
840
1574
|
* @param value - 外描边宽度
|
|
841
1575
|
* @returns
|
|
842
1576
|
*/ _proto.setOutlineWidth = function setOutlineWidth(value) {
|
|
843
|
-
|
|
1577
|
+
this.unsupported("setOutlineWidth");
|
|
844
1578
|
};
|
|
845
1579
|
/**
|
|
846
1580
|
* 该方法富文本组件不支持
|
|
847
1581
|
* @param value - 是否自动设置宽度
|
|
848
1582
|
*/ _proto.setAutoWidth = function setAutoWidth(value) {
|
|
849
|
-
|
|
1583
|
+
this.unsupported("setAutoWidth");
|
|
850
1584
|
};
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
this.
|
|
855
|
-
this.text = options.text ? options.text.toString() : " ";
|
|
1585
|
+
/**
|
|
1586
|
+
* 该方法富文本组件不支持
|
|
1587
|
+
*/ _proto.setFontSize = function setFontSize(value) {
|
|
1588
|
+
this.unsupported("setFontSize");
|
|
856
1589
|
};
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
this.updateTexture();
|
|
1590
|
+
/**
|
|
1591
|
+
* @deprecated 2.8.0 本方法已废弃,请使用 setTextVerticalAlign 替代。
|
|
1592
|
+
*/ _proto.setTextBaseline = function setTextBaseline(value) {
|
|
1593
|
+
console.warn("setTextBaseline 已废弃,请改用 setTextVerticalAlign。" + "本次调用将转调用 setTextVerticalAlign。");
|
|
1594
|
+
this.setTextVerticalAlign(value);
|
|
863
1595
|
};
|
|
864
1596
|
return RichTextComponent;
|
|
865
|
-
}(
|
|
1597
|
+
}(MaskableGraphic);
|
|
866
1598
|
RichTextComponent = __decorate([
|
|
867
1599
|
effectsClass(spec.DataType.RichTextComponent)
|
|
868
1600
|
], RichTextComponent);
|
|
1601
|
+
applyMixins(RichTextComponent, [
|
|
1602
|
+
TextComponentBase
|
|
1603
|
+
]);
|
|
869
1604
|
|
|
870
1605
|
/**
|
|
871
1606
|
* 插件版本号
|
|
872
|
-
*/ var version = "2.
|
|
1607
|
+
*/ var version = "2.8.0-alpha.1";
|
|
873
1608
|
registerPlugin("rich-text", RichTextLoader, VFXItem);
|
|
874
1609
|
logger.info("Plugin rich text version: " + version + ".");
|
|
875
1610
|
if (version !== EFFECTS.version) {
|