zrender-nightly 6.0.0-dev.20250718 → 6.0.0-dev.20250719

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.
@@ -1,9 +1,9 @@
1
1
  import { __extends } from "tslib";
2
2
  import Displayable from './Displayable.js';
3
- import { getBoundingRect } from '../contain/text.js';
4
3
  import { DEFAULT_PATH_STYLE } from './Path.js';
5
4
  import { createObject, defaults } from '../core/util.js';
6
5
  import { DEFAULT_FONT } from '../core/platform.js';
6
+ import { tSpanCreateBoundingRect, tSpanHasStroke } from './helper/parseText.js';
7
7
  export var DEFAULT_TSPAN_STYLE = defaults({
8
8
  strokeFirst: true,
9
9
  font: DEFAULT_FONT,
@@ -19,9 +19,7 @@ var TSpan = (function (_super) {
19
19
  return _super !== null && _super.apply(this, arguments) || this;
20
20
  }
21
21
  TSpan.prototype.hasStroke = function () {
22
- var style = this.style;
23
- var stroke = style.stroke;
24
- return stroke != null && stroke !== 'none' && style.lineWidth > 0;
22
+ return tSpanHasStroke(this.style);
25
23
  };
26
24
  TSpan.prototype.hasFill = function () {
27
25
  var style = this.style;
@@ -35,21 +33,8 @@ var TSpan = (function (_super) {
35
33
  this._rect = rect;
36
34
  };
37
35
  TSpan.prototype.getBoundingRect = function () {
38
- var style = this.style;
39
36
  if (!this._rect) {
40
- var text = style.text;
41
- text != null ? (text += '') : (text = '');
42
- var rect = getBoundingRect(text, style.font, style.textAlign, style.textBaseline);
43
- rect.x += style.x || 0;
44
- rect.y += style.y || 0;
45
- if (this.hasStroke()) {
46
- var w = style.lineWidth;
47
- rect.x -= w / 2;
48
- rect.y -= w / 2;
49
- rect.width += w;
50
- rect.height += w;
51
- }
52
- this._rect = rect;
37
+ this._rect = tSpanCreateBoundingRect(this.style);
53
38
  }
54
39
  return this._rect;
55
40
  };
@@ -1,5 +1,5 @@
1
1
  import { __extends } from "tslib";
2
- import { parseRichText, parsePlainText, calcInnerTextOverflowArea } from './helper/parseText.js';
2
+ import { parseRichText, parsePlainText, calcInnerTextOverflowArea, tSpanCreateBoundingRect2, } from './helper/parseText.js';
3
3
  import TSpan from './TSpan.js';
4
4
  import { retrieve2, each, normalizeCssArray, trim, retrieve3, extend, keys, defaults } from '../core/util.js';
5
5
  import { adjustTextX, adjustTextY } from '../contain/text.js';
@@ -200,7 +200,6 @@ var ZRText = (function (_super) {
200
200
  var bgColorDrawn = !!(style.backgroundColor);
201
201
  var outerHeight = contentBlock.outerHeight;
202
202
  var outerWidth = contentBlock.outerWidth;
203
- var contentWidth = contentBlock.contentWidth;
204
203
  var textLines = contentBlock.lines;
205
204
  var lineHeight = contentBlock.lineHeight;
206
205
  this.isTruncated = !!contentBlock.isTruncated;
@@ -222,6 +221,7 @@ var ZRText = (function (_super) {
222
221
  }
223
222
  }
224
223
  var defaultLineWidth = 0;
224
+ var usingDefaultStroke = false;
225
225
  var useDefaultFill = false;
226
226
  var textFill = getFill('fill' in style
227
227
  ? style.fill
@@ -230,12 +230,9 @@ var ZRText = (function (_super) {
230
230
  ? style.stroke
231
231
  : (!bgColorDrawn
232
232
  && (!defaultStyle.autoStroke || useDefaultFill))
233
- ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke)
233
+ ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, usingDefaultStroke = true, defaultStyle.stroke)
234
234
  : null);
235
235
  var hasShadow = style.textShadowBlur > 0;
236
- var fixedBoundingRect = style.width != null
237
- && (style.overflow === 'truncate' || style.overflow === 'break' || style.overflow === 'breakAll');
238
- var calculatedLineHeight = contentBlock.calculatedLineHeight;
239
236
  for (var i = 0; i < textLines.length; i++) {
240
237
  var el = this._getOrCreateChild(TSpan);
241
238
  var subElStyle = el.createStyle();
@@ -265,9 +262,7 @@ var ZRText = (function (_super) {
265
262
  subElStyle.font = textFont;
266
263
  setSeparateFont(subElStyle, style);
267
264
  textY += lineHeight;
268
- if (fixedBoundingRect) {
269
- el.setBoundingRect(new BoundingRect(adjustTextX(subElStyle.x, contentWidth, subElStyle.textAlign), adjustTextY(subElStyle.y, calculatedLineHeight, subElStyle.textBaseline), contentWidth, calculatedLineHeight));
270
- }
265
+ el.setBoundingRect(tSpanCreateBoundingRect2(subElStyle, contentBlock.contentWidth, contentBlock.calculatedLineHeight, usingDefaultStroke ? 0 : null));
271
266
  }
272
267
  };
273
268
  ZRText.prototype._updateRichTexts = function () {
@@ -364,6 +359,7 @@ var ZRText = (function (_super) {
364
359
  var defaultStyle = this._defaultStyle;
365
360
  var useDefaultFill = false;
366
361
  var defaultLineWidth = 0;
362
+ var usingDefaultStroke = false;
367
363
  var textFill = getFill('fill' in tokenStyle ? tokenStyle.fill
368
364
  : 'fill' in style ? style.fill
369
365
  : (useDefaultFill = true, defaultStyle.fill));
@@ -371,7 +367,7 @@ var ZRText = (function (_super) {
371
367
  : 'stroke' in style ? style.stroke
372
368
  : (!bgColorDrawn
373
369
  && !parentBgColorDrawn
374
- && (!defaultStyle.autoStroke || useDefaultFill)) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke)
370
+ && (!defaultStyle.autoStroke || useDefaultFill)) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, usingDefaultStroke = true, defaultStyle.stroke)
375
371
  : null);
376
372
  var hasShadow = tokenStyle.textShadowBlur > 0
377
373
  || style.textShadowBlur > 0;
@@ -398,9 +394,7 @@ var ZRText = (function (_super) {
398
394
  if (textFill) {
399
395
  subElStyle.fill = textFill;
400
396
  }
401
- var textWidth = token.contentWidth;
402
- var textHeight = token.contentHeight;
403
- el.setBoundingRect(new BoundingRect(adjustTextX(subElStyle.x, textWidth, subElStyle.textAlign), adjustTextY(subElStyle.y, textHeight, subElStyle.textBaseline), textWidth, textHeight));
397
+ el.setBoundingRect(tSpanCreateBoundingRect2(subElStyle, token.contentWidth, token.contentHeight, usingDefaultStroke ? 0 : null));
404
398
  };
405
399
  ZRText.prototype._renderBackground = function (style, topStyle, x, y, width, height) {
406
400
  var textBackgroundColor = style.backgroundColor;
@@ -1,5 +1,7 @@
1
1
  import { TextAlign, TextVerticalAlign, NullUndefined } from '../../core/types';
2
- import { DefaultTextStyle, TextStyleProps } from '../Text';
2
+ import type { DefaultTextStyle, TextStyleProps } from '../Text';
3
+ import type { TSpanStyleProps } from '../TSpan';
4
+ import BoundingRect from '../../core/BoundingRect';
3
5
  interface InnerTruncateOption {
4
6
  maxIteration?: number;
5
7
  minChar?: number;
@@ -19,7 +21,7 @@ export interface PlainTextContentBlock {
19
21
  lines: string[];
20
22
  isTruncated: boolean;
21
23
  }
22
- export declare function parsePlainText(text: string, style: Omit<TextStyleProps, 'align' | 'verticalAlign'>, defaultOuterWidth: number | NullUndefined, defaultOuterHeight: number | NullUndefined): PlainTextContentBlock;
24
+ export declare function parsePlainText(rawText: unknown, style: Omit<TextStyleProps, 'align' | 'verticalAlign'>, defaultOuterWidth: number | NullUndefined, defaultOuterHeight: number | NullUndefined): PlainTextContentBlock;
23
25
  declare class RichTextToken {
24
26
  styleName: string;
25
27
  text: string;
@@ -52,7 +54,7 @@ export declare class RichTextContentBlock {
52
54
  lines: RichTextLine[];
53
55
  isTruncated: boolean;
54
56
  }
55
- export declare function parseRichText(text: string, style: Omit<TextStyleProps, 'align' | 'verticalAlign'>, defaultOuterWidth: number | NullUndefined, defaultOuterHeight: number | NullUndefined, topTextAlign: TextAlign): RichTextContentBlock;
57
+ export declare function parseRichText(rawText: unknown, style: Omit<TextStyleProps, 'align' | 'verticalAlign'>, defaultOuterWidth: number | NullUndefined, defaultOuterHeight: number | NullUndefined, topTextAlign: TextAlign): RichTextContentBlock;
56
58
  export declare function calcInnerTextOverflowArea(out: CalcInnerTextOverflowAreaOut, overflowRect: DefaultTextStyle['overflowRect'], baseX: number, baseY: number, textAlign: TextAlign, textVerticalAlign: TextVerticalAlign): void;
57
59
  export declare type CalcInnerTextOverflowAreaOut = {
58
60
  baseX: number;
@@ -60,4 +62,7 @@ export declare type CalcInnerTextOverflowAreaOut = {
60
62
  outerWidth: number | NullUndefined;
61
63
  outerHeight: number | NullUndefined;
62
64
  };
65
+ export declare function tSpanCreateBoundingRect(style: Pick<TSpanStyleProps, 'text' | 'font' | 'x' | 'y' | 'textAlign' | 'textBaseline' | 'lineWidth'>): BoundingRect;
66
+ export declare function tSpanCreateBoundingRect2(style: Pick<TSpanStyleProps, 'x' | 'y' | 'textAlign' | 'textBaseline' | 'lineWidth'>, contentWidth: number, contentHeight: number, forceLineWidth: number | NullUndefined): BoundingRect;
67
+ export declare function tSpanHasStroke(style: TSpanStyleProps): boolean;
63
68
  export {};
@@ -93,8 +93,8 @@ function estimateLength(text, contentWidth, fontMeasureInfo) {
93
93
  }
94
94
  return i;
95
95
  }
96
- export function parsePlainText(text, style, defaultOuterWidth, defaultOuterHeight) {
97
- text != null && (text += '');
96
+ export function parsePlainText(rawText, style, defaultOuterWidth, defaultOuterHeight) {
97
+ var text = formatText(rawText);
98
98
  var overflow = style.overflow;
99
99
  var padding = style.padding;
100
100
  var paddingH = padding ? padding[1] + padding[3] : 0;
@@ -195,9 +195,9 @@ var RichTextContentBlock = (function () {
195
195
  return RichTextContentBlock;
196
196
  }());
197
197
  export { RichTextContentBlock };
198
- export function parseRichText(text, style, defaultOuterWidth, defaultOuterHeight, topTextAlign) {
198
+ export function parseRichText(rawText, style, defaultOuterWidth, defaultOuterHeight, topTextAlign) {
199
199
  var contentBlock = new RichTextContentBlock();
200
- text != null && (text += '');
200
+ var text = formatText(rawText);
201
201
  if (!text) {
202
202
  return contentBlock;
203
203
  }
@@ -523,3 +523,30 @@ export function calcInnerTextOverflowArea(out, overflowRect, baseX, baseY, textA
523
523
  }
524
524
  var tmpCITCTextRect = new BoundingRect(0, 0, 0, 0);
525
525
  var tmpCITCIntersectRectOpt = { outIntersectRect: {}, clamp: true };
526
+ function formatText(text) {
527
+ return text != null ? (text += '') : (text = '');
528
+ }
529
+ export function tSpanCreateBoundingRect(style) {
530
+ var text = formatText(style.text);
531
+ var font = style.font;
532
+ var contentWidth = measureWidth(ensureFontMeasureInfo(font), text);
533
+ var contentHeight = getLineHeight(font);
534
+ return tSpanCreateBoundingRect2(style, contentWidth, contentHeight, null);
535
+ }
536
+ export function tSpanCreateBoundingRect2(style, contentWidth, contentHeight, forceLineWidth) {
537
+ var rect = new BoundingRect(adjustTextX(style.x || 0, contentWidth, style.textAlign), adjustTextY(style.y || 0, contentHeight, style.textBaseline), contentWidth, contentHeight);
538
+ var lineWidth = forceLineWidth != null
539
+ ? forceLineWidth
540
+ : (tSpanHasStroke(style) ? style.lineWidth : 0);
541
+ if (lineWidth > 0) {
542
+ rect.x -= lineWidth / 2;
543
+ rect.y -= lineWidth / 2;
544
+ rect.width += lineWidth;
545
+ rect.height += lineWidth;
546
+ }
547
+ return rect;
548
+ }
549
+ export function tSpanHasStroke(style) {
550
+ var stroke = style.stroke;
551
+ return stroke != null && stroke !== 'none' && style.lineWidth > 0;
552
+ }
package/lib/zrender.d.ts CHANGED
@@ -90,7 +90,7 @@ export declare type ElementSSRData = zrUtil.HashMap<unknown>;
90
90
  export declare type ElementSSRDataGetter<T> = (el: Element) => zrUtil.HashMap<T>;
91
91
  export declare function getElementSSRData(el: Element): ElementSSRData;
92
92
  export declare function registerSSRDataGetter<T>(getter: ElementSSRDataGetter<T>): void;
93
- export declare const version = "6.0.0-dev.20250718";
93
+ export declare const version = "6.0.0-dev.20250719";
94
94
  export interface ZRenderType extends ZRender {
95
95
  }
96
96
  export {};
package/lib/zrender.js CHANGED
@@ -324,5 +324,5 @@ export function getElementSSRData(el) {
324
324
  export function registerSSRDataGetter(getter) {
325
325
  ssrDataGetter = getter;
326
326
  }
327
- export var version = '6.0.0-dev.20250718';
327
+ export var version = '6.0.0-dev.20250719';
328
328
  ;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zrender-nightly",
3
- "version": "6.0.0-dev.20250718",
3
+ "version": "6.0.0-dev.20250719",
4
4
  "description": "A lightweight graphic library providing 2d draw for Apache ECharts",
5
5
  "keywords": [
6
6
  "canvas",
@@ -106,7 +106,7 @@ export function measureWidth(fontMeasureInfo: FontMeasureInfo, text: string): nu
106
106
 
107
107
 
108
108
  /**
109
- *
109
+ * @deprecated See `getBoundingRect`.
110
110
  * Get bounding rect for inner usage(TSpan)
111
111
  * Which not include text newline.
112
112
  */
@@ -128,6 +128,9 @@ export function innerGetBoundingRect(
128
128
  }
129
129
 
130
130
  /**
131
+ * @deprecated Use `(new Text(...)).getBoundingRect()` or `(new TSpan(...)).getBoundingRect()` instead.
132
+ * This method behaves differently from `Text#getBoundingRect()` - e.g., it does not support the overflow
133
+ * strategy, and only has single line height even if multiple lines.
131
134
  *
132
135
  * Get bounding rect for outer usage. Compatitable with old implementation
133
136
  * Which includes text newline.
@@ -1,10 +1,10 @@
1
1
  import Displayable, { DisplayableProps, DisplayableStatePropNames } from './Displayable';
2
- import { getBoundingRect } from '../contain/text';
3
2
  import BoundingRect from '../core/BoundingRect';
4
3
  import { PathStyleProps, DEFAULT_PATH_STYLE } from './Path';
5
4
  import { createObject, defaults } from '../core/util';
6
- import { FontStyle, FontWeight, TextAlign, TextVerticalAlign } from '../core/types';
5
+ import { FontStyle, FontWeight } from '../core/types';
7
6
  import { DEFAULT_FONT } from '../core/platform';
7
+ import { tSpanCreateBoundingRect, tSpanHasStroke } from './helper/parseText';
8
8
 
9
9
  export interface TSpanStyleProps extends PathStyleProps {
10
10
 
@@ -53,9 +53,7 @@ class TSpan extends Displayable<TSpanProps> {
53
53
  style: TSpanStyleProps
54
54
 
55
55
  hasStroke() {
56
- const style = this.style;
57
- const stroke = style.stroke;
58
- return stroke != null && stroke !== 'none' && style.lineWidth > 0;
56
+ return tSpanHasStroke(this.style);
59
57
  }
60
58
 
61
59
  hasFill() {
@@ -81,31 +79,8 @@ class TSpan extends Displayable<TSpanProps> {
81
79
  }
82
80
 
83
81
  getBoundingRect(): BoundingRect {
84
- const style = this.style;
85
-
86
82
  if (!this._rect) {
87
- let text = style.text;
88
- text != null ? (text += '') : (text = '');
89
-
90
- const rect = getBoundingRect(
91
- text,
92
- style.font,
93
- style.textAlign as TextAlign,
94
- style.textBaseline as TextVerticalAlign
95
- );
96
-
97
- rect.x += style.x || 0;
98
- rect.y += style.y || 0;
99
-
100
- if (this.hasStroke()) {
101
- const w = style.lineWidth;
102
- rect.x -= w / 2;
103
- rect.y -= w / 2;
104
- rect.width += w;
105
- rect.height += w;
106
- }
107
-
108
- this._rect = rect;
83
+ this._rect = tSpanCreateBoundingRect(this.style);
109
84
  }
110
85
 
111
86
  return this._rect;
@@ -6,7 +6,8 @@ import {
6
6
  TextAlign, TextVerticalAlign, ImageLike, Dictionary, MapToType, FontWeight, FontStyle, NullUndefined
7
7
  } from '../core/types';
8
8
  import {
9
- parseRichText, parsePlainText, CalcInnerTextOverflowAreaOut, calcInnerTextOverflowArea
9
+ parseRichText, parsePlainText, CalcInnerTextOverflowAreaOut, calcInnerTextOverflowArea,
10
+ tSpanCreateBoundingRect2,
10
11
  } from './helper/parseText';
11
12
  import TSpan, { TSpanStyleProps } from './TSpan';
12
13
  import { retrieve2, each, normalizeCssArray, trim, retrieve3, extend, keys, defaults } from '../core/util';
@@ -332,7 +333,7 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
332
333
  }
333
334
  }
334
335
 
335
- updateTransform() {
336
+ updateTransform() {
336
337
  const innerTransformable = this.innerTransformable;
337
338
  if (innerTransformable) {
338
339
  innerTransformable.updateTransform();
@@ -528,7 +529,6 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
528
529
 
529
530
  const outerHeight = contentBlock.outerHeight;
530
531
  const outerWidth = contentBlock.outerWidth;
531
- const contentWidth = contentBlock.contentWidth;
532
532
 
533
533
  const textLines = contentBlock.lines;
534
534
  const lineHeight = contentBlock.lineHeight;
@@ -544,6 +544,13 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
544
544
  const boxY = adjustTextY(baseY, outerHeight, verticalAlign);
545
545
  needDrawBg && this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight);
546
546
  }
547
+ // PENDING:
548
+ // Should text bounding rect contains style.padding, style.width, style.height when NO background
549
+ // and border displayed? It depends on how to define "boundingRect". HTML `getBoundingClientRect`
550
+ // contains padding in that case. But currently ZRText does not.
551
+ // If implement that, an extra invisible Rect may need to be added as the placeholder for the bounding
552
+ // rect computation, considering animation of padding. But will it degrade performance for the most
553
+ // used plain texts cases?
547
554
 
548
555
  // `textBaseline` is set as 'middle'.
549
556
  textY += lineHeight / 2;
@@ -559,6 +566,7 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
559
566
  }
560
567
 
561
568
  let defaultLineWidth = 0;
569
+ let usingDefaultStroke = false;
562
570
  let useDefaultFill = false;
563
571
  const textFill = getFill(
564
572
  'fill' in style
@@ -580,16 +588,12 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
580
588
  // we give the auto lineWidth to display the given stoke color.
581
589
  && (!defaultStyle.autoStroke || useDefaultFill)
582
590
  )
583
- ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke)
591
+ ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, usingDefaultStroke = true, defaultStyle.stroke)
584
592
  : null
585
593
  );
586
594
 
587
595
  const hasShadow = style.textShadowBlur > 0;
588
596
 
589
- const fixedBoundingRect = style.width != null
590
- && (style.overflow === 'truncate' || style.overflow === 'break' || style.overflow === 'breakAll');
591
- const calculatedLineHeight = contentBlock.calculatedLineHeight;
592
-
593
597
  for (let i = 0; i < textLines.length; i++) {
594
598
  const el = this._getOrCreateChild(TSpan);
595
599
  // Always create new style.
@@ -633,19 +637,27 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
633
637
 
634
638
  textY += lineHeight;
635
639
 
636
- if (fixedBoundingRect) {
637
- el.setBoundingRect(new BoundingRect(
638
- adjustTextX(subElStyle.x, contentWidth, subElStyle.textAlign as TextAlign),
639
- adjustTextY(subElStyle.y, calculatedLineHeight, subElStyle.textBaseline as TextVerticalAlign),
640
- /**
641
- * Text boundary should be the real text width.
642
- * Otherwise, there will be extra space in the
643
- * bounding rect calculated.
644
- */
645
- contentWidth,
646
- calculatedLineHeight
647
- ));
648
- }
640
+ // Always set tspan bounding rect to guarantee the consistency if users lays out based
641
+ // on these bounding rects.
642
+ el.setBoundingRect(tSpanCreateBoundingRect2(
643
+ subElStyle,
644
+ contentBlock.contentWidth,
645
+ contentBlock.calculatedLineHeight,
646
+ // Should text bounding rect includes text stroke width?
647
+ // Pros:
648
+ // - Intuitively, and by convention, bounding rect of `Path` always includes stroke width.
649
+ // Cons:
650
+ // - It's unpredictable for users whether "auto stroke" is applied. If stroke width is included
651
+ // and multiple texts are laid out based on its bounding rect, the position of texts may vary
652
+ // and is unpredictable - especially in limited space (e.g., see echarts pie label cases).
653
+ // - "auto stroke" attempts to use the same color as the background to make the border to be
654
+ // invisible in most cases, thus it might be more reasonable to be excluded from bounding rect.
655
+ // Conclusion:
656
+ // - If users specifies style.stroke, it will be included into the bounding rect as normal.
657
+ // Otherwise, keep the stroke width as `0` in this case to guarantee consistency of bounding
658
+ // rect based layout, regardless of whether "auto stroke" is applied.
659
+ usingDefaultStroke ? 0 : null
660
+ ));
649
661
  }
650
662
  }
651
663
 
@@ -801,6 +813,7 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
801
813
  const defaultStyle = this._defaultStyle;
802
814
  let useDefaultFill = false;
803
815
  let defaultLineWidth = 0;
816
+ let usingDefaultStroke = false;
804
817
  const textFill = getFill(
805
818
  'fill' in tokenStyle ? tokenStyle.fill
806
819
  : 'fill' in style ? style.fill
@@ -812,9 +825,9 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
812
825
  : (
813
826
  !bgColorDrawn
814
827
  && !parentBgColorDrawn
815
- // See the strategy explained above.
828
+ // See the strategy explained `_updatePlainTexts`.
816
829
  && (!defaultStyle.autoStroke || useDefaultFill)
817
- ) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke)
830
+ ) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, usingDefaultStroke = true, defaultStyle.stroke)
818
831
  : null
819
832
  );
820
833
 
@@ -852,14 +865,13 @@ class ZRText extends Displayable<TextProps> implements GroupLike {
852
865
  subElStyle.fill = textFill;
853
866
  }
854
867
 
855
- const textWidth = token.contentWidth;
856
- const textHeight = token.contentHeight;
857
868
  // NOTE: Should not call dirtyStyle after setBoundingRect. Or it will be cleared.
858
- el.setBoundingRect(new BoundingRect(
859
- adjustTextX(subElStyle.x, textWidth, subElStyle.textAlign as TextAlign),
860
- adjustTextY(subElStyle.y, textHeight, subElStyle.textBaseline as TextVerticalAlign),
861
- textWidth,
862
- textHeight
869
+ el.setBoundingRect(tSpanCreateBoundingRect2(
870
+ subElStyle,
871
+ token.contentWidth,
872
+ token.contentHeight,
873
+ // See the strategy explained `_updatePlainTexts`.
874
+ usingDefaultStroke ? 0 : null
863
875
  ));
864
876
  }
865
877
 
@@ -6,7 +6,8 @@ import {
6
6
  reduce,
7
7
  } from '../../core/util';
8
8
  import { TextAlign, TextVerticalAlign, ImageLike, Dictionary, NullUndefined } from '../../core/types';
9
- import { DefaultTextStyle, TextStyleProps } from '../Text';
9
+ import type { DefaultTextStyle, TextStyleProps } from '../Text';
10
+ import type { TSpanStyleProps } from '../TSpan';
10
11
  import {
11
12
  adjustTextX,
12
13
  adjustTextY,
@@ -210,12 +211,12 @@ export interface PlainTextContentBlock {
210
211
  }
211
212
 
212
213
  export function parsePlainText(
213
- text: string,
214
+ rawText: unknown,
214
215
  style: Omit<TextStyleProps, 'align' | 'verticalAlign'>, // Exclude props in DefaultTextStyle
215
216
  defaultOuterWidth: number | NullUndefined,
216
217
  defaultOuterHeight: number | NullUndefined
217
218
  ): PlainTextContentBlock {
218
- text != null && (text += '');
219
+ const text = formatText(rawText);
219
220
 
220
221
  // textPadding has been normalized
221
222
  const overflow = style.overflow;
@@ -382,7 +383,7 @@ type WrapInfo = {
382
383
  * If styleName is undefined, it is plain text.
383
384
  */
384
385
  export function parseRichText(
385
- text: string,
386
+ rawText: unknown,
386
387
  style: Omit<TextStyleProps, 'align' | 'verticalAlign'>, // Exclude props in DefaultTextStyle
387
388
  defaultOuterWidth: number | NullUndefined,
388
389
  defaultOuterHeight: number | NullUndefined,
@@ -390,7 +391,7 @@ export function parseRichText(
390
391
  ): RichTextContentBlock {
391
392
  const contentBlock = new RichTextContentBlock();
392
393
 
393
- text != null && (text += '');
394
+ const text = formatText(rawText);
394
395
  if (!text) {
395
396
  return contentBlock;
396
397
  }
@@ -890,3 +891,61 @@ export type CalcInnerTextOverflowAreaOut = {
890
891
  outerHeight: number | NullUndefined
891
892
  };
892
893
 
894
+ // For backward compatibility, and possibly loose type.
895
+ function formatText(text: unknown): string {
896
+ return text != null ? (text += '') : (text = '');
897
+ }
898
+
899
+ export function tSpanCreateBoundingRect(
900
+ style: Pick<TSpanStyleProps, 'text' | 'font' | 'x' | 'y' | 'textAlign' | 'textBaseline' | 'lineWidth'>,
901
+ ): BoundingRect {
902
+ // Should follow the same way as `parsePlainText` to guarantee the consistency of the result.
903
+ const text = formatText(style.text);
904
+ const font = style.font;
905
+ const contentWidth = measureWidth(ensureFontMeasureInfo(font), text);
906
+ const contentHeight = getLineHeight(font);
907
+
908
+ return tSpanCreateBoundingRect2(
909
+ style,
910
+ contentWidth,
911
+ contentHeight,
912
+ null
913
+ );
914
+ }
915
+
916
+ export function tSpanCreateBoundingRect2(
917
+ style: Pick<TSpanStyleProps, 'x' | 'y' | 'textAlign' | 'textBaseline' | 'lineWidth'>,
918
+ contentWidth: number,
919
+ contentHeight: number,
920
+ forceLineWidth: number | NullUndefined,
921
+ ): BoundingRect {
922
+ const rect = new BoundingRect(
923
+ adjustTextX(style.x || 0, contentWidth, style.textAlign as TextAlign),
924
+ adjustTextY(style.y || 0, contentHeight, style.textBaseline as TextVerticalAlign),
925
+ /**
926
+ * Text boundary should be the real text width.
927
+ * Otherwise, there will be extra space in the
928
+ * bounding rect calculated.
929
+ */
930
+ contentWidth,
931
+ contentHeight
932
+ );
933
+
934
+ const lineWidth = forceLineWidth != null
935
+ ? forceLineWidth
936
+ : (tSpanHasStroke(style) ? style.lineWidth : 0);
937
+ if (lineWidth > 0) {
938
+ rect.x -= lineWidth / 2;
939
+ rect.y -= lineWidth / 2;
940
+ rect.width += lineWidth;
941
+ rect.height += lineWidth;
942
+ }
943
+
944
+ return rect;
945
+ }
946
+
947
+ export function tSpanHasStroke(style: TSpanStyleProps): boolean {
948
+ const stroke = style.stroke;
949
+ return stroke != null && stroke !== 'none' && style.lineWidth > 0;
950
+ }
951
+
package/src/zrender.ts CHANGED
@@ -556,7 +556,7 @@ export function registerSSRDataGetter<T>(getter: ElementSSRDataGetter<T>) {
556
556
  /**
557
557
  * @type {string}
558
558
  */
559
- export const version = '6.0.0-dev.20250718';
559
+ export const version = '6.0.0-dev.20250719';
560
560
 
561
561
 
562
562
  export interface ZRenderType extends ZRender {};